{"id":25575672,"url":"https://github.com/bunsdev/cct-linklabs","last_synced_at":"2026-03-26T14:30:15.291Z","repository":{"id":278641282,"uuid":"934122866","full_name":"BunsDev/cct-linklabs","owner":"BunsDev","description":null,"archived":false,"fork":false,"pushed_at":"2025-02-20T21:03:57.000Z","size":1159,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-02-20T22:20:01.568Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Solidity","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/BunsDev.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2025-02-17T10:07:17.000Z","updated_at":"2025-02-20T21:04:01.000Z","dependencies_parsed_at":"2025-02-20T22:20:09.717Z","dependency_job_id":null,"html_url":"https://github.com/BunsDev/cct-linklabs","commit_stats":null,"previous_names":["bunsdev/cct-linklabs"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BunsDev%2Fcct-linklabs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BunsDev%2Fcct-linklabs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BunsDev%2Fcct-linklabs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BunsDev%2Fcct-linklabs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/BunsDev","download_url":"https://codeload.github.com/BunsDev/cct-linklabs/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":239946871,"owners_count":19723014,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-02-21T02:39:57.209Z","updated_at":"2026-03-26T14:30:15.227Z","avatar_url":"https://github.com/BunsDev.png","language":"Solidity","funding_links":[],"categories":[],"sub_categories":[],"readme":"_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._\n\n\n\u003cdiv align=\"center\" style=\"margin: 30px; width: 100%; display: flex; justify-content: center; align-items: center;\"\u003e\n\u003ca href=\"https://cct.wiki/\"\u003e\n  \u003cimg alt=\"logo\" src=\"https://cct.wiki/og.jpg\" style=\"width: 100%;\" align=\"center\"\u003e\n\u003c/a\u003e\n\u003c/div\u003e\n\n# Building with the Cross Chain Token (CCT) Standard\n\u003e _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._\n\n## Overview\nThis 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.\n\n## Table of Contents\n\n1. **Initial Setup**\n   - [Install Dependencies](#step-1--install-dependencies)\n   - [Setup Environment](#step-2--setup-environment)\n   - [Create Wallet](#step-3--create-wallet)\n\n2. **Testing**\n   - [Test Contracts](#step-4--test-contracts)\n\n3. **Token Deployment**\n   - [Deploy Tokens](#step-5--deploy-tokens)\n     - [Ethereum Sepolia Implementation](./receipts/transactions/tokenEthSepolia.md)\n     - [Base Sepolia Implementation](./receipts/transactions/tokenBaseSepolia.md)\n\n4. **Pool Management**\n   - [Deploy Pools](#step-6--deploy-pools)\n     - [Ethereum Sepolia Pool](./receipts/transactions/poolEthSepolia.md)\n     - [Base Sepolia Pool](./receipts/transactions/poolBaseSepolia.md)\n\n5. **Administrative Setup**\n   - [Claim Admin Role](#step-7--claim-admin-role)  \n   - [Accept Admin Role](#step-8--accept-admin-role)\n   - [Set Pool](#step-9--set-pool)\n   - [Apply Chain](#step-10--apply-chain)\n\n6. **Token Operations**\n   - [Mint Tokens](#step-11--mint-tokens)\n   - [Transfer Tokens](#step-12--transfer-tokens)\n\n## Key Components\n\n1. **Environment Setup**\n   - Configuration of environment variables\n   - Wallet creation and management\n   - Network RPC endpoints setup\n\n2. **Smart Contracts**\n   - Token contracts\n   - Pool contracts\n   - Management contracts\n   - Transfer contracts\n\n3. **Network Support**\n   - Ethereum Sepolia testnet\n   - Base Sepolia testnet\n\n4. **Administrative Functions**\n   - Role management\n   - Pool configuration\n   - Chain setup\n   - Token minting and transfer capabilities\n\n\u003e #### Each step includes detailed commands and verification steps, with transaction receipts stored in the `./receipts/transactions/` directory and visual confirmations in `./receipts/screenshots/`.\n\n\n# Step 1 | Install Dependencies\n\n```bash\nyarn \u0026\u0026 make\n```\n\n# Step 2 | Setup Environment\n\nRun the command below, then update the .env `PRIVATE_KEY` and `ETHERSCAN_API_KEY` variables.\n\n```bash\nif [ -f .env ]; then\n    echo \"We will use the .env your have already created.\"\n    else\n    if [ -z \"${DOTENV}\" ]; then\n        echo \"Creating and setting .env\"\n        cp .env.example .env \u0026\u0026 source .env\n        echo \"Set your PRIVATE_KEY and ETHERSCAN_API_KEY in .env\"\n    fi\nfi\n```\n\n# Step 3 | Create Wallet\n\nTo 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.\n\n```shell\n# Grabs the PRIVATE_KEY from the .env file.\nPRIVATE_KEY=$(grep PRIVATE_KEY .env | cut -d '=' -f2)\n\nif [ -f keystore/secret ]; then\n    echo \"Found keystore in workspace\"\n    else\n    if [ -z \"${DOTENV}\" ]; then\n        echo \"Creating and setting keystore\"\n        mkdir keystore\n        cast wallet import --private-key $PRIVATE_KEY -k keystore secret\n        echo \"keystore/secret created\"\n    fi\nfi\n```\n\nFor ease use of the keystore we already configured a environment variable called `KEYSTORE` pointing to the `keystore` file in the working directory.\n\nYou 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.\n\n```bash\nKEYSTORE=$(grep KEYSTORE .env | cut -d '=' -f2)\n\ncast wallet address --keystore $KEYSTORE\nexport WALLET_ADDRESS=$(cast wallet address --keystore $KEYSTORE)\n\n```\n![setupWallet](./screenshots/setupWallet.png)\n\n# Step 4 | [Test Contracts](./test/BnM.t.sol)\n\nBefore we proceed with deployment, it is best practice to run tests, which can be executed as follows:\n\n```bash\nforge test -vvv\n```\n\n### Test Output\n```plaintext\nRan 1 test for test/BnM.t.sol:BurnMintPoolFork\n[PASS] test_cctDeployment() (gas: 7404858)\nLogs:\n  [1] mockERC20TokenEthSepolia deployed\n  [2] mockERC20TokenBaseSepolia deployed\n  [3] burnMintTokenPoolEthSepolia deployed\n  [4] burnMintTokenPoolBaseSepolia deployed\n  [5] mint and burn roles granted to burnMintTokenPoolEthSepolia\n  [6] mint and burn roles granted to burnMintTokenPoolBaseSepolia\n  [7] Claim Admin role on Ethereum Sepolia\n  [8] Claim Admin role on Base Sepolia\n  [9] Accept Admin role on Ethereum Sepolia\n  [10] Accept Admin role on Base Sepolia\n  [11] Link token to pool on Ethereum Sepolia\n  [12] Link token to pool on Base Sepolia\n  [13] Configured Token Pool on Ethereum Sepolia\n  [14] Configured Token Pool on Base Sepolia\n  [15] minted and sent tokens from Ethereum Sepolia to Base Sepolia\n  [16] received tokens in Base Sepolia\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 9.56s (7.21s CPU time)\n```\n\n# Step 5 | [Deploy Tokens](./script/deploy/DeployTokens.s.sol)\nIn order to interact with our contracts, we first need to deploy them, which is simplified in the [`script/deploy`](./script/deploy) smart contracts, so let's deploy each contract applying the deployment script for each of the following commands.\n\n### 5 | Deploy Tokens | [Ethereum Sepolia](./receipts/transactions/tokenEthSepolia.md)\n\n```bash\nETH_SEPOLIA_RPC=$(grep ETH_SEPOLIA_RPC .env | cut -d '=' -f2)\nWALLET_ADDRESS=$(grep WALLET_ADDRESS .env | cut -d '=' -f2)\nPRIVATE_KEY=$(grep PRIVATE_KEY .env | cut -d '=' -f2)\n\nif ! [ -f .env ]; then\n    echo \"Missing necessary environment variables for deployment\" \n    echo \"Please set the following environment variables:\"\n    echo \"ETH_SEPOLIA_RPC, KEYSTORE, and WALLET_ADDRESS\"\nelse \n    if [ -z \"${DOTENV}\" ]; then\n        echo \"Deploying Token on Sepolia\"\n        rm -rf keystore\n        cast wallet import --private-key $PRIVATE_KEY -k keystore secret\n        forge script ./script/deploy/DeployTokens.s.sol:DeployToken -vvv --broadcast --rpc-url $ETH_SEPOLIA_RPC --sender $WALLET_ADDRESS --private-key $PRIVATE_KEY\n        echo \"Token deployed on Sepolia\"\n    fi\nfi\n```\n\u003c!-- ![Deploy Token Ethereum Sepolia](./receipts/screenshots/deployTokenEthSepolia.png) --\u003e\n\n### 5 | Deploy Tokens | [Base Sepolia](./receipts/transactions/tokenBaseSepolia.md)\n\n```bash\nBASE_SEPOLIA_RPC=$(grep BASE_SEPOLIA_RPC .env | cut -d '=' -f2)\nWALLET_ADDRESS=$(grep WALLET_ADDRESS .env | cut -d '=' -f2)\nPRIVATE_KEY=$(grep PRIVATE_KEY .env | cut -d '=' -f2)\n\nif ! [ -f .env ]; then\n    echo \"Missing necessary environment variables for deployment\" \n    echo \"Please set the following environment variables:\"\n    echo \"BASE_SEPOLIA_RPC, KEYSTORE, and WALLET_ADDRESS\"\nelse \n    if [ -z \"${DOTENV}\" ]; then\n        echo \"Deploying Token on Base Sepolia\"\n        rm -rf keystore\n        cast wallet import --private-key $PRIVATE_KEY -k keystore secret\n        forge script ./script/deploy/DeployTokens.s.sol:DeployToken -vvv --broadcast --rpc-url $BASE_SEPOLIA_RPC --sender $WALLET_ADDRESS --private-key $PRIVATE_KEY\n        echo \"Token deployed on Base Sepolia\"\n    fi\nfi\n```\n![Deploy Token Base Sepolia](./receipts/screenshots/deployTokenBaseSepolia.png)\n\n# Step 6 | Deploy Pools\n\n### Deploy Pools | [Ethereum Sepolia](./receipts/transactions/poolEthSepolia.md)\n```bash\nETH_SEPOLIA_RPC=$(grep ETH_SEPOLIA_RPC .env | cut -d '=' -f2)\nWALLET_ADDRESS=$(grep WALLET_ADDRESS .env | cut -d '=' -f2)\nPRIVATE_KEY=$(grep PRIVATE_KEY .env | cut -d '=' -f2)\nforge script ./script/deploy/DeployPool.s.sol:DeployPool -vvv --broadcast --rpc-url $ETH_SEPOLIA_RPC --sender $WALLET_ADDRESS --private-key $PRIVATE_KEY\n```\n\u003c!-- ![Deploy Pool Ethereum Sepolia](./receipts/screenshots/deployPoolEthSepolia.png) --\u003e\n\n### Deploy Pools | [Base Sepolia](./receipts/transactions/poolBaseSepolia.md)\n```bash\nBASE_SEPOLIA_RPC=$(grep BASE_SEPOLIA_RPC .env | cut -d '=' -f2)\nWALLET_ADDRESS=$(grep WALLET_ADDRESS .env | cut -d '=' -f2)\nPRIVATE_KEY=$(grep PRIVATE_KEY .env | cut -d '=' -f2)\nforge script ./script/deploy/DeployPool.s.sol:DeployPool -vvv --broadcast --rpc-url $BASE_SEPOLIA_RPC --sender $WALLET_ADDRESS --private-key $PRIVATE_KEY\n```\n![Deploy Pool Base Sepolia](./receipts/screenshots/deployPoolBaseSepolia.png)\n\n\n# Step 7 | [Claim Admin Role](./script/manage/ClaimAdmin.s.sol)\n\n### 7 | Claim Admin Role | [Ethereum Sepolia](./receipts/transactions/claimAdminEthSepolia.md)\n```bash\nETH_SEPOLIA_RPC=$(grep ETH_SEPOLIA_RPC .env | cut -d '=' -f2)\nWALLET_ADDRESS=$(grep WALLET_ADDRESS .env | cut -d '=' -f2)\nPRIVATE_KEY=$(grep PRIVATE_KEY .env | cut -d '=' -f2)\nforge script ./script/admin/ClaimAdmin.s.sol:ClaimAdmin --rpc-url $ETH_SEPOLIA_RPC --broadcast --sender $WALLET_ADDRESS --private-key $PRIVATE_KEY\n```\n\n### 7 | Claim Admin Role | [Base Sepolia](./receipts/transactions/claimAdminBaseSepolia.md)\n\n```bash\nBASE_SEPOLIA_RPC=$(grep BASE_SEPOLIA_RPC .env | cut -d '=' -f2)\nWALLET_ADDRESS=$(grep WALLET_ADDRESS .env | cut -d '=' -f2)\nPRIVATE_KEY=$(grep PRIVATE_KEY .env | cut -d '=' -f2)\nforge script ./script/admin/ClaimAdmin.s.sol:ClaimAdmin --rpc-url $BASE_SEPOLIA_RPC --broadcast --sender $WALLET_ADDRESS --private-key $PRIVATE_KEY\n```\n![Claim Admin Role Base Sepolia](./receipts/screenshots/claimAdminBaseSepolia.png)\n\n# Step 8 | [Accept Admin Role](./script/admin/AcceptAdmin.s.sol)\n\n### 8 | Accept Admin Role | [Ethereum Sepolia](./receipts/transactions/acceptAdminEthSepolia.md)\n\n```bash\nETH_SEPOLIA_RPC=$(grep ETH_SEPOLIA_RPC .env | cut -d '=' -f2)\nWALLET_ADDRESS=$(grep WALLET_ADDRESS .env | cut -d '=' -f2)\nPRIVATE_KEY=$(grep PRIVATE_KEY .env | cut -d '=' -f2)\nforge script ./script/admin/AcceptAdmin.s.sol:AcceptAdmin --rpc-url $ETH_SEPOLIA_RPC --broadcast --sender $WALLET_ADDRESS --private-key $PRIVATE_KEY\n```\n\n### 8 | Accept Admin Role | [Base Sepolia](./receipts/transactions/acceptAdminBaseSepolia.md)\n```bash\nBASE_SEPOLIA_RPC=$(grep BASE_SEPOLIA_RPC .env | cut -d '=' -f2)\nWALLET_ADDRESS=$(grep WALLET_ADDRESS .env | cut -d '=' -f2)\nPRIVATE_KEY=$(grep PRIVATE_KEY .env | cut -d '=' -f2)\nforge script ./script/admin/AcceptAdmin.s.sol:AcceptAdmin --rpc-url $BASE_SEPOLIA_RPC --broadcast --sender $WALLET_ADDRESS --private-key $PRIVATE_KEY\n```\n![Accept Admin Role Base Sepolia](./receipts/screenshots/acceptAdminBaseSepolia.png)\n\n# Step 9 | [Set Pool](./script/manage/SetPool.s.sol)\n\n### 9 | Set Pool | [Ethereum Sepolia](./receipts/transactions/setPoolEthSepolia.md)\n```bash\nETH_SEPOLIA_RPC=$(grep ETH_SEPOLIA_RPC .env | cut -d '=' -f2)\nWALLET_ADDRESS=$(grep WALLET_ADDRESS .env | cut -d '=' -f2)\nPRIVATE_KEY=$(grep PRIVATE_KEY .env | cut -d '=' -f2)\nforge script ./script/manage/SetPool.s.sol:SetPool --rpc-url $ETH_SEPOLIA_RPC --broadcast --sender $WALLET_ADDRESS --private-key $PRIVATE_KEY\n```\n\n### 9 | Set Pool | [Base Sepolia](./receipts/transactions/setPoolBaseSepolia.md)\n\n```bash\nBASE_SEPOLIA_RPC=$(grep BASE_SEPOLIA_RPC .env | cut -d '=' -f2)\nWALLET_ADDRESS=$(grep WALLET_ADDRESS .env | cut -d '=' -f2)\nPRIVATE_KEY=$(grep PRIVATE_KEY .env | cut -d '=' -f2)\nforge script ./script/manage/SetPool.s.sol:SetPool --rpc-url $BASE_SEPOLIA_RPC --broadcast --sender $WALLET_ADDRESS --private-key $PRIVATE_KEY\n```\n![Set Pool Base Sepolia](./receipts/screenshots/setPoolBaseSepolia.png)\n\n# Step 10 | [Apply Chain](./script/manage/ApplyChain.s.sol)\n\n### 10 | Apply Chain | [Ethereum Sepolia](./receipts/transactions/applyChainEthSepolia.md)\n```bash\nETH_SEPOLIA_RPC=$(grep ETH_SEPOLIA_RPC .env | cut -d '=' -f2)\nWALLET_ADDRESS=$(grep WALLET_ADDRESS .env | cut -d '=' -f2)\nPRIVATE_KEY=$(grep PRIVATE_KEY .env | cut -d '=' -f2)\nforge script ./script/manage/ApplyChain.s.sol:ApplyChain --rpc-url $ETH_SEPOLIA_RPC --broadcast --sender $WALLET_ADDRESS --private-key $PRIVATE_KEY\n```\n\n### 10 | Apply Chain | [Base Sepolia](./receipts/transactions/applyChainBaseSepolia.md)\n```bash\nBASE_SEPOLIA_RPC=$(grep BASE_SEPOLIA_RPC .env | cut -d '=' -f2)\nWALLET_ADDRESS=$(grep WALLET_ADDRESS .env | cut -d '=' -f2)\nPRIVATE_KEY=$(grep PRIVATE_KEY .env | cut -d '=' -f2)\nforge script ./script/manage/ApplyChain.s.sol:ApplyChain --rpc-url $BASE_SEPOLIA_RPC --broadcast --sender $WALLET_ADDRESS --private-key $PRIVATE_KEY\n```\n![Apply Chain Base Sepolia](./receipts/screenshots/applyChainBaseSepolia.png)\n\n# Step 11 | [Mint Tokens](./script/mint/MintTokens.s.sol)\n\n### 11 | Mint Tokens | [Ethereum Sepolia](./receipts/transactions/mintEthSepolia.md)\n```bash\nETH_SEPOLIA_RPC=$(grep ETH_SEPOLIA_RPC .env | cut -d '=' -f2)\nWALLET_ADDRESS=$(grep WALLET_ADDRESS .env | cut -d '=' -f2)\nPRIVATE_KEY=$(grep PRIVATE_KEY .env | cut -d '=' -f2)\nforge script ./script/mint/MintTokens.s.sol:MintTokens --rpc-url $ETH_SEPOLIA_RPC --broadcast --sender $WALLET_ADDRESS --private-key $PRIVATE_KEY\n```\n![Mint Tokens Ethereum Sepolia](./receipts/screenshots/mintEthSepolia.png)\n\n# Step 12 | [Transfer Tokens](./script/transfer/TransferTokens.s.sol)\n\n### 12 | Transfer Tokens | [Ethereum Sepolia](./receipts/transactions/transferEthSepolia.md)\n```bash\nETH_SEPOLIA_RPC=$(grep ETH_SEPOLIA_RPC .env | cut -d '=' -f2)\nWALLET_ADDRESS=$(grep WALLET_ADDRESS .env | cut -d '=' -f2)\nPRIVATE_KEY=$(grep PRIVATE_KEY .env | cut -d '=' -f2)\nforge script ./script/transfer/TransferTokens.s.sol:TransferTokens --rpc-url $ETH_SEPOLIA_RPC --broadcast --sender $WALLET_ADDRESS --private-key $PRIVATE_KEY\n```\n![Transfer Tokens Ethereum Sepolia](./receipts/screenshots/transferEthSepolia.png)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbunsdev%2Fcct-linklabs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbunsdev%2Fcct-linklabs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbunsdev%2Fcct-linklabs/lists"}