编译器
0.8.28+commit.7893614a
文件 1 的 13:AccessControl.sol
pragma solidity ^0.8.20;
import {IAccessControl} from "./IAccessControl.sol";
import {Context} from "../utils/Context.sol";
import {ERC165} from "../utils/introspection/ERC165.sol";
abstract contract AccessControl is Context, IAccessControl, ERC165 {
struct RoleData {
mapping(address account => bool) hasRole;
bytes32 adminRole;
}
mapping(bytes32 role => RoleData) private _roles;
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
modifier onlyRole(bytes32 role) {
_checkRole(role);
_;
}
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
}
function hasRole(bytes32 role, address account) public view virtual returns (bool) {
return _roles[role].hasRole[account];
}
function _checkRole(bytes32 role) internal view virtual {
_checkRole(role, _msgSender());
}
function _checkRole(bytes32 role, address account) internal view virtual {
if (!hasRole(role, account)) {
revert AccessControlUnauthorizedAccount(account, role);
}
}
function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {
return _roles[role].adminRole;
}
function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
_grantRole(role, account);
}
function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
_revokeRole(role, account);
}
function renounceRole(bytes32 role, address callerConfirmation) public virtual {
if (callerConfirmation != _msgSender()) {
revert AccessControlBadConfirmation();
}
_revokeRole(role, callerConfirmation);
}
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
bytes32 previousAdminRole = getRoleAdmin(role);
_roles[role].adminRole = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
function _grantRole(bytes32 role, address account) internal virtual returns (bool) {
if (!hasRole(role, account)) {
_roles[role].hasRole[account] = true;
emit RoleGranted(role, account, _msgSender());
return true;
} else {
return false;
}
}
function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {
if (hasRole(role, account)) {
_roles[role].hasRole[account] = false;
emit RoleRevoked(role, account, _msgSender());
return true;
} else {
return false;
}
}
}
文件 2 的 13:Context.sol
pragma solidity ^0.8.20;
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}
文件 3 的 13:ERC165.sol
pragma solidity ^0.8.20;
import {IERC165} from "./IERC165.sol";
abstract contract ERC165 is IERC165 {
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}
文件 4 的 13:IAccessControl.sol
pragma solidity ^0.8.20;
interface IAccessControl {
error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);
error AccessControlBadConfirmation();
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
function hasRole(bytes32 role, address account) external view returns (bool);
function getRoleAdmin(bytes32 role) external view returns (bytes32);
function grantRole(bytes32 role, address account) external;
function revokeRole(bytes32 role, address account) external;
function renounceRole(bytes32 role, address callerConfirmation) external;
}
文件 5 的 13:IERC1363.sol
pragma solidity ^0.8.20;
import {IERC20} from "./IERC20.sol";
import {IERC165} from "./IERC165.sol";
interface IERC1363 is IERC20, IERC165 {
function transferAndCall(address to, uint256 value) external returns (bool);
function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);
function transferFromAndCall(address from, address to, uint256 value) external returns (bool);
function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);
function approveAndCall(address spender, uint256 value) external returns (bool);
function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);
}
文件 6 的 13:IERC165.sol
pragma solidity ^0.8.20;
import {IERC165} from "../utils/introspection/IERC165.sol";
文件 7 的 13:IERC20.sol
pragma solidity ^0.8.20;
import {IERC20} from "../token/ERC20/IERC20.sol";
文件 8 的 13:Market_Factory.sol
pragma solidity 0.8.28;
import "@openzeppelin/contracts/access/AccessControl.sol";
import "./WODS_Market.sol";
import "./TokenLocking.sol";
contract Market_Factory is AccessControl {
address public _platformAddress;
uint256 public _platformFee;
uint256 public _creatorFee;
mapping(address user => address[] markets) private _userPredictions;
address[] private _predictions;
uint256 public predictionCount;
bytes32 private constant _MARKET_CREATOR_ROLE = keccak256("MARKET_CREATOR_ROLE");
TokenLocking private _tokenLockingContract;
uint256 public lockAmount;
event MarketDeployed(address tokenAddress);
event PlatformDetailsUpdated(address platformAddress, uint256 platformFee);
event UserPredictionsUpdated(address user, address[] markets);
error InvalidDescription(string error);
error InvalidOutcomes(string error);
error InvalidAmount(string error);
error InvalidResolveTime(string error);
constructor(
address platformAddress,
uint256 platformFee,
uint256 creatorFee,
address tokenLockingAddress,
uint256 requiredLockAmount
) {
_platformAddress = platformAddress;
_platformFee = platformFee;
_creatorFee = creatorFee;
_tokenLockingContract = TokenLocking(tokenLockingAddress);
lockAmount = requiredLockAmount;
_grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
_grantRole(_MARKET_CREATOR_ROLE, msg.sender);
}
modifier _checkMarketParams(
string memory _description,
string[] memory _outcomes,
uint256 _endTimestamp,
uint256 _minPrice,
uint256 _maxPrice
) {
if (bytes(_description).length == 0) {
revert InvalidDescription("EMPTY_DESCRIPTION");
}
if (_minPrice > _maxPrice) {
revert InvalidAmount("MIN_PRICE_IS_HIGH");
}
if (_outcomes.length < 2) {
revert InvalidOutcomes("MIN_2_OUTCOMES");
}
if (_endTimestamp <= block.timestamp) {
revert InvalidResolveTime("NOT_FUTURE_RESOLVE_TIME");
}
_;
}
function deployMarket(
address _tokenAddress,
string memory _description,
string[] memory _outcomes,
uint256 _tokenDecimals,
uint256 _endTimestamp,
uint256 _minPrice,
uint256 _maxPrice
)
public
onlyRole(_MARKET_CREATOR_ROLE)
_checkMarketParams(_description, _outcomes, _endTimestamp, _minPrice, _maxPrice)
returns (address)
{
WODS_Market prediction = new WODS_Market(
_tokenAddress,
_platformAddress,
msg.sender,
_description,
_outcomes,
_tokenDecimals,
_endTimestamp,
_minPrice,
_maxPrice,
_platformFee,
_creatorFee
);
_tokenLockingContract.lockTokens(address(prediction), lockAmount, msg.sender);
_predictions.push(address(prediction));
_userPredictions[msg.sender].push(address(prediction));
predictionCount++;
emit UserPredictionsUpdated(msg.sender, _userPredictions[msg.sender]);
emit MarketDeployed(address(prediction));
return address(prediction);
}
function getAllMarkets() public view returns (address[] memory) {
return _predictions;
}
function getAllUserMarkets(address _account) public view returns (address[] memory) {
return _userPredictions[_account];
}
function grantMarketCreatorRole(address _account) public onlyRole(DEFAULT_ADMIN_ROLE) {
grantRole(_MARKET_CREATOR_ROLE, _account);
}
function revokeMarketCreatorRole(address _account) public onlyRole(DEFAULT_ADMIN_ROLE) {
revokeRole(_MARKET_CREATOR_ROLE, _account);
}
function getPlatformDetails() external view onlyRole(_MARKET_CREATOR_ROLE) returns (address, uint256) {
return (_platformAddress, _platformFee);
}
function updateCreatorFee(uint256 _fee) public onlyRole(DEFAULT_ADMIN_ROLE) {
_creatorFee = _fee;
emit PlatformDetailsUpdated(_platformAddress, _creatorFee);
}
function setLockAmount(uint256 amount) external onlyRole(DEFAULT_ADMIN_ROLE) {
lockAmount = amount;
}
function MARKET_CREATOR_ROLE() public pure returns (bytes32) {
return keccak256("MARKET_CREATOR_ROLE");
}
function updatePlatformDetails(address _address, uint256 _fee) public onlyRole(DEFAULT_ADMIN_ROLE) {
_platformAddress = _address;
_platformFee = _fee;
emit PlatformDetailsUpdated(_platformAddress, _platformFee);
}
}
文件 9 的 13:Ownable.sol
pragma solidity ^0.8.20;
import {Context} from "../utils/Context.sol";
abstract contract Ownable is Context {
address private _owner;
error OwnableUnauthorizedAccount(address account);
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor(address initialOwner) {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
modifier onlyOwner() {
_checkOwner();
_;
}
function owner() public view virtual returns (address) {
return _owner;
}
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
文件 10 的 13:ReentrancyGuard.sol
pragma solidity ^0.8.20;
abstract contract ReentrancyGuard {
uint256 private constant NOT_ENTERED = 1;
uint256 private constant ENTERED = 2;
uint256 private _status;
error ReentrancyGuardReentrantCall();
constructor() {
_status = NOT_ENTERED;
}
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
if (_status == ENTERED) {
revert ReentrancyGuardReentrantCall();
}
_status = ENTERED;
}
function _nonReentrantAfter() private {
_status = NOT_ENTERED;
}
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == ENTERED;
}
}
文件 11 的 13:SafeERC20.sol
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC1363} from "../../../interfaces/IERC1363.sol";
library SafeERC20 {
error SafeERC20FailedOperation(address token);
error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
}
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
forceApprove(token, spender, oldAllowance + value);
}
function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
unchecked {
uint256 currentAllowance = token.allowance(address(this), spender);
if (currentAllowance < requestedDecrease) {
revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
}
forceApprove(token, spender, currentAllowance - requestedDecrease);
}
}
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
_callOptionalReturn(token, approvalCall);
}
}
function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
if (to.code.length == 0) {
safeTransfer(token, to, value);
} else if (!token.transferAndCall(to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
function transferFromAndCallRelaxed(
IERC1363 token,
address from,
address to,
uint256 value,
bytes memory data
) internal {
if (to.code.length == 0) {
safeTransferFrom(token, from, to, value);
} else if (!token.transferFromAndCall(from, to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
if (to.code.length == 0) {
forceApprove(token, to, value);
} else if (!token.approveAndCall(to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
function _callOptionalReturn(IERC20 token, bytes memory data) private {
uint256 returnSize;
uint256 returnValue;
assembly ("memory-safe") {
let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
if iszero(success) {
let ptr := mload(0x40)
returndatacopy(ptr, 0, returndatasize())
revert(ptr, returndatasize())
}
returnSize := returndatasize()
returnValue := mload(0)
}
if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) {
revert SafeERC20FailedOperation(address(token));
}
}
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
bool success;
uint256 returnSize;
uint256 returnValue;
assembly ("memory-safe") {
success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
returnSize := returndatasize()
returnValue := mload(0)
}
return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1);
}
}
文件 12 的 13:TokenLocking.sol
pragma solidity 0.8.28;
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "./WODS_Market.sol";
contract TokenLocking {
using SafeERC20 for IERC20;
IERC20 private immutable _lockToken;
struct Lock {
uint256 amount;
address creator;
bool claimed;
}
mapping(address market => Lock lock) private _locks;
event TokensLocked(address indexed market, address indexed creator, uint256 amount);
event TokensUnlocked(address indexed market, address indexed creator, uint256 amount);
constructor(address tokenAddress) {
_lockToken = IERC20(tokenAddress);
}
function lockTokens(address market, uint256 amount, address creator) external {
require(_locks[market].amount == 0, "Tokens already locked for this market");
require(amount > 0, "Amount must be greater than zero");
_locks[market] = Lock(amount, creator, false);
_lockToken.safeTransferFrom(creator, address(this), amount);
emit TokensLocked(market, creator, amount);
}
function unlockTokens(address market) external {
WODS_Market wodsMarket = WODS_Market(market);
require(wodsMarket.isResolved(), "Market is not resolved yet");
Lock storage lock = _locks[market];
require(lock.amount > 0, "No tokens locked for this market");
require(!lock.claimed, "Tokens already claimed");
require(msg.sender == lock.creator, "Only creator can unlock tokens");
lock.claimed = true;
_lockToken.safeTransfer(lock.creator, lock.amount);
emit TokensUnlocked(market, lock.creator, lock.amount);
}
function getLockedTokens(address market) external view returns (uint256) {
return _locks[market].amount;
}
function isClaimed(address market) external view returns (bool) {
return _locks[market].claimed;
}
}
文件 13 的 13:WODS_Market.sol
pragma solidity 0.8.28;
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
contract WODS_Market is Ownable, ReentrancyGuard {
using SafeERC20 for IERC20;
IERC20 private _rewardToken;
address private _platformAddress;
address private _creatorAddress;
uint256 private _platformFee;
uint256 private _creatorFee;
struct Market {
address admin;
address tokenAddress;
string description;
uint256 tokenDecimals;
uint256 minPrice;
uint256 maxPrice;
uint256 fee;
uint256 totalRewards;
uint256 totalBets;
uint256 totalSponsors;
uint256 endTimestamp;
uint256 outcomes;
uint256 finalOutcome;
bool resolved;
bool cancelled;
}
struct Outcome {
string name;
uint256 totalAmount;
uint256 totalBets;
address[] users;
}
Market public market;
mapping(uint256 index => Outcome outcome) public outcomes;
mapping(uint256 index => address sponsor) public sponsors;
mapping(address user => uint256 amount) public userWithdrawals;
mapping(address user => uint256 outcome) public userBets;
mapping(address user => uint256 amount) public userAmounts;
mapping(address sponsor => uint256 amount) public sponsorAmounts;
event BetPlaced(address indexed bettor, uint256 outcome, uint256 amount);
event MarketUpdated();
event MarketCancelled();
event MarketResolved(uint256 outcome);
event RewardsAmplified(address indexed sponsor, uint256 amount);
event WinningsWithdrawn(address indexed user, uint256 amount);
event FundsWithdrawn(address indexed user, uint256 amount);
event PlatformDetailsUpdated(address platformAddress, uint256 platformFee);
error InvalidAmount(string error);
error InvalidMarketState(string error);
error InvalidAllowance(uint256 amount);
error InvalidOutcome(uint256 outcome);
error InvalidUserAction(string error);
modifier marketNotResolved() {
if (market.resolved || market.endTimestamp <= block.timestamp) {
revert InvalidMarketState("MARKET_RESOLVED");
}
_;
}
modifier marketNotCancelled() {
if (market.cancelled) {
revert InvalidMarketState("MARKET_CANCELLED");
}
_;
}
modifier marketResolved() {
if (!market.resolved || market.endTimestamp > block.timestamp) {
revert InvalidMarketState("MARKET_NOT_RESOLVED");
}
_;
}
modifier onlyParticipants(address _address) {
if (userBets[_address] == 0) {
revert InvalidUserAction("NOT_VALID_PARTICIPANT");
}
_;
}
modifier notAParticipant() {
if (userBets[msg.sender] > 0) {
revert InvalidUserAction("VALID_PARTICIPANT");
}
_;
}
modifier notWithdrawn() {
if (userWithdrawals[msg.sender] != 0) {
revert InvalidUserAction("NO_PENDING_REWARDS");
}
_;
}
modifier hasAllowance(uint256 _amount) {
if (_rewardToken.allowance(msg.sender, address(this)) < _amount) {
revert InvalidAllowance(_amount);
}
_;
}
constructor(
address _tokenAddress,
address _pAddress,
address _marketCreator,
string memory _description,
string[] memory _marketOutcomes,
uint256 _tokenDecimals,
uint256 _endTimestamp,
uint256 _minPrice,
uint256 _maxPrice,
uint256 platformFee_,
uint256 creatorFee_
) Ownable(_marketCreator) {
_rewardToken = IERC20(_tokenAddress);
_platformAddress = _pAddress;
_creatorAddress = _marketCreator;
_platformFee = platformFee_;
_creatorFee = creatorFee_;
market.admin = _marketCreator;
market.description = _description;
market.fee = 0;
market.minPrice = _minPrice;
market.maxPrice = _maxPrice;
market.totalBets = 0;
market.totalSponsors = 0;
market.endTimestamp = _endTimestamp;
market.resolved = false;
market.cancelled = false;
market.outcomes = _marketOutcomes.length;
market.tokenAddress = _tokenAddress;
market.tokenDecimals = _tokenDecimals;
for (uint256 i = 0; i < _marketOutcomes.length; i++) {
Outcome storage outcome = outcomes[i];
outcome.name = _marketOutcomes[i];
outcome.totalBets = 0;
outcome.totalAmount = 0;
}
}
function participate(uint256 _outcome, uint256 _amount)
external
notAParticipant
marketNotResolved
marketNotCancelled
hasAllowance(_amount)
{
if (_amount < market.minPrice) {
revert InvalidAmount("LESS_PRICE");
}
if (_amount > market.maxPrice) {
revert InvalidAmount("MORE_PRICE");
}
if (market.outcomes <= _outcome) {
revert InvalidOutcome(_outcome);
}
Outcome storage extOutcome = outcomes[_outcome];
extOutcome.totalBets++;
extOutcome.totalAmount += _amount;
extOutcome.users.push(msg.sender);
userBets[msg.sender] = _outcome + 1;
userAmounts[msg.sender] = _amount;
market.totalBets++;
market.totalRewards += _amount;
_rewardToken.safeTransferFrom(msg.sender, address(this), _amount);
emit BetPlaced(msg.sender, _outcome, _amount);
}
function getParticipants(uint256 outcome) external view returns (address[] memory) {
return outcomes[outcome].users;
}
function updateMarket(string memory _description, uint256 _endTimestamp, uint256 _minPrice, uint256 _maxPrice)
external
onlyOwner
marketNotCancelled
{
if (market.resolved) {
revert InvalidMarketState("MARKET_RESOLVED");
}
market.description = _description;
market.endTimestamp = _endTimestamp;
market.minPrice = _minPrice;
market.maxPrice = _maxPrice;
emit MarketUpdated();
}
function cancelMarket() external onlyOwner nonReentrant marketNotCancelled {
if (market.resolved) {
revert InvalidMarketState("MARKET_RESOLVED");
}
market.cancelled = true;
market.endTimestamp = block.timestamp;
for (uint256 index = 0; index < market.outcomes; index++) {
Outcome memory outcome = outcomes[index];
for (uint256 uIndex = 0; uIndex < outcome.totalBets; uIndex++) {
_rewardToken.safeTransfer(outcome.users[uIndex], userAmounts[outcome.users[uIndex]]);
}
}
for (uint256 index = 0; index < market.totalSponsors; index++) {
address sponsor = sponsors[index];
uint256 amount = sponsorAmounts[sponsor];
if (getContractBalance() >= amount) {
_rewardToken.safeTransfer(sponsor, amount);
}
}
emit MarketCancelled();
}
function resolveMarket(uint256 _outcome) external onlyOwner marketNotCancelled {
require(!market.resolved, "Market already resolved");
require(_outcome < market.outcomes, "Invalid outcome");
require(block.timestamp > market.endTimestamp, "Market need to End First ");
market.resolved = true;
market.endTimestamp = block.timestamp;
market.finalOutcome = _outcome;
uint256 platformFeeAmount = (market.totalRewards * _platformFee) / 10000;
uint256 creatorFeeAmount = (market.totalRewards * _creatorFee) / 10000;
market.fee = platformFeeAmount + creatorFeeAmount;
market.totalRewards -= market.fee;
_rewardToken.safeTransfer(_platformAddress, platformFeeAmount);
_rewardToken.safeTransfer(_creatorAddress, creatorFeeAmount);
emit MarketResolved(_outcome);
}
function withdrawWinnings() external onlyParticipants(msg.sender) marketResolved notWithdrawn {
uint256 userBet = userBets[msg.sender];
if (market.finalOutcome + 1 != userBet) {
revert InvalidUserAction("NOT_A_WINNER");
}
uint256 winnings = calculateWinnings(msg.sender);
if (winnings == 0) {
revert InvalidAmount("ZERO_WINNINGS_AMOUNT");
}
userWithdrawals[msg.sender] = winnings;
_rewardToken.safeTransfer(msg.sender, winnings);
emit WinningsWithdrawn(msg.sender, winnings);
}
function calculateWinnings(address userAddress)
public
view
onlyParticipants(userAddress)
marketResolved
returns (uint256)
{
uint256 outcomeAmount = outcomes[market.finalOutcome].totalAmount;
if (outcomeAmount == 0) {
revert InvalidAmount("ZERO_OUTCOME_AMOUNT");
}
uint256 multiplier = uint256(10) ** market.tokenDecimals;
uint256 winPercentage = (userAmounts[userAddress] * multiplier) / outcomeAmount;
uint256 winnings = (market.totalRewards * winPercentage) / multiplier;
return winnings;
}
function retrieveFunds() external onlyOwner {
uint256 total_funds = getContractBalance();
_rewardToken.safeTransfer(msg.sender, total_funds);
emit FundsWithdrawn(owner(), total_funds);
}
function amplifyRewards(uint256 _amount)
external
marketNotResolved
marketNotCancelled
hasAllowance(_amount)
returns (uint256)
{
market.totalRewards += _amount;
if (sponsorAmounts[msg.sender] == 0) {
sponsors[market.totalSponsors] = msg.sender;
sponsorAmounts[msg.sender] = _amount;
market.totalSponsors += 1;
} else {
sponsorAmounts[msg.sender] += _amount;
}
_rewardToken.safeTransferFrom(msg.sender, address(this), _amount);
emit RewardsAmplified(msg.sender, sponsorAmounts[msg.sender]);
return getContractBalance();
}
function updatePlatformDetails(address _address, uint256 _fee)
public
onlyOwner
marketNotResolved
marketNotCancelled
{
_platformFee = _fee;
_platformAddress = _address;
emit PlatformDetailsUpdated(_platformAddress, _fee);
}
function getContractBalance() public view returns (uint256) {
return _rewardToken.balanceOf(address(this));
}
function isResolved() external view returns (bool) {
return market.resolved;
}
}
{
"compilationTarget": {
"src/Market_Factory.sol": "Market_Factory"
},
"evmVersion": "cancun",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": [
":@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
":erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
":forge-std/=lib/forge-std/src/",
":halmos-cheatcodes/=lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/",
":openzeppelin-contracts/=lib/openzeppelin-contracts/"
],
"viaIR": true
}
[{"inputs":[{"internalType":"address","name":"platformAddress","type":"address"},{"internalType":"uint256","name":"platformFee","type":"uint256"},{"internalType":"uint256","name":"creatorFee","type":"uint256"},{"internalType":"address","name":"tokenLockingAddress","type":"address"},{"internalType":"uint256","name":"requiredLockAmount","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"string","name":"error","type":"string"}],"name":"InvalidAmount","type":"error"},{"inputs":[{"internalType":"string","name":"error","type":"string"}],"name":"InvalidDescription","type":"error"},{"inputs":[{"internalType":"string","name":"error","type":"string"}],"name":"InvalidOutcomes","type":"error"},{"inputs":[{"internalType":"string","name":"error","type":"string"}],"name":"InvalidResolveTime","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"tokenAddress","type":"address"}],"name":"MarketDeployed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"platformAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"platformFee","type":"uint256"}],"name":"PlatformDetailsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"address[]","name":"markets","type":"address[]"}],"name":"UserPredictionsUpdated","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MARKET_CREATOR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"_creatorFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_platformAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_platformFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenAddress","type":"address"},{"internalType":"string","name":"_description","type":"string"},{"internalType":"string[]","name":"_outcomes","type":"string[]"},{"internalType":"uint256","name":"_tokenDecimals","type":"uint256"},{"internalType":"uint256","name":"_endTimestamp","type":"uint256"},{"internalType":"uint256","name":"_minPrice","type":"uint256"},{"internalType":"uint256","name":"_maxPrice","type":"uint256"}],"name":"deployMarket","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getAllMarkets","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"getAllUserMarkets","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPlatformDetails","outputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"grantMarketCreatorRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lockAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"predictionCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"revokeMarketCreatorRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"setLockAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_fee","type":"uint256"}],"name":"updateCreatorFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"},{"internalType":"uint256","name":"_fee","type":"uint256"}],"name":"updatePlatformDetails","outputs":[],"stateMutability":"nonpayable","type":"function"}]