Skip to content

Commit

Permalink
UI created to visuals of CCIP
Browse files Browse the repository at this point in the history
  • Loading branch information
viral-sangani committed Jul 7, 2024
1 parent 99dcebe commit f02f8c8
Show file tree
Hide file tree
Showing 30 changed files with 10,697 additions and 583 deletions.
4 changes: 2 additions & 2 deletions packages/hardhat/.env.example
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
MNEMONIC=""
PRIVATE_KEY=""
CELOSCAN_API_KEY=""
CELOSCAN_API_KEY=""
ETHERSCAN_API_KEY=""
3 changes: 3 additions & 0 deletions packages/hardhat/addresses.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
SourceMinter (alfajores) = 0xF11f9085D5d8AFB2e5de62466F6e82F379E74509
CeloNFT (Sepolia) = 0x5F7d03E873c2E2F544540A03c46dD34bC4A47436
DestinationMinter (Sepolia) = 0x98413ff50d1e41C34a41bd7910b362A358610469
16 changes: 16 additions & 0 deletions packages/hardhat/contracts/CeloNFT.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

contract CeloNFT is ERC721, Ownable {
uint256 private _nextTokenId;

constructor() ERC721("CeloNFT", "CNFT") Ownable(msg.sender) {}

function safeMint(address to) public onlyOwner {
uint256 tokenId = _nextTokenId++;
_safeMint(to, tokenId);
}
}
24 changes: 24 additions & 0 deletions packages/hardhat/contracts/DestinationMinter.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;

import {CCIPReceiver} from "@chainlink/contracts-ccip/src/v0.8/ccip/applications/CCIPReceiver.sol";
import {Client} from "@chainlink/contracts-ccip/src/v0.8/ccip/libraries/Client.sol";
import {CeloNFT} from "./CeloNFT.sol";

contract DestinationMinter is CCIPReceiver {
CeloNFT nft;

event MintCallSuccessfull();

constructor(address router, address nftAddress) CCIPReceiver(router) {
nft = CeloNFT(nftAddress);
}

function _ccipReceive(
Client.Any2EVMMessage memory message
) internal override {
(bool success, ) = address(nft).call(message.data);
require(success);
emit MintCallSuccessfull();
}
}
63 changes: 63 additions & 0 deletions packages/hardhat/contracts/SourceMinter.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;

import {LinkTokenInterface} from "@chainlink/contracts/src/v0.8/shared/interfaces/LinkTokenInterface.sol";
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 {Withdraw} from "./utils/Withdraw.sol";

contract SourceMinter is Withdraw {
enum PayFeesIn {
Native,
LINK
}

address immutable i_router;
address immutable i_link;

event MessageSent(bytes32 messageId);

constructor(address router, address link) {
i_router = router;
i_link = link;
LinkTokenInterface(i_link).approve(i_router, type(uint256).max);
}

receive() external payable {}

function mint(
uint64 destinationChainSelector,
address receiver,
PayFeesIn payFeesIn
) external {
Client.EVM2AnyMessage memory message = Client.EVM2AnyMessage({
receiver: abi.encode(receiver),
data: abi.encodeWithSignature("mint(address)", msg.sender),
tokenAmounts: new Client.EVMTokenAmount[](0),
extraArgs: "",
feeToken: payFeesIn == PayFeesIn.LINK ? i_link : address(0)
});

uint256 fee = IRouterClient(i_router).getFee(
destinationChainSelector,
message
);

bytes32 messageId;

if (payFeesIn == PayFeesIn.LINK) {
// LinkTokenInterface(i_link).approve(i_router, fee);
messageId = IRouterClient(i_router).ccipSend(
destinationChainSelector,
message
);
} else {
messageId = IRouterClient(i_router).ccipSend{value: fee}(
destinationChainSelector,
message
);
}

emit MessageSent(messageId);
}
}
23 changes: 23 additions & 0 deletions packages/hardhat/contracts/utils/Withdraw.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;

import {OwnerIsCreator} from "@chainlink/contracts-ccip/src/v0.8/shared/access/OwnerIsCreator.sol";
import {IERC20} from "@chainlink/contracts-ccip/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol";

contract Withdraw is OwnerIsCreator {
error FailedToWithdrawEth(address owner, address target, uint256 value);

function withdraw(address beneficiary) public onlyOwner {
uint256 amount = address(this).balance;
(bool sent, ) = beneficiary.call{value: amount}("");
if (!sent) revert FailedToWithdrawEth(msg.sender, beneficiary, amount);
}

function withdrawToken(
address beneficiary,
address token
) public onlyOwner {
uint256 amount = IERC20(token).balanceOf(address(this));
IERC20(token).transfer(beneficiary, amount);
}
}
77 changes: 45 additions & 32 deletions packages/hardhat/hardhat.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,39 +3,52 @@ require("dotenv").config();

/** @type import('hardhat/config').HardhatUserConfig */
module.exports = {
solidity: "0.8.17",
networks: {
alfajores: {
url: "https://alfajores-forno.celo-testnet.org",
accounts: [process.env.PRIVATE_KEY],
solidity: "0.8.20",
networks: {
alfajores: {
url: "https://alfajores-forno.celo-testnet.org",
accounts: [process.env.PRIVATE_KEY],
},
celo: {
url: "https://forno.celo.org",
accounts: [process.env.PRIVATE_KEY],
},
sepolia: {
url: "https://ethereum-sepolia-rpc.publicnode.com",
accounts: [process.env.PRIVATE_KEY],
},
},
etherscan: {
apiKey: {
alfajores: process.env.CELOSCAN_API_KEY,
celo: process.env.CELOSCAN_API_KEY,
sepolia: process.env.ETHERSCAN_API_KEY,
},
customChains: [
{
network: "alfajores",
chainId: 44787,
urls: {
apiURL: "https://api-alfajores.celoscan.io/api",
browserURL: "https://alfajores.celoscan.io",
},
celo: {
url: "https://forno.celo.org",
accounts: [process.env.PRIVATE_KEY],
},
{
network: "celo",
chainId: 42220,
urls: {
apiURL: "https://api.celoscan.io/api",
browserURL: "https://celoscan.io/",
},
},
etherscan: {
apiKey: {
alfajores: process.env.CELOSCAN_API_KEY,
celo: process.env.CELOSCAN_API_KEY,
},
{
network: "sepolia",
chainId: 1337,
urls: {
apiURL: "https://api-sepolia.etherscan.io/api",
browserURL: "https://sepolia.etherscan.io/",
},
customChains: [
{
network: "alfajores",
chainId: 44787,
urls: {
apiURL: "https://api-alfajores.celoscan.io/api",
browserURL: "https://alfajores.celoscan.io",
},
},
{
network: "celo",
chainId: 42220,
urls: {
apiURL: "https://api.celoscan.io/api",
browserURL: "https://celoscan.io/",
},
},
],
},
},
],
},
};
3 changes: 3 additions & 0 deletions packages/hardhat/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@
"compile": "npx hardhat compile"
},
"dependencies": {
"@chainlink/contracts": "^1.1.1",
"@chainlink/contracts-ccip": "^1.4.0",
"@openzeppelin/contracts": "^5.0.2",
"dotenv": "^16.3.1"
}
}
31 changes: 31 additions & 0 deletions packages/hardhat/scripts/1.deploy.source.alfajores.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
const hre = require("hardhat");

const routerAddress = "0xb00E95b773528E2Ea724DB06B75113F239D15Dca";
const linkTokenAddress = "0x32E08557B14FaD8908025619797221281D439071";

async function main() {
console.log(`Deploying Source Minter...`);
const SourceMinter = await hre.ethers.getContractFactory("SourceMinter");
const sourceMinter = await SourceMinter.deploy(
routerAddress,
linkTokenAddress
);

await sourceMinter.deployed();

console.log(`Source Minter deployed to :: ${sourceMinter.address}`);
// verify hardhat
try {
await hre.run("verify:verify", {
address: sourceMinter.address,
constructorArguments: [routerAddress, linkTokenAddress],
});
} catch (e) {
console.log("Cannot verify the contract");
}
}

main().catch((error) => {
console.error(error);
process.exitCode = 1;
});
26 changes: 26 additions & 0 deletions packages/hardhat/scripts/2.deploy.celonft.sepolia.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
const hre = require("hardhat");

async function main() {
console.log(`Deploying Celo NFT...`);

const CeloNFT = await hre.ethers.getContractFactory("CeloNFT");
const celoNFT = await CeloNFT.deploy();

await celoNFT.deployed();

console.log(`CeloNFT deployed to :: ${celoNFT.address}`);

// verify hardhat
try {
await hre.run("verify:verify", {
address: celoNFT.address,
});
} catch (e) {
console.log("Cannot verify the contract");
}
}

main().catch((error) => {
console.error(error);
process.exitCode = 1;
});
34 changes: 34 additions & 0 deletions packages/hardhat/scripts/3.deploy.destination.sepolia.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
const hre = require("hardhat");

const routerAddress = "0x0BF3dE8c5D3e8A2B34D2BEeB17ABfCeBaf363A59";
const celoNFTAddress = "0x5F7d03E873c2E2F544540A03c46dD34bC4A47436";

async function main() {
console.log(`Deploying Destination Minter...`);
const DestinationMinter = await hre.ethers.getContractFactory(
"DestinationMinter"
);
const destinationMinter = await DestinationMinter.deploy(
routerAddress,
celoNFTAddress
);

await destinationMinter.deployed();

console.log(`Destination Minter deployed to :: ${destinationMinter.address}`);

// verify hardhat
try {
await hre.run("verify:verify", {
address: destinationMinter.address,
constructorArguments: [routerAddress, celoNFTAddress],
});
} catch (e) {
console.log("Cannot verify the contract");
}
}

main().catch((error) => {
console.error(error);
process.exitCode = 1;
});
22 changes: 22 additions & 0 deletions packages/hardhat/scripts/4.transfer-ownership.sepolia.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
const hre = require("hardhat");

const celoNFTAddress = "0x5F7d03E873c2E2F544540A03c46dD34bC4A47436";
// DestinationMinter contract address
const newOwner = "0x98413ff50d1e41C34a41bd7910b362A358610469";

async function main() {
console.log(`Transfering Ownership of CeloNFT to Destination Minter...`);

const [deployer] = await ethers.getSigners();
const contractABI = ["function transferOwnership(address newOwner) public"];
const contract = new ethers.Contract(celoNFTAddress, contractABI, deployer);

// Call the transferOwnership function
const tx = await contract.transferOwnership(newOwner);
await tx.wait();
}

main().catch((error) => {
console.error(error);
process.exitCode = 1;
});
30 changes: 30 additions & 0 deletions packages/hardhat/scripts/5.mint-nft.alfajores.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
const hre = require("hardhat");
const {
abi,
} = require("../artifacts/contracts/SourceMinter.sol/SourceMinter.json");

const sourceMinterAddress = "0xF11f9085D5d8AFB2e5de62466F6e82F379E74509";
const destinationChainSelector = "16015286601757825753";
const receiverDestinationMinterAddress =
"0x98413ff50d1e41C34a41bd7910b362A358610469";

async function main() {
console.log(`Minting NFT from Alfajores to Sepolia...`);

const [deployer] = await ethers.getSigners();
const contract = new ethers.Contract(sourceMinterAddress, abi, deployer);

// Call the transferOwnership function
const tx = await contract.mint(
destinationChainSelector,
receiverDestinationMinterAddress,
1
);
await tx.wait();
console.log("tx", tx);
}

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

0 comments on commit f02f8c8

Please sign in to comment.