Enable your tokens in CCIP (Burn & Mint): Register from Safe multisig using Hardhat

This tutorial will guide you through enabling your tokens in CCIP using Hardhat and Safe Multisig smart accounts. You will learn how to deploy tokens and set up Burn & Mint token pools using a 2-of-3 multi-signature Safe. After that, you will register the tokens in CCIP and configure them using multisig transactions without needing manual intervention. Finally, you will test the Burn & Mint token handling mechanism, where tokens are burned on the source blockchain, and an equivalent amount is minted on the destination blockchain.

Introduction to Smart Accounts and Safe Multisig

Introduction

A smart account (also known as a smart contract account) leverages the programmability of smart contracts to extend their functionality and improve their security compared to externally owned accounts (EOAs). Smart accounts are controlled by one or multiple EOAs or other smart accounts, and all transactions must be initiated by one of these controllers.

Some common features of smart accounts include:

  • Multi-signature schemes: Require multiple approvals for a transaction to be executed, enhancing security.
  • Transaction batching: Combine multiple actions into a single transaction, reducing costs and improving efficiency.
  • Account recovery: Allow for recovery mechanisms in case of lost access.
  • Gasless transactions: Enable transaction fees to be paid by a third party or relayer.

Safe is one of the most trusted implementations of a smart account, offering a robust multi-signature mechanism. In this tutorial, we will use a Safe Multisig account, specifically a 2-of-3 multi-signature setup, where two out of three owners must approve a transaction to execute it. This setup ensures enhanced security and decentralized control over the assets.

The Protocol Kit from Safe allows developers to interact with Safe, smart accounts through a TypeScript interface. This kit can be used to create new Safe accounts, update configurations, propose transactions, and execute them, making it an ideal choice for blockchain projects.

How Safe Multisig Works

Before we proceed, let's take a moment to understand how the multisig transaction process works with a Safe smart account.

In this tutorial, we'll use a 2-of-3 multi-signature setup as an example, where at least two out of the three Smart Account Owners must approve each transaction. Depending on your project's needs, this multisig process is valid for any scheme (e.g., 3-of-5, 4-of-7). In Safe smart accounts, the Smart Account Owners are responsible for approving actions. Transactions are signed off-chain by the required number of owners, which improves efficiency and reduces gas costs. Once the necessary threshold is met, the signed transactions are submitted to the blockchain for execution. The Safe smart account (a smart contract) verifies the signatures and enforces the required number of approvals before executing the transaction. This process enhances security, particularly for sensitive tasks such as registering a token administrator or configuring a token pool. Multi-signature ensures that no single owner can act alone.

The steps for enabling your tokens in CCIP follow the same flow as the previous tutorials that used externally owned accounts (EOA). The key difference here is that for sensitive actions like token administrator registration or token pool configuration, we assume your project uses a Safe multisig. Therefore, multiple signatures are required off-chain; in some cases, a batch of transactions will be submitted to save on gas costs.

The following sequence diagram illustrates the multisig transaction flow in a Safe smart account, from off-chain signature collection to on-chain execution:

How Safe Multisig works

In this diagram, the process is as follows:

  1. Signer 1 initiates the batch of transactions (one or multiple transactions) and signs off-chain.
  2. Signer 1 shares the batch with Signer 2, who signs it off-chain.
  3. Once the required number of signatures is collected (in this case, two), the batch is submitted for execution.
  4. The Smart Account verifies the signatures and checks that the signature threshold has been met.
  5. The Smart Account then executes each transaction in the batch, interacting with the Target Smart Contract(s).
  6. If any transaction fails, the entire batch is reverted. If all transactions succeed, they are confirmed on-chain.

By following this process, we maintain the security of multisig transactions while improving efficiency through the off-chain signature collection and gas savings from transaction batching.

Steps covered in this tutorial

We will cover the following key steps:

  1. Creating a Safe Account: You will create a 2-of-3 multi-signature Safe that will serve as the owner of the token and token pool contracts. This Safe will also manage administrative tasks, such as configuring token pools and registering as the token admin in the token admin registry.

  2. Deploying Tokens: You will deploy your BurnMintERC677 tokens on the Ethereum Sepolia and BASE Sepolia testnets and transfer ownership to the Safe account.

  3. Deploying Token Pools: Once your tokens are deployed, you will deploy BurnMintTokenPool token pools on Ethereum Sepolia and BASE Sepolia. The Safe account will own each token pool.

  4. Claiming and Accepting the Admin Role: This is a two-step process that will be managed using the Safe multi-signature account. It involves creating and signing multiple meta-transactions off-chain before executing them on-chain to register Safe as the token admin and accept the admin role for managing the tokens and token pools.

    1. You will call the RegistryModuleOwnerCustom contract's registerAdminViaOwner function to register the Safe as the token admin. This role is required to enable your token in CCIP.

    2. Once claimed, you will call the TokenAdminRegistry contract's acceptAdminRole function to complete the registration process.

    Meta-transactions are used here to batch these two actions, allowing both steps to be executed efficiently. The meta-transactions are created off-chain and signed by each of the two required Safe owners. This off-chain signing process reduces gas costs and enhances security, as the transactions are only broadcasted to the blockchain once all required signatures are collected.

  5. Linking Tokens to Pools: You will use the Safe account to call the TokenAdminRegistry contract's setPool function to associate each token with its respective token pool.

  6. Configuring Token Pools: You will configure each token pool by setting cross-chain transfer parameters, such as token pool rate limits and enabled destination chains, using multisig transactions through the Safe account.

  7. Granting Mint and Burn Roles: You will grant the mint and burn roles to the token pools on each linked token using the Safe account. These roles are required for the token pools to mint and burn tokens during cross-chain transfers.

  8. Minting Tokens: You will mint tokens on Ethereum Sepolia. These tokens will later be used to test cross-chain transfers to BASE Sepolia.

  9. Transferring Tokens: Finally, you will transfer tokens from Ethereum Sepolia to BASE Sepolia using CCIP. You can pay CCIP fees using either LINK tokens or native gas tokens.

By the end of this tutorial, you will have successfully deployed, registered, configured, and enabled your tokens and token pools for use in CCIP. All are managed securely through a multi-signature Safe account.

Before You Begin

  1. Make sure you have Node.js v18 or above installed. If not, install Node.js v18:
    Download Node.js 18 if you don't have it installed. Optionally, you can use the nvm package to switch between Node.js versions:

    nvm use 18
    

    Verify that the correct version of Node.js is installed:

    node -v
    

    Example output:

    $ node -v
    v18.7.0
    
  2. Clone the repository and navigate to the project directory:

    git clone https://github.com/smartcontractkit/smart-contract-examples.git
    cd smart-contract-examples/ccip/cct/hardhat
    
  3. Install dependencies for the project:

    npm install
    
  4. Compile the project:

    npm run compile
    
  5. Encrypt your environment variables for higher security:
    The project uses @chainlink/env-enc to encrypt your environment variables at rest. Follow the steps below to configure your environment securely:

    1. Set an encryption password for your environment variables:

      npx env-enc set-pw
      
    2. Set up a .env.enc file with the necessary variables for Ethereum Sepolia and BASE Sepolia testnets. Use the following command to add the variables:

      npx env-enc set
      

      Variables to configure:

      • ETHEREUM_SEPOLIA_RPC_URL: A URL for the Ethereum Sepolia testnet. You can get a personal endpoint from services like Alchemy or Infura.
      • BASE_SEPOLIA_RPC_URL: A URL for the BASE Sepolia testnet. You can sign up for a personal endpoint from Alchemy or Infura.
      • PRIVATE_KEY: The private key for the first signer of the Safe multisig account. If you use MetaMask, you can follow this guide to export your private key. Note: This key is used to create and sign the transaction of the first signer.
      • PRIVATE_KEY_2: The private key for the second signer of the Safe multisig account. If you use MetaMask, you can follow this guide to export your private key. Note: This key is used to create and sign the transaction of the second signer.
      • ETHERSCAN_API_KEY: An API key from Etherscan to verify your contracts. You can obtain one from Etherscan.
      • BASESCAN_API_KEY: An API key from Basescan to verify your contracts on BASE. See this guide to get one from Basescan.
  6. Fund the EOA linked to the first private key with LINK and native gas tokens:
    Make sure your EOA has enough LINK and native gas tokens on Ethereum Sepolia and BASE Sepolia to cover transaction fees. You can use the Chainlink faucets to get testnet tokens. Important clarifications:

    • Off-chain signatures are collected for this tutorial. The first EOA is responsible for sending the transactions to the Safe smart account, meaning only the first EOA requires enough native gas tokens for these transactions.
    • When transferring the deployed tokens from Ethereum Sepolia to BASE Sepolia, the first EOA will be used to pay the CCIP fees in LINK. Therefore, it is crucial that the first EOA has sufficient LINK tokens to cover these fees. If a different EOA were to initiate the CCIP transfer, that EOA would need to hold enough LINK tokens.

Tutorial

Deploy Safe Smart Accounts

In this step, you will deploy a Safe smart account on both Ethereum Sepolia and BASE Sepolia using the deploySafe task. The Safe smart account will serve as the multi-signature account, requiring approvals from multiple owners to authorize transactions. You can customize the number of owners and the required threshold for signatures.

Below is an explanation of the parameters used during deployment:

ParameterDescriptionDefaultRequired
ownersA comma-separated list of owner addresses. These are the Ethereum addresses that will control the Safe smart account and authorize transactions.N/AYes
thresholdThe number of required signatures to authorize a transaction. This must be at least 1 and cannot exceed the number of owners provided.1Yes
networkThe blockchain on which the Safe smart account will be deployed. Examples include sepolia for Ethereum Sepolia and baseSepolia for BASE Sepolia.N/AYes
  1. Deploy a Safe on Ethereum Sepolia (Replace 0xOwnerAddress1, 0xOwnerAddress2, and 0xOwnerAddress3 with your Ethereum addresses):

    npx hardhat deploySafe --owners "0xOwnerAddress1,0xOwnerAddress2,0xOwnerAddress3" --threshold 2 --network sepolia
    

    Example output:

    $ npx hardhat deploySafe --owners 0x9d087fC03ae39b088326b67fA3C788236645b717,0x109690437eC588caA0caA414D1bb447aA423d018,0x2Ae947aDC044091EE1b8D4FB8262308C6A4F34E0 --threshold 2 --network sepolia
    024-10-20T14:57:28.031Z info: Initializing Safe Protocol Kit...
    2024-10-20T14:57:28.541Z info: Deploying Safe with the following configuration:
    2024-10-20T14:57:28.542Z info: Owners: 0x9d087fC03ae39b088326b67fA3C788236645b717, 0x109690437eC588caA0caA414D1bb447aA423d018, 0x2Ae947aDC044091EE1b8D4FB8262308C6A4F34E0
    2024-10-20T14:57:28.542Z info: Threshold: 2
    2024-10-20T14:57:28.542Z info: Salt nonce: 102665029316435310121057348181745079700181767429012824209946078868006320683778
    2024-10-20T14:57:42.551Z info: Safe deployed successfully at address: 0x5899B1556Bc0769F678961B9F9B044DBe1868748
    
  2. Deploy a Safe on BASE Sepolia (Replace 0xOwnerAddress1, 0xOwnerAddress2, and 0xOwnerAddress3 with your Ethereum addresses):

    npx hardhat deploySafe --owners "0xOwnerAddress1,0xOwnerAddress2,0xOwnerAddress3" --threshold 2 --network baseSepolia
    

    Example output:

    $ npx hardhat deploySafe --owners 0x9d087fC03ae39b088326b67fA3C788236645b717,0x109690437eC588caA0caA414D1bb447aA423d018,0x2Ae947aDC044091EE1b8D4FB8262308C6A4F34E0 --threshold 2 --network baseSepolia
    2024-10-20T14:58:41.430Z info: Initializing Safe Protocol Kit...
    2024-10-20T14:58:42.123Z info: Deploying Safe with the following configuration:
    2024-10-20T14:58:42.123Z info: Owners: 0x9d087fC03ae39b088326b67fA3C788236645b717, 0x109690437eC588caA0caA414D1bb447aA423d018, 0x2Ae947aDC044091EE1b8D4FB8262308C6A4F34E0
    2024-10-20T14:58:42.123Z info: Threshold: 2
    2024-10-20T14:58:42.123Z info: Salt nonce: 77196524336537926223375508408885200380673362997640380014548358436098374575834
    2024-10-20T14:58:48.581Z info: Safe deployed successfully at address: 0x9f0cF3CC2cd1d86A43d85896c3b5f9f8720123a9
    

Deploy Tokens

In this step, you will deploy a token on both Ethereum Sepolia and BASE Sepolia using the deployTokenWithSafe task, then transfer ownership of the token to the Safe multisig account. This ensures that the Safe smart account controls the token, requiring multiple signatures to authorize any future administrative actions.

Below is an explanation of the parameters used during deployment:

ParameterDescriptionDefaultRequired
safeaddressThe address of the Safe smart account that will own the deployed token.N/AYes
withgetccipadminWhether to deploy a token contract that has the getCCIPAdmin() function. By default, we deploy a token contract that has the owner() function.falseNo
ccipadminaddressThe address of the CCIP admin. This is only applicable if withgetccipadmin is set to true.N/ANo
nameThe full name of the token.N/AYes
symbolThe shorthand symbol representing the token.N/AYes
decimalsThe number of decimal places the token supports (e.g., 18 means 1 token is represented as 1e18 smallest units).18No
initialsupplyThe initial supply of tokens to be created upon deployment. Set to 0 to deploy the token with no initial supply.0No
verifycontractWhether to verify the contract on Etherscan or a similar blockchain explorer.falseNo
networkThe blockchain on which the token will be deployed. Examples include sepolia for Ethereum Sepolia and baseSepolia for BASE Sepolia.N/AYes
  1. Deploy a token on Ethereum Sepolia (Replace 0xSafeAddress with the address of the Safe smart account. You can also adapt the token name and symbol as needed):

    npx hardhat deployTokenWithSafe --safeaddress 0xSafeAddress --name "BnM aem multisig" --symbol BnMaem --decimals 18 --initialsupply 0 --verifycontract true --network sepolia
    

    Example output:

    $ npx hardhat deployTokenWithSafe --safeaddress 0x5899B1556Bc0769F678961B9F9B044DBe1868748 --name "BnM aem multisig" --symbol BnMaem --decimals 18 --initialsupply 0 --withgetccipadmin false --verifycontract true --network sepolia
    2024-10-20T15:07:52.374Z info: Deploying BurnMintERC677 contract to sepolia
    2024-10-20T15:07:52.375Z info: Waiting 2 blocks for transaction 0xbef44f47fb24f94bcb4c68ecf16f4f8e0b7a6b89e85d616ac578725ff372e0de to be confirmed...
    2024-10-20T15:08:25.556Z info: Token deployed to: 0xa852f8E6FCEfCFf4F74828811055c7eCDFf247af
    2024-10-20T15:08:25.556Z info: Verifying contract on Etherscan...
    The contract 0xa852f8E6FCEfCFf4F74828811055c7eCDFf247af has already been verified on the block explorer. If you're trying to verify a partially verified contract, please use the --force flag.
    https://sepolia.etherscan.io/address/0xa852f8E6FCEfCFf4F74828811055c7eCDFf247af#code
    
    2024-10-20T15:08:26.203Z info: Token contract deployed and verified
    2024-10-20T15:08:26.203Z info: Transferring ownership of token to Safe at 0x5899B1556Bc0769F678961B9F9B044DBe1868748
    2024-10-20T15:08:48.980Z info: Ownership of token transferred to Safe at 0x5899B1556Bc0769F678961B9F9B044DBe1868748
    
  2. Deploy a token on BASE Sepolia (Replace 0xSafeAddress with the address of the Safe smart account. You can also adapt the token name and symbol as needed):

    npx hardhat deployTokenWithSafe --safeaddress 0xSafeAddress --name "BnM aem multisig" --symbol BnMaem --decimals 18 --initialsupply 0 --verifycontract true --network baseSepolia
    

    Example output:

    $ npx hardhat deployTokenWithSafe --safeaddress 0x9f0cF3CC2cd1d86A43d85896c3b5f9f8720123a9 --name "BnM aem multisig" --symbol BnMaem --decimals 18 --initialsupply 0 --verifycontract true --network baseSepolia
    2024-10-20T15:11:32.755Z info: Deploying BurnMintERC677 contract to baseSepolia
    2024-10-20T15:11:32.757Z info: Waiting 2 blocks for transaction 0x193b01f218978daa3dc5e3b818d66736d75c0ed360f650ef87c28f4177d6fa30 to be confirmed...
    2024-10-20T15:11:32.912Z info: Token deployed to: 0xCa6485F192605FEe752b6c81Eef9EFB6d73C898b
    2024-10-20T15:11:32.912Z info: Verifying contract on Etherscan...
    The contract 0xCa6485F192605FEe752b6c81Eef9EFB6d73C898b has already been verified on the block explorer. If you're trying to verify a partially verified contract, please use the --force flag.
    https://sepolia.basescan.org/address/0xCa6485F192605FEe752b6c81Eef9EFB6d73C898b#code
    
    2024-10-20T15:11:33.484Z info: Token contract deployed and verified
    2024-10-20T15:11:33.485Z info: Transferring ownership of token to Safe at 0x9f0cF3CC2cd1d86A43d85896c3b5f9f8720123a9
    2024-10-20T15:11:39.419Z info: Ownership of token transferred to Safe at 0x9f0cF3CC2cd1d86A43d85896c3b5f9f8720123a9
    

Accept Ownership of Tokens

After deploying the token and transferring ownership to the Safe smart account, the Safe smart account must formally accept ownership of the contract. This is done by collecting signatures from two owners off-chain and then submitting the transaction for on-chain execution.

The acceptOwnershipFromSafe task handles this process, ensuring that the Safe smart account securely accepts ownership of the deployed token contract.

Below is an explanation of the parameters used during this task:

ParameterDescriptionRequired
contractaddressThe address of the contract whose ownership the Safe smart account is accepting.Yes
safeaddressThe address of the Safe smart account that will accept ownership of the contract.Yes
networkThe blockchain network where the transaction will be executed. Examples include sepolia for Ethereum Sepolia and baseSepolia for BASE Sepolia.Yes
  1. Accept ownership of the token on Ethereum Sepolia (Replace 0xContractAddress and 0xSafeAddress with the token contract address and Safe smart account address, respectively):

    npx hardhat acceptOwnershipFromSafe --contractaddress 0xContractAddress --safeaddress 0xSafeAddress --network sepolia
    

    Example output:

    $ npx hardhat acceptOwnershipFromSafe --contractaddress 0xa852f8E6FCEfCFf4F74828811055c7eCDFf247af --safeaddress 0x5899B1556Bc0769F678961B9F9B044DBe1868748 --network sepolia
    2024-10-20T15:16:56.678Z info: Encoding acceptOwnership call for contract at 0xa852f8E6FCEfCFf4F74828811055c7eCDFf247af...
    2024-10-20T15:16:56.680Z info: Setting up Safe transaction...
    2024-10-20T15:16:58.379Z info: Safe transaction created
    2024-10-20T15:16:59.019Z info: Safe transaction signed by owner 1
    2024-10-20T15:16:59.602Z info: Safe transaction signed by owner 2
    2024-10-20T15:16:59.602Z info: Executing Safe transaction to accept ownership...
    2024-10-20T15:17:00.890Z info: Executed Safe transaction
    2024-10-20T15:17:00.890Z info: Waiting for 2 blocks for transaction 0x81407f7787bfd73b35394482da3f968836ffebda35769a34ef7406bfefec2d2d to be confirmed...
    2024-10-20T15:18:02.704Z info: Transaction confirmed after 2 blocks.
    
  2. Accept ownership of the token on BASE Sepolia (Replace 0xContractAddress and 0xSafeAddress with the token contract address and Safe smart account address, respectively):

     npx hardhat acceptOwnershipFromSafe --contractaddress 0xContractAddress --safeaddress 0xSafeAddress --network baseSepolia
    

    Example output:

    $ npx hardhat acceptOwnershipFromSafe --contractaddress 0xCa6485F192605FEe752b6c81Eef9EFB6d73C898b --safeaddress 0x9f0cF3CC2cd1d86A43d85896c3b5f9f8720123a9 --network baseSepolia
    2024-10-20T15:19:31.675Z info: Encoding acceptOwnership call for contract at 0xCa6485F192605FEe752b6c81Eef9EFB6d73C898b...
    2024-10-20T15:19:31.678Z info: Setting up Safe transaction...
    2024-10-20T15:19:34.256Z info: Safe transaction created
    2024-10-20T15:19:35.057Z info: Safe transaction signed by owner 1
    2024-10-20T15:19:35.988Z info: Safe transaction signed by owner 2
    2024-10-20T15:19:35.988Z info: Executing Safe transaction to accept ownership...
    2024-10-20T15:19:37.811Z info: Executed Safe transaction
    2024-10-20T15:19:37.812Z info: Waiting for 2 blocks for transaction 0x0012997ef1d2120c7720d8a9be6def0a7c34572a91b3ee24fb1abad15115eeb7 to be confirmed...
    2024-10-20T15:19:42.328Z info: Transaction confirmed after 2 blocks.
    

Deploy Token Pools

In this step, you will deploy a token pool on both Ethereum Sepolia and BASE Sepolia using the deployTokenPoolWithSafe task, then transfer ownership of the token pool to the Safe smart account. This ensures that the Safe smart account controls the token pool, providing a secure, multisig setup for managing the token pool operations.

Below is an explanation of the parameters used during deployment:

ParameterDescriptionDefaultRequired
tokenaddressThe address of the token that the pool will manage.N/AYes
safeaddressThe address of the Safe smart account that will own the token pool.N/AYes
verifycontractWhether to verify the contract on Etherscan or a similar blockchain explorer.falseNo
networkThe blockchain on which the token pool will be deployed. Examples include sepolia for Ethereum Sepolia and baseSepolia for BASE Sepolia.N/AYes
  1. Deploy a Burn and Mint token pool on Ethereum Sepolia (Replace 0xTokenAddress and 0xSafeAddress with the token address and Safe smart account address, respectively):

    npx hardhat deployTokenPoolWithSafe --tokenaddress 0xTokenAddress --safeaddress 0xSafeAddress --verifycontract true --network sepolia
    

    Example output:

    $ npx hardhat deployTokenPoolWithSafe --tokenaddress 0xa852f8E6FCEfCFf4F74828811055c7eCDFf247af --safeaddress 0x5899B1556Bc0769F678961B9F9B044DBe1868748 --verifycontract true --network sepolia
    2024-10-20T15:23:27.745Z info: Waiting 2 blocks for transaction 0xec12b302cf81a79e1458386bd1f13c7b38175e749ef4841706bd768ee23da1ec to be confirmed...
    2024-10-20T15:24:01.936Z info: Token pool deployed to: 0x1e602Ba0B6A7DE4e4586FeA9c175cB22C86B274B
    2024-10-20T15:24:01.937Z info: Verifying contract on Etherscan...
    The contract 0x1e602Ba0B6A7DE4e4586FeA9c175cB22C86B274B has already been verified on the block explorer. If you're trying to verify a partially verified contract, please use the --force flag.
    https://sepolia.etherscan.io/address/0x1e602Ba0B6A7DE4e4586FeA9c175cB22C86B274B#code
    
    2024-10-20T15:24:02.471Z info: Token pool contract deployed and verified
    2024-10-20T15:24:02.471Z info: Transferring ownership of Token Pool to Safe at 0x5899B1556Bc0769F678961B9F9B044DBe1868748
    2024-10-20T15:24:36.953Z info: Ownership of Token Pool transferred to Safe at 0x5899B1556Bc0769F678961B9F9B044DBe1868748
    
  2. Deploy a Burn and Mint token pool on BASE Sepolia (Replace 0xTokenAddress and 0xSafeAddress with the token address and Safe smart account address, respectively):

    npx hardhat deployTokenPoolWithSafe --tokenaddress 0xTokenAddress --safeaddress 0xSafeAddress --verifycontract true --network baseSepolia
    

    Example output:

    $ npx hardhat deployTokenPoolWithSafe --tokenaddress 0xCa6485F192605FEe752b6c81Eef9EFB6d73C898b --safeaddress 0x9f0cF3CC2cd1d86A43d85896c3b5f9f8720123a9 --verifycontract true --network baseSepolia
    2024-10-20T15:25:35.193Z info: Waiting 2 blocks for transaction 0x4637fed18d6d8c15e3c4b817e9d40719f926992f807fa1c2a503aecafc29bb3d to be confirmed...
    2024-10-20T15:25:35.370Z info: Token pool deployed to: 0xaBFAF5B0683d0aCA58129510E6B90388e74D9E1B
    2024-10-20T15:25:35.371Z info: Verifying contract on Etherscan...
    The contract 0xaBFAF5B0683d0aCA58129510E6B90388e74D9E1B has already been verified on the block explorer. If you're trying to verify a partially verified contract, please use the --force flag.
    https://sepolia.basescan.org/address/0xaBFAF5B0683d0aCA58129510E6B90388e74D9E1B#code
    
    2024-10-20T15:25:35.977Z info: Token pool contract deployed and verified
    2024-10-20T15:25:35.977Z info: Transferring ownership of Token Pool to Safe at 0x9f0cF3CC2cd1d86A43d85896c3b5f9f8720123a9
    2024-10-20T15:25:41.866Z info: Ownership of Token Pool transferred to Safe at 0x9f0cF3CC2cd1d86A43d85896c3b5f9f8720123a9
    

Accept Ownership of Token Pools

Just like with the tokens, after deploying the token pools and transferring ownership to the Safe smart account, the Safe smart account must formally accept ownership of the token pools. This ensures that all administrative actions for the token pools will require multisig approval, ensuring a secure and decentralized management process.

The process of accepting ownership is identical to the one described in the Accept Ownership of Tokens step above. You will use the same function to accept ownership of the token pools, with two Safe owners signing the transaction off-chain, and one of them submitting it for on-chain execution.

Refer to the table in the Accept Ownership of Tokens section for the required parameters.

  1. Accept ownership of the token pool on Ethereum Sepolia (Replace 0xContractAddress and 0xSafeAddress with the token pool contract address and Safe smart account address, respectively):

    npx hardhat acceptOwnershipFromSafe --contractaddress 0xContractAddress --safeaddress 0xSafeAddress --network sepolia
    

    Example output:

    $ npx hardhat acceptOwnershipFromSafe --contractaddress 0x1e602Ba0B6A7DE4e4586FeA9c175cB22C86B274B --safeaddress 0x5899B1556Bc0769F678961B9F9B044DBe1868748 --network sepolia
    2024-10-20T15:33:01.991Z info: Encoding acceptOwnership call for contract at 0x1e602Ba0B6A7DE4e4586FeA9c175cB22C86B274B...
    2024-10-20T15:33:01.993Z info: Setting up Safe transaction...
    2024-10-20T15:33:03.611Z info: Safe transaction created
    2024-10-20T15:33:04.199Z info: Safe transaction signed by owner 1
    2024-10-20T15:33:04.850Z info: Safe transaction signed by owner 2
    2024-10-20T15:33:04.850Z info: Executing Safe transaction to accept ownership...
    2024-10-20T15:33:06.065Z info: Executed Safe transaction
    2024-10-20T15:33:06.065Z info: Waiting for 2 blocks for transaction 0x17be8c25eef474b958523e8aebba3ef29dc34375b62a74fa33091f2bbd4290b1 to be confirmed...
    2024-10-20T15:33:26.810Z info: Transaction confirmed after 2 blocks.
    
  2. Accept ownership of the token pool on BASE Sepolia (Replace 0xContractAddress and 0xSafeAddress with the token pool contract address and Safe smart account address, respectively):

     npx hardhat acceptOwnershipFromSafe --contractaddress 0xContractAddress --safeaddress 0xSafeAddress --network baseSepolia
    

    Example output:

    $ npx hardhat acceptOwnershipFromSafe --contractaddress 0xaBFAF5B0683d0aCA58129510E6B90388e74D9E1B --safeaddress 0x9f0cF3CC2cd1d86A43d85896c3b5f9f8720123a9 --network baseSepolia
    2024-10-20T15:34:31.588Z info: Encoding acceptOwnership call for contract at 0xaBFAF5B0683d0aCA58129510E6B90388e74D9E1B...
    2024-10-20T15:34:31.590Z info: Setting up Safe transaction...
    2024-10-20T15:34:34.216Z info: Safe transaction created
    2024-10-20T15:34:34.976Z info: Safe transaction signed by owner 1
    2024-10-20T15:34:36.161Z info: Safe transaction signed by owner 2
    2024-10-20T15:34:36.162Z info: Executing Safe transaction to accept ownership...
    2024-10-20T15:34:37.915Z info: Executed Safe transaction
    2024-10-20T15:34:37.916Z info: Waiting for 2 blocks for transaction 0x53550833781a2ec1b1b1bab4b700291baffc368184f35b55aef550834a0ed8a1 to be confirmed...
    2024-10-20T15:34:46.638Z info: Transaction confirmed after 2 blocks.
    

Claim and Accept Token Admin Role using Safe

In this step, you will use the claimAndAcceptAdminRoleFromSafe task to claim and accept the admin role for the deployed tokens in a single Ethereum transaction. By leveraging Safe's batching feature, we can efficiently combine the two operations—claiming the admin role and accepting the admin role—into one on-chain interaction. This reduces gas costs and improves efficiency.

The process will use the Safe smart account to sign the transaction off-chain, collect the required signatures from multiple owners, and then execute it on-chain.

Below is an explanation of the parameters used during this task:

ParameterDescriptionDefaultRequired
withccipadminA flag indicating whether the token contract has a CCIP admin. If false, the admin role is claimed using the owner() function.falseNo
tokenaddressThe address of the token for which the admin role will be claimed and accepted.N/AYes
safeaddressThe address of the Safe smart account that will execute the transactions and become the token admin.N/AYes
networkThe blockchain on which the transaction will be executed. Examples include sepolia for Ethereum Sepolia and baseSepolia for BASE Sepolia.N/AYes
  1. Claim and accept the admin role for the token on Ethereum Sepolia (Replace 0xTokenAddress and 0xSafeAddress with the token address and Safe smart account address, respectively):

    npx hardhat claimAndAcceptAdminRoleFromSafe --tokenaddress 0xTokenAddress --safeaddress 0xSafeAddress --network sepolia
    

    Example output:

     $ npx hardhat claimAndAcceptAdminRoleFromSafe --tokenaddress 0xa852f8E6FCEfCFf4F74828811055c7eCDFf247af --safeaddress 0x5899B1556Bc0769F678961B9F9B044DBe1868748 --network sepolia
     2024-10-20T15:41:45.186Z info: Current token owner: 0x5899B1556Bc0769F678961B9F9B044DBe1868748
     2024-10-20T15:41:45.187Z info: Claiming admin of 0xa852f8E6FCEfCFf4F74828811055c7eCDFf247af for Safe at 0x5899B1556Bc0769F678961B9F9B044DBe1868748
     2024-10-20T15:41:45.189Z info: Adding second MetaTransaction to accept admin role for token 0xa852f8E6FCEfCFf4F74828811055c7eCDFf247af
     2024-10-20T15:41:46.807Z info: Safe transaction with two meta transactions created
     2024-10-20T15:41:47.388Z info: Safe transaction signed by owner 1
     2024-10-20T15:41:47.947Z info: Safe transaction signed by owner 2
     2024-10-20T15:41:47.947Z info: Executing Safe transaction to claim and accept admin role...
     2024-10-20T15:41:49.288Z info: Executed Safe transaction
     2024-10-20T15:41:49.289Z info: Waiting for 2 blocks for transaction 0x53877d20d5b680124cc31869b65492de7a5e3331e45e92a875116cdbda0b18a1 to be confirmed...
     2024-10-20T15:42:26.501Z info: Transaction confirmed after 2 blocks.
     2024-10-20T15:42:26.502Z info: Claiming admin of token 0xa852f8E6FCEfCFf4F74828811055c7eCDFf247af via Safe and accepted admin role successfully.
    
  2. Claim and accept the admin role for the token on BASE Sepolia (Replace 0xTokenAddress and 0xSafeAddress with the token address and Safe smart account address, respectively):

    npx hardhat claimAndAcceptAdminRoleFromSafe --tokenaddress 0xTokenAddress --safeaddress 0xSafeAddress --network baseSepolia
    

    Example output:

     $ npx hardhat claimAndAcceptAdminRoleFromSafe --tokenaddress 0xCa6485F192605FEe752b6c81Eef9EFB6d73C898b --safeaddress 0x9f0cF3CC2cd1d86A43d85896c3b5f9f8720123a9 --network baseSepolia
     2024-10-20T16:09:57.904Z info: Current token owner: 0x9f0cF3CC2cd1d86A43d85896c3b5f9f8720123a9
     2024-10-20T16:09:57.906Z info: Claiming admin of 0xCa6485F192605FEe752b6c81Eef9EFB6d73C898b for Safe at 0x9f0cF3CC2cd1d86A43d85896c3b5f9f8720123a9
     2024-10-20T16:09:57.907Z info: Adding second MetaTransaction to accept admin role for token 0xCa6485F192605FEe752b6c81Eef9EFB6d73C898b
     2024-10-20T16:10:00.272Z info: Safe transaction with two meta transactions created
     2024-10-20T16:10:01.109Z info: Safe transaction signed by owner 1
     2024-10-20T16:10:01.953Z info: Safe transaction signed by owner 2
     2024-10-20T16:10:01.953Z info: Executing Safe transaction to claim and accept admin role...
     2024-10-20T16:10:03.819Z info: Executed Safe transaction
     2024-10-20T16:10:03.819Z info: Waiting for 2 blocks for transaction 0xc50eeb9f04592e8f2ce0df4717a60d7276d5ff0545530287a32707b1b6252015 to be confirmed...
     2024-10-20T16:10:08.375Z info: Transaction confirmed after 2 blocks.
     2024-10-20T16:10:08.375Z info: Claiming admin of token 0xCa6485F192605FEe752b6c81Eef9EFB6d73C898b via Safe and accepted admin role successfully.
    

Grant Mint and Burn Roles using Safe

In this step, you will use the grantMintBurnRoleFromSafe task to grant mint and burn roles to both the token pool and the Safe smart account on Ethereum Sepolia and BASE Sepolia. The Safe smart account will handle the transaction to securely assign these roles, ensuring that multiple owners sign off on the operation. Granting mint and burn roles is essential to allow the token pool and the Safe account to manage token issuance and burning, and to prepare for future cross-chain transfers.

This process will grant:

  • Mint and burn roles to the token pool for handling cross-chain operations.
  • Mint and burn roles to the Safe smart account for minting tokens to EOAs for testing purposes.

Below is an explanation of the parameters used during this task:

ParameterDescriptionRequired
tokenaddressThe address of the deployed token contract for which mint and burn roles will be granted.Yes
burnermintersA comma-separated list of addresses (token pools and Safe smart account) to which mint and burn roles will be granted.Yes
safeaddressThe address of the Safe smart account that will execute the transaction to grant mint and burn roles.Yes
networkThe blockchain on which the mint and burn roles will be granted. Examples include sepolia for Ethereum Sepolia and baseSepolia for BASE Sepolia.Yes
  1. Grant mint and burn roles on Ethereum Sepolia (Replace 0xTokenAddress, 0xPoolAddress, and 0xSafeAddress with the token address, token pool address, and Safe smart account address, respectively):

    npx hardhat grantMintBurnRoleFromSafe --tokenaddress 0xTokenAddress --burnerminters 0xPoolAddress,0xSafeAddress --safeaddress 0xSafeAddress --network sepolia
    

    Example output:

     $ npx hardhat grantMintBurnRoleFromSafe --tokenaddress 0xa852f8E6FCEfCFf4F74828811055c7eCDFf247af --burnerminters 0x1e602Ba0B6A7DE4e4586FeA9c175cB22C86B274B,0x5899B1556Bc0769F678961B9F9B044DBe1868748 --safeaddress 0x5899B1556Bc0769F678961B9F9B044DBe1868748 --network sepolia
     2024-10-20T16:55:24.316Z info: Connecting to token contract at 0xa852f8E6FCEfCFf4F74828811055c7eCDFf247af...
     2024-10-20T16:55:25.919Z info: Setting up Safe transactions to grant mint and burn roles to: 0x1e602Ba0B6A7DE4e4586FeA9c175cB22C86B274B, 0x5899B1556Bc0769F678961B9F9B044DBe1868748
     2024-10-20T16:55:26.187Z info: Safe transaction created
     2024-10-20T16:55:26.798Z info: Safe transaction signed by owner 1
     2024-10-20T16:55:27.359Z info: Safe transaction signed by owner 2
     2024-10-20T16:55:27.359Z info: Executing Safe transaction to grant mint and burn roles...
     2024-10-20T16:55:28.788Z info: Executed Safe transaction
     2024-10-20T16:55:28.788Z info: Waiting for 2 blocks for transaction 0x6dc4441c3bdef5513a0bd46f7842323b3101c506f1219136ab6e8ce87e5a0111 to be confirmed...
     2024-10-20T16:55:49.527Z info: Transaction confirmed after 2 blocks.
     2024-10-20T16:55:49.528Z info: Mint and burn roles granted to 0x1e602Ba0
    
    
  2. Grant mint and burn roles on BASE Sepolia (Replace 0xTokenAddress, 0xPoolAddress, and 0xSafeAddress with the token address, token pool address, and Safe smart account address, respectively):

    npx hardhat grantMintBurnRoleFromSafe --tokenaddress 0xTokenAddress --burnerminters 0xPoolAddress,0xSafeAddress --safeaddress 0xSafeAddress --network baseSepolia
    

    Example output:

     $ npx hardhat grantMintBurnRoleFromSafe --tokenaddress 0xCa6485F192605FEe752b6c81Eef9EFB6d73C898b --burnerminters 0xaBFAF5B0683d0aCA58129510E6B90388e74D9E1B,0x9f0cF3CC2cd1d86A43d85896c3b5f9f8720123a9 --safeaddress 0x9f0cF3CC2cd1d86A43d85896c3b5f9f8720123a9 --network baseSepolia
     2024-10-20T16:56:53.698Z info: Connecting to token contract at 0xCa6485F192605FEe752b6c81Eef9EFB6d73C898b...
     2024-10-20T16:56:55.988Z info: Setting up Safe transactions to grant mint and burn roles to: 0xaBFAF5B0683d0aCA58129510E6B90388e74D9E1B, 0x9f0cF3CC2cd1d86A43d85896c3b5f9f8720123a9
     2024-10-20T16:56:56.335Z info: Safe transaction created
     2024-10-20T16:56:57.239Z info: Safe transaction signed by owner 1
     2024-10-20T16:56:58.080Z info: Safe transaction signed by owner 2
     2024-10-20T16:56:58.080Z info: Executing Safe transaction to grant mint and burn roles...
     2024-10-20T16:56:59.974Z info: Executed Safe transaction
     2024-10-20T16:56:59.975Z info: Waiting for 2 blocks for transaction 0x8633b45f1598b35460f953e92f7995daaba9529d501add8771a9fadf6439e075 to be confirmed...
     2024-10-20T16:57:08.752Z info: Transaction confirmed after 2 blocks.
     2024-10-20T16:57:08.753Z info: Mint and burn roles granted to 0xaBFAF5B0683d0aCA58129510E6B90388e74D9E1B, 0x9f0cF3CC2cd1d86A43d85896c3b5f9f8720123a9
    

Set Pool using Safe

In this step, you will use the setPoolFromSafe task to link a token to a token pool on both Ethereum Sepolia and BASE Sepolia. The Safe smart account will be used to execute the transaction, ensuring that the pool is set securely with multisig approval. Multiple owners will sign the transaction off-chain before it is executed on-chain.

Below is an explanation of the parameters used during this task:

ParameterDescriptionRequired
tokenaddressThe address of the token for which the pool will be set.Yes
pooladdressThe address of the token pool to be linked to the token.Yes
safeaddressThe address of the Safe smart account that will execute the transaction.Yes
networkThe blockchain on which the transaction will be executed. Examples include sepolia for Ethereum Sepolia and baseSepolia for BASE Sepolia.Yes
  1. Set the token pool on Ethereum Sepolia (Replace 0xTokenAddress, 0xPoolAddress, and 0xSafeAddress with the token address, token pool address, and Safe smart account address, respectively):

    npx hardhat setPoolFromSafe --tokenaddress 0xTokenAddress --pooladdress 0xPoolAddress --safeaddress 0xSafeAddress --network sepolia
    

    Example output:

    $ npx hardhat setPoolFromSafe --tokenaddress 0xa852f8E6FCEfCFf4F74828811055c7eCDFf247af --pooladdress 0x1e602Ba0B6A7DE4e4586FeA9c175cB22C86B274B --safeaddress 0x5899B1556Bc0769F678961B9F9B044DBe1868748 --network sepolia
    2024-10-20T16:14:17.906Z info: Connecting to TokenAdminRegistry contract at 0x95F29FEE11c5C55d26cCcf1DB6772DE953B37B82...
    2024-10-20T16:14:18.216Z info: Setting pool for token 0xa852f8E6FCEfCFf4F74828811055c7eCDFf247af to 0x1e602Ba0B6A7DE4e4586FeA9c175cB22C86B274B by 0x5899B1556Bc0769F678961B9F9B044DBe1868748
    2024-10-20T16:14:19.742Z info: Safe transaction created for setting the pool
    2024-10-20T16:14:20.332Z info: Safe transaction signed by owner 1
    2024-10-20T16:14:20.860Z info: Safe transaction signed by owner 2
    2024-10-20T16:14:20.861Z info: Executing Safe transaction to set pool for token 0xa852f8E6FCEfCFf4F74828811055c7eCDFf247af...
    2024-10-20T16:14:22.037Z info: Executed Safe transaction
    2024-10-20T16:14:22.038Z info: Waiting for 2 blocks for transaction 0x0556c0c861d815f289062999b7ef4e7ff8cb78f6c56033ba08530b50150b5fa1 to be confirmed...
    2024-10-20T16:14:38.663Z info: Transaction confirmed after 2 blocks.
    2024-10-20T16:14:38.663Z info: Pool set for token 0xa852f8E6FCEfCFf4F74828811055c7eCDFf247af to 0x1e602Ba0B6A7DE4e4586FeA9c175cB22C86B274B successfully.
    
  2. Set the token pool on BASE Sepolia (Replace 0xTokenAddress, 0xPoolAddress, and 0xSafeAddress with the token address, token pool address, and Safe smart account address, respectively):

    npx hardhat setPoolFromSafe --tokenaddress 0xTokenAddress --pooladdress 0xPoolAddress --safeaddress 0xSafeAddress --network baseSepolia
    

    Example output:

     $ npx hardhat setPoolFromSafe --tokenaddress 0xCa6485F192605FEe752b6c81Eef9EFB6d73C898b --pooladdress 0xaBFAF5B0683d0aCA58129510E6B90388e74D9E1B --safeaddress 0x9f0cF3CC2cd1d86A43d85896c3b5f9f8720123a9 --network baseSepolia
     2024-10-20T16:15:47.979Z info: Connecting to TokenAdminRegistry contract at 0x736D0bBb318c1B27Ff686cd19804094E66250e17...
     2024-10-20T16:15:48.411Z info: Setting pool for token 0xCa6485F192605FEe752b6c81Eef9EFB6d73C898b to 0xaBFAF5B0683d0aCA58129510E6B90388e74D9E1B by 0x9f0cF3CC2cd1d86A43d85896c3b5f9f8720123a9
     2024-10-20T16:15:51.088Z info: Safe transaction created for setting the pool
     2024-10-20T16:15:52.058Z info: Safe transaction signed by owner 1
     2024-10-20T16:15:52.985Z info: Safe transaction signed by owner 2
     2024-10-20T16:15:52.985Z info: Executing Safe transaction to set pool for token 0xCa6485F192605FEe752b6c81Eef9EFB6d73C898b...
     2024-10-20T16:15:54.664Z info: Executed Safe transaction
     2024-10-20T16:15:54.665Z info: Waiting for 2 blocks for transaction 0x95341bb4572c66c1fec59105010cdcf75d6e7e13d651f86214a8e6fd3c0524d9 to be confirmed...
     2024-10-20T16:15:59.274Z info: Transaction confirmed after 2 blocks.
     2024-10-20T16:15:59.274Z info: Pool set for token 0xCa6485F192605FEe752b6c81Eef9EFB6d73C898b to 0xaBFAF5B0683d0aCA58129510E6B90388e74D9E1B successfully.
    

Configure Token Pools using Safe

In this step, you will use the applyChainUpdatesFromSafe task to configure a token pool for cross-chain interactions. By leveraging the Safe smart account, you can securely update the configuration of the token pool to support remote chains, including setting rate limits and linking it to remote pools and tokens.

The task handles complex cross-chain setups, allowing you to define rate limits for both inbound and outbound token transfers. The transaction is signed by the Safe owners off-chain and then executed on-chain, ensuring secure multi-signature control over the pool configuration.

Below is an explanation of the parameters used during this task:

ParameterDescriptionDefaultRequired
pooladdressThe address of the token pool to be configured.N/AYes
remotechainThe identifier of the remote blockchain (e.g., sepolia for Ethereum Sepolia or baseSepolia for BASE Sepolia).N/AYes
allowedA flag indicating whether token transfers to the remote chain are allowed.trueNo
remotepooladdressThe address of the remote token pool on the remote chain.N/AYes
remotetokenaddressThe address of the token on the remote chain.N/AYes
outboundratelimitenabledWhether the outbound rate limit for the token pool is enabled.falseNo
outboundratelimitcapacityThe maximum number of tokens that can be transferred outbound in a single burst (bucket capacity for the outbound rate limiter).0No
outboundratelimitrateThe rate at which tokens are refilled in the outbound bucket (tokens per second).0No
inboundratelimitenabledWhether the inbound rate limit for the token pool is enabled.falseNo
inboundratelimitcapacityThe maximum number of tokens that can be transferred inbound in a single burst (bucket capacity for the inbound rate limiter).0No
inboundratelimitrateThe rate at which tokens are refilled in the inbound bucket (tokens per second).0No
safeaddressThe address of the Safe smart account that will execute the transaction to configure the pool.N/AYes
networkThe blockchain on which the pool is being configured. Examples include sepolia for Ethereum Sepolia and baseSepolia for BASE Sepolia.N/AYes
  1. Configure the token pool on Ethereum Sepolia (Replace 0xPoolAddress, 0xRemotePoolAddress, 0xRemoteTokenAddress, and 0xSafeAddress with the token pool address, remote token pool address, remote token address, and Safe smart account address, respectively):

    npx hardhat applyChainUpdatesFromSafe --pooladdress 0xPoolAddress --remotechain baseSepolia  --remotepooladdress 0xRemotePoolAddress --remotetokenaddress 0xRemoteTokenAddress --safeaddress 0xSafeAddress --network sepolia
    

    Example output:

     $ npx hardhat applyChainUpdatesFromSafe --pooladdress 0x1e602Ba0B6A7DE4e4586FeA9c175cB22C86B274B --remotechain baseSepolia --remotepooladdress 0xaBFAF5B0683d0aCA58129510E6B90388e74D9E1B --remotetokenaddress 0xCa6485F192605FEe752b6c81Eef9EFB6d73C898b --safeaddress 0x5899B1556Bc0769F678961B9F9B044DBe1868748 --network sepolia
     2024-10-20T16:28:59.975Z info: Configuring pool at address: 0x1e602Ba0B6A7DE4e4586FeA9c175cB22C86B274B for remote chain baseSepolia
     2024-10-20T16:29:01.657Z info: Safe transaction created for configuring the pool
     2024-10-20T16:29:02.242Z info: Safe transaction signed by owner 1
     2024-10-20T16:29:02.798Z info: Safe transaction signed by owner 2
     2024-10-20T16:29:02.798Z info: Executing Safe transaction to configure pool 0x1e602Ba0B6A7DE4e4586FeA9c175cB22C86B274B...
     2024-10-20T16:29:04.169Z info: Executed Safe transaction
     2024-10-20T16:29:04.169Z info: Waiting for 2 blocks for transaction 0x435defb5b024696d7cd0e1242bc1fc9d3789fc98618637fde2373394aef8da2a to be confirmed...
     2024-10-20T16:29:29.013Z info: Transaction confirmed after 2 blocks.
     2024-10-20T16:29:29.013Z info: Pool configured successfully for remote chain baseSepolia
    
  2. Configure the token pool on BASE Sepolia (Replace 0xPoolAddress, 0xRemotePoolAddress, 0xRemoteTokenAddress, and 0xSafeAddress with the token pool address, remote token pool address, remote token address, and Safe smart account address, respectively):

    npx hardhat applyChainUpdatesFromSafe --pooladdress 0xPoolAddress --remotechain sepolia  --remotepooladdress 0xRemotePoolAddress --remotetokenaddress 0xRemoteTokenAddress --safeaddress 0xSafeAddress --network baseSepolia
    

    Example output:

     $ npx hardhat applyChainUpdatesFromSafe --pooladdress 0xaBFAF5B0683d0aCA58129510E6B90388e74D9E1B --remotechain sepolia --remotepooladdress 0x1e602Ba0B6A7DE4e4586FeA9c175cB22C86B274B --remotetokenaddress 0xa852f8E6FCEfCFf4F74828811055c7eCDFf247af --safeaddress 0x9f0cF3CC2cd1d86A43d85896c3b5f9f8720123a9 --network baseSepolia
     2024-10-20T16:30:23.128Z info: Configuring pool at address: 0xaBFAF5B0683d0aCA58129510E6B90388e74D9E1B for remote chain sepolia
     2024-10-20T16:30:25.787Z info: Safe transaction created for configuring the pool
     2024-10-20T16:30:26.730Z info: Safe transaction signed by owner 1
     2024-10-20T16:30:27.673Z info: Safe transaction signed by owner 2
     2024-10-20T16:30:27.673Z info: Executing Safe transaction to configure pool 0xaBFAF5B0683d0aCA58129510E6B90388e74D9E1B...
     2024-10-20T16:30:29.407Z info: Executed Safe transaction
     2024-10-20T16:30:29.407Z info: Waiting for 2 blocks for transaction 0x79d1e9a31a622a6a83f63c241344361e7328b5809f72d2a182530f35c9b3c9b1 to be confirmed...
     2024-10-20T16:30:33.975Z info: Transaction confirmed after 2 blocks.
     2024-10-20T16:30:33.975Z info: Pool configured successfully for remote chain sepolia
    

Mint Tokens to an EOA using Safe

In this step, you will use the mintTokensFromSafe task to mint tokens to an EOA on Ethereum Sepolia. This process uses a Safe smart account to securely manage the minting process, ensuring that the transaction is signed by multiple owners off-chain before being executed on-chain. These tokens will be used for transfers through CCIP from Ethereum Sepolia to BASE Sepolia.

Below is an explanation of the parameters used during this task:

ParameterDescriptionRequired
tokenaddressThe address of the token contract from which the tokens will be minted.Yes
amountThe amount of tokens to mint for each recipient address.Yes
receiveraddressesA comma-separated list of recipient addresses (EOAs) that will receive the minted tokens.Yes
safeaddressThe address of the Safe smart account that will execute the transaction to mint tokens.Yes
networkThe blockchain on which the minting transaction will be executed. For example, sepolia for Ethereum Sepolia.Yes
  1. Mint tokens to an EOA on Ethereum Sepolia (Replace 0xTokenAddress, 0xSafeAddress, and 0xReceiverAddress with the token address, Safe smart account address, and recipient address, respectively):

    npx hardhat mintTokensFromSafe --tokenaddress 0xTokenAddress --amount 100000000000000000000 --receiveraddresses 0xReceiverAddress --safeaddress 0xSafeAddress --network sepolia
    

    Example output:

     $ npx hardhat mintTokensFromSafe --tokenaddress 0xa852f8E6FCEfCFf4F74828811055c7eCDFf247af --amount 100000000000000000000 --receiveraddresses 0x9d087fc03ae39b088326b67fa3c788236645b717 --safeaddress 0x5899B1556Bc0769F678961B9F9B044DBe1868748 --network sepolia
     2024-10-20T16:58:19.897Z info: Connecting to token contract at 0xa852f8E6FCEfCFf4F74828811055c7eCDFf247af...
     2024-10-20T16:58:19.958Z info: Minting 100000000000000000000 of BnMaem tokens to multiple addresses: 0x9d087fc03ae39b088326b67fa3c788236645b717
     2024-10-20T16:58:21.563Z info: Safe transaction created
     2024-10-20T16:58:22.111Z info: Safe transaction signed by owner 1
     2024-10-20T16:58:22.636Z info: Safe transaction signed by owner 2
     2024-10-20T16:58:22.636Z info: Executing Safe transaction to mint tokens to multiple addresses...
     2024-10-20T16:58:23.874Z info: Executed Safe transaction
     2024-10-20T16:58:23.875Z info: Waiting for 2 blocks for transaction 0x8a21f04dafb3aa8695b5a1d875935a2fea60ed29d62202c1a109ee99c8a94b56 to be confirmed...
     2024-10-20T16:58:52.804Z info: Transaction confirmed after 2 blocks.
     2024-10-20T16:58:52.893Z info: Minted 100000000000000000000 of BnMaem tokens to 0x9d087fc03ae39b088326b67fa3c788236645b717
     2024-10-20T16:58:52.992Z info: Current balance of 0x9d087fc03ae39b088326b67fa3c788236645b717 is 200000000000000000000 BnMaem
    

Transfer Tokens

In this step, you will use the transferTokens task to transfer tokens from Ethereum Sepolia to BASE Sepolia using CCIP. You have two options for paying CCIP fees: using LINK tokens or native gas tokens.

You will interact with the IRouterClient contract, specifically calling the ccipSend() function to initiate the token transfer.

Below is an explanation of the parameters used during the token transfer process:

ParameterDescriptionDefaultRequired
tokenaddressThe address of the token being transferred.N/AYes
amountThe amount of tokens to transfer.N/AYes
destinationchainThe blockchain to which the tokens will be transferred. Examples include baseSepolia, and sepolia.N/AYes
receiveraddressThe address of the receiver on the destination blockchain.N/AYes
feeThe type of fee used for the transfer, either LINK or native.LINKNo
networkThe blockchain on which the token transfer will be initiated. Examples include baseSepolia, and sepolia.N/AYes

Call the CCIP Router to transfer tokens from Ethereum Sepolia to BASE Sepolia, paying the CCIP fees in LINK tokens. Replace the token address, amount, receiver address, and blockchain with the appropriate values:

npx hardhat transferTokens --tokenaddress 0xTokenAddress --amount 2000000000000000000 --destinationchain baseSepolia --receiveraddress 0xReceiverAddress --fee LINK --network sepolia

Example output:

$ npx hardhat transferTokens --tokenaddress 0xa852f8E6FCEfCFf4F74828811055c7eCDFf247af --amount 2000000000000000000 --destinationchain baseSepolia --receiveraddress 0x9d087fc03ae39b088326b67fa3c788236645b717 --fee LINK --network sepolia
2024-10-20T17:01:57.420Z info: Estimated fees: 19882491967266251
2024-10-20T17:01:57.421Z info: Approving 2000000000000000000 0xa852f8E6FCEfCFf4F74828811055c7eCDFf247af to 0x0BF3dE8c5D3e8A2B34D2BEeB17ABfCeBaf363A59
2024-10-20T17:02:12.753Z info: Approving 19882491967266251 LINK to 0x0BF3dE8c5D3e8A2B34D2BEeB17ABfCeBaf363A59
2024-10-20T17:02:37.159Z info: Transferring 2000000000000000000 of 0xa852f8E6FCEfCFf4F74828811055c7eCDFf247af to 0x9d087fc03ae39b088326b67fa3c788236645b717 on chain baseSepolia with 19882491967266251 of LINK as fees
2024-10-20T17:03:02.102Z info: Transaction hash: 0x33cbc6eed84483716e8d5a19040101fe09e42be8c14f8c315ed1c099ccd36213
2024-10-20T17:03:02.321Z info: ✅ Transferred 2000000000000000000 of 0xa852f8E6FCEfCFf4F74828811055c7eCDFf247af to 0x9d087fc03ae39b088326b67fa3c788236645b717 on chain baseSepolia. Transaction hash: 0x33cbc6eed84483716e8d5a19040101fe09e42be8c14f8c315ed1c099ccd36213 - CCIP message id: 0x5e6d50efc9a9d325cee140058893698c8e591e0e1b0f36da5d24c04c1d1c3136
2024-10-20T17:03:02.322Z info: Check status of message on https://ccip.chain.link/msg/0x5e6d50efc9a9d325cee140058893698c8e591e0e1b0f36da5d24c04c1d1c3136

You can check the status of the message on the Chainlink CCIP Explorer by visiting the provided URL. In this example, the message ID is 0x5e6d50efc9a9d325cee140058893698c8e591e0e1b0f36da5d24c04c1d1c3136.

Pay fees in native gas tokens

Call the CCIP Router to transfer tokens from Ethereum Sepolia to BASE Sepolia, paying the CCIP fees in native gas tokens. Replace the token address, amount, receiver address, and blockchain with the appropriate values:

npx hardhat transferTokens --tokenaddress 0xTokenAddress --amount 2000000000000000000 --destinationchain baseSepolia --receiveraddress 0xReceiverAddress --fee native --network sepolia

Example output:

$ npx hardhat transferTokens --tokenaddress 0xa852f8E6FCEfCFf4F74828811055c7eCDFf247af --amount 2000000000000000000 --destinationchain baseSepolia --receiveraddress 0x9d087fc03ae39b088326b67fa3c788236645b717 --fee native --network sepolia
2024-10-20T17:03:48.908Z info: Estimated fees: 95096968223814
2024-10-20T17:03:48.909Z info: Approving 2000000000000000000 0xa852f8E6FCEfCFf4F74828811055c7eCDFf247af to 0x0BF3dE8c5D3e8A2B34D2BEeB17ABfCeBaf363A59
2024-10-20T17:04:37.334Z info: Transferring 2000000000000000000 of 0xa852f8E6FCEfCFf4F74828811055c7eCDFf247af to 0x9d087fc03ae39b088326b67fa3c788236645b717 on chain baseSepolia with 95096968223814 of native token as fees
2024-10-20T17:05:26.122Z info: Transaction hash: 0x506559fd215347866f0c08ec4d38b1ca4a8882812a37900cf1ec244b9877e78b
2024-10-20T17:05:26.152Z info: ✅ Transferred 2000000000000000000 of 0xa852f8E6FCEfCFf4F74828811055c7eCDFf247af to 0x9d087fc03ae39b088326b67fa3c788236645b717 on chain baseSepolia. Transaction hash: 0x506559fd215347866f0c08ec4d38b1ca4a8882812a37900cf1ec244b9877e78b - CCIP message id: 0x05a8af8effe1b5baaea0bf7117e9da2a15bd0d3c7c0702048e44ef444abad33b
2024-10-20T17:05:26.152Z info: Check status of message on https://ccip.chain.link/msg/0x05a8af8effe1b5baaea0bf7117e9da2a15bd0d3c7c0702048e44ef444abad33b

You can check the status of the message on the Chainlink CCIP Explorer by visiting the provided URL. In this example, the message ID is 0x05a8af8effe1b5baaea0bf7117e9da2a15bd0d3c7c0702048e44ef444abad33b.

Get the latest Chainlink content straight to your inbox.