// SPDX-License-Identifier: MIT pragma solidity >=0.4.22 <0.9.0; import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; import "@openzeppelin/contracts/utils/Counters.sol"; import "@openzeppelin/contracts/utils/Base64.sol"; import "@openzeppelin/contracts/utils/Strings.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; contract SoulboundToken is ERC721, Ownable { using Counters for Counters.Counter; Counters.Counter private _tokenIds; struct Certificate { address addr; uint number; } mapping(address => bool) private isReliableBank; mapping(address => Certificate[]) private certificates; event Borrow(address client, address bank, uint id, uint amount); event Repay(address client, address bank, uint id, uint amount, bool finish); event Warning(address client, address bank); constructor() ERC721("Credit System Soulbound Token", "CS_SBT") {} function mint(address player) public onlyOwner returns (uint256) { _tokenIds.increment(); uint256 newItemId = _tokenIds.current(); _mint(player, newItemId); return newItemId; } function _beforeTokenTransfer(address from, address to, uint256 firstTokenId, uint256 batchSize) internal virtual override { require(from == address(0) || to == address(0), "SOULBOUND: Non-Transferable."); require(balanceOf(to)==0, "SOULBOUND: Everyone should only have 1 SBT."); super._beforeTokenTransfer(from, to, firstTokenId, batchSize); } function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { _requireMinted(tokenId); string memory json = Base64.encode( bytes( string( abi.encodePacked( '{"name": "Credit System Soulbound Token (CS_SBT) #', Strings.toString(tokenId), '",', '"image_data": "', getSvgImage(tokenId), '"', "}" ) ) ) ); return string(abi.encodePacked("data:application/json;base64,", json)); } function getSvgImage(uint uid) private pure returns (string memory){ string memory uid_str = Strings.toString(uid); string memory a = "Credit System Soulbound Token (CSSBT)#"; string memory b = ""; return string(abi.encodePacked(a, uid_str, b)); } modifier onlyBank { require(isReliableBank[msg.sender] == true, "Only bank can access this function"); _; } modifier onlyRegister { require(balanceOf(msg.sender)!=0, "Only Register can access this function"); _; } function addReliableBank(address bank) public onlyOwner { isReliableBank[bank] = true; } function removeReliableBank(address bank) public onlyOwner { isReliableBank[bank] = false; } function logBorrowing(address client, uint id, uint amount) public onlyBank { emit Borrow(client, msg.sender, id, amount); } function logRepaying(address client, uint id, uint amount, bool finish) public onlyBank { emit Repay(client, msg.sender, id, amount, finish); } function logWarning(address client) public onlyBank { emit Warning(client, msg.sender); } function addCertificate(address addr, uint number) public onlyRegister{ certificates[msg.sender].push(Certificate(addr, number)); } function listCertificate(address client) public view onlyBank returns (Certificate[] memory){ return certificates[client]; } }