Feature Tip: Add private address tag to any address under My Name Tag !
Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 290 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Purchase Market ... | 15341586 | 851 days ago | IN | 0 ETH | 0.00098387 | ||||
Purchase Market ... | 15338794 | 851 days ago | IN | 0 ETH | 0.00039485 | ||||
Purchase Market ... | 15329739 | 853 days ago | IN | 0 ETH | 0.00225878 | ||||
Purchase Market ... | 15326865 | 853 days ago | IN | 0 ETH | 0.00095638 | ||||
Purchase Market ... | 15323420 | 854 days ago | IN | 0 ETH | 0.00199919 | ||||
Purchase Market ... | 15322988 | 854 days ago | IN | 0 ETH | 0.00126435 | ||||
Purchase Market ... | 15322876 | 854 days ago | IN | 0 ETH | 0.00230634 | ||||
Purchase Market ... | 15319768 | 854 days ago | IN | 0 ETH | 0.00172744 | ||||
Purchase Market ... | 15319290 | 854 days ago | IN | 0 ETH | 0.00179511 | ||||
Purchase Market ... | 15318960 | 854 days ago | IN | 0 ETH | 0.00115233 | ||||
Purchase Market ... | 15318933 | 854 days ago | IN | 0 ETH | 0.00105993 | ||||
Purchase Market ... | 15318919 | 854 days ago | IN | 0 ETH | 0.00185065 | ||||
Purchase Market ... | 15318907 | 854 days ago | IN | 0 ETH | 0.0013277 | ||||
Purchase Market ... | 15318356 | 854 days ago | IN | 0 ETH | 0.00174124 | ||||
Purchase Market ... | 15318294 | 854 days ago | IN | 0 ETH | 0.00247121 | ||||
Purchase Market ... | 15318276 | 854 days ago | IN | 0 ETH | 0.00330264 | ||||
Purchase Market ... | 15318027 | 854 days ago | IN | 0 ETH | 0.00260055 | ||||
Purchase Market ... | 15317839 | 854 days ago | IN | 0 ETH | 0.00114766 | ||||
Purchase Market ... | 15317833 | 854 days ago | IN | 0 ETH | 0.0013711 | ||||
Purchase Market ... | 15317814 | 854 days ago | IN | 0 ETH | 0.00165931 | ||||
Purchase Market ... | 15316914 | 855 days ago | IN | 0 ETH | 0.0032934 | ||||
Purchase Market ... | 15316776 | 855 days ago | IN | 0 ETH | 0.00332209 | ||||
Purchase Market ... | 15316703 | 855 days ago | IN | 0 ETH | 0.00094877 | ||||
Purchase Market ... | 15316486 | 855 days ago | IN | 0 ETH | 0.00182999 | ||||
Purchase Market ... | 15316404 | 855 days ago | IN | 0 ETH | 0.00138728 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
Marketplace
Compiler Version
v0.8.13+commit.abaa5c0e
Optimization Enabled:
Yes with 10000 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; // -\**:. `"^` // ;HNXav*,^;}?|:,.` // tbKX&]:,:7I}=\:-_._,` // :OKgTv)*7}ri=*;::,^``:;:^ // :&S@OTnccvtl])*\;:--~.`_;;-,^.` // :cdXDOhT&Yuctl1=*;::,^..,;+*;:--,"~^. // ;LX8dXSDOhasocv}1>+|;:---:;|||;:--,"_^^^..` // :3@bd8dXSDPTasocvtl]>+|;::::;;;:::--,_~^^^..'```` // `laP@d88d@DhT0Yo3cjt}i]=+*\;;:::::::---,_^^^..'`` `` // `)3&hSd8dbDhT&YoccvIt}l17=)*|;;:::::::--,"_^^^..'``` `` // ;=rnOb88d@OT&nucvjItr}i17==+**\;;;:::::--,"~^^^..''`` ` // ^^:lnOXg8XDhaYucvjttr}lir3Luv=**|;;;;;:::--,_~^^....'-XMMh=' ` // ``~>YOdKKd@haYucvttrrINMMMMMMMMMMj\;;;;::::-,"~^^....-MMMHDr=:` // ,7YDgmK8@haYucItr}}MMMMMMMMmt|1MMM=;;;;::::-,_^^....MMQ8OT-`';` // ` `-}&Smqm8SPTsucjr}}lMMMMMMMMMDl|]MMMM|;;;;:::--"^^..''MMmSOhV7)1:` // '"^,+vhdHNNEbOT&ocjtllitMMMMMMMMMMMMMMMMM1||\;;;::-"^..''`TMNKSDhaLt\- // =)=}nOmNQBHgDhaYuvIrli?jMMMMMMMMMMMMMMMMM1|||;;;::-~.'''``.dMBq8Oaor*| // cLY0OgNQQQWHdDh0Yuvt}i?11MMMMMMMMMMMMMMMMM**|;;;:::-_..''```.c#WHSaul7+ ` // =OS8mNQMMMMQH8DhasucIrli111MMMMMMMMMMMMMMM+*|;;;::::-,^..''````.1VEHda7` `` // @mHWQMMMMMMQNEbDkan3vtli1]>=?SMMMMMMMMMh)**|\;;::::--,~^..-'```````,,`````` `` // NQMMMMMMMMMMQNKbOh0Luv}i7==))))))))+*****||\;;;1MMMXkncuOKo.'''```````````````````` // QMMMMMMMMMMMMQNmdDh&n3I}17==)))))))+****|\;;;;:::::*71=;,~^^...''''```````````````` // QMMMMMMMMMMMMMQBHEbOTVocjtli?11]>>==)+**||;;;;::::::----,,_~^^^.........''''''```` // jMMMMMMMMMMMMMMMQ#q8@hTVLuccvjt}}l?1]>=)***|\;;;::::::-----,,,"__~^^^^^......''``` // qMMMMMMMMMMMMMMMMWNmXDha&noouccjtr}li17==)+**|\;;;::::::::-----,,,"_~^^^....'``' // MMMMMMMMMMMMMMMMMQBHgbOhT0Vnoo3cvIt}li117>=)***|\;;;;::::::::----,,,_~^^^..''' // QMMMMMMMMMMMMMMMMQWNq8bOhTa&snoucvjt}ll?1]>=))**||\;;;;;:::::::----,"_^^^..' // -MMMMMMMMMMMMMMMMMQWNq8bDOhka0sLo3cvjIr}li?1]7>==)+***|\;;;;:::::----,,~^ // ;NMMMMMMMMMMMMMMMMQQNqEgdSDOhka0Ynou3ccvjItr}lli117>=))***||;;;:::::- // ]MMMMMMMMMMMMMMMMQQWBNHmKdb@OhkTa&sYLooucccvjItr}}li?17==)+*||:' // .1qMMMMMMMMMMMMMMMQQBNHqEKdSDOPkaa&snoou3cccvvjItr}li1]>;,` // :IOMMMMMMMMMMMMQQBNHm8XSOPka0Vnou3cvjtr}llli?>:"` // _|jnbQMMMMMMMMQBNqK8XSDPTasLucvI|~.` // oMMMMMMMMMMMMQqSTocri7)*|:. // IMMMMMMMMMMNdksc}1)\::-,~^..'` // lTMMMQMMMQqD0oj}1=*;:-_^.'``````` // -cOQMN8KMMM#gO&uj}1=*;:-^.''````````` // :hHQ#gDSQMMMMHSTs3v}])|:-~^.'````` '.`` // 1KMQEOaLXMMMMMQEDTn3Ii7+;:-_^.''````'^.'` // -WMMghYuYHMMMMMM#dO0Lcr?=|;:-_^..'```.^^.' // gMMKhscckWMMMMMMQm@Ts3Il7*\::-_^..'``^",~.' // ?MMNPscvobMMMMMMMMN8Paov}1)*;:-,_^..``,---~.` // .MMWS&utvV8MMMMMMMMWEDTs3jl>*\;:--"^.`.:\;:-_` // lMMNOLjrcTgMMMMMMMMMNXOTYujl>*\:::-,^.`;ll=-` // 'MMNDYccclQMMMMMMMMMWq8@PTsct1)|;;;:" // -;\-` QMMMMMMMQ#HEEgdSOaLv}i]+:,^ // ]MMMMMHdhs3t` ^P8gbhu];-. // MMMMW8kci>) hgKDV}|:^' // @MMMHho1*;: hNHDYl\:^ // dMMmav=;: |t3v7:. // '~^' // // author: phaze import "@openzeppelin/contracts/interfaces/IERC721.sol"; import "@openzeppelin/contracts/interfaces/IERC20.sol"; import "./BaoToken.sol"; import "./Ownable.sol"; error NotActive(); error NoSupplyLeft(); error InsufficientValue(); error MaxEntriesReached(); error ContractCallNotAllowed(); contract Marketplace is Ownable { /* ------------- Events ------------- */ event MarketItemPurchased(address indexed user, bytes32 indexed id); /* ------------- Structs ------------- */ struct MarketItemData { uint256 start; uint256 end; uint256 tokenPrice; uint256 ethPrice; uint256 maxEntries; uint256 maxSupply; bytes32 dataHash; } /* ------------- Storage ------------- */ mapping(bytes32 => uint256) public totalSupply; mapping(bytes32 => mapping(address => uint256)) public numEntries; BaoToken public immutable baoToken; constructor(BaoToken token) { baoToken = token; } /* ------------- External ------------- */ function purchaseMarketItem(MarketItemData[] calldata marketItemData, bool tokenPayment) external payable onlyEOA { uint256 totalPayment; for (uint256 i; i < marketItemData.length; ) { MarketItemData calldata item = marketItemData[i]; bytes32 itemHash = keccak256(abi.encode(item)); unchecked { if (++totalSupply[itemHash] > item.maxSupply) revert NoSupplyLeft(); if (block.timestamp < item.start || item.end < block.timestamp) revert NotActive(); if (++numEntries[itemHash][msg.sender] > item.maxEntries) revert MaxEntriesReached(); // overflow not possible, limited by supply if (tokenPayment) totalPayment += item.tokenPrice; else totalPayment += item.ethPrice; } emit MarketItemPurchased(msg.sender, itemHash); unchecked { ++i; } } if (tokenPayment) baoToken.burnFrom(msg.sender, totalPayment); else if (msg.value != totalPayment) revert InsufficientValue(); } /* ------------- Owner ------------- */ function withdraw() external onlyOwner { uint256 balance = address(this).balance; payable(msg.sender).transfer(balance); } function recoverToken(IERC20 token) external onlyOwner { token.transfer(msg.sender, token.balanceOf(address(this))); } function recoverNFT(IERC721 token, uint256 id) external onlyOwner { token.transferFrom(address(this), msg.sender, id); } /* ------------- Modifier ------------- */ modifier onlyEOA() { if (msg.sender != tx.origin) revert ContractCallNotAllowed(); _; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (interfaces/IERC721.sol) pragma solidity ^0.8.0; import "../token/ERC721/IERC721.sol";
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (interfaces/IERC20.sol) pragma solidity ^0.8.0; import "../token/ERC20/IERC20.sol";
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; // -\**:. `"^` // ;HNXav*,^;}?|:,.` // tbKX&]:,:7I}=\:-_._,` // :OKgTv)*7}ri=*;::,^``:;:^ // :&S@OTnccvtl])*\;:--~.`_;;-,^.` // :cdXDOhT&Yuctl1=*;::,^..,;+*;:--,"~^. // ;LX8dXSDOhasocv}1>+|;:---:;|||;:--,"_^^^..` // :3@bd8dXSDPTasocvtl]>+|;::::;;;:::--,_~^^^..'```` // `laP@d88d@DhT0Yo3cjt}i]=+*\;;:::::::---,_^^^..'`` `` // `)3&hSd8dbDhT&YoccvIt}l17=)*|;;:::::::--,"_^^^..'``` `` // ;=rnOb88d@OT&nucvjItr}i17==+**\;;;:::::--,"~^^^..''`` ` // ^^:lnOXg8XDhaYucvjttr}lir3Luv=**|;;;;;:::--,_~^^....'-XMMh=' ` // ``~>YOdKKd@haYucvttrrINMMMMMMMMMMj\;;;;::::-,"~^^....-MMMHDr=:` // ,7YDgmK8@haYucItr}}MMMMMMMMmt|1MMM=;;;;::::-,_^^....MMQ8OT-`';` // ` `-}&Smqm8SPTsucjr}}lMMMMMMMMMDl|]MMMM|;;;;:::--"^^..''MMmSOhV7)1:` // '"^,+vhdHNNEbOT&ocjtllitMMMMMMMMMMMMMMMMM1||\;;;::-"^..''`TMNKSDhaLt\- // =)=}nOmNQBHgDhaYuvIrli?jMMMMMMMMMMMMMMMMM1|||;;;::-~.'''``.dMBq8Oaor*| // cLY0OgNQQQWHdDh0Yuvt}i?11MMMMMMMMMMMMMMMMM**|;;;:::-_..''```.c#WHSaul7+ ` // =OS8mNQMMMMQH8DhasucIrli111MMMMMMMMMMMMMMM+*|;;;::::-,^..''````.1VEHda7` `` // @mHWQMMMMMMQNEbDkan3vtli1]>=?SMMMMMMMMMh)**|\;;::::--,~^..-'```````,,`````` `` // NQMMMMMMMMMMQNKbOh0Luv}i7==))))))))+*****||\;;;1MMMXkncuOKo.'''```````````````````` // QMMMMMMMMMMMMQNmdDh&n3I}17==)))))))+****|\;;;;:::::*71=;,~^^...''''```````````````` // QMMMMMMMMMMMMMQBHEbOTVocjtli?11]>>==)+**||;;;;::::::----,,_~^^^.........''''''```` // jMMMMMMMMMMMMMMMQ#q8@hTVLuccvjt}}l?1]>=)***|\;;;::::::-----,,,"__~^^^^^......''``` // qMMMMMMMMMMMMMMMMWNmXDha&noouccjtr}li17==)+**|\;;;::::::::-----,,,"_~^^^....'``' // MMMMMMMMMMMMMMMMMQBHgbOhT0Vnoo3cvIt}li117>=)***|\;;;;::::::::----,,,_~^^^..''' // QMMMMMMMMMMMMMMMMQWNq8bOhTa&snoucvjt}ll?1]>=))**||\;;;;;:::::::----,"_^^^..' // -MMMMMMMMMMMMMMMMMQWNq8bDOhka0sLo3cvjIr}li?1]7>==)+***|\;;;;:::::----,,~^ // ;NMMMMMMMMMMMMMMMMQQNqEgdSDOhka0Ynou3ccvjItr}lli117>=))***||;;;:::::- // ]MMMMMMMMMMMMMMMMQQWBNHmKdb@OhkTa&sYLooucccvjItr}}li?17==)+*||:' // .1qMMMMMMMMMMMMMMMQQBNHqEKdSDOPkaa&snoou3cccvvjItr}li1]>;,` // :IOMMMMMMMMMMMMQQBNHm8XSOPka0Vnou3cvjtr}llli?>:"` // _|jnbQMMMMMMMMQBNqK8XSDPTasLucvI|~.` // oMMMMMMMMMMMMQqSTocri7)*|:. // IMMMMMMMMMMNdksc}1)\::-,~^..'` // lTMMMQMMMQqD0oj}1=*;:-_^.'``````` // -cOQMN8KMMM#gO&uj}1=*;:-^.''````````` // :hHQ#gDSQMMMMHSTs3v}])|:-~^.'````` '.`` // 1KMQEOaLXMMMMMQEDTn3Ii7+;:-_^.''````'^.'` // -WMMghYuYHMMMMMM#dO0Lcr?=|;:-_^..'```.^^.' // gMMKhscckWMMMMMMQm@Ts3Il7*\::-_^..'``^",~.' // ?MMNPscvobMMMMMMMMN8Paov}1)*;:-,_^..``,---~.` // .MMWS&utvV8MMMMMMMMWEDTs3jl>*\;:--"^.`.:\;:-_` // lMMNOLjrcTgMMMMMMMMMNXOTYujl>*\:::-,^.`;ll=-` // 'MMNDYccclQMMMMMMMMMWq8@PTsct1)|;;;:" // -;\-` QMMMMMMMQ#HEEgdSOaLv}i]+:,^ // ]MMMMMHdhs3t` ^P8gbhu];-. // MMMMW8kci>) hgKDV}|:^' // @MMMHho1*;: hNHDYl\:^ // dMMmav=;: |t3v7:. // '~^' // // author: phaze import "@openzeppelin/contracts/access/AccessControl.sol"; import "@openzeppelin/contracts/interfaces/IERC721.sol"; import "./BaoStaking.sol"; contract BaoToken is AccessControl, BaoStaking { bytes32 public constant MINT_AUTHORITY = keccak256("MINT_AUTHORITY"); bytes32 public constant BURN_AUTHORITY = keccak256("BURN_AUTHORITY"); address public treasuryAddress = address(0xb0b); constructor(IBaoSociety baoSociety_) ERC20("Bao Token", "BAO", 18) BaoStaking(baoSociety_) { _setupRole(DEFAULT_ADMIN_ROLE, treasuryAddress); _mint(treasuryAddress, 10_000_000 * 1e18); } /* ------------- Restricted ------------- */ function mint(address user, uint256 amount) external payable onlyRole(MINT_AUTHORITY) { _mint(user, amount); } /* ------------- ERC20Burnable ------------- */ function burn(uint256 amount) external payable { _burn(msg.sender, amount); } function burnFrom(address user, uint256 amount) external payable { if (!hasRole(BURN_AUTHORITY, msg.sender)) { uint256 allowed = allowance[user][msg.sender]; if (allowed != type(uint256).max) allowance[user][msg.sender] = allowed - amount; } _burn(user, amount); } /* ------------- MultiCall ------------- */ // handy tool; can be dangerous for contracts that accept eth as payment function multiCall(bytes[] calldata data) external payable { unchecked { for (uint256 i; i < data.length; ++i) address(this).delegatecall(data[i]); } } /* ------------- Owner ------------- */ function withdraw() external onlyOwner { uint256 balance = address(this).balance; payable(msg.sender).transfer(balance); } function recoverToken(ERC20 token) external onlyOwner { uint256 balance = token.balanceOf(address(this)); token.transfer(msg.sender, balance); } function recoverNFT(IERC721 token, uint256 id) external onlyOwner { token.transferFrom(address(this), msg.sender, id); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; error CallerNotOwner(); abstract contract Ownable { address private _owner = msg.sender; function owner() public view returns (address) { return _owner; } function transferOwnership(address newOwner) external onlyOwner { _owner = newOwner; } modifier onlyOwner() { if (msg.sender != _owner) revert CallerNotOwner(); _; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721.sol) pragma solidity ^0.8.0; import "../../utils/introspection/IERC165.sol"; /** * @dev Required interface of an ERC721 compliant contract. */ interface IERC721 is IERC165 { /** * @dev Emitted when `tokenId` token is transferred from `from` to `to`. */ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. */ event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. */ event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of tokens in ``owner``'s account. */ function balanceOf(address owner) external view returns (uint256 balance); /** * @dev Returns the owner of the `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function ownerOf(uint256 tokenId) external view returns (address owner); /** * @dev Safely transfers `tokenId` token from `from` to `to`. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom( address from, address to, uint256 tokenId, bytes calldata data ) external; /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC721 protocol to prevent tokens from being forever locked. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom( address from, address to, uint256 tokenId ) external; /** * @dev Transfers `tokenId` token from `from` to `to`. * * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 tokenId ) external; /** * @dev Gives permission to `to` to transfer `tokenId` token to another account. * The approval is cleared when the token is transferred. * * Only a single account can be approved at a time, so approving the zero address clears previous approvals. * * Requirements: * * - The caller must own the token or be an approved operator. * - `tokenId` must exist. * * Emits an {Approval} event. */ function approve(address to, uint256 tokenId) external; /** * @dev Approve or remove `operator` as an operator for the caller. * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. * * Requirements: * * - The `operator` cannot be the caller. * * Emits an {ApprovalForAll} event. */ function setApprovalForAll(address operator, bool _approved) external; /** * @dev Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) external view returns (address operator); /** * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. * * See {setApprovalForAll} */ function isApprovedForAll(address owner, address operator) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 amount ) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (access/AccessControl.sol) pragma solidity ^0.8.0; import "./IAccessControl.sol"; import "../utils/Context.sol"; import "../utils/Strings.sol"; import "../utils/introspection/ERC165.sol"; /** * @dev Contract module that allows children to implement role-based access * control mechanisms. This is a lightweight version that doesn't allow enumerating role * members except through off-chain means by accessing the contract event logs. Some * applications may benefit from on-chain enumerability, for those cases see * {AccessControlEnumerable}. * * Roles are referred to by their `bytes32` identifier. These should be exposed * in the external API and be unique. The best way to achieve this is by * using `public constant` hash digests: * * ``` * bytes32 public constant MY_ROLE = keccak256("MY_ROLE"); * ``` * * Roles can be used to represent a set of permissions. To restrict access to a * function call, use {hasRole}: * * ``` * function foo() public { * require(hasRole(MY_ROLE, msg.sender)); * ... * } * ``` * * Roles can be granted and revoked dynamically via the {grantRole} and * {revokeRole} functions. Each role has an associated admin role, and only * accounts that have a role's admin role can call {grantRole} and {revokeRole}. * * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means * that only accounts with this role will be able to grant or revoke other * roles. More complex role relationships can be created by using * {_setRoleAdmin}. * * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to * grant and revoke this role. Extra precautions should be taken to secure * accounts that have been granted it. */ 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; /** * @dev Modifier that checks that an account has a specific role. Reverts * with a standardized message including the required role. * * The format of the revert reason is given by the following regular expression: * * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/ * * _Available since v4.1._ */ modifier onlyRole(bytes32 role) { _checkRole(role); _; } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId); } /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) public view virtual override returns (bool) { return _roles[role].members[account]; } /** * @dev Revert with a standard message if `_msgSender()` is missing `role`. * Overriding this function changes the behavior of the {onlyRole} modifier. * * Format of the revert message is described in {_checkRole}. * * _Available since v4.6._ */ function _checkRole(bytes32 role) internal view virtual { _checkRole(role, _msgSender()); } /** * @dev Revert with a standard message if `account` is missing `role`. * * The format of the revert reason is given by the following regular expression: * * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/ */ function _checkRole(bytes32 role, address account) internal view virtual { if (!hasRole(role, account)) { revert( string( abi.encodePacked( "AccessControl: account ", Strings.toHexString(uint160(account), 20), " is missing role ", Strings.toHexString(uint256(role), 32) ) ) ); } } /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) { return _roles[role].adminRole; } /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) { _grantRole(role, account); } /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) { _revokeRole(role, account); } /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been revoked `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `account`. */ function renounceRole(bytes32 role, address account) public virtual override { require(account == _msgSender(), "AccessControl: can only renounce roles for self"); _revokeRole(role, account); } /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. Note that unlike {grantRole}, this function doesn't perform any * checks on the calling account. * * [WARNING] * ==== * This function should only be called from the constructor when setting * up the initial roles for the system. * * Using this function in any other way is effectively circumventing the admin * system imposed by {AccessControl}. * ==== * * NOTE: This function is deprecated in favor of {_grantRole}. */ function _setupRole(bytes32 role, address account) internal virtual { _grantRole(role, account); } /** * @dev Sets `adminRole` as ``role``'s admin role. * * Emits a {RoleAdminChanged} event. */ function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual { bytes32 previousAdminRole = getRoleAdmin(role); _roles[role].adminRole = adminRole; emit RoleAdminChanged(role, previousAdminRole, adminRole); } /** * @dev Grants `role` to `account`. * * Internal function without access restriction. */ function _grantRole(bytes32 role, address account) internal virtual { if (!hasRole(role, account)) { _roles[role].members[account] = true; emit RoleGranted(role, account, _msgSender()); } } /** * @dev Revokes `role` from `account`. * * Internal function without access restriction. */ function _revokeRole(bytes32 role, address account) internal virtual { if (hasRole(role, account)) { _roles[role].members[account] = false; emit RoleRevoked(role, account, _msgSender()); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; // -\**:. `"^` // ;HNXav*,^;}?|:,.` // tbKX&]:,:7I}=\:-_._,` // :OKgTv)*7}ri=*;::,^``:;:^ // :&S@OTnccvtl])*\;:--~.`_;;-,^.` // :cdXDOhT&Yuctl1=*;::,^..,;+*;:--,"~^. // ;LX8dXSDOhasocv}1>+|;:---:;|||;:--,"_^^^..` // :3@bd8dXSDPTasocvtl]>+|;::::;;;:::--,_~^^^..'```` // `laP@d88d@DhT0Yo3cjt}i]=+*\;;:::::::---,_^^^..'`` `` // `)3&hSd8dbDhT&YoccvIt}l17=)*|;;:::::::--,"_^^^..'``` `` // ;=rnOb88d@OT&nucvjItr}i17==+**\;;;:::::--,"~^^^..''`` ` // ^^:lnOXg8XDhaYucvjttr}lir3Luv=**|;;;;;:::--,_~^^....'-XMMh=' ` // ``~>YOdKKd@haYucvttrrINMMMMMMMMMMj\;;;;::::-,"~^^....-MMMHDr=:` // ,7YDgmK8@haYucItr}}MMMMMMMMmt|1MMM=;;;;::::-,_^^....MMQ8OT-`';` // ` `-}&Smqm8SPTsucjr}}lMMMMMMMMMDl|]MMMM|;;;;:::--"^^..''MMmSOhV7)1:` // '"^,+vhdHNNEbOT&ocjtllitMMMMMMMMMMMMMMMMM1||\;;;::-"^..''`TMNKSDhaLt\- // =)=}nOmNQBHgDhaYuvIrli?jMMMMMMMMMMMMMMMMM1|||;;;::-~.'''``.dMBq8Oaor*| // cLY0OgNQQQWHdDh0Yuvt}i?11MMMMMMMMMMMMMMMMM**|;;;:::-_..''```.c#WHSaul7+ ` // =OS8mNQMMMMQH8DhasucIrli111MMMMMMMMMMMMMMM+*|;;;::::-,^..''````.1VEHda7` `` // @mHWQMMMMMMQNEbDkan3vtli1]>=?SMMMMMMMMMh)**|\;;::::--,~^..-'```````,,`````` `` // NQMMMMMMMMMMQNKbOh0Luv}i7==))))))))+*****||\;;;1MMMXkncuOKo.'''```````````````````` // QMMMMMMMMMMMMQNmdDh&n3I}17==)))))))+****|\;;;;:::::*71=;,~^^...''''```````````````` // QMMMMMMMMMMMMMQBHEbOTVocjtli?11]>>==)+**||;;;;::::::----,,_~^^^.........''''''```` // jMMMMMMMMMMMMMMMQ#q8@hTVLuccvjt}}l?1]>=)***|\;;;::::::-----,,,"__~^^^^^......''``` // qMMMMMMMMMMMMMMMMWNmXDha&noouccjtr}li17==)+**|\;;;::::::::-----,,,"_~^^^....'``' // MMMMMMMMMMMMMMMMMQBHgbOhT0Vnoo3cvIt}li117>=)***|\;;;;::::::::----,,,_~^^^..''' // QMMMMMMMMMMMMMMMMQWNq8bOhTa&snoucvjt}ll?1]>=))**||\;;;;;:::::::----,"_^^^..' // -MMMMMMMMMMMMMMMMMQWNq8bDOhka0sLo3cvjIr}li?1]7>==)+***|\;;;;:::::----,,~^ // ;NMMMMMMMMMMMMMMMMQQNqEgdSDOhka0Ynou3ccvjItr}lli117>=))***||;;;:::::- // ]MMMMMMMMMMMMMMMMQQWBNHmKdb@OhkTa&sYLooucccvjItr}}li?17==)+*||:' // .1qMMMMMMMMMMMMMMMQQBNHqEKdSDOPkaa&snoou3cccvvjItr}li1]>;,` // :IOMMMMMMMMMMMMQQBNHm8XSOPka0Vnou3cvjtr}llli?>:"` // _|jnbQMMMMMMMMQBNqK8XSDPTasLucvI|~.` // oMMMMMMMMMMMMQqSTocri7)*|:. // IMMMMMMMMMMNdksc}1)\::-,~^..'` // lTMMMQMMMQqD0oj}1=*;:-_^.'``````` // -cOQMN8KMMM#gO&uj}1=*;:-^.''````````` // :hHQ#gDSQMMMMHSTs3v}])|:-~^.'````` '.`` // 1KMQEOaLXMMMMMQEDTn3Ii7+;:-_^.''````'^.'` // -WMMghYuYHMMMMMM#dO0Lcr?=|;:-_^..'```.^^.' // gMMKhscckWMMMMMMQm@Ts3Il7*\::-_^..'``^",~.' // ?MMNPscvobMMMMMMMMN8Paov}1)*;:-,_^..``,---~.` // .MMWS&utvV8MMMMMMMMWEDTs3jl>*\;:--"^.`.:\;:-_` // lMMNOLjrcTgMMMMMMMMMNXOTYujl>*\:::-,^.`;ll=-` // 'MMNDYccclQMMMMMMMMMWq8@PTsct1)|;;;:" // -;\-` QMMMMMMMQ#HEEgdSOaLv}i]+:,^ // ]MMMMMHdhs3t` ^P8gbhu];-. // MMMMW8kci>) hgKDV}|:^' // @MMMHho1*;: hNHDYl\:^ // dMMmav=;: |t3v7:. // '~^' // // author: phaze import {IERC721 as IBaoSociety} from "@openzeppelin/contracts/interfaces/IERC721.sol"; import "../lib/solmate/src/tokens/ERC20.sol"; import "./Ownable.sol"; error IncorrectOwner(); abstract contract BaoStaking is Ownable, ERC20 { struct TokenData { address owner; uint40 lastClaimed; uint40 rarity; } struct StakeData { uint40 rarityBonus; uint40 numStaked; uint40 lastClaimed; } uint256 constant DAILY_BASE_REWARD = 100; uint256 constant DAILY_STAKED_REWARD = 150; uint256 public immutable REWARD_EMISSION_START = block.timestamp; uint256 public immutable REWARD_EMISSION_END = block.timestamp + 5 * 365 days; mapping(uint256 => TokenData) public tokenData; mapping(address => StakeData) public stakeData; IBaoSociety public immutable baoSociety; constructor(IBaoSociety baoSociety_) { baoSociety = baoSociety_; } /* ------------- External ------------- */ function stake(uint256[] calldata tokenIds) external payable { unchecked { claimRewardStaked(); TokenData storage tData; StakeData storage sData = stakeData[msg.sender]; uint256 tokenId; uint256 reward; uint256 rarityBonus = sData.rarityBonus; for (uint256 i; i < tokenIds.length; ++i) { tokenId = tokenIds[i]; baoSociety.transferFrom(msg.sender, address(this), tokenId); tData = tokenData[tokenId]; tData.owner = msg.sender; // accrue non-staked rewards reward += _calculateRewardSingleClaim(tData, tokenId); rarityBonus += getRarityBonus(tData); } sData.numStaked += uint40(tokenIds.length); sData.rarityBonus = uint40(rarityBonus); _mint(msg.sender, reward); } } function unstake(uint256[] calldata tokenIds) external payable { unchecked { claimRewardStaked(); TokenData storage tData; StakeData storage sData = stakeData[msg.sender]; uint256 tokenId; uint256 rarityBonus = sData.rarityBonus; for (uint256 i; i < tokenIds.length; ++i) { tokenId = tokenIds[i]; tData = tokenData[tokenId]; if (tData.owner != msg.sender) revert IncorrectOwner(); baoSociety.transferFrom(address(this), msg.sender, tokenId); rarityBonus -= getRarityBonus(tData); // underflow not possible if rarity stays constant tData.lastClaimed = uint40(block.timestamp); } sData.numStaked -= uint40(tokenIds.length); sData.rarityBonus = uint40(rarityBonus); } } function claimRewardStaked() public payable { uint256 reward = pendingRewardStaked(msg.sender); _mint(msg.sender, reward); stakeData[msg.sender].lastClaimed = uint40(block.timestamp); } function claimReward(uint256[] calldata tokenIds) external payable { unchecked { TokenData storage tData; uint256 reward; uint256 tokenId; for (uint256 i; i < tokenIds.length; ++i) { tokenId = tokenIds[i]; tData = tokenData[tokenId]; if (baoSociety.ownerOf(tokenId) != msg.sender) revert IncorrectOwner(); reward += _calculateRewardSingleClaim(tData, tokenId); tData.lastClaimed = uint40(block.timestamp); } _mint(msg.sender, reward); } } /* ------------- View ------------- */ function pendingRewardStaked(address user) public view returns (uint256) { unchecked { uint256 staked = stakeData[user].numStaked; if (staked == 0) return 0; uint256 timestamp = block.timestamp; uint256 lastClaimed = stakeData[user].lastClaimed; if (timestamp < REWARD_EMISSION_START || REWARD_EMISSION_END < lastClaimed) return 0; if (REWARD_EMISSION_END < timestamp) timestamp = REWARD_EMISSION_END; // follows: 0 <= lastClaimed <= timestamp <= REWARD_EMISSION_END // note: lastClaimed can be 0, `staked` will however also be 0 then return // does not overflow under assumption type(uint40).max * 3888 * 1000 * 1e18 << type(uint256).max ((timestamp - lastClaimed) * (staked * DAILY_STAKED_REWARD + stakeData[user].rarityBonus) * 1e18) / 1 days; } } function dailyRewardStaked(address user) external view returns (uint256) { unchecked { return ((uint256(stakeData[user].numStaked) * DAILY_STAKED_REWARD + stakeData[user].rarityBonus) * 1e18); } } function pendingReward(uint256[] calldata tokenIds) external view returns (uint256) { unchecked { TokenData storage tData; uint256 reward; uint256 tokenId; for (uint256 i; i < tokenIds.length; ++i) { tokenId = tokenIds[i]; tData = tokenData[tokenId]; reward += _calculateRewardSingleClaim(tData, tokenId); } return reward; } } function dailyReward(uint256[] calldata tokenIds) external view returns (uint256) { unchecked { uint256 reward; for (uint256 i; i < tokenIds.length; ++i) reward += (DAILY_BASE_REWARD + getRarityBonus(tokenData[tokenIds[i]])) * 1e18; return reward; } } function getRarityBonus(uint256 tokenId) external view returns (uint256) { return getRarityBonus(tokenData[tokenId]); } function numStaked(address user) external view returns (uint256) { return stakeData[user].numStaked; } function numOwned(address user) external view returns (uint256) { return baoSociety.balanceOf(user) + stakeData[user].numStaked; } function totalNumStaked() external view returns (uint256) { return baoSociety.balanceOf(address(this)); } /* ------------- Private ------------- */ function getRarityBonus(TokenData storage tData) private view returns (uint256) { uint256 rarity = tData.rarity; return rarity == 0 ? 5 : rarity; } function _calculateRewardSingleClaim(TokenData storage tData, uint256 tokenId) private view returns (uint256) { uint256 rewardBonus; uint256 timestamp = block.timestamp; uint256 lastClaimed = tData.lastClaimed; // if (timestamp < REWARD_EMISSION_START) revert ClaimingNotEnabled(); // note: enabling this line enables staking/claiming before emission start date if (timestamp < REWARD_EMISSION_START || REWARD_EMISSION_END < lastClaimed) return 0; if (REWARD_EMISSION_END < timestamp) timestamp = REWARD_EMISSION_END; if (lastClaimed < REWARD_EMISSION_START) { if (lastClaimed == 0 && tokenId % 5 == 0) rewardBonus = 1500 * 1e18; // one-time bonus reward to every 5th tokenId lastClaimed = REWARD_EMISSION_START; } // follows: REWARD_EMISSION_START <= lastClaimed <= timestamp <= REWARD_EMISSION_END unchecked { return // does not overflow under assumption 1500e18 + type(uint40).max * 3888 * 1000 * 1e18 << type(uint256).max rewardBonus + ((timestamp - lastClaimed) * (DAILY_BASE_REWARD + getRarityBonus(tData)) * 1e18) / 1 days; } } /* ------------- Owner ------------- */ // @note should only be called once before any interaction happens // bad things (underflow) can happen if this is changed while someone is staking function setRarities(uint256[] calldata ids, uint256[] calldata rarities) external onlyOwner { unchecked { for (uint256 i; i < ids.length; ++i) tokenData[ids[i]].rarity = uint40(rarities[i]); } } /* ------------- O(n) Read-Only ------------- */ function stakedTokenIdsOf(address user) external view returns (uint256[] memory) { uint256 staked = stakeData[user].numStaked; uint256[] memory stakedIds = new uint256[](staked); if (staked == 0) return stakedIds; uint256 count; for (uint256 i = 1; i < 3888 + 1; ++i) { if (tokenData[i].owner == user) { stakedIds[count++] = i; if (staked == count) return stakedIds; } } return stakedIds; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol) pragma solidity ^0.8.0; /** * @dev External interface of AccessControl declared to support ERC165 detection. */ interface IAccessControl { /** * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` * * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite * {RoleAdminChanged} not being emitted signaling this. * * _Available since v3.1._ */ event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole); /** * @dev Emitted when `account` is granted `role`. * * `sender` is the account that originated the contract call, an admin role * bearer except when using {AccessControl-_setupRole}. */ event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Emitted when `account` is revoked `role`. * * `sender` is the account that originated the contract call: * - if using `revokeRole`, it is the admin role bearer * - if using `renounceRole`, it is the role bearer (i.e. `account`) */ event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) external view returns (bool); /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {AccessControl-_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) external view returns (bytes32); /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function grantRole(bytes32 role, address account) external; /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function revokeRole(bytes32 role, address account) external; /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been granted `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `account`. */ function renounceRole(bytes32 role, address account) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Strings.sol) pragma solidity ^0.8.0; /** * @dev String operations. */ library Strings { bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef"; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { // Inspired by OraclizeAPI's implementation - MIT licence // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol if (value == 0) { return "0"; } uint256 temp = value; uint256 digits; while (temp != 0) { digits++; temp /= 10; } bytes memory buffer = new bytes(digits); while (value != 0) { digits -= 1; buffer[digits] = bytes1(uint8(48 + uint256(value % 10))); value /= 10; } return string(buffer); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { if (value == 0) { return "0x00"; } uint256 temp = value; uint256 length = 0; while (temp != 0) { length++; temp >>= 8; } return toHexString(value, length); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = _HEX_SYMBOLS[value & 0xf]; value >>= 4; } require(value == 0, "Strings: hex length insufficient"); return string(buffer); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol) pragma solidity ^0.8.0; import "./IERC165.sol"; /** * @dev Implementation of the {IERC165} interface. * * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check * for the additional interface id that will be supported. For example: * * ```solidity * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); * } * ``` * * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. */ abstract contract ERC165 is IERC165 { /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IERC165).interfaceId; } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; /// @notice Modern and gas efficient ERC20 + EIP-2612 implementation. /// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC20.sol) /// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol) /// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it. abstract contract ERC20 { /*////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////*/ event Transfer(address indexed from, address indexed to, uint256 amount); event Approval(address indexed owner, address indexed spender, uint256 amount); /*////////////////////////////////////////////////////////////// METADATA STORAGE //////////////////////////////////////////////////////////////*/ string public name; string public symbol; uint8 public immutable decimals; /*////////////////////////////////////////////////////////////// ERC20 STORAGE //////////////////////////////////////////////////////////////*/ uint256 public totalSupply; mapping(address => uint256) public balanceOf; mapping(address => mapping(address => uint256)) public allowance; /*////////////////////////////////////////////////////////////// EIP-2612 STORAGE //////////////////////////////////////////////////////////////*/ uint256 internal immutable INITIAL_CHAIN_ID; bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR; mapping(address => uint256) public nonces; /*////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////*/ constructor( string memory _name, string memory _symbol, uint8 _decimals ) { name = _name; symbol = _symbol; decimals = _decimals; INITIAL_CHAIN_ID = block.chainid; INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator(); } /*////////////////////////////////////////////////////////////// ERC20 LOGIC //////////////////////////////////////////////////////////////*/ function approve(address spender, uint256 amount) public virtual returns (bool) { allowance[msg.sender][spender] = amount; emit Approval(msg.sender, spender, amount); return true; } function transfer(address to, uint256 amount) public virtual returns (bool) { balanceOf[msg.sender] -= amount; // Cannot overflow because the sum of all user // balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } emit Transfer(msg.sender, to, amount); return true; } function transferFrom( address from, address to, uint256 amount ) public virtual returns (bool) { uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals. if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount; balanceOf[from] -= amount; // Cannot overflow because the sum of all user // balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } emit Transfer(from, to, amount); return true; } /*////////////////////////////////////////////////////////////// EIP-2612 LOGIC //////////////////////////////////////////////////////////////*/ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) public virtual { require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED"); // Unchecked because the only math done is incrementing // the owner's nonce which cannot realistically overflow. unchecked { address recoveredAddress = ecrecover( keccak256( abi.encodePacked( "\x19\x01", DOMAIN_SEPARATOR(), keccak256( abi.encode( keccak256( "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)" ), owner, spender, value, nonces[owner]++, deadline ) ) ) ), v, r, s ); require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER"); allowance[recoveredAddress][spender] = value; } emit Approval(owner, spender, value); } function DOMAIN_SEPARATOR() public view virtual returns (bytes32) { return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator(); } function computeDomainSeparator() internal view virtual returns (bytes32) { return keccak256( abi.encode( keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"), keccak256(bytes(name)), keccak256("1"), block.chainid, address(this) ) ); } /*////////////////////////////////////////////////////////////// INTERNAL MINT/BURN LOGIC //////////////////////////////////////////////////////////////*/ function _mint(address to, uint256 amount) internal virtual { totalSupply += amount; // Cannot overflow because the sum of all user // balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } emit Transfer(address(0), to, amount); } function _burn(address from, uint256 amount) internal virtual { balanceOf[from] -= amount; // Cannot underflow because a user's balance // will never be larger than the total supply. unchecked { totalSupply -= amount; } emit Transfer(from, address(0), amount); } }
{ "optimizer": { "enabled": true, "runs": 10000 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"contract BaoToken","name":"token","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"CallerNotOwner","type":"error"},{"inputs":[],"name":"ContractCallNotAllowed","type":"error"},{"inputs":[],"name":"InsufficientValue","type":"error"},{"inputs":[],"name":"MaxEntriesReached","type":"error"},{"inputs":[],"name":"NoSupplyLeft","type":"error"},{"inputs":[],"name":"NotActive","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"bytes32","name":"id","type":"bytes32"}],"name":"MarketItemPurchased","type":"event"},{"inputs":[],"name":"baoToken","outputs":[{"internalType":"contract BaoToken","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"address","name":"","type":"address"}],"name":"numEntries","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"start","type":"uint256"},{"internalType":"uint256","name":"end","type":"uint256"},{"internalType":"uint256","name":"tokenPrice","type":"uint256"},{"internalType":"uint256","name":"ethPrice","type":"uint256"},{"internalType":"uint256","name":"maxEntries","type":"uint256"},{"internalType":"uint256","name":"maxSupply","type":"uint256"},{"internalType":"bytes32","name":"dataHash","type":"bytes32"}],"internalType":"struct Marketplace.MarketItemData[]","name":"marketItemData","type":"tuple[]"},{"internalType":"bool","name":"tokenPayment","type":"bool"}],"name":"purchaseMarketItem","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IERC721","name":"token","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"recoverNFT","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"}],"name":"recoverToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60a0604052600080546001600160a01b0319163317905534801561002257600080fd5b50604051610b47380380610b4783398101604081905261004191610052565b6001600160a01b0316608052610082565b60006020828403121561006457600080fd5b81516001600160a01b038116811461007b57600080fd5b9392505050565b608051610aa36100a4600039600081816101db01526105ec0152610aa36000f3fe6080604052600436106100965760003560e01c80638da5cb5b11610069578063b524abcf1161004e578063b524abcf1461019c578063ecb16c95146101c9578063f2fde38b146101fd57600080fd5b80638da5cb5b146101305780639be65a601461017c57600080fd5b80633319a00d1461009b5780633ccfd60b146100bd57806364cd28e9146100d2578063714b37691461011d575b600080fd5b3480156100a757600080fd5b506100bb6100b63660046108db565b61021d565b005b3480156100c957600080fd5b506100bb6102fe565b3480156100de57600080fd5b5061010a6100ed366004610907565b600260209081526000928352604080842090915290825290205481565b6040519081526020015b60405180910390f35b6100bb61012b366004610945565b610382565b34801561013c57600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610114565b34801561018857600080fd5b506100bb6101973660046109cb565b6106a1565b3480156101a857600080fd5b5061010a6101b73660046109ef565b60016020526000908152604090205481565b3480156101d557600080fd5b506101577f000000000000000000000000000000000000000000000000000000000000000081565b34801561020957600080fd5b506100bb6102183660046109cb565b61081e565b60005473ffffffffffffffffffffffffffffffffffffffff16331461026e576040517f5cd8319200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f23b872dd0000000000000000000000000000000000000000000000000000000081523060048201523360248201526044810182905273ffffffffffffffffffffffffffffffffffffffff8316906323b872dd90606401600060405180830381600087803b1580156102e257600080fd5b505af11580156102f6573d6000803e3d6000fd5b505050505050565b60005473ffffffffffffffffffffffffffffffffffffffff16331461034f576040517f5cd8319200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040514790339082156108fc029083906000818181858888f1935050505015801561037e573d6000803e3d6000fd5b5050565b3332146103bb576040517f9453980400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000805b838110156105b057368585838181106103da576103da610a08565b905060e00201905060008160405160200161043e9190600060e082019050823582526020830135602083015260408301356040830152606083013560608301526080830135608083015260a083013560a083015260c083013560c083015292915050565b6040516020818303038152906040528051906020012090508160a00135600160008381526020019081526020016000206000815460010191905081905511156104b3576040517f800113cb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81354210806104c55750428260200135105b156104fc576040517f80cb55e200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600081815260026020908152604080832033845290915290208054600101908190556080830135101561055b576040517f97922f9800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b841561056f57816040013584019350610579565b8160600135840193505b604051819033907f86bdc2f48d78757371009492a8c940c24219d5fce24c0e4d2e331f4266b594e190600090a350506001016103bf565b508115610662576040517f79cc6790000000000000000000000000000000000000000000000000000000008152336004820152602481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906379cc679090604401600060405180830381600087803b15801561064557600080fd5b505af1158015610659573d6000803e3d6000fd5b5050505061069b565b80341461069b576040517f1101129400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505050565b60005473ffffffffffffffffffffffffffffffffffffffff1633146106f2576040517f5cd8319200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff82169063a9059cbb90339083906370a0823190602401602060405180830381865afa158015610766573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061078a9190610a37565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff909216600483015260248201526044016020604051808303816000875af11580156107fa573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061037e9190610a50565b60005473ffffffffffffffffffffffffffffffffffffffff16331461086f576040517f5cd8319200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b73ffffffffffffffffffffffffffffffffffffffff811681146108d857600080fd5b50565b600080604083850312156108ee57600080fd5b82356108f9816108b6565b946020939093013593505050565b6000806040838503121561091a57600080fd5b82359150602083013561092c816108b6565b809150509250929050565b80151581146108d857600080fd5b60008060006040848603121561095a57600080fd5b833567ffffffffffffffff8082111561097257600080fd5b818601915086601f83011261098657600080fd5b81358181111561099557600080fd5b87602060e0830285010111156109aa57600080fd5b602092830195509350508401356109c081610937565b809150509250925092565b6000602082840312156109dd57600080fd5b81356109e8816108b6565b9392505050565b600060208284031215610a0157600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060208284031215610a4957600080fd5b5051919050565b600060208284031215610a6257600080fd5b81516109e88161093756fea26469706673582212201b4dcf5c2f53b83d988d618f21cfee1bd17804c0d7ddefb33e79a7a290103bd564736f6c634300080d003300000000000000000000000051d7e3713dc5eb06974a93c1f755724fece53540
Deployed Bytecode
0x6080604052600436106100965760003560e01c80638da5cb5b11610069578063b524abcf1161004e578063b524abcf1461019c578063ecb16c95146101c9578063f2fde38b146101fd57600080fd5b80638da5cb5b146101305780639be65a601461017c57600080fd5b80633319a00d1461009b5780633ccfd60b146100bd57806364cd28e9146100d2578063714b37691461011d575b600080fd5b3480156100a757600080fd5b506100bb6100b63660046108db565b61021d565b005b3480156100c957600080fd5b506100bb6102fe565b3480156100de57600080fd5b5061010a6100ed366004610907565b600260209081526000928352604080842090915290825290205481565b6040519081526020015b60405180910390f35b6100bb61012b366004610945565b610382565b34801561013c57600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610114565b34801561018857600080fd5b506100bb6101973660046109cb565b6106a1565b3480156101a857600080fd5b5061010a6101b73660046109ef565b60016020526000908152604090205481565b3480156101d557600080fd5b506101577f00000000000000000000000051d7e3713dc5eb06974a93c1f755724fece5354081565b34801561020957600080fd5b506100bb6102183660046109cb565b61081e565b60005473ffffffffffffffffffffffffffffffffffffffff16331461026e576040517f5cd8319200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f23b872dd0000000000000000000000000000000000000000000000000000000081523060048201523360248201526044810182905273ffffffffffffffffffffffffffffffffffffffff8316906323b872dd90606401600060405180830381600087803b1580156102e257600080fd5b505af11580156102f6573d6000803e3d6000fd5b505050505050565b60005473ffffffffffffffffffffffffffffffffffffffff16331461034f576040517f5cd8319200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040514790339082156108fc029083906000818181858888f1935050505015801561037e573d6000803e3d6000fd5b5050565b3332146103bb576040517f9453980400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000805b838110156105b057368585838181106103da576103da610a08565b905060e00201905060008160405160200161043e9190600060e082019050823582526020830135602083015260408301356040830152606083013560608301526080830135608083015260a083013560a083015260c083013560c083015292915050565b6040516020818303038152906040528051906020012090508160a00135600160008381526020019081526020016000206000815460010191905081905511156104b3576040517f800113cb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81354210806104c55750428260200135105b156104fc576040517f80cb55e200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600081815260026020908152604080832033845290915290208054600101908190556080830135101561055b576040517f97922f9800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b841561056f57816040013584019350610579565b8160600135840193505b604051819033907f86bdc2f48d78757371009492a8c940c24219d5fce24c0e4d2e331f4266b594e190600090a350506001016103bf565b508115610662576040517f79cc6790000000000000000000000000000000000000000000000000000000008152336004820152602481018290527f00000000000000000000000051d7e3713dc5eb06974a93c1f755724fece5354073ffffffffffffffffffffffffffffffffffffffff16906379cc679090604401600060405180830381600087803b15801561064557600080fd5b505af1158015610659573d6000803e3d6000fd5b5050505061069b565b80341461069b576040517f1101129400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505050565b60005473ffffffffffffffffffffffffffffffffffffffff1633146106f2576040517f5cd8319200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff82169063a9059cbb90339083906370a0823190602401602060405180830381865afa158015610766573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061078a9190610a37565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff909216600483015260248201526044016020604051808303816000875af11580156107fa573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061037e9190610a50565b60005473ffffffffffffffffffffffffffffffffffffffff16331461086f576040517f5cd8319200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b73ffffffffffffffffffffffffffffffffffffffff811681146108d857600080fd5b50565b600080604083850312156108ee57600080fd5b82356108f9816108b6565b946020939093013593505050565b6000806040838503121561091a57600080fd5b82359150602083013561092c816108b6565b809150509250929050565b80151581146108d857600080fd5b60008060006040848603121561095a57600080fd5b833567ffffffffffffffff8082111561097257600080fd5b818601915086601f83011261098657600080fd5b81358181111561099557600080fd5b87602060e0830285010111156109aa57600080fd5b602092830195509350508401356109c081610937565b809150509250925092565b6000602082840312156109dd57600080fd5b81356109e8816108b6565b9392505050565b600060208284031215610a0157600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060208284031215610a4957600080fd5b5051919050565b600060208284031215610a6257600080fd5b81516109e88161093756fea26469706673582212201b4dcf5c2f53b83d988d618f21cfee1bd17804c0d7ddefb33e79a7a290103bd564736f6c634300080d0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000051d7e3713dc5eb06974a93c1f755724fece53540
-----Decoded View---------------
Arg [0] : token (address): 0x51D7e3713Dc5eB06974A93C1F755724fece53540
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 00000000000000000000000051d7e3713dc5eb06974a93c1f755724fece53540
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.