diff --git a/contracts/CrossNftDestinationMinter.sol b/contracts/CrossNftDestinationMinter.sol index 73876bf..2b0a303 100644 --- a/contracts/CrossNftDestinationMinter.sol +++ b/contracts/CrossNftDestinationMinter.sol @@ -1,22 +1,82 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.20; +import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol"; +import {OwnerIsCreator} from "@chainlink/contracts-ccip/src/v0.8/shared/access/OwnerIsCreator.sol"; 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 {MyNFT} from "./MyNFT.sol"; -contract CrossNftDestinationMinter is CCIPReceiver { - MyNFT nft; +contract MyNFT is ERC721URIStorage, OwnerIsCreator { + // string constant TOKEN_URI = + // "https://ipfs.io/ipfs/QmYuKY45Aq87LeL1R5dhb1hqHLp6ZFbJaCP8jxqKM1MX6y/babe_ruth_1.json"; + uint256 internal tokenId; + + constructor() ERC721("MyNFT", "MNFT"){} + + function mint(address to, string memory TOKEN_URI) public onlyOwner { + _safeMint(to, tokenId); + _setTokenURI(tokenId, TOKEN_URI); + unchecked { + tokenId++; + } + } +} +contract CrossNftDestinationMinter is CCIPReceiver, OwnerIsCreator{ + MyNFT public nft; + uint256 price; + + event MintCallSuccessfull(); + mapping(uint64 => bool) public whitelistedSourceChains; + mapping(address => bool) public whitelistedSenders; event MintCallSuccessfull(); - constructor(address router, address nftAddress) CCIPReceiver(router) { - nft = MyNFT(nftAddress); + error SourceChainNotWhitelisted(uint64 sourceChainSelector); + error SenderNotWhitelisted(address sender); + + modifier onlyWhitelistedSourceChain(uint64 _sourceChainSelector) { + if (!whitelistedSourceChains[_sourceChainSelector]) + revert SourceChainNotWhitelisted(_sourceChainSelector); + _; + } + + modifier onlyWhitelistedSenders(address _sender) { + if (!whitelistedSenders[_sender]) revert SenderNotWhitelisted(_sender); + _; } + constructor(address router, uint256 _price) CCIPReceiver(router) { + nft = new MyNFT(); + price = _price; + } + + function whitelistSourceChain( + uint64 _sourceChainSelector + ) external onlyOwner { + whitelistedSourceChains[_sourceChainSelector] = true; + } + + function denylistSourceChain( + uint64 _sourceChainSelector + ) external onlyOwner { + whitelistedSourceChains[_sourceChainSelector] = false; + } + + function whitelistSender(address _sender) external onlyOwner { + whitelistedSenders[_sender] = true; + } + + function denySender(address _sender) external onlyOwner { + whitelistedSenders[_sender] = false; + } function _ccipReceive( Client.Any2EVMMessage memory message - ) internal override { + ) internal + onlyWhitelistedSourceChain(message.sourceChainSelector) + onlyWhitelistedSenders(abi.decode(message.sender, (address))) + override + { + require(message.destTokenAmounts[0].amount >= price, "Not enough CCIP-BnM for mint"); (bool success, ) = address(nft).call(message.data); require(success); emit MintCallSuccessfull(); diff --git a/contracts/CrossNftSourceMinter.sol b/contracts/CrossNftSourceMinter.sol index 4429efc..da7a484 100644 --- a/contracts/CrossNftSourceMinter.sol +++ b/contracts/CrossNftSourceMinter.sol @@ -77,7 +77,7 @@ contract CrossNftSourceMinter is OwnerIsCreator{ // Build the CCIP Message Client.EVM2AnyMessage memory message = Client.EVM2AnyMessage({ receiver: abi.encode(_receiver), - data: abi.encodeWithSignature("mint(address, _metadataURL)", msg.sender), + data: abi.encodeWithSignature("mint(address, string)", msg.sender, _metadataURL), tokenAmounts: tokenAmounts, extraArgs: Client._argsToBytes( Client.EVMExtraArgsV1({gasLimit: 200_000, strict: false}) diff --git a/contracts/MyNFT.sol b/contracts/MyNFT.sol deleted file mode 100644 index 0b4635f..0000000 --- a/contracts/MyNFT.sol +++ /dev/null @@ -1,21 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.20; - -import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol"; -import "@openzeppelin/contracts/access/Ownable.sol"; - -contract MyNFT is ERC721URIStorage, Ownable { - string constant TOKEN_URI = - "https://ipfs.io/ipfs/QmYuKY45Aq87LeL1R5dhb1hqHLp6ZFbJaCP8jxqKM1MX6y/babe_ruth_1.json"; - uint256 internal tokenId; - - constructor(address initialOwner) ERC721("MyNFT", "MNFT") Ownable(initialOwner){} - - function mint(address to) public onlyOwner { - _safeMint(to, tokenId); - _setTokenURI(tokenId, TOKEN_URI); - unchecked { - tokenId++; - } - } -} \ No newline at end of file