Contract Name:
GenArt721Minter3
Contract Source Code:
File 1 of 1 : GenArt721Minter3
// File contracts/GenArt721Minter3.sol
/**
*Submitted for verification at Etherscan.io on 2020-12-20
*/
// File contracts/libs/SafeMath.sol
// File: openzeppelin-solidity/contracts/math/SafeMath.sol
pragma solidity ^0.5.0;
/**
* @dev Wrappers over Solidity's arithmetic operations with added overflow
* checks.
*
* Arithmetic operations in Solidity wrap on overflow. This can easily result
* in bugs, because programmers usually assume that an overflow raises an
* error, which is the standard behavior in high level programming languages.
* `SafeMath` restores this intuition by reverting the transaction when an
* operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*/
library SafeMath {
/**
* @dev Returns the addition of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `+` operator.
*
* Requirements:
* - Addition cannot overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
require(b <= a, "SafeMath: subtraction overflow");
uint256 c = a - b;
return c;
}
/**
* @dev Returns the multiplication of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `*` operator.
*
* Requirements:
* - Multiplication cannot overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
if (a == 0) {
return 0;
}
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
/**
* @dev Returns the integer division of two unsigned integers. Reverts on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
// Solidity only automatically asserts when dividing by 0
require(b > 0, "SafeMath: division by zero");
uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}
}
// File contracts/libs/Strings.sol
// File: contracts/Strings.sol
pragma solidity ^0.5.0;
//https://github.com/oraclize/ethereum-api/blob/master/oraclizeAPI_0.5.sol
library Strings {
function strConcat(string memory _a, string memory _b) internal pure returns (string memory _concatenatedString) {
return strConcat(_a, _b, "", "", "");
}
function strConcat(string memory _a, string memory _b, string memory _c) internal pure returns (string memory _concatenatedString) {
return strConcat(_a, _b, _c, "", "");
}
function strConcat(string memory _a, string memory _b, string memory _c, string memory _d) internal pure returns (string memory _concatenatedString) {
return strConcat(_a, _b, _c, _d, "");
}
function strConcat(string memory _a, string memory _b, string memory _c, string memory _d, string memory _e) internal pure returns (string memory _concatenatedString) {
bytes memory _ba = bytes(_a);
bytes memory _bb = bytes(_b);
bytes memory _bc = bytes(_c);
bytes memory _bd = bytes(_d);
bytes memory _be = bytes(_e);
string memory abcde = new string(_ba.length + _bb.length + _bc.length + _bd.length + _be.length);
bytes memory babcde = bytes(abcde);
uint k = 0;
uint i = 0;
for (i = 0; i < _ba.length; i++) {
babcde[k++] = _ba[i];
}
for (i = 0; i < _bb.length; i++) {
babcde[k++] = _bb[i];
}
for (i = 0; i < _bc.length; i++) {
babcde[k++] = _bc[i];
}
for (i = 0; i < _bd.length; i++) {
babcde[k++] = _bd[i];
}
for (i = 0; i < _be.length; i++) {
babcde[k++] = _be[i];
}
return string(babcde);
}
function uint2str(uint _i) internal pure returns (string memory _uintAsString) {
if (_i == 0) {
return "0";
}
uint j = _i;
uint len;
while (j != 0) {
len++;
j /= 10;
}
bytes memory bstr = new bytes(len);
uint k = len - 1;
while (_i != 0) {
bstr[k--] = byte(uint8(48 + _i % 10));
_i /= 10;
}
return string(bstr);
}
}
pragma solidity ^0.5.0;
interface GenArt721CoreContract {
function isWhitelisted(address sender) external view returns (bool);
function projectIdToCurrencySymbol(uint256 _projectId) external view returns (string memory);
function projectIdToCurrencyAddress(uint256 _projectId) external view returns (address);
function projectIdToArtistAddress(uint256 _projectId) external view returns (address payable);
function projectIdToPricePerTokenInWei(uint256 _projectId) external view returns (uint256);
function projectIdToAdditionalPayee(uint256 _projectId) external view returns (address payable);
function projectIdToAdditionalPayeePercentage(uint256 _projectId) external view returns (uint256);
function artblocksAddress() external view returns (address payable);
function artblocksPercentage() external view returns (uint256);
function mint(address _to, uint256 _projectId, address _by) external returns (uint256 tokenId);
}
interface ERC20 {
function balanceOf(address _owner) external view returns (uint balance);
function transferFrom(address _from, address _to, uint _value) external returns (bool success);
function allowance(address _owner, address _spender) external view returns (uint remaining);
}
interface BonusContract {
function triggerBonus(address _to) external returns (bool);
function bonusIsActive() external view returns (bool);
}
contract GenArt721Minter3 {
using SafeMath for uint256;
GenArt721CoreContract public artblocksContract;
address payable public ownerAddress;
uint256 public ownerPercentage;
mapping(uint256 => bool) public projectIdToBonus;
mapping(uint256 => address) public projectIdToBonusContractAddress;
mapping(uint256 => bool) public contractFilterProject;
mapping(address => mapping (uint256 => uint256)) public projectMintCounter;
mapping(uint256 => uint256) public projectMintLimit;
constructor(address _genArt721Address) public {
artblocksContract=GenArt721CoreContract(_genArt721Address);
}
function getYourBalanceOfProjectERC20(uint256 _projectId) public view returns (uint256){
uint256 balance = ERC20(artblocksContract.projectIdToCurrencyAddress(_projectId)).balanceOf(msg.sender);
return balance;
}
function checkYourAllowanceOfProjectERC20(uint256 _projectId) public view returns (uint256){
uint256 remaining = ERC20(artblocksContract.projectIdToCurrencyAddress(_projectId)).allowance(msg.sender, address(this));
return remaining;
}
function setProjectMintLimit(uint256 _projectId,uint8 _limit) public {
require(artblocksContract.isWhitelisted(msg.sender), "can only be set by admin");
projectMintLimit[_projectId] = _limit;
}
function setOwnerAddress(address payable _ownerAddress) public {
require(artblocksContract.isWhitelisted(msg.sender), "can only be set by admin");
ownerAddress = _ownerAddress;
}
function setOwnerPercentage(uint256 _ownerPercentage) public {
require(artblocksContract.isWhitelisted(msg.sender), "can only be set by admin");
ownerPercentage = _ownerPercentage;
}
function toggleContractFilter(uint256 _projectId) public {
require(artblocksContract.isWhitelisted(msg.sender), "can only be set by admin");
contractFilterProject[_projectId]=!contractFilterProject[_projectId];
}
function artistToggleBonus(uint256 _projectId) public {
require(msg.sender==artblocksContract.projectIdToArtistAddress(_projectId), "can only be set by artist");
projectIdToBonus[_projectId]=!projectIdToBonus[_projectId];
}
function artistSetBonusContractAddress(uint256 _projectId, address _bonusContractAddress) public {
require(msg.sender==artblocksContract.projectIdToArtistAddress(_projectId), "can only be set by artist");
projectIdToBonusContractAddress[_projectId]=_bonusContractAddress;
}
function purchase(uint256 _projectId) public payable returns (uint256 _tokenId) {
return purchaseTo(msg.sender, _projectId);
}
//remove public and payable to prevent public use of purchaseTo function
function purchaseTo(address _to, uint256 _projectId) public payable returns(uint256 _tokenId){
if (keccak256(abi.encodePacked(artblocksContract.projectIdToCurrencySymbol(_projectId))) != keccak256(abi.encodePacked("ETH"))){
require(msg.value==0, "this project accepts a different currency and cannot accept ETH");
require(ERC20(artblocksContract.projectIdToCurrencyAddress(_projectId)).allowance(msg.sender, address(this)) >= artblocksContract.projectIdToPricePerTokenInWei(_projectId), "Insufficient Funds Approved for TX");
require(ERC20(artblocksContract.projectIdToCurrencyAddress(_projectId)).balanceOf(msg.sender) >= artblocksContract.projectIdToPricePerTokenInWei(_projectId), "Insufficient balance.");
_splitFundsERC20(_projectId);
} else {
require(msg.value>=artblocksContract.projectIdToPricePerTokenInWei(_projectId), "Must send minimum value to mint!");
_splitFundsETH(_projectId);
}
// if contract filter is active prevent calls from another contract
if (contractFilterProject[_projectId]) require(msg.sender == tx.origin, "No Contract Buys");
// limit mints per address by project
if (projectMintLimit[_projectId] > 0) {
require(projectMintCounter[msg.sender][_projectId] < projectMintLimit[_projectId], "Reached minting limit");
projectMintCounter[msg.sender][_projectId]++;
}
uint256 tokenId = artblocksContract.mint(_to, _projectId, msg.sender);
if (projectIdToBonus[_projectId]){
require(BonusContract(projectIdToBonusContractAddress[_projectId]).bonusIsActive(), "bonus must be active");
BonusContract(projectIdToBonusContractAddress[_projectId]).triggerBonus(msg.sender);
}
return tokenId;
}
function _splitFundsETH(uint256 _projectId) internal {
if (msg.value > 0) {
uint256 pricePerTokenInWei = artblocksContract.projectIdToPricePerTokenInWei(_projectId);
uint256 refund = msg.value.sub(artblocksContract.projectIdToPricePerTokenInWei(_projectId));
if (refund > 0) {
msg.sender.transfer(refund);
}
uint256 artBlocksAmount = pricePerTokenInWei.div(100).mul(artblocksContract.artblocksPercentage());
if (artBlocksAmount > 0) {
artblocksContract.artblocksAddress().transfer(artBlocksAmount);
}
uint256 remainingFunds = pricePerTokenInWei.sub(artBlocksAmount);
uint256 ownerFunds = remainingFunds.div(100).mul(ownerPercentage);
if (ownerFunds > 0) {
ownerAddress.transfer(ownerFunds);
}
uint256 projectFunds = pricePerTokenInWei.sub(artBlocksAmount).sub(ownerFunds);
uint256 additionalPayeeAmount;
if (artblocksContract.projectIdToAdditionalPayeePercentage(_projectId) > 0) {
additionalPayeeAmount = projectFunds.div(100).mul(artblocksContract.projectIdToAdditionalPayeePercentage(_projectId));
if (additionalPayeeAmount > 0) {
artblocksContract.projectIdToAdditionalPayee(_projectId).transfer(additionalPayeeAmount);
}
}
uint256 creatorFunds = projectFunds.sub(additionalPayeeAmount);
if (creatorFunds > 0) {
artblocksContract.projectIdToArtistAddress(_projectId).transfer(creatorFunds);
}
}
}
function _splitFundsERC20(uint256 _projectId) internal {
uint256 pricePerTokenInWei = artblocksContract.projectIdToPricePerTokenInWei(_projectId);
uint256 artBlocksAmount = pricePerTokenInWei.div(100).mul(artblocksContract.artblocksPercentage());
if (artBlocksAmount > 0) {
ERC20(artblocksContract.projectIdToCurrencyAddress(_projectId)).transferFrom(msg.sender, artblocksContract.artblocksAddress(), artBlocksAmount);
}
uint256 remainingFunds = pricePerTokenInWei.sub(artBlocksAmount);
uint256 ownerFunds = remainingFunds.div(100).mul(ownerPercentage);
if (ownerFunds > 0) {
ERC20(artblocksContract.projectIdToCurrencyAddress(_projectId)).transferFrom(msg.sender, ownerAddress, ownerFunds);
}
uint256 projectFunds = pricePerTokenInWei.sub(artBlocksAmount).sub(ownerFunds);
uint256 additionalPayeeAmount;
if (artblocksContract.projectIdToAdditionalPayeePercentage(_projectId) > 0) {
additionalPayeeAmount = projectFunds.div(100).mul(artblocksContract.projectIdToAdditionalPayeePercentage(_projectId));
if (additionalPayeeAmount > 0) {
ERC20(artblocksContract.projectIdToCurrencyAddress(_projectId)).transferFrom(msg.sender, artblocksContract.projectIdToAdditionalPayee(_projectId), additionalPayeeAmount);
}
}
uint256 creatorFunds = projectFunds.sub(additionalPayeeAmount);
if (creatorFunds > 0) {
ERC20(artblocksContract.projectIdToCurrencyAddress(_projectId)).transferFrom(msg.sender, artblocksContract.projectIdToArtistAddress(_projectId), creatorFunds);
}
}
}