编译器
0.8.18+commit.87f61d96
文件 1 的 6:Address.sol
pragma solidity ^0.8.1;
library Address {
function isContract(address account) internal view returns (bool) {
return account.code.length > 0;
}
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
文件 2 的 6:FeeCollector.sol
pragma solidity 0.8.18;
import { IFeeCollector } from "./interfaces/IFeeCollector.sol";
import { LibAddress } from "./lib/LibAddress.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/utils/Multicall.sol";
contract FeeCollector is IFeeCollector, Multicall {
using LibAddress for address payable;
address payable public guildFeeCollector;
uint96 public guildShareBps;
Vault[] internal vaults;
constructor(address payable guildFeeCollector_, uint96 guildShareBps_) {
guildFeeCollector = guildFeeCollector_;
guildShareBps = guildShareBps_;
}
function registerVault(address owner, address token, bool multiplePayments, uint120 fee) external {
Vault storage vault = vaults.push();
vault.owner = owner;
vault.token = token;
vault.multiplePayments = multiplePayments;
vault.fee = fee;
emit VaultRegistered(vaults.length - 1, owner, token, fee);
}
function payFee(uint256 vaultId) external payable {
if (vaultId >= vaults.length) revert VaultDoesNotExist(vaultId);
Vault storage vault = vaults[vaultId];
if (!vault.multiplePayments && vault.paid[msg.sender]) revert AlreadyPaid(vaultId, msg.sender);
uint256 requiredAmount = vault.fee;
vault.collected += uint128(requiredAmount);
vault.paid[msg.sender] = true;
address tokenAddress = vault.token;
if (tokenAddress == address(0)) {
if (msg.value != requiredAmount) revert IncorrectFee(vaultId, msg.value, requiredAmount);
} else {
if (msg.value != 0) revert IncorrectFee(vaultId, msg.value, 0);
if (!IERC20(tokenAddress).transferFrom(msg.sender, address(this), requiredAmount))
revert TransferFailed(msg.sender, address(this));
}
emit FeeReceived(vaultId, msg.sender, requiredAmount);
}
function withdraw(uint256 vaultId) external {
if (vaultId >= vaults.length) revert VaultDoesNotExist(vaultId);
Vault storage vault = vaults[vaultId];
uint256 collected = vault.collected;
vault.collected = 0;
uint256 guildAmount = (collected * guildShareBps) / 10000;
uint256 ownerAmount = collected - guildAmount;
address tokenAddress = vault.token;
if (tokenAddress == address(0)) _withdrawEther(guildAmount, ownerAmount, vault.owner);
else _withdrawToken(guildAmount, ownerAmount, vault.owner, tokenAddress);
emit Withdrawn(vaultId, guildAmount, ownerAmount);
}
function setGuildFeeCollector(address payable newFeeCollector) external {
if (msg.sender != guildFeeCollector) revert AccessDenied(msg.sender, guildFeeCollector);
guildFeeCollector = newFeeCollector;
emit GuildFeeCollectorChanged(newFeeCollector);
}
function setGuildShareBps(uint96 newShare) external {
if (msg.sender != guildFeeCollector) revert AccessDenied(msg.sender, guildFeeCollector);
guildShareBps = newShare;
emit GuildShareBpsChanged(newShare);
}
function setVaultDetails(uint256 vaultId, address newOwner, bool newMultiplePayments, uint120 newFee) external {
if (vaultId >= vaults.length) revert VaultDoesNotExist(vaultId);
Vault storage vault = vaults[vaultId];
if (msg.sender != vault.owner) revert AccessDenied(msg.sender, vault.owner);
vault.owner = newOwner;
vault.multiplePayments = newMultiplePayments;
vault.fee = newFee;
emit VaultDetailsChanged(vaultId);
}
function getVault(
uint256 vaultId
) external view returns (address owner, address token, bool multiplePayments, uint120 fee, uint128 collected) {
if (vaultId >= vaults.length) revert VaultDoesNotExist(vaultId);
Vault storage vault = vaults[vaultId];
return (vault.owner, vault.token, vault.multiplePayments, vault.fee, vault.collected);
}
function hasPaid(uint256 vaultId, address account) external view returns (bool paid) {
if (vaultId >= vaults.length) revert VaultDoesNotExist(vaultId);
return vaults[vaultId].paid[account];
}
function _withdrawEther(uint256 guildAmount, uint256 ownerAmount, address eventOwner) internal {
guildFeeCollector.sendEther(guildAmount);
payable(eventOwner).sendEther(ownerAmount);
}
function _withdrawToken(
uint256 guildAmount,
uint256 ownerAmount,
address eventOwner,
address tokenAddress
) internal {
IERC20 token = IERC20(tokenAddress);
if (!token.transfer(guildFeeCollector, guildAmount)) revert TransferFailed(address(this), guildFeeCollector);
if (!token.transfer(eventOwner, ownerAmount)) revert TransferFailed(address(this), eventOwner);
}
}
文件 3 的 6:IERC20.sol
pragma solidity ^0.8.0;
interface IERC20 {
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address to, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(
address from,
address to,
uint256 amount
) external returns (bool);
}
文件 4 的 6:IFeeCollector.sol
pragma solidity ^0.8.0;
interface IFeeCollector {
struct Vault {
address owner;
address token;
bool multiplePayments;
uint120 fee;
uint128 collected;
mapping(address => bool) paid;
}
function registerVault(address owner, address token, bool multiplePayments, uint120 fee) external;
function payFee(uint256 vaultId) external payable;
function setGuildFeeCollector(address payable newFeeCollector) external;
function setGuildShareBps(uint96 newShare) external;
function setVaultDetails(uint256 vaultId, address newOwner, bool newMultiplePayments, uint120 newFee) external;
function withdraw(uint256 vaultId) external;
function getVault(
uint256 vaultId
) external view returns (address owner, address token, bool multiplePayments, uint120 fee, uint128 collected);
function hasPaid(uint256 vaultId, address account) external view returns (bool paid);
function guildFeeCollector() external view returns (address payable);
function guildShareBps() external view returns (uint96);
event FeeReceived(uint256 indexed vaultId, address indexed account, uint256 amount);
event GuildFeeCollectorChanged(address newFeeCollector);
event GuildShareBpsChanged(uint96 newShare);
event VaultDetailsChanged(uint256 vaultId);
event VaultRegistered(uint256 vaultId, address indexed owner, address indexed token, uint256 fee);
event Withdrawn(uint256 indexed vaultId, uint256 guildAmount, uint256 ownerAmount);
error AlreadyPaid(uint256 vaultId, address sender);
error IncorrectFee(uint256 vaultId, uint256 paid, uint256 requiredAmount);
error AccessDenied(address sender, address owner);
error TransferFailed(address from, address to);
error VaultDoesNotExist(uint256 vaultId);
}
文件 5 的 6:LibAddress.sol
pragma solidity ^0.8.0;
library LibAddress {
error FailedToSendEther(address recipient);
function sendEther(address payable recipient, uint256 amount) internal {
(bool success, ) = recipient.call{ value: amount }("");
if (!success) revert FailedToSendEther(recipient);
}
}
文件 6 的 6:Multicall.sol
pragma solidity ^0.8.0;
import "./Address.sol";
abstract contract Multicall {
function multicall(bytes[] calldata data) external virtual returns (bytes[] memory results) {
results = new bytes[](data.length);
for (uint256 i = 0; i < data.length; i++) {
results[i] = Address.functionDelegateCall(address(this), data[i]);
}
return results;
}
}
{
"compilationTarget": {
"contracts/FeeCollector.sol": "FeeCollector"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address payable","name":"guildFeeCollector_","type":"address"},{"internalType":"uint96","name":"guildShareBps_","type":"uint96"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"AccessDenied","type":"error"},{"inputs":[{"internalType":"uint256","name":"vaultId","type":"uint256"},{"internalType":"address","name":"sender","type":"address"}],"name":"AlreadyPaid","type":"error"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"}],"name":"FailedToSendEther","type":"error"},{"inputs":[{"internalType":"uint256","name":"vaultId","type":"uint256"},{"internalType":"uint256","name":"paid","type":"uint256"},{"internalType":"uint256","name":"requiredAmount","type":"uint256"}],"name":"IncorrectFee","type":"error"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"}],"name":"TransferFailed","type":"error"},{"inputs":[{"internalType":"uint256","name":"vaultId","type":"uint256"}],"name":"VaultDoesNotExist","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"vaultId","type":"uint256"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FeeReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newFeeCollector","type":"address"}],"name":"GuildFeeCollectorChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint96","name":"newShare","type":"uint96"}],"name":"GuildShareBpsChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"vaultId","type":"uint256"}],"name":"VaultDetailsChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"vaultId","type":"uint256"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"}],"name":"VaultRegistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"vaultId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"guildAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"ownerAmount","type":"uint256"}],"name":"Withdrawn","type":"event"},{"inputs":[{"internalType":"uint256","name":"vaultId","type":"uint256"}],"name":"getVault","outputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"bool","name":"multiplePayments","type":"bool"},{"internalType":"uint120","name":"fee","type":"uint120"},{"internalType":"uint128","name":"collected","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"guildFeeCollector","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"guildShareBps","outputs":[{"internalType":"uint96","name":"","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"vaultId","type":"uint256"},{"internalType":"address","name":"account","type":"address"}],"name":"hasPaid","outputs":[{"internalType":"bool","name":"paid","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"vaultId","type":"uint256"}],"name":"payFee","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"bool","name":"multiplePayments","type":"bool"},{"internalType":"uint120","name":"fee","type":"uint120"}],"name":"registerVault","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"newFeeCollector","type":"address"}],"name":"setGuildFeeCollector","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint96","name":"newShare","type":"uint96"}],"name":"setGuildShareBps","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"vaultId","type":"uint256"},{"internalType":"address","name":"newOwner","type":"address"},{"internalType":"bool","name":"newMultiplePayments","type":"bool"},{"internalType":"uint120","name":"newFee","type":"uint120"}],"name":"setVaultDetails","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"vaultId","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]