Skip to content

Commit

Permalink
feat: add eth nft contracts
Browse files Browse the repository at this point in the history
  • Loading branch information
pygman committed Jul 7, 2022
1 parent 01ba729 commit 39c409d
Show file tree
Hide file tree
Showing 8 changed files with 801 additions and 1 deletion.
2 changes: 1 addition & 1 deletion .github/workflows/code-coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
override: true
components: rustfmt, clippy
- name: install-tarpaulin
run: cargo install cargo-tarpaulin -f --version 0.19.0
run: cargo install cargo-tarpaulin -f --version 0.20.0
- name: run coverage test
run: |
export CODECOV_TOKEN=${{secrets.CODECOV_TOKEN}}
Expand Down
31 changes: 31 additions & 0 deletions eth-contracts/contracts/NervosMirrorNftToken.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

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

/// @title NervosMirrorNftToken - A token contract used for bridged nft token from Nervos Chain
contract NervosMirrorNftToken is ERC1155, Ownable{
address public factory;
string public classId;

event CreatedNftToken(address tokenAddr, string classId, address factory);

constructor(string memory uri_, string memory classId_) ERC1155(uri_) {
factory = msg.sender;
classId = classId_;
emit CreatedNftToken(address(this), classId, factory);
}

function mint(address to, uint256 id, uint256 amount, bytes memory data) public onlyOwner {
_mint(to, id, amount, data);
}

function mintBatch(address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data) public onlyOwner {
_mintBatch(to, ids, amounts, data);
}

function burn(address account, uint256 id, uint256 value) public onlyOwner {
_burn(account, id, value);
}
}
124 changes: 124 additions & 0 deletions eth-contracts/contracts/NftClassManager.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "./interfaces/IMirrorToken.sol";
import "./interfaces/IMirrorNftToken.sol";
import "./NervosMirrorNftToken.sol";

/// @title Asset Manager - The entry to manage all bridged tokens from Nervos chain
/// The owner of this contract should be transferred to the gnosis multi-sig wallet of Force Bridge committee when the
/// initializing is done.
/// All tokens recorded in this contract should be authorized to mint, and burn through this contract to make bridge action.
contract NftClassManager is Ownable, ReentrancyGuard {
string private uri_ = "";

struct ChainMetadata {
uint8 chain; // 0: CKB
uint8 chainId;
uint8 nftType; // 1: mnft 2: nrc721 3: cota
uint256 cellTxHash;
uint32 cellIndex;
bytes sourceOwner;
string classId;
address token;
}

// classId is the identifier of the nft class cell on Nervos Chain
mapping(address => ChainMetadata) public tokenToChainMap;
mapping(string => ChainMetadata) public classIdToChainMap;
address[] public allTokens;

event MintNft(
string indexed classId,
address indexed token,
address indexed to,
uint256 nftId,
bytes lockId
);

event BurnNft(
string indexed classId,
address indexed token,
address indexed from,
uint256 nftId,
uint256 fee,
bytes recipient,
bytes extraData
);

struct MintNftRecord {
string classId; // nft class id locked on Nervos chain
address to; // address of the receiver
uint256 nftId; // nft id on Nervos chain
bytes lockId; // used to identify the lock transaction on Nervos Chain
}

function createClass2(ChainMetadata memory chain) internal returns(address tokenAddr){
tokenToChainMap[chain.token] = chain;
classIdToChainMap[chain.classId] = chain;
bytes32 salt = keccak256(abi.encodePacked(chain.classId));
NervosMirrorNftToken nervosMirrorNftToken = new NervosMirrorNftToken{salt: salt}(uri_, chain.classId);
tokenAddr = address(nervosMirrorNftToken);
chain.token = tokenAddr;
allTokens.push(tokenAddr);
tokenToChainMap[tokenAddr] = chain;
classIdToChainMap[chain.classId] = chain;
}

/// @dev Mint an nft.
/// @param records The mint records.
/// This function should only be invoked by the gnosis multi-sig wallet of Force Bridge committee.
function mintNft(MintNftRecord[] memory records) public onlyOwner {
for (uint256 i = 0; i < records.length; i++) {
ChainMetadata memory chain = classIdToChainMap[records[i].classId];
if (chain.token == address(0)) {
chain.token = createClass2(chain);
} else {
chain.token = classIdToChainMap[chain.classId].token;
}
require(chain.token != address(0), "nft class not found");
IMirrorNftToken(chain.token).mint(records[i].to, records[i].nftId, 1, "");
emit MintNft(
records[i].classId,
chain.token,
records[i].to,
records[i].nftId,
records[i].lockId
);
}
}

/// @dev Burn an nft and get the locked amount back on Nervos chain.
/// @param token The address of the token to burn.
/// @param nftId The nft id.
/// @param recipient The recipient on Nervos Chain.
/// @param extraData Extra data to be sent to the recipient.
function burnNft(
address token,
uint256 nftId,
bytes calldata recipient,
bytes calldata extraData
) public payable nonReentrant {
ChainMetadata memory chain = tokenToChainMap[token];
require(chain.chainId != 0, "chain not supported");
require(chain.token != address(0), "token not supported");
// pay the fee to bridge committee
if (msg.value > 0) {
(bool success, ) = payable(owner()).call{value: msg.value}("");
require(success, "fee payment to bridge committee failed");
}
// burn the nft
IMirrorNftToken(token).burn(_msgSender(), nftId, 1);
emit BurnNft(
chain.classId,
token,
_msgSender(),
nftId,
msg.value,
recipient,
extraData
);
}
}
Loading

0 comments on commit 39c409d

Please sign in to comment.