Skip to content

Commit

Permalink
Merge pull request #5 from crossnft-labs/feature/pay-for-nft-minting
Browse files Browse the repository at this point in the history
Feature/pay for nft minting on source chain
  • Loading branch information
cross-nft-labs authored Dec 5, 2023
2 parents 5c9b12d + 44235f3 commit a617d51
Showing 1 changed file with 97 additions and 35 deletions.
132 changes: 97 additions & 35 deletions contracts/CrossNftSourceMinter.sol
Original file line number Diff line number Diff line change
@@ -1,62 +1,124 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;

import {LinkTokenInterface} from "@chainlink/contracts/src/v0.8/shared/interfaces/LinkTokenInterface.sol";
import {OwnerIsCreator} from "@chainlink/contracts-ccip/src/v0.8/shared/access/OwnerIsCreator.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";
import {IERC20} from "@chainlink/contracts-ccip/src/v0.8/vendor/openzeppelin-solidity/v4.8.0/token/ERC20/IERC20.sol";
import {LinkTokenInterface} from "@chainlink/contracts/src/v0.8/interfaces/LinkTokenInterface.sol";

contract CrossNftSourceMinter is Withdraw {
contract CrossNftSourceMinter is OwnerIsCreator{
enum PayFeesIn {
Native,
LINK
}
ddress immutable i_router;
address immutable i_router;
address immutable i_link;

event MessageSent(bytes32 messageId);
mapping(uint64 => bool) public whitelistedChains;

error NotEnoughBalance(uint256 currentBalance, uint256 calculatedFees);
error DestinationChainNotWhitelisted(uint64 destinationChainSelector);
error NothingToWithdraw();

//event MessageSent(bytes32 messageId);

event TokensTransferred(
bytes32 indexed messageId, // The unique ID of the message.
uint64 indexed destinationChainSelector, // The chain selector of the destination chain.
address receiver, // The address of the receiver on the destination chain.
address token, // The token address that was transferred.
uint256 tokenAmount, // The token amount that was transferred.
uint256 fees // The fees paid for sending the message.
);

modifier onlyWhitelistedChain(uint64 _destinationChainSelector) {
if (!whitelistedChains[_destinationChainSelector])
revert DestinationChainNotWhitelisted(_destinationChainSelector);
_;
}

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

receive() external payable {}
function whitelistChain(
uint64 _destinationChainSelector
) external onlyOwner {
whitelistedChains[_destinationChainSelector] = true;
}

function denylistChain(
uint64 _destinationChainSelector
) external onlyOwner {
whitelistedChains[_destinationChainSelector] = false;
}

function mint(
uint64 destinationChainSelector,
address receiver,
PayFeesIn payFeesIn
) external {
uint64 _destinationChainSelector,
address _receiver,
address _token,
uint256 _amount,
string _metadataURL
)
external
onlyWhitelistedChain(_destinationChainSelector)
returns (bytes32 messageId)
{
Client.EVMTokenAmount[]
memory tokenAmounts = new Client.EVMTokenAmount[](1);
Client.EVMTokenAmount memory tokenAmount = Client.EVMTokenAmount({
token: _token,
amount: _amount
});
tokenAmounts[0] = tokenAmount;

// Build the CCIP Message
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)
receiver: abi.encode(_receiver),
data: abi.encodeWithSignature("mint(address, _metadataURL)", msg.sender),
tokenAmounts: tokenAmounts,
extraArgs: Client._argsToBytes(
Client.EVMExtraArgsV1({gasLimit: 200_000, strict: false})
),
feeToken: address(linkToken)
});

// CCIP Fees Management
uint256 fees = router.getFee(_destinationChainSelector, message);

uint256 fee = IRouterClient(i_router).getFee(
destinationChainSelector,
message
if (fees > linkToken.balanceOf(address(this)))
revert NotEnoughBalance(linkToken.balanceOf(address(this)), fees);

linkToken.approve(address(router), fees);

// Approve Router to spend CCIP-BnM tokens we send
IERC20(_token).approve(address(router), _amount);

// Send CCIP Message
messageId = router.ccipSend(_destinationChainSelector, message);

emit TokensTransferred(
messageId,
_destinationChainSelector,
_receiver,
_token,
_amount,
fees
);
}

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);
function withdrawToken(
address _beneficiary,
address _token
) public onlyOwner {
uint256 amount = IERC20(_token).balanceOf(address(this));

if (amount == 0) revert NothingToWithdraw();

IERC20(_token).transfer(_beneficiary, amount);
}

receive() external payable {}
}

0 comments on commit a617d51

Please sign in to comment.