Skip to content

Instantly share code, notes, and snippets.

@mwaqasaslam
Created December 21, 2022 14:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mwaqasaslam/d5f957dc5d960d38f080182736c629cd to your computer and use it in GitHub Desktop.
Save mwaqasaslam/d5f957dc5d960d38f080182736c629cd to your computer and use it in GitHub Desktop.
Created using remix-ide: Realtime Ethereum Contract Compiler and Runtime. Load this file by pasting this gists URL or ID at https://remix.ethereum.org/#version=soljson-v0.8.17+commit.8df45f5f.js&optimize=false&runs=200&gist=
REMIX DEFAULT WORKSPACE
Remix default workspace is present when:
i. Remix loads for the very first time
ii. A new workspace is created with 'Default' template
iii. There are no files existing in the File Explorer
This workspace contains 3 directories:
1. 'contracts': Holds three contracts with increasing levels of complexity.
2. 'scripts': Contains four typescript files to deploy a contract. It is explained below.
3. 'tests': Contains one Solidity test file for 'Ballot' contract & one JS test file for 'Storage' contract.
SCRIPTS
The 'scripts' folder has four typescript files which help to deploy the 'Storage' contract using 'web3.js' and 'ethers.js' libraries.
For the deployment of any other contract, just update the contract's name from 'Storage' to the desired contract and provide constructor arguments accordingly
in the file `deploy_with_ethers.ts` or `deploy_with_web3.ts`
In the 'tests' folder there is a script containing Mocha-Chai unit tests for 'Storage' contract.
To run a script, right click on file name in the file explorer and click 'Run'. Remember, Solidity file must already be compiled.
Output from script will appear in remix terminal.
Please note, require/import is supported in a limited manner for Remix supported modules.
For now, modules supported by Remix are ethers, web3, swarmgw, chai, multihashes, remix and hardhat only for hardhat.ethers object/plugin.
For unsupported modules, an error like this will be thrown: '<module_name> module require is not supported by Remix IDE' will be shown.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
import "@openzeppelin/contracts/token/ERC1155/extensions/ERC1155URIStorage.sol";
import "@openzeppelin/contracts/token/ERC1155/extensions/ERC1155Supply.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";
import "@openzeppelin/contracts/security/Pausable.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
/**
* @dev Implementation of the multi-token standard for Babylon Club House collections.
* Originally based on code by Enjin: https://github.com/enjin/erc-1155
*/
contract BCHERC1155 is ERC1155, ERC1155URIStorage, ERC1155Supply, Ownable, Pausable, ReentrancyGuard{
mapping(uint256 => address) public creators;
string[] public tracks;
string public symbol;
string public name;
struct Utils {
string title;
string desc;
string utilities;
string serialNumber;
string salesContractLink;
}
mapping (uint256 => Utils) private utils;
/**
* @dev sets `_name` , `_symbol`, `_tracks` as the for the contract construction.
*/
constructor(string memory _name, string memory _symbol, string[] memory _tracks) ERC1155("") {
name = _name;
symbol = _symbol;
tracks = _tracks;
}
/**
* @dev modifier for setting tokenCreators w.r.t to tokenId.
*/
modifier onlyTokenCreator(uint256 tokenId) {
require(creators[tokenId] == _msgSender(), "must be the creator of the token");
_;
}
/**
* @dev modifier for setting tokenOwners w.r.t to tokenId.
*/
modifier onlyTokenOwner (uint256 tokenId) {
require(balanceOf(_msgSender(), tokenId) > 0, "must be the owner of the token");
_;
}
/**
* @dev get all sound tracks.
*/
function getTracks() public view returns (string[] memory) {
return tracks;
}
/**
* @dev Internal function to set the tokenCreator.
*/
function _setTokenCreator(address account, uint256 tokenId) internal {
creators[tokenId] = account;
}
/**
* @dev get tokenCreator for the tokenId.
*/
function getTokenCreator(uint256 tokenId) public view returns(address) {
return creators[tokenId];
}
/**
* @dev Internal function to set the nft utilities.
*/
function _setUtils(uint256 tokenId, string memory _title, string memory _desc, string memory _utilities, string memory _serialNumber, string memory _salesContractLink) internal {
utils[tokenId] = Utils({
title : _title,
desc : _desc,
utilities : _utilities,
serialNumber : _serialNumber,
salesContractLink : _salesContractLink
});
}
/**
* @dev get utilities providing with the tokenId.
*/
function getUtils(uint256 tokenId) public view returns(string memory, string memory, string memory, string memory){
return (utils[tokenId].title, utils[tokenId].desc, utils[tokenId].utilities, utils[tokenId].salesContractLink);
}
/**
* @dev Sets `baseURI` as the `_baseURI` for all tokens
*/
function setBaseURI(string memory baseURI) external onlyOwner {
_setBaseURI(baseURI);
}
/**
* @dev View the uri providing tokenId.
*/
function uri(uint256 tokenId) public view virtual override (ERC1155, ERC1155URIStorage) returns (string memory) {
return super.uri(tokenId);
}
/**
* @dev Admin level function to pause the functionality of the contract.
*/
function pause() public onlyOwner {
_pause();
}
/**
* @dev Admin level function to unpause the functionality of the contract.
*/
function unpause() public onlyOwner {
_unpause();
}
/**
* @dev Mint the tokens with utils (NFTs) providing with tokenId, total edition for the token and their respective tokenUri.
*/
function mintWithUtils(address to, uint256 tokenId, uint256 edition, string memory tokenUri, string memory title,
string memory desc, string memory utilities, string memory serialNumber, string memory salesContractLink) external{
_mint(to, tokenId, edition, "0x00");
_setURI(tokenId, tokenUri);
_setUtils(tokenId, title, desc, utilities, serialNumber, salesContractLink);
_setTokenCreator(to, tokenId);
}
/**
* @dev MintBatch the tokens with utils (NFTs) providing with tokenIds, total editions for the tokens and their respective tokenUris.
*/
function mintBatchWithUtils(address to, uint256[] memory tokenIds, uint256[] memory editions, string[] memory tokenUris,
string[] memory titles, string[] memory descs, string[] memory utilities, string[] memory serialNumber, string[] memory salesContractLinks) external {
require(tokenIds.length == tokenUris.length, "ERC1155: ids and uris length mismatch");
for (uint256 i = 0; i < tokenIds.length;) {
_setURI(tokenIds[i], tokenUris[i]);
_setUtils(tokenIds[i], titles[i], descs[i], utilities[i], serialNumber[i], salesContractLinks[i]);
unchecked {
i++;
}
}
_mintBatch(to, tokenIds, editions, "0x00");
}
/**
* @dev Mint the tokens (NFTs) providing with tokenId, total edition for the token and their respective tokenUri.
*/
function mint(address to, uint256 tokenId, uint256 edition, string memory tokenUri) external {
_mint(to, tokenId, edition, "0x00");
_setURI(tokenId, tokenUri);
_setTokenCreator(to, tokenId);
}
/**
* @dev MintBatch the tokens (NFTs) providing with tokenIds, total editions for the tokens and their respective tokenUris.
*/
function mintBatch(address to, uint256[] memory tokenIds, uint256[] memory editions, string[] memory tokenUris) external{
require(tokenIds.length == tokenUris.length, "ERC1155: ids and uris length mismatch");
for (uint256 i = 0; i < tokenIds.length;) {
_setURI(tokenIds[i], tokenUris[i]);
unchecked {
i++;
}
}
_mintBatch(to, tokenIds, editions, "0x00");
}
/**
* @dev Update the token uri providing newUri for the existing token. Only tokenOwner can change the uri.
*/
function updateURI(uint256 tokenId, string memory newUri) external onlyTokenOwner(tokenId) returns (bool){
_setURI(tokenId, newUri);
return true;
}
/**
* Fetch supply for multiple tokens
*/
function totalSupplyBatch(uint256[] memory tokenIds) public view returns (uint256[] memory){
uint256[] memory batchSupply = new uint256[](tokenIds.length);
for (uint256 i = 0; i < tokenIds.length; i++) {
batchSupply[i] = totalSupply(tokenIds[i]);
}
return batchSupply;
}
/**
* @dev Destroy the token if token owner wants to burn the NFT.
*/
function burn(uint256 tokenId, uint256 edition) external onlyTokenOwner(tokenId) {
_burn(_msgSender(), tokenId, edition);
}
/**
* @dev Support interface.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC1155) returns (bool) {
return super.supportsInterface(interfaceId);
}
/**
* @dev Internal hook to manage the minting , burning and transfer of the NFT functionality.
*/
function _beforeTokenTransfer(address operator, address from, address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data)
internal
whenNotPaused
nonReentrant
override(ERC1155, ERC1155Supply)
{
super._beforeTokenTransfer(operator, from, to, ids, amounts, data);
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.11;
import "./IRoyalty.sol";
import "./IERC2981.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/security/Pausable.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "./CurrencyTransferLib.sol";
import "./IPrimarySale.sol";
contract BCHERC721 is ERC721, ERC721Enumerable, ERC721URIStorage, ERC721Burnable, Pausable, Ownable, IRoyalty, ReentrancyGuard {
mapping(uint256 => address) private creator;
string[] public tracks;
uint256 private constant MAX_BPS = 10_000;
address private royaltyRecipient;
uint128 private royaltyBps;
mapping(uint256 => RoyaltyInfo) private royaltyInfoForToken;
event TokenURIUpdated(uint256 indexed _tokenId, string _uri);
struct Utils {
string title;
string desc;
string utilities;
string serialNumber;
string salesContractLink;
}
mapping (uint256 => Utils) private utils;
constructor(string memory _name, string memory _symbol, string[] memory _tracks) ERC721(_name, _symbol){
tracks = _tracks;
}
modifier onlyERC721Owner(uint256 _tokenId){
address owner = ownerOf(_tokenId);
require(owner == _msgSender(), "ERC721:Must be the owner of the token");
_;
}
function pause() public onlyOwner {
_pause();
}
function unpause() public onlyOwner {
_unpause();
}
function _setUtils(uint256 tokenId, string memory _title, string memory _desc, string memory _utilities, string memory _serialNumber, string memory _salesContractLink) internal {
utils[tokenId] = Utils({
title : _title,
desc : _desc,
serialNumber : _serialNumber,
utilities : _utilities,
salesContractLink : _salesContractLink
});
}
function getTracks() public view returns (string[] memory) {
return tracks;
}
function getUtils(uint256 tokenId) public view returns(string memory, string memory, string memory, string memory, string memory){
return (utils[tokenId].title, utils[tokenId].desc, utils[tokenId].utilities, utils[tokenId].serialNumber, utils[tokenId].salesContractLink);
}
function mintWithUtils(uint256 tokenId, string memory tokenUri, string memory title,
string memory desc, string memory utilities, string memory serialNumber, string memory salesContractLink) public {
_safeMint(_msgSender(), tokenId);
_setTokenURI(tokenId, tokenUri);
_setUtils(tokenId, title, desc, utilities, serialNumber, salesContractLink);
_setCreator(tokenId, _msgSender());
}
function mint(uint256 tokenId, string memory uri) public {
_safeMint(_msgSender(), tokenId);
_setTokenURI(tokenId, uri);
_setCreator(tokenId, _msgSender());
setRoyaltyInfoForToken(tokenId, _msgSender(), 2400);
}
function _setCreator(uint256 _tokenId, address _creator) internal{
creator[_tokenId] = _creator;
}
function getCreator(uint256 _tokenId) public view returns (address){
return creator[_tokenId];
}
function updateMetadata(uint256 _tokenId, string memory _newUri) public onlyERC721Owner(_tokenId){
_setTokenURI(_tokenId, _newUri);
emit TokenURIUpdated(_tokenId, _newUri);
}
function _beforeTokenTransfer(address from, address to, uint256 tokenId)
internal
whenNotPaused
nonReentrant
override(ERC721, ERC721Enumerable)
{
super._beforeTokenTransfer(from, to, tokenId);
}
function _burn(uint256 tokenId) internal override(ERC721, ERC721URIStorage) {
super._burn(tokenId);
}
function tokenURI(uint256 tokenId)
public
view
override(ERC721, ERC721URIStorage)
returns (string memory)
{
return super.tokenURI(tokenId);
}
// function supportsInterface(bytes4 interfaceId)
// public
// view
// override(ERC721, ERC721Enumerable)
// returns (bool)
// {
// return super.supportsInterface(interfaceId);
// }
function supportsInterface(bytes4 interfaceId)
public
view
virtual
override(ERC721, ERC721Enumerable, IERC165)
returns (bool)
{
return super.supportsInterface(interfaceId) || interfaceId == type(IERC2981).interfaceId;
}
function royaltyInfo(uint256 tokenId, uint256 salePrice)
external
view
virtual
returns (address receiver, uint256 royaltyAmount)
{
(address recipient, uint256 bps) = getRoyaltyInfoForToken(tokenId);
receiver = recipient;
royaltyAmount = (salePrice * bps) / MAX_BPS;
}
function setDefaultRoyaltyInfo(address _royaltyRecipient, uint256 _royaltyBps)
external
// onlyRole(DEFAULT_ADMIN_ROLE)
{
require(_royaltyBps <= MAX_BPS, "exceed royalty bps");
royaltyRecipient = _royaltyRecipient;
royaltyBps = uint128(_royaltyBps);
emit DefaultRoyalty(_royaltyRecipient, _royaltyBps);
}
/// @dev Lets a module admin set the royalty recipient for a particular token Id.
function setRoyaltyInfoForToken(
uint256 _tokenId,
address _recipient,
uint256 _bps
) public override
// onlyRole(DEFAULT_ADMIN_ROLE)
{
require(_bps <= MAX_BPS, "exceed royalty bps");
royaltyInfoForToken[_tokenId] = RoyaltyInfo({ recipient: _recipient, bps: _bps });
emit RoyaltyForToken(_tokenId, _recipient, _bps);
}
/// @dev Returns the platform fee bps and recipient.
function getDefaultRoyaltyInfo() external view returns (address, uint16) {
return (royaltyRecipient, uint16(royaltyBps));
}
/// @dev Returns the royalty recipient for a particular token Id.
function getRoyaltyInfoForToken(uint256 _tokenId) public view returns (address, uint16) {
RoyaltyInfo memory royaltyForToken = royaltyInfoForToken[_tokenId];
return
royaltyForToken.recipient == address(0)
? (royaltyRecipient, uint16(royaltyBps))
: (royaltyForToken.recipient, uint16(royaltyForToken.bps));
}
}
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
// import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
library CurrencyTransferLib {
// using SafeERC20 for IERC20;
// /// @dev The address interpreted as native token of the chain.
// address public constant NATIVE_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
// /// @dev Transfers a given amount of currency.
// function transferCurrency(
// address _currency,
// // address _from,
// address _to,
// uint256 _amount
// ) internal {
// if (_amount == 0) {
// return;
// }
// if (_currency == NATIVE_TOKEN) {
// safeTransferNativeToken(_to, _amount);
// }
// }
/// @dev Transfers `amount` of native token to `to`.
function safeTransferNativeToken(address to, uint256 value) internal {
// solhint-disable avoid-low-level-calls
// slither-disable-next-line low-level-calls
(bool success, ) = to.call{ value: value }("");
// (bool success,) = to.call{value: msg.value}("");
require(success, "native token transfer failed");
}
}
mintBatchWithUtils
-- userAddress
-- [4,5] ---tokenIDs
-- [40,50] ---- editions
-- ["https://ipfs/test/4/","https://ipfs/test/5/"] ------toeknUris
-- ["NFT-test4","NFT-test5"]-----------titiles
-- ["Test4 NFT is avatar","Test5 NFT is meta"]--------descriptions
-- ["Well kept","Percentage 10"]-----------utililities
-- ["https://salesTest4/","https://salesTest5/"]------------salesContractLinks
erc721 ----> mintSingle (no batch)
erc1155 ----> mintSingle, mintBatch
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.11;
// Interface
// import { ITokenERC721 } from "../interfaces/token/ITokenERC721.sol";
// import "../interfaces/IThirdwebContract.sol";
// import "../extension/interface/IPlatformFee.sol";
import "./IPrimarySale.sol";
import "./IRoyalty.sol";
// import "../extension/interface/IOwnable.sol";
// Token
import "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721EnumerableUpgradeable.sol";
// Signature utils
// import "@openzeppelin/contracts-upgradeable/utils/cryptography/ECDSAUpgradeable.sol";
// import "@openzeppelin/contracts-upgradeable/utils/cryptography/draft-EIP712Upgradeable.sol";
// Access Control + security
import "@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol";
// Meta transactions
// import "../openzeppelin-presets/metatx/ERC2771ContextUpgradeable.sol";
// Utils
import "@openzeppelin/contracts-upgradeable/utils/StringsUpgradeable.sol";
// import "@openzeppelin/contracts-upgradeable/utils/MulticallUpgradeable.sol";
import "./CurrencyTransferLib.sol";
// import "../lib/FeeType.sol";
// Helper interfaces
import "@openzeppelin/contracts-upgradeable/interfaces/IERC2981Upgradeable.sol";
contract TokenERC721 is
Initializable,
// IThirdwebContract,
// IOwnable,
IRoyalty,
IPrimarySale,
// IPlatformFee,
ReentrancyGuardUpgradeable,
// EIP712Upgradeable,
// ERC2771ContextUpgradeable,
// MulticallUpgradeable,
AccessControlEnumerableUpgradeable,
ERC721EnumerableUpgradeable
// ITokenERC721
{
// using ECDSAUpgradeable for bytes32;
using StringsUpgradeable for uint256;
bytes32 private constant MODULE_TYPE = bytes32("TokenERC721");
uint256 private constant VERSION = 1;
// bytes32 private constant TYPEHASH =
// keccak256(
// "MintRequest(address to,address royaltyRecipient,uint256 royaltyBps,address primarySaleRecipient,string uri,uint256 price,address currency,uint128 validityStartTimestamp,uint128 validityEndTimestamp,bytes32 uid)"
// );
/// @dev Only TRANSFER_ROLE holders can have tokens transferred from or to them, during restricted transfers.
// bytes32 private constant TRANSFER_ROLE = keccak256("TRANSFER_ROLE");
/// @dev Only MINTER_ROLE holders can sign off on `MintRequest`s.
// bytes32 private constant MINTER_ROLE = keccak256("MINTER_ROLE");
/// @dev Max bps in the thirdweb system
uint256 private constant MAX_BPS = 10_000;
/// @dev Owner of the contract (purpose: OpenSea compatibility, etc.)
address private _owner;
/// @dev The token ID of the next token to mint.
uint256 public nextTokenIdToMint;
/// @dev The adress that receives all primary sales value.
address public primarySaleRecipient;
/// @dev The adress that receives all primary sales value.
address public platformFeeRecipient;
/// @dev The recipient of who gets the royalty.
address private royaltyRecipient;
/// @dev The percentage of royalty how much royalty in basis points.
uint128 private royaltyBps;
/// @dev The % of primary sales collected by the contract as fees.
uint128 private platformFeeBps;
/// @dev Contract level metadata.
string public contractURI;
/// @dev Mapping from mint request UID => whether the mint request is processed.
mapping(bytes32 => bool) private minted;
/// @dev Mapping from tokenId => URI
mapping(uint256 => string) private uri;
/// @dev Token ID => royalty recipient and bps for token
mapping(uint256 => RoyaltyInfo) private royaltyInfoForToken;
// constructor() initializer {}
/// @dev Initiliazes the contract, like a constructor.
function initialize(
// address _defaultAdmin,
string memory _name,
string memory _symbol
// string memory _contractURI,
// address[] memory _trustedForwarders,
// address _saleRecipient,
// address _royaltyRecipient,
// uint128 _royaltyBps
// uint128 _platformFeeBps,
// address _platformFeeRecipient
) external initializer {
// Initialize inherited contracts, most base-like -> most derived.
__ReentrancyGuard_init();
// __EIP712_init("TokenERC721", "1");
// __ERC2771Context_init(_trustedForwarders);
__ERC721_init(_name, _symbol);
// Initialize this contract's state.
// royaltyRecipient = _royaltyRecipient;
// royaltyBps = _royaltyBps;
// platformFeeRecipient = _platformFeeRecipient;
// primarySaleRecipient = _saleRecipient;
// contractURI = _contractURI;
// require(_platformFeeBps <= MAX_BPS, "exceeds MAX_BPS");
// platformFeeBps = _platformFeeBps;
// _owner = _defaultAdmin;
// _setupRole(DEFAULT_ADMIN_ROLE, _defaultAdmin);
// _setupRole(MINTER_ROLE, _defaultAdmin);
// _setupRole(TRANSFER_ROLE, _defaultAdmin);
// _setupRole(TRANSFER_ROLE, address(0));
}
/// ===== Public functions =====
/// @dev Returns the module type of the contract.
function contractType() external pure returns (bytes32) {
return MODULE_TYPE;
}
/// @dev Returns the version of the contract.
function contractVersion() external pure returns (uint8) {
return uint8(VERSION);
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view returns (address) {
return hasRole(DEFAULT_ADMIN_ROLE, _owner) ? _owner : address(0);
}
// /// @dev Verifies that a mint request is signed by an account holding MINTER_ROLE (at the time of the function call).
// function verify(MintRequest calldata _req, bytes calldata _signature) public view returns (bool, address) {
// address signer = recoverAddress(_req, _signature);
// return (!minted[_req.uid] && hasRole(MINTER_ROLE, signer), signer);
// }
/// @dev Returns the URI for a tokenId
function tokenURI(uint256 _tokenId) public view override returns (string memory) {
return uri[_tokenId];
}
/// @dev Lets an account with MINTER_ROLE mint an NFT.
function mintTo(address _to, string calldata _uri) external
// onlyRole(MINTER_ROLE)
returns (uint256) {
// `_mintTo` is re-used. `mintTo` just adds a minter role check.
return _mintTo(_to, _uri);
}
/// ===== External functions =====
/// @dev See EIP-2981
function royaltyInfo(uint256 tokenId, uint256 salePrice)
external
view
virtual
returns (address receiver, uint256 royaltyAmount)
{
(address recipient, uint256 bps) = getRoyaltyInfoForToken(tokenId);
receiver = recipient;
royaltyAmount = (salePrice * bps) / MAX_BPS;
}
// /// @dev Mints an NFT according to the provided mint request.
// function mintWithSignature(MintRequest calldata _req, bytes calldata _signature)
// external
// payable
// nonReentrant
// returns (uint256 tokenIdMinted)
// {
// address signer = verifyRequest(_req, _signature);
// address receiver = _req.to;
// tokenIdMinted = _mintTo(receiver, _req.uri);
// if (_req.royaltyRecipient != address(0)) {
// royaltyInfoForToken[tokenIdMinted] = RoyaltyInfo({
// recipient: _req.royaltyRecipient,
// bps: _req.royaltyBps
// });
// }
// collectPrice(_req);
// emit TokensMintedWithSignature(signer, receiver, tokenIdMinted, _req);
// }
// ===== Setter functions =====
/// @dev Lets a module admin set the default recipient of all primary sales.
function setPrimarySaleRecipient(address _saleRecipient) external
// onlyRole(DEFAULT_ADMIN_ROLE)
{
primarySaleRecipient = _saleRecipient;
emit PrimarySaleRecipientUpdated(_saleRecipient);
}
/// @dev Lets a module admin update the royalty bps and recipient.
function setDefaultRoyaltyInfo(address _royaltyRecipient, uint256 _royaltyBps)
external
// onlyRole(DEFAULT_ADMIN_ROLE)
{
require(_royaltyBps <= MAX_BPS, "exceed royalty bps");
royaltyRecipient = _royaltyRecipient;
royaltyBps = uint128(_royaltyBps);
emit DefaultRoyalty(_royaltyRecipient, _royaltyBps);
}
/// @dev Lets a module admin set the royalty recipient for a particular token Id.
function setRoyaltyInfoForToken(
uint256 _tokenId,
address _recipient,
uint256 _bps
) external
// onlyRole(DEFAULT_ADMIN_ROLE)
{
require(_bps <= MAX_BPS, "exceed royalty bps");
royaltyInfoForToken[_tokenId] = RoyaltyInfo({ recipient: _recipient, bps: _bps });
emit RoyaltyForToken(_tokenId, _recipient, _bps);
}
/// @dev Lets a module admin update the fees on primary sales.
function setPlatformFeeInfo(address _platformFeeRecipient, uint256 _platformFeeBps)
external
// onlyRole(DEFAULT_ADMIN_ROLE)
{
require(_platformFeeBps <= MAX_BPS, "exceeds MAX_BPS");
platformFeeBps = uint64(_platformFeeBps);
platformFeeRecipient = _platformFeeRecipient;
// emit PlatformFeeInfoUpdated(_platformFeeRecipient, _platformFeeBps);
}
// /// @dev Lets a module admin set a new owner for the contract. The new owner must be a module admin.
// function setOwner(address _newOwner) external onlyRole(DEFAULT_ADMIN_ROLE) {
// require(hasRole(DEFAULT_ADMIN_ROLE, _newOwner), "new owner not module admin.");
// // address _prevOwner = _owner;
// _owner = _newOwner;
// // emit OwnerUpdated(_prevOwner, _newOwner);
// }
/// @dev Lets a module admin set the URI for contract-level metadata.
function setContractURI(string calldata _uri) external onlyRole(DEFAULT_ADMIN_ROLE) {
contractURI = _uri;
}
/// ===== Getter functions =====
/// @dev Returns the platform fee bps and recipient.
function getPlatformFeeInfo() external view returns (address, uint16) {
return (platformFeeRecipient, uint16(platformFeeBps));
}
/// @dev Returns the platform fee bps and recipient.
function getDefaultRoyaltyInfo() external view returns (address, uint16) {
return (royaltyRecipient, uint16(royaltyBps));
}
/// @dev Returns the royalty recipient for a particular token Id.
function getRoyaltyInfoForToken(uint256 _tokenId) public view returns (address, uint16) {
RoyaltyInfo memory royaltyForToken = royaltyInfoForToken[_tokenId];
return
royaltyForToken.recipient == address(0)
? (royaltyRecipient, uint16(royaltyBps))
: (royaltyForToken.recipient, uint16(royaltyForToken.bps));
}
/// ===== Internal functions =====
/// @dev Mints an NFT to `to`
function _mintTo(address _to, string calldata _uri) internal returns (uint256 tokenIdToMint) {
tokenIdToMint = nextTokenIdToMint;
nextTokenIdToMint += 1;
require(bytes(_uri).length > 0, "empty uri.");
uri[tokenIdToMint] = _uri;
_safeMint(_to, tokenIdToMint);
// emit TokensMinted(_to, tokenIdToMint, _uri);
}
// /// @dev Returns the address of the signer of the mint request.
// function recoverAddress(MintRequest calldata _req, bytes calldata _signature) private view returns (address) {
// return _hashTypedDataV4(keccak256(_encodeRequest(_req))).recover(_signature);
// }
// /// @dev Resolves 'stack too deep' error in `recoverAddress`.
// function _encodeRequest(MintRequest calldata _req) private pure returns (bytes memory) {
// return
// abi.encode(
// TYPEHASH,
// _req.to,
// _req.royaltyRecipient,
// _req.royaltyBps,
// _req.primarySaleRecipient,
// keccak256(bytes(_req.uri)),
// _req.price,
// _req.currency,
// _req.validityStartTimestamp,
// _req.validityEndTimestamp,
// _req.uid
// );
// }
/// @dev Verifies that a mint request is valid.
// function verifyRequest(MintRequest calldata _req, bytes calldata _signature) internal returns (address) {
// (bool success, address signer) = verify(_req, _signature);
// require(success, "invalid signature");
// require(
// _req.validityStartTimestamp <= block.timestamp && _req.validityEndTimestamp >= block.timestamp,
// "request expired"
// );
// require(_req.to != address(0), "recipient undefined");
// minted[_req.uid] = true;
// return signer;
// }
// /// @dev Collects and distributes the primary sale value of tokens being claimed.
// function collectPrice(MintRequest calldata _req) internal {
// if (_req.price == 0) {
// return;
// }
// uint256 totalPrice = _req.price;
// uint256 platformFees = (totalPrice * platformFeeBps) / MAX_BPS;
// if (_req.currency == CurrencyTransferLib.NATIVE_TOKEN) {
// require(msg.value == totalPrice, "must send total price.");
// } else {
// require(msg.value == 0, "msg value not zero");
// }
// address saleRecipient = _req.primarySaleRecipient == address(0)
// ? primarySaleRecipient
// : _req.primarySaleRecipient;
// CurrencyTransferLib.transferCurrency(_req.currency, _msgSender(), platformFeeRecipient, platformFees);
// CurrencyTransferLib.transferCurrency(_req.currency, _msgSender(), saleRecipient, totalPrice - platformFees);
// }
/// ===== Low-level overrides =====
/// @dev Burns `tokenId`. See {ERC721-_burn}.
function burn(uint256 tokenId) public virtual {
//solhint-disable-next-line max-line-length
require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721Burnable: caller is not owner nor approved");
_burn(tokenId);
}
// /// @dev See {ERC721-_beforeTokenTransfer}.
// function _beforeTokenTransfer(
// address from,
// address to,
// uint256 tokenId
// ) internal (ERC721EnumerableUpgradeable) {
// super._beforeTokenTransfer(from, to, tokenId);
// // if transfer is restricted on the contract, we still want to allow burning and minting
// if (!hasRole(TRANSFER_ROLE, address(0)) && from != address(0) && to != address(0)) {
// require(hasRole(TRANSFER_ROLE, from) || hasRole(TRANSFER_ROLE, to), "restricted to TRANSFER_ROLE holders");
// }
// }
function supportsInterface(bytes4 interfaceId)
public
view
virtual
override(ERC721EnumerableUpgradeable, AccessControlEnumerableUpgradeable, IERC165)
returns (bool)
{
return super.supportsInterface(interfaceId) || interfaceId == type(IERC2981Upgradeable).interfaceId;
}
// function _msgSender()
// internal
// view
// virtual
// override(ContextUpgradeable, ERC2771ContextUpgradeable)
// returns (address sender)
// {
// return ERC2771ContextUpgradeable._msgSender();
// }
// function _msgData()
// internal
// view
// virtual
// override(ContextUpgradeable, ERC2771ContextUpgradeable)
// returns (bytes calldata)
// {
// return ERC2771ContextUpgradeable._msgData();
// }
}
// 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
* [EIP](https://eips.ethereum.org/EIPS/eip-165).
*
* 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
* [EIP section](https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified)
* 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: Apache 2.0
pragma solidity ^0.8.0;
// import "./IERC165.sol";
import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
/**
* @dev Interface for the NFT Royalty Standard.
*
* A standardized way to retrieve royalty payment information for non-fungible tokens (NFTs) to enable universal
* support for royalty payments across all NFT marketplaces and ecosystem participants.
*
* _Available since v4.5._
*/
interface IERC2981 is IERC165 {
/**
* @dev Returns how much royalty is owed and to whom, based on a sale price that may be denominated in any unit of
* exchange. The royalty amount is denominated and should be payed in that same unit of exchange.
*/
function royaltyInfo(uint256 tokenId, uint256 salePrice)
external
view
returns (address receiver, uint256 royaltyAmount);
}
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
interface IPrimarySale {
function primarySaleRecipient() external view returns (address);
function setPrimarySaleRecipient(address _saleRecipient) external;
event PrimarySaleRecipientUpdated(address indexed recipient);
}
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.11;
import "./IPlatformFee.sol";
interface IMarketplace is IPlatformFee {
enum TokenType {
ERC1155,
ERC721
}
struct ListingParameters {
address assetContract;
uint256 tokenId;
uint256 quantityToList;
uint256 buyoutPricePerToken;
}
struct Listing {
uint256 listingId;
address tokenOwner;
address assetContract;
uint256 tokenId;
uint256 quantity;
uint256 buyoutPricePerToken;
TokenType tokenType;
}
function NETWORK_FEE() external pure returns (uint64);
function BCH_INTITIAL_FEE() external pure returns (uint64);
function BCH_FEE() external pure returns (uint64);
event ListingUpdated(uint256 indexed listingId, address indexed listingCreator);
event ListingRemoved(uint256 indexed listingId, address indexed listingCreator);
function createListing(ListingParameters memory _params, address _tokenOwner) external;
function updateListing(uint256 _listingId, uint256 _quantityToList, uint256 _buyoutPricePerToken) external;
function buy(uint256 _listingId, address _buyFor, uint256 _quantity, uint256 _totalPrice) external payable;
event ListingAdded(uint256 indexed listingId, address indexed assetContract, address indexed lister, Listing listing);
event NewSale(uint256 indexed listingId, address indexed assetContract, address indexed lister, address buyer, uint256 quantityBought, uint256 totalPricePaid);
}
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
/**
* Thirdweb's `PlatformFee` is a contract extension to be used with any base contract. It exposes functions for setting and reading
* the recipient of platform fee and the platform fee basis points, and lets the inheriting contract perform conditional logic
* that uses information about platform fees, if desired.
*/
interface IPlatformFee {
/// @dev Returns the platform fee bps and recipient.
function getPlatformFeeInfo() external view returns (address, uint16);
/// @dev Lets a module admin update the fees on primary sales.
function setPlatformFeeInfo(address _platformFeeRecipient, uint256 _platformFeeBps) external;
/// @dev Emitted when fee on primary sales is updated.
event PlatformFeeInfoUpdated(address indexed platformFeeRecipient, uint256 platformFeeBps);
}
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
interface IPrimarySale {
function primarySaleRecipient() external view returns (address);
function setPrimarySaleRecipient(address _saleRecipient) external;
event PrimarySaleRecipientUpdated(address indexed recipient);
}
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
import "./IERC2981.sol";
/**
* Thirdweb's `Royalty` is a contract extension to be used with any base contract. It exposes functions for setting and reading
* the recipient of royalty fee and the royalty fee basis points, and lets the inheriting contract perform conditional logic
* that uses information about royalty fees, if desired.
*
* The `Royalty` contract is ERC2981 compliant.
*/
interface IRoyalty is IERC2981 {
struct RoyaltyInfo {
address recipient;
uint256 bps;
}
/// @dev Returns the royalty recipient and fee bps.
function getDefaultRoyaltyInfo() external view returns (address, uint16);
/// @dev Lets a module admin update the royalty bps and recipient.
function setDefaultRoyaltyInfo(address _royaltyRecipient, uint256 _royaltyBps) external;
/// @dev Lets a module admin set the royalty recipient for a particular token Id.
function setRoyaltyInfoForToken(
uint256 tokenId,
address recipient,
uint256 bps
) external;
/// @dev Returns the royalty recipient for a particular token Id.
function getRoyaltyInfoForToken(uint256 tokenId) external view returns (address, uint16);
/// @dev Emitted when royalty info is updated.
event DefaultRoyalty(address indexed newRoyaltyRecipient, uint256 newRoyaltyBps);
/// @dev Emitted when royalty recipient for tokenId is set
event RoyaltyForToken(uint256 indexed tokenId, address indexed royaltyRecipient, uint256 royaltyBps);
}
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
interface IPrimarySale {
function primarySaleRecipient() external view returns (address);
function setPrimarySaleRecipient(address _saleRecipient) external;
event PrimarySaleRecipientUpdated(address indexed recipient);
}
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
interface IPrimarySale {
function primarySaleRecipient() external view returns (address);
function setPrimarySaleRecipient(address _saleRecipient) external;
event PrimarySaleRecipientUpdated(address indexed recipient);
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
contract market {
constructor (address _token) {
}
}
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.11;
// import "@openzeppelin/contracts-upgradeable/token/ERC1155/IERC1155Upgradeable.sol";
import "@openzeppelin/contracts/token/ERC1155/IERC1155.sol";
// import "@openzeppelin/contracts-upgradeable/token/ERC721/IERC721Upgradeable.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
// import "@openzeppelin/contracts-upgradeable/token/ERC1155/IERC1155ReceiverUpgradeable.sol";
import "@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol";
// import "@openzeppelin/contracts-upgradeable/token/ERC721/IERC721ReceiverUpgradeable.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
// import "@openzeppelin/contracts-upgradeable/utils/introspection/IERC165Upgradeable.sol";
// import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
// import "@openzeppelin/contracts-upgradeable/interfaces/IERC2981Upgradeable.sol";
// import "@openzeppelin/contracts/interfaces/IERC2981.sol";
// import "@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol";
import "@openzeppelin/contracts/access/AccessControlEnumerable.sol";
// import "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
// import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "./IMarketplace.sol";
import "./CurrencyTransferLib.sol";
import "./SaleType.sol";
import "./IRoyalty.sol";
contract Marketplace is
// Initializable,
Ownable,
IMarketplace,
IRoyalty,
ReentrancyGuard,
AccessControlEnumerable,
IERC721Receiver,
IERC1155Receiver
{
uint256 public totalListings;
address private platformFeeRecipient;
uint256 public saleType = 1;
/// @dev The max bps of the contract. So, 10_000 == 100 %
uint64 public constant MAX_BPS = 10_000;
uint64 public constant INITIAL_BCH_FEE_BPS = 25_00;
uint64 public constant ONWARD_BCH_FEE_BPS = 14_00;
uint64 public constant NETWORK_FEE_BPS = 2_00;
uint64 public constant COLLECTOR_FEE_BPS = 8_00;
address[] private collectors;
uint64 private platformFeeBps;
mapping(uint256 => Listing) public listings;
address private royaltyRecipient;
uint128 private royaltyBps;
mapping(uint256 => RoyaltyInfo) private royaltyInfoForToken;
modifier onlyListingCreator(uint256 _listingId) {
require(listings[_listingId].tokenOwner == _msgSender(), "!OWNER");
_;
}
modifier onlyExistingListing(uint256 _listingId) {
require(listings[_listingId].assetContract != address(0), "DNE");
_;
}
// function initialize(address _platformFeeRecipient) external initializer {
// __ReentrancyGuard_init();
// platformFeeRecipient = _platformFeeRecipient;
// }
constructor(address _platformFeeRecipient){
platformFeeRecipient = _platformFeeRecipient;
}
receive() external payable {}
function onERC1155Received(
address,
address,
uint256,
uint256,
bytes memory
) public virtual override returns (bytes4) {
return this.onERC1155Received.selector;
}
function onERC1155BatchReceived(
address,
address,
uint256[] memory,
uint256[] memory,
bytes memory
) public virtual override returns (bytes4) {
return this.onERC1155BatchReceived.selector;
}
function onERC721Received(
address,
address,
uint256,
bytes calldata
) external pure override returns (bytes4) {
return this.onERC721Received.selector;
}
function supportsInterface(bytes4 interfaceId)
public
view
virtual
override(AccessControlEnumerable, IERC165)
returns (bool)
{
return
interfaceId == type(IERC1155Receiver).interfaceId ||
interfaceId == type(IERC721Receiver).interfaceId ||
super.supportsInterface(interfaceId);
}
function getCollectorsList() public view returns (address[] memory){
return collectors;
}
function NETWORK_FEE() external pure returns (uint64){
return NETWORK_FEE_BPS;
}
function BCH_INTITIAL_FEE() external pure returns (uint64){
return INITIAL_BCH_FEE_BPS;
}
function BCH_FEE() external pure returns (uint64){
return ONWARD_BCH_FEE_BPS;
}
function createListing(ListingParameters memory _params, address _tokenOwner) external override {
uint256 listingId = totalListings;
totalListings += 1;
address tokenOwner = _tokenOwner;
TokenType tokenTypeOfListing = getTokenType(_params.assetContract);
uint256 tokenAmountToList = getSafeQuantity(tokenTypeOfListing, _params.quantityToList);
require(tokenAmountToList > 0, "QUANTITY");
validateOwnershipAndApproval(
tokenOwner,
_params.assetContract,
_params.tokenId,
tokenAmountToList,
tokenTypeOfListing
);
Listing memory newListing = Listing({
listingId: listingId,
tokenOwner: tokenOwner,
assetContract: _params.assetContract,
tokenId: _params.tokenId,
quantity: tokenAmountToList,
buyoutPricePerToken: _params.buyoutPricePerToken,
tokenType: tokenTypeOfListing
});
listings[listingId] = newListing;
emit ListingAdded(listingId, _params.assetContract, tokenOwner, newListing);
}
/// @dev Lets a listing's creator edit the listing's parameters.
function updateListing(
uint256 _listingId,
uint256 _quantityToList,
uint256 _buyoutPricePerToken
) external onlyListingCreator(_listingId) {
Listing memory targetListing = listings[_listingId];
uint256 safeNewQuantity = getSafeQuantity(targetListing.tokenType, _quantityToList);
require(safeNewQuantity != 0, "QUANTITY");
listings[_listingId] = Listing({
listingId: _listingId,
tokenOwner: _msgSender(),
assetContract: targetListing.assetContract,
tokenId: targetListing.tokenId,
quantity: safeNewQuantity,
buyoutPricePerToken: _buyoutPricePerToken,
tokenType: targetListing.tokenType
});
if (targetListing.quantity != safeNewQuantity) {
validateOwnershipAndApproval(
targetListing.tokenOwner,
targetListing.assetContract,
targetListing.tokenId,
safeNewQuantity,
targetListing.tokenType
);
}
emit ListingUpdated(_listingId, targetListing.tokenOwner);
}
function cancelDirectListing(uint256 _listingId) external onlyListingCreator(_listingId) {
Listing memory targetListing = listings[_listingId];
delete listings[_listingId];
emit ListingRemoved(_listingId, targetListing.tokenOwner);
}
function buy(uint256 _listingId, address _buyFor, uint256 _quantityToBuy, uint256 _totalPrice) external payable nonReentrant onlyExistingListing(_listingId) {
Listing memory targetListing = listings[_listingId];
require(_totalPrice == (targetListing.buyoutPricePerToken * _quantityToBuy),"!PRICE");
executeSale(targetListing, _buyFor, targetListing.buyoutPricePerToken * _quantityToBuy, _quantityToBuy);
}
function executeSale(
Listing memory _targetListing,
address _receiver,
uint256 _currencyAmountToTransfer,
uint256 _listingTokenAmountToTransfer
) internal {
validateDirectListingSale(
_targetListing,
_listingTokenAmountToTransfer,
_currencyAmountToTransfer
);
_targetListing.quantity -= _listingTokenAmountToTransfer;
listings[_targetListing.listingId] = _targetListing;
payout(_targetListing.tokenOwner, _currencyAmountToTransfer, _targetListing);
transferListingTokens(_targetListing.tokenOwner, _receiver, _listingTokenAmountToTransfer, _targetListing);
saleType += 1;
emit NewSale(
_targetListing.listingId,
_targetListing.assetContract,
_targetListing.tokenOwner,
_receiver,
_listingTokenAmountToTransfer,
_currencyAmountToTransfer
);
}
function transferListingTokens(
address _from,
address _to,
uint256 _quantity,
Listing memory _listing
) internal {
if (_listing.tokenType == TokenType.ERC1155) {
IERC1155(_listing.assetContract).safeTransferFrom(_from, _to, _listing.tokenId, _quantity, "");
} else if (_listing.tokenType == TokenType.ERC721) {
IERC721(_listing.assetContract).safeTransferFrom(_from, _to, _listing.tokenId, "");
}
}
function getRoyaltyInfo(uint256 _totalPayoutAmount, Listing memory _listing) internal view returns(address adr, uint256 val){
address recipient;
uint256 fee;
try IERC2981(_listing.assetContract).royaltyInfo(_listing.tokenId, _totalPayoutAmount) returns (
address royaltyFeeRecipient,
uint256 royaltyFeeAmount
) {
if (royaltyFeeRecipient != address(0) && royaltyFeeAmount > 0) {
require(royaltyFeeAmount <= _totalPayoutAmount, "fees exceed the price");
recipient = royaltyFeeRecipient;
fee = royaltyFeeAmount;
}
return (recipient, fee);
} catch {}
}
/// @dev Pays out stakeholders in a sale.
function payout(address _payee, uint256 _totalPayoutAmount, Listing memory _listing) internal {
uint256 networkFee = (_totalPayoutAmount * NETWORK_FEE_BPS) / MAX_BPS;
if (saleType == SaleType.INITIAL_SALE){
uint256 platformFeeInitial = (_totalPayoutAmount * INITIAL_BCH_FEE_BPS) / MAX_BPS;
CurrencyTransferLib.safeTransferNativeToken(platformFeeRecipient, networkFee);
CurrencyTransferLib.safeTransferNativeToken(platformFeeRecipient, platformFeeInitial);
CurrencyTransferLib.safeTransferNativeToken(_payee, _totalPayoutAmount - (networkFee + platformFeeInitial));
} else if (saleType == SaleType.SECONDARY_SALE){
uint256 platformFee = (_totalPayoutAmount * ONWARD_BCH_FEE_BPS) / MAX_BPS;
// uint256 royaltyPercentage1;
// address royaltyRecipient1;
(address royaltyFeeRecipient, uint256 royaltyFeeAmount) = getRoyaltyInfo(_totalPayoutAmount, _listing);
// // Distribute royalties. See Sushiswap's https://github.com/sushiswap/shoyu/blob/master/contracts/base/BaseExchange.sol#L296
// try IERC2981Upgradeable(_listing.assetContract).royaltyInfo(_listing.tokenId, _totalPayoutAmount) returns (
// address royaltyFeeRecipient,
// uint256 royaltyFeeAmount
// ) {
// if (royaltyFeeRecipient != address(0) && royaltyFeeAmount > 0) {
// require(royaltyFeeAmount + networkFee + platformFee <= _totalPayoutAmount, "fees exceed the price");
// royaltyRecipient1 = royaltyFeeRecipient;
// royaltyPercentage1 = royaltyFeeAmount;
// }
// } catch {}
CurrencyTransferLib.safeTransferNativeToken(platformFeeRecipient, networkFee);
CurrencyTransferLib.safeTransferNativeToken(platformFeeRecipient, platformFee);
CurrencyTransferLib.safeTransferNativeToken(royaltyFeeRecipient, royaltyFeeAmount);
CurrencyTransferLib.safeTransferNativeToken(_payee, _totalPayoutAmount - (networkFee + platformFee + royaltyFeeAmount));
setRoyaltyInfoForToken(_listing.tokenId, _payee, 2400);
collectors.push(_payee);
} else if (saleType == SaleType.THIRD_SALE){
address firstCollector = collectors[0];
uint256 firstCollectorFee = (_totalPayoutAmount * COLLECTOR_FEE_BPS) / MAX_BPS;
uint256 platformFee = (_totalPayoutAmount * ONWARD_BCH_FEE_BPS) / MAX_BPS;
// uint256 royaltyPercentage2;
// address royaltyRecipient2;
// // Distribute royalties. See Sushiswap's https://github.com/sushiswap/shoyu/blob/master/contracts/base/BaseExchange.sol#L296
// try IERC2981Upgradeable(_listing.assetContract).royaltyInfo(_listing.tokenId, _totalPayoutAmount) returns (
// address royaltyFeeRecipient,
// uint256 royaltyFeeAmount
// ) {
// if (royaltyFeeRecipient != address(0) && royaltyFeeAmount > 0) {
// require(royaltyFeeAmount + networkFee + platformFee <= _totalPayoutAmount, "fees exceed the price");
// royaltyRecipient2 = royaltyFeeRecipient;
// royaltyPercentage2 = royaltyFeeAmount;
// }
// } catch {}
(address royaltyFeeRecipient, uint256 royaltyFeeAmount) = getRoyaltyInfo(_totalPayoutAmount, _listing);
CurrencyTransferLib.safeTransferNativeToken(platformFeeRecipient, networkFee);
CurrencyTransferLib.safeTransferNativeToken(platformFeeRecipient, platformFee);
CurrencyTransferLib.safeTransferNativeToken(royaltyFeeRecipient, royaltyFeeAmount);
CurrencyTransferLib.safeTransferNativeToken(firstCollector, firstCollectorFee);
CurrencyTransferLib.safeTransferNativeToken(_payee, _totalPayoutAmount - (networkFee + platformFee + royaltyFeeAmount + firstCollectorFee));
collectors.push(_payee);
} else if (saleType == SaleType.NORMAL_SALE || saleType > SaleType.NORMAL_SALE) {
uint256 collectorsFee = (_totalPayoutAmount * COLLECTOR_FEE_BPS) / MAX_BPS;
uint256 platformFee = (_totalPayoutAmount * ONWARD_BCH_FEE_BPS) / MAX_BPS;
// uint256 royaltyPercentage;
// address royaltyRecipient;
// try IERC2981Upgradeable(_listing.assetContract).royaltyInfo(_listing.tokenId, _totalPayoutAmount) returns (
// address royaltyFeeRecipient,
// uint256 royaltyFeeAmount
// ) {
// if (royaltyFeeRecipient != address(0) && royaltyFeeAmount > 0) {
// require(royaltyFeeAmount + networkFee + platformFee <= _totalPayoutAmount, "fees exceed the price");
// royaltyRecipient = royaltyFeeRecipient;
// royaltyPercentage = royaltyFeeAmount;
// }
// } catch {}
(address royaltyFeeRecipient, uint256 royaltyFeeAmount) = getRoyaltyInfo(_totalPayoutAmount, _listing);
CurrencyTransferLib.safeTransferNativeToken(platformFeeRecipient, networkFee);
CurrencyTransferLib.safeTransferNativeToken(platformFeeRecipient, platformFee);
CurrencyTransferLib.safeTransferNativeToken(royaltyFeeRecipient, royaltyFeeAmount);
uint256 count = collectors.length;
uint256 eachCollectorFee = collectorsFee / count;
for(uint256 i = 0; i < collectors.length; i++){
CurrencyTransferLib.safeTransferNativeToken(collectors[i], eachCollectorFee);
}
CurrencyTransferLib.safeTransferNativeToken(_payee, _totalPayoutAmount - (networkFee + platformFee + royaltyFeeAmount + collectorsFee));
collectors.push(_payee);
}
}
// function distributeCollectorsFee(uint256 amount) public payable {
// uint256 collectorsFee = (amount * COLLECTOR_FEE_BPS) / MAX_BPS;
// uint256 count = collectors.length;
// // uint256 count = 2;
// uint256 eachCollectorFee = collectorsFee / count;
// // eachCollectorFee = 10;
// for(uint256 i = 0; i < collectors.length; i++){
// CurrencyTransferLib.safeTransferNativeToken(collectors[i], eachCollectorFee);
// }
// }
function validateOwnershipAndApproval(
address _tokenOwner,
address _assetContract,
uint256 _tokenId,
uint256 _quantity,
TokenType _tokenType
) internal view {
address market = address(this);
bool isValid;
if (_tokenType == TokenType.ERC1155) {
isValid =
IERC1155(_assetContract).balanceOf(_tokenOwner, _tokenId) >= _quantity &&
IERC1155(_assetContract).isApprovedForAll(_tokenOwner, market);
} else if (_tokenType == TokenType.ERC721) {
isValid =
IERC721(_assetContract).ownerOf(_tokenId) == _tokenOwner &&
(IERC721(_assetContract).getApproved(_tokenId) == market ||
IERC721(_assetContract).isApprovedForAll(_tokenOwner, market));
}
require(isValid, "!BALNFT");
}
function validateDirectListingSale(
Listing memory _listing,
uint256 _quantityToBuy,
uint256 settledTotalPrice
) internal {
require(
_listing.quantity > 0 && _quantityToBuy > 0 && _quantityToBuy <= _listing.quantity,
"invalid amount of tokens."
);
require(msg.value == settledTotalPrice, "msg.value != price");
validateOwnershipAndApproval(
_listing.tokenOwner,
_listing.assetContract,
_listing.tokenId,
_quantityToBuy,
_listing.tokenType
);
}
function getSafeQuantity(TokenType _tokenType, uint256 _quantityToCheck)
internal
pure
returns (uint256 safeQuantity)
{
if (_quantityToCheck == 0) {
safeQuantity = 0;
} else {
safeQuantity = _tokenType == TokenType.ERC721 ? 1 : _quantityToCheck;
}
}
function getTokenType(address _assetContract) internal view returns (TokenType tokenType) {
if (IERC165(_assetContract).supportsInterface(type(IERC1155).interfaceId)) {
tokenType = TokenType.ERC1155;
} else if (IERC165(_assetContract).supportsInterface(type(IERC721).interfaceId)) {
tokenType = TokenType.ERC721;
} else {
revert("token must be ERC1155 or ERC721.");
}
}
function getPlatformFeeInfo() external view returns (address, uint16) {
return (platformFeeRecipient, uint16(platformFeeBps));
}
function setPlatformFeeInfo(address _platformFeeRecipient, uint256 _platformFeeBps)
external
onlyRole(DEFAULT_ADMIN_ROLE)
{
require(_platformFeeBps <= MAX_BPS, "bps <= 10000.");
platformFeeBps = uint64(_platformFeeBps);
platformFeeRecipient = _platformFeeRecipient;
emit PlatformFeeInfoUpdated(_platformFeeRecipient, _platformFeeBps);
}
function royaltyInfo(uint256 tokenId, uint256 salePrice)
external
view
virtual
returns (address receiver, uint256 royaltyAmount)
{
(address recipient, uint256 bps) = getRoyaltyInfoForToken(tokenId);
receiver = recipient;
royaltyAmount = (salePrice * bps) / MAX_BPS;
}
function setDefaultRoyaltyInfo(address _royaltyRecipient, uint256 _royaltyBps)
external
// onlyRole(DEFAULT_ADMIN_ROLE)
{
require(_royaltyBps <= MAX_BPS, "exceed royalty bps");
royaltyRecipient = _royaltyRecipient;
royaltyBps = uint128(_royaltyBps);
emit DefaultRoyalty(_royaltyRecipient, _royaltyBps);
}
/// @dev Lets a module admin set the royalty recipient for a particular token Id.
function setRoyaltyInfoForToken(
uint256 _tokenId,
address _recipient,
uint256 _bps
) public override
// onlyRole(DEFAULT_ADMIN_ROLE)
{
require(_bps <= MAX_BPS, "exceed royalty bps");
royaltyInfoForToken[_tokenId] = RoyaltyInfo({ recipient: _recipient, bps: _bps });
emit RoyaltyForToken(_tokenId, _recipient, _bps);
}
/// @dev Returns the platform fee bps and recipient.
function getDefaultRoyaltyInfo() external view returns (address, uint16) {
return (royaltyRecipient, uint16(royaltyBps));
}
/// @dev Returns the royalty recipient for a particular token Id.
function getRoyaltyInfoForToken(uint256 _tokenId) public view returns (address, uint16) {
RoyaltyInfo memory royaltyForToken = royaltyInfoForToken[_tokenId];
return
royaltyForToken.recipient == address(0)
? (royaltyRecipient, uint16(royaltyBps))
: (royaltyForToken.recipient, uint16(royaltyForToken.bps));
}
}
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.11;
library SaleType {
uint256 internal constant INITIAL_SALE = 1;
uint256 internal constant SECONDARY_SALE = 2;
uint256 internal constant THIRD_SALE = 3;
uint256 internal constant NORMAL_SALE = 4;
}
// This script can be used to deploy the "Storage" contract using ethers.js library.
// Please make sure to compile "./contracts/1_Storage.sol" file before running this script.
// And use Right click -> "Run" from context menu of the file to run the script. Shortcut: Ctrl+Shift+S
import { deploy } from './ethers-lib'
(async () => {
try {
const result = await deploy('Storage', [])
console.log(`address: ${result.address}`)
} catch (e) {
console.log(e.message)
}
})()
// This script can be used to deploy the "Storage" contract using Web3 library.
// Please make sure to compile "./contracts/1_Storage.sol" file before running this script.
// And use Right click -> "Run" from context menu of the file to run the script. Shortcut: Ctrl+Shift+S
import { deploy } from './web3-lib'
(async () => {
try {
const result = await deploy('Storage', [])
console.log(`address: ${result.address}`)
} catch (e) {
console.log(e.message)
}
})()
import { ethers } from 'ethers'
/**
* Deploy the given contract
* @param {string} contractName name of the contract to deploy
* @param {Array<any>} args list of constructor' parameters
* @param {Number} accountIndex account index from the exposed account
* @return {Contract} deployed contract
*/
export const deploy = async (contractName: string, args: Array<any>, accountIndex?: number): Promise<ethers.Contract> => {
console.log(`deploying ${contractName}`)
// Note that the script needs the ABI which is generated from the compilation artifact.
// Make sure contract is compiled and artifacts are generated
const artifactsPath = `browser/contracts/artifacts/${contractName}.json` // Change this for different path
const metadata = JSON.parse(await remix.call('fileManager', 'getFile', artifactsPath))
// 'web3Provider' is a remix global variable object
const signer = (new ethers.providers.Web3Provider(web3Provider)).getSigner(accountIndex)
const factory = new ethers.ContractFactory(metadata.abi, metadata.data.bytecode.object, signer)
const contract = await factory.deploy(...args)
// The contract is NOT deployed yet; we must wait until it is mined
await contract.deployed()
return contract
}
import Web3 from 'web3'
import { Contract, ContractSendMethod, Options } from 'web3-eth-contract'
/**
* Deploy the given contract
* @param {string} contractName name of the contract to deploy
* @param {Array<any>} args list of constructor' parameters
* @param {string} from account used to send the transaction
* @param {number} gas gas limit
* @return {Options} deployed contract
*/
export const deploy = async (contractName: string, args: Array<any>, from?: string, gas?: number): Promise<Options> => {
const web3 = new Web3(web3Provider)
console.log(`deploying ${contractName}`)
// Note that the script needs the ABI which is generated from the compilation artifact.
// Make sure contract is compiled and artifacts are generated
const artifactsPath = `browser/contracts/artifacts/${contractName}.json`
const metadata = JSON.parse(await remix.call('fileManager', 'getFile', artifactsPath))
const accounts = await web3.eth.getAccounts()
const contract: Contract = new web3.eth.Contract(metadata.abi)
const contractSend: ContractSendMethod = contract.deploy({
data: metadata.data.bytecode.object,
arguments: args
})
const newContractInstance = await contractSend.send({
from: from || accounts[0],
gas: gas || 1500000
})
return newContractInstance.options
}
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
import "remix_tests.sol"; // this import is automatically injected by Remix.
import "hardhat/console.sol";
import "../contracts/3_Ballot.sol";
contract BallotTest {
bytes32[] proposalNames;
Ballot ballotToTest;
function beforeAll () public {
proposalNames.push(bytes32("candidate1"));
ballotToTest = new Ballot(proposalNames);
}
function checkWinningProposal () public {
console.log("Running checkWinningProposal");
ballotToTest.vote(0);
Assert.equal(ballotToTest.winningProposal(), uint(0), "proposal at index 0 should be the winning proposal");
Assert.equal(ballotToTest.winnerName(), bytes32("candidate1"), "candidate1 should be the winner name");
}
function checkWinninProposalWithReturnValue () public view returns (bool) {
return ballotToTest.winningProposal() == 0;
}
}
// Right click on the script name and hit "Run" to execute
const { expect } = require("chai");
const { ethers } = require("hardhat");
describe("Storage", function () {
it("test initial value", async function () {
const Storage = await ethers.getContractFactory("Storage");
const storage = await Storage.deploy();
await storage.deployed();
console.log('storage deployed at:'+ storage.address)
expect((await storage.retrieve()).toNumber()).to.equal(0);
});
it("test updating and retrieving updated value", async function () {
const Storage = await ethers.getContractFactory("Storage");
const storage = await Storage.deploy();
await storage.deployed();
const storage2 = await ethers.getContractAt("Storage", storage.address);
const setValue = await storage2.store(56);
await setValue.wait();
expect((await storage2.retrieve()).toNumber()).to.equal(56);
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment