文件 1 的 12:AccessControl.sol
pragma solidity ^0.8.0;
import "../utils/Context.sol";
import "../utils/introspection/ERC165.sol";
interface IAccessControl {
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 account) external;
}
abstract contract AccessControl is Context, IAccessControl, ERC165 {
struct RoleData {
mapping (address => bool) members;
bytes32 adminRole;
}
mapping (bytes32 => RoleData) private _roles;
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
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 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 override returns (bool) {
return _roles[role].members[account];
}
function getRoleAdmin(bytes32 role) public view override returns (bytes32) {
return _roles[role].adminRole;
}
function grantRole(bytes32 role, address account) public virtual override {
require(hasRole(getRoleAdmin(role), _msgSender()), "AccessControl: sender must be an admin to grant");
_grantRole(role, account);
}
function revokeRole(bytes32 role, address account) public virtual override {
require(hasRole(getRoleAdmin(role), _msgSender()), "AccessControl: sender must be an admin to revoke");
_revokeRole(role, account);
}
function renounceRole(bytes32 role, address account) public virtual override {
require(account == _msgSender(), "AccessControl: can only renounce roles for self");
_revokeRole(role, account);
}
function _setupRole(bytes32 role, address account) internal virtual {
_grantRole(role, account);
}
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
emit RoleAdminChanged(role, getRoleAdmin(role), adminRole);
_roles[role].adminRole = adminRole;
}
function _grantRole(bytes32 role, address account) private {
if (!hasRole(role, account)) {
_roles[role].members[account] = true;
emit RoleGranted(role, account, _msgSender());
}
}
function _revokeRole(bytes32 role, address account) private {
if (hasRole(role, account)) {
_roles[role].members[account] = false;
emit RoleRevoked(role, account, _msgSender());
}
}
}
文件 2 的 12:Constants.sol
pragma solidity >=0.8.0 <0.9.0;
contract Constants {
uint256 constant cMaxRandom = 10000;
uint8 constant cFutureBlockOffset = 2;
uint8 constant cNumRareHeroTypes = 16;
uint8 constant cNumEpicHeroTypes = 11;
uint8 constant cNumLegendaryHeroTypes = 8;
uint256 constant numProduct = 9;
uint8 constant cNumHeroTypes =
cNumRareHeroTypes + cNumEpicHeroTypes + cNumLegendaryHeroTypes;
uint16 constant cReferralDiscount = 500;
uint16 constant cReferrerBonus = 500;
bytes32 public constant PRODUCT_OWNER_ROLE =
keccak256("PRODUCT_OWNER_ROLE");
bytes32 public constant TREASURER_ROLE = keccak256("TREASURER_ROLE");
bytes32 public constant IMMUTABLE_SYSTEM_ROLE =
keccak256("IMMUTABLE_SYSTEM_ROLE");
enum Product {
RareHeroPack,
EpicHeroPack,
LegendaryHeroPack,
PetPack,
EnergyToken,
BasicGuildToken,
Tier1GuildToken,
Tier2GuildToken,
Tier3GuildToken
}
enum Rarity {Rare, Epic, Legendary, Common, NA}
enum Price {FirstSale, LastSale}
}
文件 3 的 12: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) {
this;
return msg.data;
}
}
文件 4 的 12:Dice.sol
pragma solidity >=0.8.0 <0.9.0;
contract Dice {
uint256 maxDiceRoll;
uint8 offset;
event SecondDiceRoll(
uint256 indexed _firstDiceRoll,
uint256 indexed _commitBlock,
uint256 _secondDiceRoll
);
constructor(uint256 _maxDiceRoll, uint8 _offset) {
maxDiceRoll = _maxDiceRoll;
offset = _offset;
}
function getSecondDiceRoll(uint256 _firstDiceRoll, uint256 _commitBlock)
public
view
returns (uint256)
{
return _getSecondDiceRoll(_firstDiceRoll, _commitBlock);
}
function emitSecondDiceRoll(uint256 _firstDiceRoll, uint256 _commitBlock)
public
{
emit SecondDiceRoll(
_firstDiceRoll,
_commitBlock,
_getSecondDiceRoll(_firstDiceRoll, _commitBlock)
);
}
function _getSecondDiceRoll(uint256 _firstDiceRoll, uint256 _commitBlock)
internal
view
returns (uint256)
{
return
uint256(
keccak256(
abi.encodePacked(
_firstDiceRoll,
_getFutureBlockhash(_commitBlock)
)
)
) % maxDiceRoll;
}
function _getFutureBlockhash(uint256 _commitBlock)
internal
view
returns (bytes32)
{
uint256 delta = block.number - _commitBlock;
require(delta < offset + 256, "Called too late");
require(delta >= offset + 1, "Called too early");
bytes32 futureBlockhash = blockhash(_commitBlock + offset);
require(futureBlockhash != bytes32(0), "Future blockhash empty");
return futureBlockhash;
}
function getFirstDiceRoll(uint256 _userProvidedSeed)
public
view
returns (uint256 randomNumber)
{
return
uint256(
keccak256(
abi.encodePacked(
blockhash(block.number - 1),
block.timestamp,
msg.sender,
_userProvidedSeed
)
)
) % maxDiceRoll;
}
function _diceWin(
uint256 _random,
uint256 _chance,
uint256 _maxDiceRoll
) internal pure returns (bool) {
return _random < (_maxDiceRoll * _chance) / _maxDiceRoll;
}
function _diceWinRanged(
uint256 _random,
uint256 _lowerLimit,
uint256 _upperLimit,
uint256 _maxDiceRoll
) internal pure returns (bool) {
return
_random < (_maxDiceRoll * _upperLimit) / _maxDiceRoll &&
_random >= (_maxDiceRoll * _lowerLimit) / _maxDiceRoll;
}
}
文件 5 的 12:ERC165.sol
pragma solidity ^0.8.0;
import "./IERC165.sol";
abstract contract ERC165 is IERC165 {
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}
文件 6 的 12:ExchangeRate.sol
pragma solidity >=0.8.0 <0.9.0;
import "@openzeppelin/contracts/access/AccessControl.sol";
import "./Constants.sol";
import "./interfaces/IUniswapV2Pair.sol";
contract ExchangeRate is Constants, AccessControl {
address public usdEthPairAddress;
uint256 constant cUsdDecimals = 2;
IUniswapV2Pair usdEthPair;
event UpdateUsdToEthPair(address _usdToEthPairAddress);
constructor(address _usdEthPairAddress) {
usdEthPairAddress = _usdEthPairAddress;
usdEthPair = IUniswapV2Pair(_usdEthPairAddress);
}
function updateUsdToEthPair(address _usdEthPairAddress) public {
require(
hasRole(PRODUCT_OWNER_ROLE, msg.sender),
"Caller is not product owner"
);
usdEthPairAddress = _usdEthPairAddress;
usdEthPair = IUniswapV2Pair(usdEthPairAddress);
emit UpdateUsdToEthPair(_usdEthPairAddress);
}
function getWeiPrice(uint256 _amountInUsd) public view returns (uint256) {
(uint112 usdReserve, uint112 ethReserve, uint32 blockTimestampLast) =
usdEthPair.getReserves();
return _calcWeiFromUsd(usdReserve, ethReserve, _amountInUsd);
}
function _calcWeiFromUsd(
uint112 _usdReserve,
uint112 _ethReserve,
uint256 _amountInUsd
) public pure returns (uint256) {
return
(_amountInUsd * _ethReserve * (10**18)) /
(_usdReserve * (10**cUsdDecimals));
}
}
文件 7 的 12:GuildOfGuardiansPreSale.sol
pragma solidity >=0.8.0 <0.9.0;
import "@openzeppelin/contracts/access/AccessControl.sol";
import "./Dice.sol";
import "./Treasury.sol";
import "./Constants.sol";
import "./Inventory.sol";
contract GuildOfGuardiansPreSale is
Constants,
AccessControl,
Treasury,
Inventory
{
constructor(address _usdEthPairAddress)
Inventory(_usdEthPairAddress)
{
_setupRole(DEFAULT_ADMIN_ROLE, msg.sender);
_setupRole(PRODUCT_OWNER_ROLE, msg.sender);
_setupRole(TREASURER_ROLE, msg.sender);
_setupRole(IMMUTABLE_SYSTEM_ROLE, msg.sender);
settings.firstChromaChance = 1200;
settings.secondChromaChance = 200;
settings.rareToEpicUpgradeChance = 400;
settings.rareToLegendaryUpgradeChance = 100;
settings.epicToLegendaryUpgradeChance = 500;
settings.petRareChance = 2700;
settings.petEpicChance = 1000;
settings.petLegendaryChance = 300;
settings.rareHeroMythicChance = 3;
settings.epicHeroMythicChance = 8;
settings.legendaryHeroMythicChance = 22;
productPrices[uint256(Product.RareHeroPack)][
uint256(Price.FirstSale)
] = 1000;
productPrices[uint256(Product.RareHeroPack)][
uint256(Price.LastSale)
] = 1250;
productPrices[uint256(Product.EpicHeroPack)][
uint256(Price.FirstSale)
] = 4400;
productPrices[uint256(Product.EpicHeroPack)][
uint256(Price.LastSale)
] = 5500;
productPrices[uint256(Product.LegendaryHeroPack)][
uint256(Price.FirstSale)
] = 20000;
productPrices[uint256(Product.LegendaryHeroPack)][
uint256(Price.LastSale)
] = 25000;
productPrices[uint256(Product.PetPack)][
uint256(Price.FirstSale)
] = 6000;
productPrices[uint256(Product.PetPack)][uint256(Price.LastSale)] = 7500;
productPrices[uint256(Product.EnergyToken)][
uint256(Price.FirstSale)
] = 12000;
productPrices[uint256(Product.EnergyToken)][
uint256(Price.LastSale)
] = 15000;
productPrices[uint256(Product.BasicGuildToken)][
uint256(Price.FirstSale)
] = 16000;
productPrices[uint256(Product.BasicGuildToken)][
uint256(Price.LastSale)
] = 20000;
productPrices[uint256(Product.Tier1GuildToken)][
uint256(Price.FirstSale)
] = 320000;
productPrices[uint256(Product.Tier1GuildToken)][
uint256(Price.LastSale)
] = 400000;
productPrices[uint256(Product.Tier2GuildToken)][
uint256(Price.FirstSale)
] = 1600000;
productPrices[uint256(Product.Tier2GuildToken)][
uint256(Price.LastSale)
] = 2000000;
productPrices[uint256(Product.Tier3GuildToken)][
uint256(Price.FirstSale)
] = 8000000;
productPrices[uint256(Product.Tier3GuildToken)][
uint256(Price.LastSale)
] = 10000000;
originalStock[uint256(Product.RareHeroPack)] = 0;
originalStock[uint256(Product.EpicHeroPack)] = 0;
originalStock[uint256(Product.LegendaryHeroPack)] = 0;
originalStock[uint256(Product.EnergyToken)] = 0;
originalStock[uint256(Product.BasicGuildToken)] = 0;
originalStock[uint256(Product.Tier1GuildToken)] = 0;
originalStock[uint256(Product.Tier2GuildToken)] = 0;
originalStock[uint256(Product.Tier3GuildToken)] = 0;
originalStock[uint256(Product.PetPack)] = 0;
stockAvailable[uint256(Product.RareHeroPack)] = 0;
stockAvailable[uint256(Product.EpicHeroPack)] = 0;
stockAvailable[uint256(Product.LegendaryHeroPack)] = 0;
stockAvailable[uint256(Product.EnergyToken)] = 0;
stockAvailable[uint256(Product.BasicGuildToken)] = 0;
stockAvailable[uint256(Product.Tier1GuildToken)] = 0;
stockAvailable[uint256(Product.Tier2GuildToken)] = 0;
stockAvailable[uint256(Product.Tier3GuildToken)] = 0;
stockAvailable[uint256(Product.PetPack)] = 0;
}
}
文件 8 的 12:IERC165.sol
pragma solidity ^0.8.0;
interface IERC165 {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
文件 9 的 12:IUniswapV2Pair.sol
pragma solidity >=0.5.0;
interface IUniswapV2Pair {
event Approval(
address indexed owner,
address indexed spender,
uint256 value
);
event Transfer(address indexed from, address indexed to, uint256 value);
function name() external pure returns (string memory);
function symbol() external pure returns (string memory);
function decimals() external pure returns (uint8);
function totalSupply() external view returns (uint256);
function balanceOf(address owner) external view returns (uint256);
function allowance(address owner, address spender)
external
view
returns (uint256);
function approve(address spender, uint256 value) external returns (bool);
function transfer(address to, uint256 value) external returns (bool);
function transferFrom(
address from,
address to,
uint256 value
) external returns (bool);
function DOMAIN_SEPARATOR() external view returns (bytes32);
function PERMIT_TYPEHASH() external pure returns (bytes32);
function nonces(address owner) external view returns (uint256);
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
event Mint(address indexed sender, uint256 amount0, uint256 amount1);
event Burn(
address indexed sender,
uint256 amount0,
uint256 amount1,
address indexed to
);
event Swap(
address indexed sender,
uint256 amount0In,
uint256 amount1In,
uint256 amount0Out,
uint256 amount1Out,
address indexed to
);
event Sync(uint112 reserve0, uint112 reserve1);
function MINIMUM_LIQUIDITY() external pure returns (uint256);
function factory() external view returns (address);
function token0() external view returns (address);
function token1() external view returns (address);
function getReserves()
external
view
returns (
uint112 reserve0,
uint112 reserve1,
uint32 blockTimestampLast
);
function price0CumulativeLast() external view returns (uint256);
function price1CumulativeLast() external view returns (uint256);
function kLast() external view returns (uint256);
function mint(address to) external returns (uint256 liquidity);
function burn(address to)
external
returns (uint256 amount0, uint256 amount1);
function swap(
uint256 amount0Out,
uint256 amount1Out,
address to,
bytes calldata data
) external;
function skim(address to) external;
function sync() external;
function initialize(address, address) external;
}
文件 10 的 12:Inventory.sol
pragma solidity >=0.8.0 <0.9.0;
import "@openzeppelin/contracts/access/AccessControl.sol";
import "./Constants.sol";
import "./Dice.sol";
import "./ExchangeRate.sol";
import "./Referral.sol";
contract Inventory is Constants, AccessControl, Dice, ExchangeRate, Referral {
address[cNumHeroTypes] public mythicOwner;
Settings settings;
uint256[numProduct] public originalStock;
uint256[numProduct] public stockAvailable;
bool public stockFixed = false;
uint256[2][numProduct] public productPrices;
struct Settings {
uint256 firstChromaChance;
uint256 secondChromaChance;
uint256 rareToEpicUpgradeChance;
uint256 rareToLegendaryUpgradeChance;
uint256 epicToLegendaryUpgradeChance;
uint256 petRareChance;
uint256 petEpicChance;
uint256 petLegendaryChance;
uint256 rareHeroMythicChance;
uint256 epicHeroMythicChance;
uint256 legendaryHeroMythicChance;
}
struct AllocatedOrder {
uint256 firstDiceRoll;
uint16[] order;
}
struct DetailedAllocation {
Product product;
Rarity rarity;
uint8 heroPetType;
uint8 chroma;
bool potentialMythic;
}
event AllocateOrder(
AllocatedOrder _allocatedOrder,
address indexed _owner,
uint256 _orderPrice
);
event PermanentlyLockStock();
event GiftOrder(address indexed _giftRecipient);
event ClaimMythic(
AllocatedOrder _allocatedOrder,
uint256 _mythicOrderLine,
address indexed _customerAddr
);
constructor(address _usdEthPairAddress)
Dice(cMaxRandom, cFutureBlockOffset)
ExchangeRate(_usdEthPairAddress)
Referral(cReferralDiscount, cReferrerBonus)
{}
function addStock(uint16[] memory _stockToAdd) public {
require(
hasRole(PRODUCT_OWNER_ROLE, msg.sender),
"Caller is not product owner"
);
require(!stockFixed, "No more stock can be added");
for (uint256 i = 0; i < numProduct; i++) {
originalStock[i] += _stockToAdd[i];
stockAvailable[i] += _stockToAdd[i];
}
}
function permanentlyLockStock() public {
require(
hasRole(PRODUCT_OWNER_ROLE, msg.sender),
"Caller is not product owner"
);
require(!stockFixed, "Stock already locked");
stockFixed = true;
emit PermanentlyLockStock();
}
function _updateStockLevels(uint16[] memory _order) internal {
require(_order.length == numProduct, "Unexpected number of orderlines");
stockAvailable[uint8(Product.RareHeroPack)] -= _order[
uint8(Product.RareHeroPack)
];
stockAvailable[uint8(Product.EpicHeroPack)] -= _order[
uint8(Product.EpicHeroPack)
];
stockAvailable[uint8(Product.LegendaryHeroPack)] -= _order[
uint8(Product.LegendaryHeroPack)
];
stockAvailable[uint8(Product.PetPack)] -= _order[
uint8(Product.PetPack)
];
stockAvailable[uint8(Product.EnergyToken)] -= _order[
uint8(Product.EnergyToken)
];
stockAvailable[uint8(Product.BasicGuildToken)] -= _order[
uint8(Product.BasicGuildToken)
];
stockAvailable[uint8(Product.Tier1GuildToken)] -= _order[
uint8(Product.Tier1GuildToken)
];
stockAvailable[uint8(Product.Tier2GuildToken)] -= _order[
uint8(Product.Tier2GuildToken)
];
stockAvailable[uint8(Product.Tier3GuildToken)] -= _order[
uint8(Product.Tier3GuildToken)
];
}
function _countStock() internal view returns (uint256) {
uint256 count;
for (uint256 i = 0; i < numProduct; i++) {
count += stockAvailable[i];
}
return count;
}
function decodeAllocation(
AllocatedOrder memory _allocatedOrder,
uint256 _secondDiceRoll
) public view returns (DetailedAllocation[] memory) {
uint256 numLines = _calcNumOrderLines(_allocatedOrder.order);
DetailedAllocation[] memory detailedAllocation =
new DetailedAllocation[](numLines);
uint16 orderLineNumber;
for (
uint256 i = 0;
i < _allocatedOrder.order[uint256(Product.RareHeroPack)];
i++
) {
Rarity rarity =
_rarityAllocation(
Rarity.Rare,
uint256(
keccak256(
abi.encodePacked(
_secondDiceRoll,
uint256(3),
orderLineNumber
)
)
)
);
uint8 chroma =
_chromaAllocation(
uint256(
keccak256(
abi.encodePacked(
_secondDiceRoll,
uint256(2),
orderLineNumber
)
)
)
);
uint8 heroType =
_heroTypeAllocation(
rarity,
uint256(
keccak256(
abi.encodePacked(
_secondDiceRoll,
uint256(1),
orderLineNumber
)
)
)
);
bool potentialMythic =
_mythicAllocation(
rarity,
uint256(
keccak256(
abi.encodePacked(
_secondDiceRoll,
uint256(4),
orderLineNumber
)
)
)
);
detailedAllocation[orderLineNumber] = DetailedAllocation({
product: Product.RareHeroPack,
rarity: rarity,
heroPetType: heroType,
chroma: chroma,
potentialMythic: potentialMythic
});
orderLineNumber++;
}
for (
uint256 i = 0;
i < _allocatedOrder.order[uint256(Product.EpicHeroPack)];
i++
) {
Rarity rarity =
_rarityAllocation(
Rarity.Epic,
uint256(
keccak256(
abi.encodePacked(
_secondDiceRoll,
uint256(3),
orderLineNumber
)
)
)
);
uint8 chroma =
_chromaAllocation(
uint256(
keccak256(
abi.encodePacked(
_secondDiceRoll,
uint256(2),
orderLineNumber
)
)
)
);
uint8 heroType =
_heroTypeAllocation(
rarity,
uint256(
keccak256(
abi.encodePacked(
_secondDiceRoll,
uint256(1),
orderLineNumber
)
)
)
);
bool potentialMythic =
_mythicAllocation(
rarity,
uint256(
keccak256(
abi.encodePacked(
_secondDiceRoll,
uint256(4),
orderLineNumber
)
)
)
);
detailedAllocation[orderLineNumber] = DetailedAllocation({
product: Product.EpicHeroPack,
rarity: rarity,
heroPetType: heroType,
chroma: chroma,
potentialMythic: potentialMythic
});
orderLineNumber++;
}
for (
uint256 i = 0;
i < _allocatedOrder.order[uint256(Product.LegendaryHeroPack)];
i++
) {
Rarity rarity =
_rarityAllocation(
Rarity.Legendary,
uint256(
keccak256(
abi.encodePacked(
_secondDiceRoll,
uint256(3),
orderLineNumber
)
)
)
);
uint8 chroma =
_chromaAllocation(
uint256(
keccak256(
abi.encodePacked(
_secondDiceRoll,
uint256(2),
orderLineNumber
)
)
)
);
uint8 heroType =
_heroTypeAllocation(
rarity,
uint256(
keccak256(
abi.encodePacked(
_secondDiceRoll,
uint256(1),
orderLineNumber
)
)
)
);
bool potentialMythic =
_mythicAllocation(
rarity,
uint256(
keccak256(
abi.encodePacked(
_secondDiceRoll,
uint256(4),
orderLineNumber
)
)
)
);
detailedAllocation[orderLineNumber] = DetailedAllocation({
product: Product.LegendaryHeroPack,
rarity: rarity,
heroPetType: heroType,
chroma: chroma,
potentialMythic: potentialMythic
});
orderLineNumber++;
}
for (
uint256 i = 0;
i < _allocatedOrder.order[uint256(Product.PetPack)];
i++
) {
uint8 petType =
_petTypeAllocation(
uint256(
keccak256(
abi.encodePacked(
_secondDiceRoll,
uint256(1),
orderLineNumber
)
)
)
);
Rarity petRarity =
_petRarityAllocation(
uint256(
keccak256(
abi.encodePacked(
_secondDiceRoll,
uint256(2),
orderLineNumber
)
)
)
);
detailedAllocation[orderLineNumber] = DetailedAllocation({
product: Product.PetPack,
rarity: petRarity,
heroPetType: petType,
chroma: 0,
potentialMythic: false
});
orderLineNumber++;
}
for (
uint256 i = 0;
i < _allocatedOrder.order[uint256(Product.BasicGuildToken)];
i++
) {
detailedAllocation[orderLineNumber] = DetailedAllocation({
product: Product.BasicGuildToken,
rarity: Rarity.NA,
heroPetType: 0,
chroma: 0,
potentialMythic: false
});
orderLineNumber++;
}
for (
uint256 i = 0;
i < _allocatedOrder.order[uint256(Product.Tier1GuildToken)];
i++
) {
detailedAllocation[orderLineNumber] = DetailedAllocation({
product: Product.Tier1GuildToken,
rarity: Rarity.NA,
heroPetType: 0,
chroma: 0,
potentialMythic: false
});
orderLineNumber++;
}
for (
uint256 i = 0;
i < _allocatedOrder.order[uint256(Product.Tier2GuildToken)];
i++
) {
detailedAllocation[orderLineNumber] = DetailedAllocation({
product: Product.Tier2GuildToken,
rarity: Rarity.NA,
heroPetType: 0,
chroma: 0,
potentialMythic: false
});
orderLineNumber++;
}
for (
uint256 i = 0;
i < _allocatedOrder.order[uint256(Product.Tier3GuildToken)];
i++
) {
detailedAllocation[orderLineNumber] = DetailedAllocation({
product: Product.Tier3GuildToken,
rarity: Rarity.NA,
heroPetType: 0,
chroma: 0,
potentialMythic: false
});
orderLineNumber++;
}
for (
uint256 i = 0;
i < _allocatedOrder.order[uint256(Product.EnergyToken)];
i++
) {
detailedAllocation[orderLineNumber] = DetailedAllocation({
product: Product.EnergyToken,
rarity: Rarity.NA,
heroPetType: 0,
chroma: 0,
potentialMythic: false
});
orderLineNumber++;
}
return detailedAllocation;
}
function claimMythicForCustomer(
AllocatedOrder memory _allocatedOrder,
uint256 _mythicOrderLine,
address _customerAddr,
uint256 _secondDiceRoll
) public {
require(
hasRole(IMMUTABLE_SYSTEM_ROLE, msg.sender),
"Caller is not immutable"
);
if (
_confirmMythic(_allocatedOrder, _mythicOrderLine, _secondDiceRoll)
) {
uint256 heroType =
_getMythicHeroType(
_allocatedOrder,
_mythicOrderLine,
_secondDiceRoll
);
mythicOwner[heroType] = _customerAddr;
}
emit ClaimMythic(_allocatedOrder, _mythicOrderLine, _customerAddr);
}
function confirmMythic(
AllocatedOrder memory _allocatedOrder,
uint256 _mythicOrderLine,
uint256 _secondDiceRoll
) public view returns (bool) {
return
_confirmMythic(_allocatedOrder, _mythicOrderLine, _secondDiceRoll);
}
function _confirmMythic(
AllocatedOrder memory _allocatedOrder,
uint256 _mythicOrderLine,
uint256 _secondDiceRoll
) internal view returns (bool) {
DetailedAllocation[] memory detailedAllocations =
decodeAllocation(_allocatedOrder, _secondDiceRoll);
DetailedAllocation memory potentialMythicAllocation =
detailedAllocations[_mythicOrderLine];
uint256 heroType = potentialMythicAllocation.heroPetType;
if (
potentialMythicAllocation.potentialMythic &&
mythicOwner[heroType] == address(0)
) {
return true;
} else {
return false;
}
}
function _getMythicHeroType(
AllocatedOrder memory _allocatedOrder,
uint256 _mythicOrderLine,
uint256 _secondDiceRoll
) internal view returns (uint256) {
DetailedAllocation[] memory detailedAllocations =
decodeAllocation(_allocatedOrder, _secondDiceRoll);
DetailedAllocation memory potentialMythicAllocation =
detailedAllocations[_mythicOrderLine];
return potentialMythicAllocation.heroPetType;
}
function _allocateStock(
uint16[] memory _order,
address _owner,
uint256 _orderPrice
) internal {
require(_order.length == numProduct, "Unexpected number of orderlines");
_updateStockLevels(_order);
uint256 firstDiceRoll = getFirstDiceRoll(_countStock());
AllocatedOrder memory ao =
AllocatedOrder({firstDiceRoll: firstDiceRoll, order: _order});
emit AllocateOrder(ao, _owner, _orderPrice);
}
function _rarityAllocation(Rarity _originalRarity, uint256 _random)
internal
view
returns (Rarity finalRarity)
{
uint256 score = _random % cMaxRandom;
if (_originalRarity == Rarity.Rare) {
if (
_diceWinRanged(
score,
0,
settings.rareToLegendaryUpgradeChance,
cMaxRandom
)
) {
return Rarity.Legendary;
} else if (
_diceWinRanged(
score,
settings.rareToLegendaryUpgradeChance,
settings.rareToLegendaryUpgradeChance +
settings.rareToEpicUpgradeChance,
cMaxRandom
)
) {
return Rarity.Epic;
} else {
return Rarity.Rare;
}
}
if (_originalRarity == Rarity.Epic) {
if (
_diceWin(
score,
settings.epicToLegendaryUpgradeChance,
cMaxRandom
)
) {
return Rarity.Legendary;
} else {
return Rarity.Epic;
}
}
return _originalRarity;
}
function _mythicAllocation(Rarity _rarity, uint256 _random)
internal
view
returns (bool)
{
uint256 score = _random % cMaxRandom;
if (
_rarity == Rarity.Rare &&
_diceWin(score, settings.rareHeroMythicChance, cMaxRandom)
) {
return true;
}
if (
_rarity == Rarity.Epic &&
_diceWin(score, settings.epicHeroMythicChance, cMaxRandom)
) {
return true;
}
if (
_rarity == Rarity.Legendary &&
_diceWin(score, settings.legendaryHeroMythicChance, cMaxRandom)
) {
return true;
}
return false;
}
function _chromaAllocation(uint256 _random) internal view returns (uint8) {
uint256 score = _random % cMaxRandom;
if (_diceWin(score, settings.secondChromaChance, cMaxRandom)) {
return 2;
}
if (_diceWin(score, settings.firstChromaChance, cMaxRandom)) {
return 1;
}
return 0;
}
function _heroTypeAllocation(Rarity _heroRarity, uint256 _random)
internal
view
returns (uint8)
{
uint8 heroType;
uint256 score = _random % cMaxRandom;
if (_heroRarity == Rarity.Legendary) {
heroType = uint8((score % cNumLegendaryHeroTypes) + 1);
} else if (_heroRarity == Rarity.Epic) {
heroType = uint8(
(score % cNumEpicHeroTypes) + cNumLegendaryHeroTypes + 1
);
} else if (_heroRarity == Rarity.Rare) {
heroType = uint8(
(score % cNumRareHeroTypes) +
cNumEpicHeroTypes +
cNumLegendaryHeroTypes +
1
);
}
return heroType;
}
function _petTypeAllocation(uint256 _random) internal view returns (uint8) {
return uint8((_random % 3) + 1);
}
function _petRarityAllocation(uint256 _random)
internal
view
returns (Rarity)
{
uint256 score = _random % cMaxRandom;
uint256 startLimit = 0;
if (_diceWinRanged(score, 0, settings.petLegendaryChance, cMaxRandom)) {
return Rarity.Legendary;
}
startLimit += settings.petLegendaryChance;
if (
_diceWinRanged(
score,
startLimit,
settings.petEpicChance,
cMaxRandom
)
) {
return Rarity.Epic;
}
startLimit += settings.petEpicChance;
if (
_diceWinRanged(
score,
startLimit,
settings.petRareChance,
cMaxRandom
)
) {
return Rarity.Rare;
}
return Rarity.Common;
}
function _calcNumOrderLines(uint16[] memory _order)
internal
view
returns (uint256)
{
require(_order.length == numProduct, "Unexpected number of orderlines");
uint256 numLines;
for (uint256 i = 0; i < numProduct; i++) {
numLines += _order[i];
}
return numLines;
}
function getProductCostUsd(uint8 _productId) public view returns (uint256) {
uint256 multiplier = 1 * 10**6;
uint256 firstPrice =
productPrices[_productId][uint256(Price.FirstSale)];
uint256 lastPrice = productPrices[_productId][uint256(Price.LastSale)];
uint256 itemsSold =
originalStock[uint8(_productId)] -
stockAvailable[uint8(_productId)];
if (itemsSold == 0) {
return firstPrice;
}
uint256 relativePriceMovement =
(itemsSold * multiplier) / originalStock[uint8(_productId)];
uint256 maxPriceChange = lastPrice - firstPrice;
uint256 actualPriceChange =
(maxPriceChange * relativePriceMovement) / multiplier;
return firstPrice + actualPriceChange;
}
function getProductCostWei(uint8 _productId) public view returns (uint256) {
return getWeiPrice(getProductCostUsd(_productId));
}
function calcOrderCostUsd(uint16[] memory _order)
public
view
returns (uint256)
{
require(_order.length == numProduct, "Unexpected number of orderlines");
uint256 orderCost;
for (uint8 i = 0; i < _order.length; i++) {
orderCost += _calcOrderLineCost(i, _order[i]);
}
return orderCost;
}
function calcOrderCostWei(uint16[] memory _order)
public
view
returns (uint256)
{
require(_order.length == numProduct, "Unexpected number of orderlines");
return getWeiPrice(calcOrderCostUsd(_order));
}
function _calcOrderLineCost(uint8 _productId, uint16 _quantity)
internal
view
returns (uint256)
{
return getProductCostUsd(_productId) * _quantity;
}
function purchase(uint16[] memory _order, address _referrer)
public
payable
{
require(_order.length == numProduct, "Unexpected number of orderlines");
_enforceOrderLimits(_order);
uint256 orderCostUsd = calcOrderCostUsd(_order);
uint256 referrerBonusUsd;
uint256 discountUsd;
if (_referrer != address(0)) {
(referrerBonusUsd, discountUsd) = _calcReferrals(orderCostUsd);
}
(uint112 usdReserve, uint112 ethReserve, uint32 blockTimestampLast) =
usdEthPair.getReserves();
if (referrerBonusUsd > 0) {
referrerBonuses[_referrer] += _calcWeiFromUsd(
usdReserve,
ethReserve,
referrerBonusUsd
);
}
uint256 discountWei =
_calcWeiFromUsd(usdReserve, ethReserve, discountUsd);
uint256 netWei =
_calcWeiFromUsd(usdReserve, ethReserve, orderCostUsd) - discountWei;
require(msg.value >= netWei, "Insufficient funds");
_allocateStock(
_order,
msg.sender,
orderCostUsd - referrerBonusUsd - discountUsd
);
if (msg.value - netWei > 0) {
(bool success, ) =
payable(msg.sender).call{value: msg.value - netWei}("");
require(success, "Transfer failed");
}
}
function giftPack(uint16[] memory _giftOrder, address _giftRecipient)
public
{
require(
hasRole(PRODUCT_OWNER_ROLE, msg.sender),
"Caller is not product owner"
);
_enforceOrderLimits(_giftOrder);
_allocateStock(_giftOrder, _giftRecipient, 0);
emit GiftOrder(_giftRecipient);
}
function addStockAndGift(uint16[] memory _giftOrder, address _giftRecipient)
public
{
require(
hasRole(PRODUCT_OWNER_ROLE, msg.sender),
"Caller is not product owner"
);
require(!stockFixed, "No more stock can be added");
_enforceOrderLimits(_giftOrder);
addStock(_giftOrder);
_allocateStock(_giftOrder, _giftRecipient, 0);
emit GiftOrder(_giftRecipient);
}
function _enforceOrderLimits(uint16[] memory _order) internal {
require(_order.length == numProduct, "Unexpected number of orderlines");
for (uint256 i = 0; i < numProduct; i++) {
require(_order[i] <= 100, "Max limit 100 per item");
}
}
}
文件 11 的 12:Referral.sol
pragma solidity >=0.8.0 <0.9.0;
contract Referral {
uint16 referralDiscount;
uint16 referrerBonus;
mapping(address => uint256) public referrerBonuses;
event WithdrawBonus(uint256 _amount, address _referrer);
constructor(uint16 _referralDiscount, uint16 _referrerBonus) {
referralDiscount = _referralDiscount;
referrerBonus = _referrerBonus;
}
function withdrawBonus() public {
uint256 amount = referrerBonuses[msg.sender];
require(amount > 0, "Nothing to withdraw");
referrerBonuses[msg.sender] = 0;
(bool success, ) = payable(msg.sender).call{value: amount}("");
require(success, "Transfer failed");
emit WithdrawBonus(amount, msg.sender);
}
function _calcReferrals(uint256 _orderCost)
internal
view
returns (uint256 toReferrer, uint256 discount)
{
toReferrer = (_orderCost * referrerBonus) / 10000;
discount = (_orderCost * referralDiscount) / 10000;
return (toReferrer, discount);
}
}
文件 12 的 12:Treasury.sol
pragma solidity >=0.8.0 <0.9.0;
import "./Constants.sol";
import "@openzeppelin/contracts/access/AccessControl.sol";
contract Treasury is Constants, AccessControl {
event Withdraw(uint256 _amount);
function withdraw(uint256 _amount) public {
require(hasRole(TREASURER_ROLE, msg.sender), "Caller is not treasurer");
(bool success, ) = payable(msg.sender).call{value: _amount}("");
require(success, "Transfer failed");
emit Withdraw(_amount);
}
}
{
"compilationTarget": {
"contracts/GuildOfGuardiansPreSale.sol": "GuildOfGuardiansPreSale"
},
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"_usdEthPairAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"components":[{"internalType":"uint256","name":"firstDiceRoll","type":"uint256"},{"internalType":"uint16[]","name":"order","type":"uint16[]"}],"indexed":false,"internalType":"struct Inventory.AllocatedOrder","name":"_allocatedOrder","type":"tuple"},{"indexed":true,"internalType":"address","name":"_owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"_orderPrice","type":"uint256"}],"name":"AllocateOrder","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"uint256","name":"firstDiceRoll","type":"uint256"},{"internalType":"uint16[]","name":"order","type":"uint16[]"}],"indexed":false,"internalType":"struct Inventory.AllocatedOrder","name":"_allocatedOrder","type":"tuple"},{"indexed":false,"internalType":"uint256","name":"_mythicOrderLine","type":"uint256"},{"indexed":true,"internalType":"address","name":"_customerAddr","type":"address"}],"name":"ClaimMythic","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_giftRecipient","type":"address"}],"name":"GiftOrder","type":"event"},{"anonymous":false,"inputs":[],"name":"PermanentlyLockStock","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":true,"internalType":"uint256","name":"_firstDiceRoll","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"_commitBlock","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_secondDiceRoll","type":"uint256"}],"name":"SecondDiceRoll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_usdToEthPairAddress","type":"address"}],"name":"UpdateUsdToEthPair","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"Withdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"_referrer","type":"address"}],"name":"WithdrawBonus","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"IMMUTABLE_SYSTEM_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PRODUCT_OWNER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TREASURER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint112","name":"_usdReserve","type":"uint112"},{"internalType":"uint112","name":"_ethReserve","type":"uint112"},{"internalType":"uint256","name":"_amountInUsd","type":"uint256"}],"name":"_calcWeiFromUsd","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint16[]","name":"_stockToAdd","type":"uint16[]"}],"name":"addStock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16[]","name":"_giftOrder","type":"uint16[]"},{"internalType":"address","name":"_giftRecipient","type":"address"}],"name":"addStockAndGift","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16[]","name":"_order","type":"uint16[]"}],"name":"calcOrderCostUsd","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16[]","name":"_order","type":"uint16[]"}],"name":"calcOrderCostWei","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"firstDiceRoll","type":"uint256"},{"internalType":"uint16[]","name":"order","type":"uint16[]"}],"internalType":"struct Inventory.AllocatedOrder","name":"_allocatedOrder","type":"tuple"},{"internalType":"uint256","name":"_mythicOrderLine","type":"uint256"},{"internalType":"address","name":"_customerAddr","type":"address"},{"internalType":"uint256","name":"_secondDiceRoll","type":"uint256"}],"name":"claimMythicForCustomer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"firstDiceRoll","type":"uint256"},{"internalType":"uint16[]","name":"order","type":"uint16[]"}],"internalType":"struct Inventory.AllocatedOrder","name":"_allocatedOrder","type":"tuple"},{"internalType":"uint256","name":"_mythicOrderLine","type":"uint256"},{"internalType":"uint256","name":"_secondDiceRoll","type":"uint256"}],"name":"confirmMythic","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"firstDiceRoll","type":"uint256"},{"internalType":"uint16[]","name":"order","type":"uint16[]"}],"internalType":"struct Inventory.AllocatedOrder","name":"_allocatedOrder","type":"tuple"},{"internalType":"uint256","name":"_secondDiceRoll","type":"uint256"}],"name":"decodeAllocation","outputs":[{"components":[{"internalType":"enum Constants.Product","name":"product","type":"uint8"},{"internalType":"enum Constants.Rarity","name":"rarity","type":"uint8"},{"internalType":"uint8","name":"heroPetType","type":"uint8"},{"internalType":"uint8","name":"chroma","type":"uint8"},{"internalType":"bool","name":"potentialMythic","type":"bool"}],"internalType":"struct Inventory.DetailedAllocation[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_firstDiceRoll","type":"uint256"},{"internalType":"uint256","name":"_commitBlock","type":"uint256"}],"name":"emitSecondDiceRoll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_userProvidedSeed","type":"uint256"}],"name":"getFirstDiceRoll","outputs":[{"internalType":"uint256","name":"randomNumber","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"_productId","type":"uint8"}],"name":"getProductCostUsd","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"_productId","type":"uint8"}],"name":"getProductCostWei","outputs":[{"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":"uint256","name":"_firstDiceRoll","type":"uint256"},{"internalType":"uint256","name":"_commitBlock","type":"uint256"}],"name":"getSecondDiceRoll","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amountInUsd","type":"uint256"}],"name":"getWeiPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16[]","name":"_giftOrder","type":"uint16[]"},{"internalType":"address","name":"_giftRecipient","type":"address"}],"name":"giftPack","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":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"mythicOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"originalStock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"permanentlyLockStock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"productPrices","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16[]","name":"_order","type":"uint16[]"},{"internalType":"address","name":"_referrer","type":"address"}],"name":"purchase","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"referrerBonuses","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","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":"","type":"uint256"}],"name":"stockAvailable","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stockFixed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_usdEthPairAddress","type":"address"}],"name":"updateUsdToEthPair","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"usdEthPairAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawBonus","outputs":[],"stateMutability":"nonpayable","type":"function"}]