增加1155的芯片
This commit is contained in:
parent
082bfb9483
commit
c756583f39
47434
build/contracts/BEChip1155.json
Normal file
47434
build/contracts/BEChip1155.json
Normal file
File diff suppressed because one or more lines are too long
24442
build/contracts/BEChipFactory.json
Normal file
24442
build/contracts/BEChipFactory.json
Normal file
File diff suppressed because one or more lines are too long
269
contracts/chip1155/BEChip1155.sol
Normal file
269
contracts/chip1155/BEChip1155.sol
Normal file
@ -0,0 +1,269 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity 0.8.10;
|
||||
|
||||
import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";
|
||||
import "@openzeppelin/contracts/access/Ownable.sol";
|
||||
import "@openzeppelin/contracts/access/AccessControl.sol";
|
||||
|
||||
contract BEChip1155 is ERC1155, AccessControl {
|
||||
bytes32 public constant URI_SETTER_ROLE = keccak256("URI_SETTER_ROLE");
|
||||
bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
|
||||
bytes32 public constant BURN_ROLE = keccak256("BURN_ROLE");
|
||||
bytes32 public constant LOCK_ROLE = keccak256("LOCK_ROLE");
|
||||
|
||||
mapping(uint256 => bool) public lockedTokens;
|
||||
|
||||
struct TokenStruct {
|
||||
uint256 tokenId;
|
||||
uint256 amount;
|
||||
}
|
||||
|
||||
mapping(address => uint256[]) private _ownedTokens;
|
||||
mapping(address => mapping(uint256 => uint256)) private _ownedTokensIndex;
|
||||
|
||||
mapping(uint256 => uint256) private _totalSupply;
|
||||
|
||||
constructor() ERC1155("https://market.cebg.games/api/nft/info/{id}") {
|
||||
_grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
|
||||
_grantRole(URI_SETTER_ROLE, msg.sender);
|
||||
}
|
||||
|
||||
function setURI(string memory newuri) external onlyRole(URI_SETTER_ROLE) {
|
||||
_setURI(newuri);
|
||||
}
|
||||
|
||||
function mint(
|
||||
address account,
|
||||
uint256 id,
|
||||
uint256 amount,
|
||||
bytes memory data
|
||||
) external onlyRole(MINTER_ROLE) {
|
||||
_mint(account, id, amount, data);
|
||||
}
|
||||
|
||||
function mintBatch(
|
||||
address to,
|
||||
uint256[] memory ids,
|
||||
uint256[] memory amounts,
|
||||
bytes memory data
|
||||
) external onlyRole(MINTER_ROLE) {
|
||||
_mintBatch(to, ids, amounts, data);
|
||||
}
|
||||
|
||||
function burn(
|
||||
address account,
|
||||
uint256 id,
|
||||
uint256 value
|
||||
) external onlyRole(BURN_ROLE) {
|
||||
_burn(account, id, value);
|
||||
}
|
||||
|
||||
function burnBatch(
|
||||
address account,
|
||||
uint256[] memory ids,
|
||||
uint256[] memory values
|
||||
) external onlyRole(BURN_ROLE) {
|
||||
_burnBatch(account, ids, values);
|
||||
}
|
||||
|
||||
// The following functions are overrides required by Solidity.
|
||||
|
||||
function supportsInterface(bytes4 interfaceId)
|
||||
public
|
||||
view
|
||||
override(ERC1155, AccessControl)
|
||||
returns (bool)
|
||||
{
|
||||
return super.supportsInterface(interfaceId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Add factory to mint/burn item
|
||||
*/
|
||||
function setMintFactory(address factory)
|
||||
external
|
||||
onlyRole(DEFAULT_ADMIN_ROLE)
|
||||
{
|
||||
_grantRole(MINTER_ROLE, factory);
|
||||
_grantRole(BURN_ROLE, factory);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Remove factory
|
||||
*/
|
||||
function removeMintFactory(address factory)
|
||||
external
|
||||
onlyRole(DEFAULT_ADMIN_ROLE)
|
||||
{
|
||||
_revokeRole(MINTER_ROLE, factory);
|
||||
_revokeRole(BURN_ROLE, factory);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Total amount of tokens in with a given id.
|
||||
*/
|
||||
function totalSupply(uint256 id) public view virtual returns (uint256) {
|
||||
return _totalSupply[id];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Indicates whether any token exist with a given id, or not.
|
||||
*/
|
||||
function exists(uint256 id) external view virtual returns (bool) {
|
||||
return BEChip1155.totalSupply(id) > 0;
|
||||
}
|
||||
|
||||
function grantLockRole(address account)
|
||||
external
|
||||
onlyRole(DEFAULT_ADMIN_ROLE)
|
||||
{
|
||||
_grantRole(LOCK_ROLE, account);
|
||||
}
|
||||
|
||||
function revokeLockRole(address account)
|
||||
external
|
||||
onlyRole(DEFAULT_ADMIN_ROLE)
|
||||
{
|
||||
_revokeRole(LOCK_ROLE, account);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Lock token to use in game or for rental
|
||||
*/
|
||||
function lock(uint256 id) external onlyRole(LOCK_ROLE) {
|
||||
require(_totalSupply[id] > 0, "Must be valid tokenId");
|
||||
require(!lockedTokens[id], "Token has already locked");
|
||||
lockedTokens[id] = true;
|
||||
}
|
||||
|
||||
function lockBatch(uint256[] memory ids) external onlyRole(LOCK_ROLE) {
|
||||
uint256 len = ids.length;
|
||||
for (uint256 i = 0; i < len; ++i) {
|
||||
uint256 id = ids[i];
|
||||
require(_totalSupply[id] > 0, "Must be valid tokenId");
|
||||
require(!lockedTokens[id], "Token has already locked");
|
||||
lockedTokens[id] = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Unlock token to use blockchain or sale on marketplace
|
||||
*/
|
||||
function unlock(uint256 id) external onlyRole(LOCK_ROLE) {
|
||||
require(_totalSupply[id] > 0, "Must be valid tokenId");
|
||||
require(lockedTokens[id], "Token has already unlocked");
|
||||
lockedTokens[id] = false;
|
||||
}
|
||||
|
||||
function unlockBatch(uint256[] memory ids) external onlyRole(LOCK_ROLE) {
|
||||
uint256 len = ids.length;
|
||||
for (uint256 i = 0; i < len; ++i) {
|
||||
uint256 id = ids[i];
|
||||
require(_totalSupply[id] > 0, "Must be valid tokenId");
|
||||
require(lockedTokens[id], "Token has already unlocked");
|
||||
lockedTokens[id] = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Get lock status
|
||||
*/
|
||||
function isLocked(uint256 id) external view returns (bool) {
|
||||
return lockedTokens[id];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev See {ERC1155-_beforeTokenTransfer}.
|
||||
*/
|
||||
function _beforeTokenTransfer(
|
||||
address operator,
|
||||
address from,
|
||||
address to,
|
||||
uint256[] memory ids,
|
||||
uint256[] memory amounts,
|
||||
bytes memory data
|
||||
) internal virtual override {
|
||||
super._beforeTokenTransfer(operator, from, to, ids, amounts, data);
|
||||
uint256 len = ids.length;
|
||||
if (from == address(0)) {
|
||||
// mint nft
|
||||
for (uint256 i = 0; i < len; ++i) {
|
||||
_totalSupply[ids[i]] += amounts[i];
|
||||
}
|
||||
} else if (from != to) {
|
||||
// transfer from -> to
|
||||
for (uint256 i = 0; i < len; ++i) {
|
||||
_removeTokenFromOwnerEnumeration(from, ids[i], amounts[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (to == address(0)) {
|
||||
// burn nft
|
||||
for (uint256 i = 0; i < len; ++i) {
|
||||
_totalSupply[ids[i]] -= amounts[i];
|
||||
}
|
||||
} else if (to != from) {
|
||||
// mint or transfer from -> to
|
||||
for (uint256 i = 0; i < len; ++i) {
|
||||
_addTokenToOwnerEnumeration(to, ids[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function _addTokenToOwnerEnumeration(address to, uint256 tokenId) private {
|
||||
if (
|
||||
_ownedTokensIndex[to][tokenId] == 0 && balanceOf(to, tokenId) == 0
|
||||
) {
|
||||
_ownedTokensIndex[to][tokenId] = _ownedTokens[to].length;
|
||||
_ownedTokens[to].push(tokenId);
|
||||
}
|
||||
}
|
||||
|
||||
function _removeTokenFromOwnerEnumeration(
|
||||
address from,
|
||||
uint256 tokenId,
|
||||
uint256 amount
|
||||
) private {
|
||||
uint256 balance = balanceOf(from, tokenId);
|
||||
if (balance == amount) {
|
||||
uint256 lastTokenIndex = _ownedTokens[from].length - 1;
|
||||
uint256 tokenIndex = _ownedTokensIndex[from][tokenId];
|
||||
|
||||
uint256 lastTokenId = _ownedTokens[from][lastTokenIndex];
|
||||
|
||||
_ownedTokens[from][tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token
|
||||
_ownedTokensIndex[from][lastTokenId] = tokenIndex; // Update the moved token's index
|
||||
|
||||
// This also deletes the contents at the last position of the array
|
||||
delete _ownedTokensIndex[from][tokenId];
|
||||
_ownedTokens[from].pop();
|
||||
}
|
||||
}
|
||||
|
||||
function userTokens(
|
||||
address user,
|
||||
uint256 start,
|
||||
uint256 page
|
||||
) external view returns (TokenStruct[] memory) {
|
||||
uint256 size = _ownedTokens[user].length;
|
||||
TokenStruct[] memory results = new TokenStruct[](page);
|
||||
if (start < size) {
|
||||
uint256 max = size;
|
||||
if (start + page < size) {
|
||||
max = start + page;
|
||||
}
|
||||
for (uint256 i = start; i < max; ++i) {
|
||||
TokenStruct memory dataObj;
|
||||
uint256 tokenId = _ownedTokens[user][i];
|
||||
dataObj.tokenId = tokenId;
|
||||
dataObj.amount = balanceOf(user, tokenId);
|
||||
results[i - start] = dataObj;
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
function tokenTypes(address user) external view returns (uint256) {
|
||||
return _ownedTokens[user].length;
|
||||
}
|
||||
}
|
110
contracts/chip1155/BEChipFactory.sol
Normal file
110
contracts/chip1155/BEChipFactory.sol
Normal file
@ -0,0 +1,110 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity 0.8.10;
|
||||
|
||||
import "@openzeppelin/contracts/access/Ownable.sol";
|
||||
import "@openzeppelin/contracts/proxy/utils/Initializable.sol";
|
||||
import "@openzeppelin/contracts/token/ERC1155/IERC1155.sol";
|
||||
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
|
||||
import "../HasSignature.sol";
|
||||
|
||||
interface IMintableERC1155 is IERC1155 {
|
||||
function mintBatch(
|
||||
address to,
|
||||
uint256[] memory ids,
|
||||
uint256[] memory amounts,
|
||||
bytes memory data
|
||||
) external;
|
||||
|
||||
function burn(
|
||||
address owner,
|
||||
uint256 tokenId,
|
||||
uint256 amount
|
||||
) external;
|
||||
}
|
||||
|
||||
|
||||
contract BEChipFactory is Ownable, Initializable, HasSignature {
|
||||
IMintableERC1155 public chip;
|
||||
|
||||
address public executor;
|
||||
|
||||
mapping(bytes => bool) public usedSignatures;
|
||||
|
||||
event Chip1155Minted(
|
||||
address contractAddress,
|
||||
address indexed to,
|
||||
uint256[] ids
|
||||
);
|
||||
|
||||
|
||||
constructor() HasSignature("BEChipFactory", "1") {}
|
||||
|
||||
function init(address _erc1155)
|
||||
external
|
||||
initializer
|
||||
onlyOwner
|
||||
{
|
||||
chip = IMintableERC1155(_erc1155);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev update executor
|
||||
*/
|
||||
function updateExecutor(address account) external onlyOwner {
|
||||
require(account != address(0), "address can not be zero");
|
||||
executor = account;
|
||||
}
|
||||
|
||||
function mintChipTo(
|
||||
address to,
|
||||
uint256[] memory ids
|
||||
) external onlyOwner {
|
||||
require(to != address(0), "to address can not be zero");
|
||||
uint256[] memory amounts = new uint256[](ids.length);
|
||||
uint256 len = ids.length;
|
||||
for (uint256 i = 0; i < len; ++i) {
|
||||
amounts[i] = 1;
|
||||
}
|
||||
chip.mintBatch(to, ids, amounts, "");
|
||||
emit Chip1155Minted(address(chip), to, ids);
|
||||
}
|
||||
|
||||
function mintChipSelf(
|
||||
uint256[] memory ids,
|
||||
uint256 saltNonce,
|
||||
bytes calldata signature
|
||||
) external{
|
||||
address to = _msgSender();
|
||||
bytes32 criteriaMessageHash = getMessageHash(
|
||||
to,
|
||||
saltNonce,
|
||||
ids
|
||||
);
|
||||
checkSigner(executor, criteriaMessageHash, signature);
|
||||
uint256[] memory amounts = new uint256[](ids.length);
|
||||
uint256 len = ids.length;
|
||||
for (uint256 i = 0; i < len; ++i) {
|
||||
amounts[i] = 1;
|
||||
}
|
||||
chip.mintBatch(to, ids, amounts, "");
|
||||
usedSignatures[signature] = true;
|
||||
emit Chip1155Minted(address(chip), to, ids);
|
||||
}
|
||||
|
||||
|
||||
function getMessageHash(
|
||||
address _to,
|
||||
uint256 _saltNonce,
|
||||
uint256[] memory _ids
|
||||
) public pure returns (bytes32) {
|
||||
bytes memory encoded = abi.encodePacked(_to, _saltNonce);
|
||||
uint256 len = _ids.length;
|
||||
for (uint256 i = 0; i < len; ++i) {
|
||||
encoded = bytes.concat(
|
||||
encoded,
|
||||
abi.encodePacked(_ids[i])
|
||||
);
|
||||
}
|
||||
return keccak256(encoded);
|
||||
}
|
||||
}
|
23
migrations/18_deploy_chip1155.js
Normal file
23
migrations/18_deploy_chip1155.js
Normal file
@ -0,0 +1,23 @@
|
||||
const Chip = artifacts.require('chip1155/BEChip1155');
|
||||
const ChipFactory = artifacts.require('chip1155/BEChipFactory');
|
||||
const config = require("../config/config");
|
||||
|
||||
module.exports = async function (deployer, network, accounts) {
|
||||
await deployer.deploy(Chip);
|
||||
const chipInstance = await Chip.deployed();
|
||||
if(chipInstance) {
|
||||
console.log("Chip 1155 successfully deployed.")
|
||||
}
|
||||
await deployer.deploy(ChipFactory);
|
||||
const factoryInstance = await ChipFactory.deployed();
|
||||
if(factoryInstance) {
|
||||
console.log("Chip 1155 Factory successfully deployed.")
|
||||
}
|
||||
await factoryInstance.init(chipInstance.address);
|
||||
await factoryInstance.updateExecutor(config.admins.admin);
|
||||
console.log("Chip 1155 Factory successfully update setting.")
|
||||
await chipInstance.setMintFactory(factoryInstance.address);
|
||||
console.log("Chip 1155 successfully update factory.")
|
||||
await chipInstance.grantLockRole(config.admins.admin);
|
||||
console.log("Chip 1155 successfully grantLockRole.")
|
||||
}
|
@ -27,7 +27,7 @@ const fs = require('fs');
|
||||
const mnemonic = fs.readFileSync(".secret").toString().trim();
|
||||
|
||||
// web3.eth.defaultAccount = '0x50A8e60041A206AcaA5F844a1104896224be6F39'
|
||||
|
||||
const kccTestnetKey = 'd9ed33809372932059c1ba7b336a33f406b4c55e7430daef8297134c67429d60';
|
||||
module.exports = {
|
||||
plugins: ['truffle-plugin-stdjsonin'],
|
||||
api_keys: {
|
||||
@ -81,7 +81,7 @@ module.exports = {
|
||||
// production: true // Treats this network as if it was a public net. (default: false)
|
||||
// }
|
||||
kcc_testnet: {
|
||||
provider: () => new HDWalletProvider(mnemonic, `https://rpc-testnet.kcc.network`),
|
||||
provider: () => new HDWalletProvider(kccTestnetKey, `https://rpc-testnet.kcc.network`),
|
||||
network_id: 322,
|
||||
confirmations: 6,
|
||||
timeoutBlocks: 5000,
|
||||
|
Loading…
x
Reference in New Issue
Block a user