文件 1 的 7:CSPLGuildPoolV2.sol
pragma solidity 0.8.6;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/security/Pausable.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
interface IGuildAsset is IERC721 {
function getTotalVolume(uint16 _guildType) external view returns (uint256);
function isValidGuildStock(uint256 _guildTokenId) external view;
function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256);
function getGuildType(uint256 _guildTokenId) external view returns (uint16);
function getShareRateWithDecimal(uint256 _guildTokenId) external view returns (uint256, uint256);
}
contract CSPLGuildPoolV2 is Ownable, Pausable, ReentrancyGuard {
IGuildAsset public guildAsset;
mapping(uint16 => uint256) private guildTypeToTotalAmount;
mapping(uint256 => uint256) private guildStockToWithdrawnAmount;
mapping(address => bool) private allowedAddresses;
event EthAddedToPool(
uint16 indexed guildType,
address txSender,
address indexed purchaseBy,
uint256 value,
uint256 at
);
event WithdrawEther(
uint256 indexed guildTokenId,
address indexed owner,
uint256 value,
uint256 at
);
event AllowedAddressSet(
address allowedAddress,
bool allowedStatus
);
constructor(address _guildAssetAddress) {
setGuildAssetAddress(_guildAssetAddress);
}
function setGuildAssetAddress(address _guildAssetAddress) public onlyOwner() {
guildAsset = IGuildAsset(_guildAssetAddress);
}
function getAllowedAddress(address _address) public view returns (bool) {
return allowedAddresses[_address];
}
function setAllowedAddress(address _address, bool desired) external onlyOwner() {
allowedAddresses[_address] = desired;
}
function getGuildStockWithdrawnAmount(uint256 _guildTokenId) public view returns (uint256) {
return guildStockToWithdrawnAmount[_guildTokenId];
}
function getGuildTypeToTotalAmount(uint16 _guildType) public view returns (uint256) {
return guildTypeToTotalAmount[_guildType];
}
function addEthToGuildPool(uint16 _guildType, address _purchaseBy) external payable whenNotPaused() nonReentrant() {
require(guildAsset.getTotalVolume(_guildType) > 0);
require(allowedAddresses[msg.sender]);
guildTypeToTotalAmount[_guildType] += msg.value;
emit EthAddedToPool(
_guildType,
msg.sender,
_purchaseBy,
msg.value,
block.timestamp
);
}
function withdrawMyAllRewards() external whenNotPaused() nonReentrant() {
uint256 withdrawValue;
uint256 balance = guildAsset.balanceOf(msg.sender);
for (uint256 i=balance; i > 0; i--) {
uint256 guildStock = guildAsset.tokenOfOwnerByIndex(msg.sender, i-1);
uint256 tmpAmount = getGuildStockWithdrawableBalance(guildStock);
withdrawValue += tmpAmount;
guildStockToWithdrawnAmount[guildStock] += tmpAmount;
emit WithdrawEther(
guildStock,
msg.sender,
tmpAmount,
block.timestamp
);
}
require(withdrawValue > 0, "no withdrawable balances left");
payable(msg.sender).transfer(withdrawValue);
}
function withdrawMyReward(uint256 _guildTokenId) external whenNotPaused() nonReentrant() {
require(guildAsset.ownerOf(_guildTokenId) == msg.sender);
uint256 withdrawableAmount = getGuildStockWithdrawableBalance(_guildTokenId);
require(withdrawableAmount > 0);
guildStockToWithdrawnAmount[_guildTokenId] += withdrawableAmount;
payable(msg.sender).transfer(withdrawableAmount);
emit WithdrawEther(
_guildTokenId,
msg.sender,
withdrawableAmount,
block.timestamp
);
}
function withdrawMyRewards(uint[] calldata _guildTokenId) external whenNotPaused() nonReentrant() {
uint256 withdrawValue;
for (uint8 i = 0; i < _guildTokenId.length; i++) {
require(guildAsset.ownerOf(_guildTokenId[i]) == msg.sender);
uint256 tmpAmount = getGuildStockWithdrawableBalance(_guildTokenId[i]);
guildStockToWithdrawnAmount[_guildTokenId[i]] += tmpAmount;
emit WithdrawEther(
_guildTokenId[i],
msg.sender,
tmpAmount,
block.timestamp
);
withdrawValue += tmpAmount;
}
require(withdrawValue > 0, "no withdrawable balances left");
payable(msg.sender).transfer(withdrawValue);
}
function getGuildStockWithdrawableBalance(uint256 _guildTokenId) public view returns (uint256) {
guildAsset.isValidGuildStock(_guildTokenId);
uint16 _guildType = guildAsset.getGuildType(_guildTokenId);
(uint256 shareRate, uint256 decimal) = guildAsset.getShareRateWithDecimal(_guildTokenId);
uint256 maxAmount = guildTypeToTotalAmount[_guildType] * shareRate / decimal;
return maxAmount - guildStockToWithdrawnAmount[_guildTokenId];
}
function getWithdrawableBalance(address _ownerAddress) public view returns (uint256) {
uint256 balance = guildAsset.balanceOf(_ownerAddress);
uint256 withdrawableAmount;
for (uint256 i=balance; i > 0; i--) {
uint256 guildTokenId = guildAsset.tokenOfOwnerByIndex(_ownerAddress, i-1);
withdrawableAmount += getGuildStockWithdrawableBalance(guildTokenId);
}
return withdrawableAmount;
}
function getGuildStockWithdrawableBalances(uint[] calldata _guildTokenId) public view returns (uint256) {
uint256 withdrawableAmount;
for (uint8 i = 0; i < _guildTokenId.length; i++) {
withdrawableAmount += getGuildStockWithdrawableBalance(_guildTokenId[i]);
}
return withdrawableAmount;
}
}
文件 2 的 7:Context.sol
pragma solidity ^0.8.0;
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}
文件 3 的 7:IERC165.sol
pragma solidity ^0.8.0;
interface IERC165 {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
文件 4 的 7:IERC721.sol
pragma solidity ^0.8.0;
import "../../utils/introspection/IERC165.sol";
interface IERC721 is IERC165 {
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
function balanceOf(address owner) external view returns (uint256 balance);
function ownerOf(uint256 tokenId) external view returns (address owner);
function safeTransferFrom(
address from,
address to,
uint256 tokenId
) external;
function transferFrom(
address from,
address to,
uint256 tokenId
) external;
function approve(address to, uint256 tokenId) external;
function getApproved(uint256 tokenId) external view returns (address operator);
function setApprovalForAll(address operator, bool _approved) external;
function isApprovedForAll(address owner, address operator) external view returns (bool);
function safeTransferFrom(
address from,
address to,
uint256 tokenId,
bytes calldata data
) external;
}
文件 5 的 7:Ownable.sol
pragma solidity ^0.8.0;
import "../utils/Context.sol";
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor() {
_setOwner(_msgSender());
}
function owner() public view virtual returns (address) {
return _owner;
}
modifier onlyOwner() {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
_;
}
function renounceOwnership() public virtual onlyOwner {
_setOwner(address(0));
}
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_setOwner(newOwner);
}
function _setOwner(address newOwner) private {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
文件 6 的 7:Pausable.sol
pragma solidity ^0.8.0;
import "../utils/Context.sol";
abstract contract Pausable is Context {
event Paused(address account);
event Unpaused(address account);
bool private _paused;
constructor() {
_paused = false;
}
function paused() public view virtual returns (bool) {
return _paused;
}
modifier whenNotPaused() {
require(!paused(), "Pausable: paused");
_;
}
modifier whenPaused() {
require(paused(), "Pausable: not paused");
_;
}
function _pause() internal virtual whenNotPaused {
_paused = true;
emit Paused(_msgSender());
}
function _unpause() internal virtual whenPaused {
_paused = false;
emit Unpaused(_msgSender());
}
}
文件 7 的 7:ReentrancyGuard.sol
pragma solidity ^0.8.0;
abstract contract ReentrancyGuard {
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
modifier nonReentrant() {
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
_status = _ENTERED;
_;
_status = _NOT_ENTERED;
}
}
{
"compilationTarget": {
"contracts2/CSPLGuildPoolV2.sol": "CSPLGuildPoolV2"
},
"evmVersion": "berlin",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"_guildAssetAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"allowedAddress","type":"address"},{"indexed":false,"internalType":"bool","name":"allowedStatus","type":"bool"}],"name":"AllowedAddressSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint16","name":"guildType","type":"uint16"},{"indexed":false,"internalType":"address","name":"txSender","type":"address"},{"indexed":true,"internalType":"address","name":"purchaseBy","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"at","type":"uint256"}],"name":"EthAddedToPool","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"guildTokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"at","type":"uint256"}],"name":"WithdrawEther","type":"event"},{"inputs":[{"internalType":"uint16","name":"_guildType","type":"uint16"},{"internalType":"address","name":"_purchaseBy","type":"address"}],"name":"addEthToGuildPool","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"}],"name":"getAllowedAddress","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_guildTokenId","type":"uint256"}],"name":"getGuildStockWithdrawableBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_guildTokenId","type":"uint256[]"}],"name":"getGuildStockWithdrawableBalances","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_guildTokenId","type":"uint256"}],"name":"getGuildStockWithdrawnAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"_guildType","type":"uint16"}],"name":"getGuildTypeToTotalAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_ownerAddress","type":"address"}],"name":"getWithdrawableBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"guildAsset","outputs":[{"internalType":"contract IGuildAsset","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"},{"internalType":"bool","name":"desired","type":"bool"}],"name":"setAllowedAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_guildAssetAddress","type":"address"}],"name":"setGuildAssetAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawMyAllRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_guildTokenId","type":"uint256"}],"name":"withdrawMyReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_guildTokenId","type":"uint256[]"}],"name":"withdrawMyRewards","outputs":[],"stateMutability":"nonpayable","type":"function"}]