// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <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 GSN 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 payable) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes memory) {
this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
return msg.data;
}
}
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.6 <0.9.0;
import "@openzeppelin/contracts/math/SafeMath.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@chainlink/contracts/src/v0.6/VRFConsumerBase.sol";
import "../Interfaces/ERC721.sol";
import "../Libraries/CurrentTime.sol";
contract Coupon is Ownable, VRFConsumerBase, CurrentTime {
mapping(uint256 => bool) internal redemptions;
uint256 internal constant REBATE_AMOUNT = 20000000000000000;
uint256 internal constant MINT_FLOOR = 40000000000000000;
uint256 public currentRebate;
uint256 public promotionStart;
uint256 public promotionEnd;
address public cryptorchidsERC721;
uint256 public pot;
address[] internal drawingEntries;
bytes32 internal randomWinnerRequestId;
bool public winnerRequested;
address public winner;
bytes32 internal keyHash;
uint256 internal vrfFee;
address public VRFCoordinator;
address public LinkToken;
constructor(
address cryptorchidsAddress,
address _VRFCoordinator,
address _LinkToken,
bytes32 _keyhash
) public payable VRFConsumerBase(_VRFCoordinator, _LinkToken) {
VRFCoordinator = _VRFCoordinator;
LinkToken = _LinkToken;
keyHash = _keyhash;
vrfFee = 2000000000000000000; // 2 LINK
cryptorchidsERC721 = cryptorchidsAddress;
promotionStart = block.timestamp;
promotionEnd = 1622520000;
currentRebate = REBATE_AMOUNT;
}
/** Public function for whether the promotion is open. The promotion is only
* open if the contract balance is greater than the currentRebate. Displayed
* on CryptOrchids nursery for transparency.
* @dev
* @return bool Whether promotion is open for entries.
*/
function promotionOpen() public view returns (bool) {
if (currentTime() > promotionEnd) return false;
uint256 balance = address(this).balance;
if (pot > balance.add(currentRebate)) return false;
if (currentRebate > balance) return false;
return true;
}
/** Check rebate value and eligible tokens. Tokens are valid if they are planted
* after this contract is deployed, alive, and not yet redeemed.
* @dev calls public functions on the CryptOrchids contract to build
* an array of eligible token IDs and a rebate amount.
* @return eligibleTokens uint256[] Uncompacted array of 0s and eligible token IDs
* @return rebateAmount uint256 Eligible tokens * currentRebate
*/
function checkEligibility() public view returns (uint256[] memory eligibleTokens, uint256 rebateAmount) {
uint256 tokenCount = ERC721(cryptorchidsERC721).balanceOf(msg.sender);
eligibleTokens = new uint256[](tokenCount);
uint256 safeBal = safeBalance();
for (uint256 index = 0; index < tokenCount; index++) {
uint256 tokenId = ERC721(cryptorchidsERC721).tokenOfOwnerByIndex(msg.sender, index);
if (redemptions[tokenId] == true) continue;
bool flowering = ERC721(cryptorchidsERC721).flowering(tokenId);
if (!flowering) continue;
(, uint256 plantedAt, , ) = ERC721(cryptorchidsERC721).getTokenMetadata(tokenId);
uint256 rebate = tokenRebate(tokenId);
if (plantedAt > promotionStart && rebateAmount + rebate <= safeBal) {
eligibleTokens[index] = tokenId;
rebateAmount += rebate;
}
}
return (eligibleTokens, rebateAmount);
}
/** Claim ETH for valid tokens. Check for valid tokens before claming.
* @dev calls checkEligibility and sets all eligibleTokens as redeemed.
* Then transfers caller rebateAmount.
*/
function redeem() public virtual returns (uint256) {
uint256 tokenCount = ERC721(cryptorchidsERC721).balanceOf(msg.sender);
uint256 safeBal = safeBalance();
uint256 rebateAmount = 0;
for (uint256 index = 0; index < tokenCount; index++) {
uint256 tokenId = ERC721(cryptorchidsERC721).tokenOfOwnerByIndex(msg.sender, index);
if (redemptions[tokenId] == true) continue;
uint256 rebate = tokenRebate(tokenId);
if (rebateAmount + rebate > safeBal) break;
bool flowering = ERC721(cryptorchidsERC721).flowering(tokenId);
if (!flowering) continue;
(, uint256 plantedAt, , ) = ERC721(cryptorchidsERC721).getTokenMetadata(tokenId);
if (plantedAt < promotionStart) continue;
rebateAmount += rebate;
redemptions[tokenId] = true;
}
require(rebateAmount > 0, "Unpayable");
payable(msg.sender).transfer(rebateAmount);
return rebateAmount;
}
/** Redeem tokens for entries in drawing.
* @dev Adds address to drawingEntries, increments entriesCount, and
* increases pot for each eligible token, while marking each token redeemed.
*/
function enter() public virtual {
uint256 tokenCount = ERC721(cryptorchidsERC721).balanceOf(msg.sender);
uint256 safeBal = safeBalance();
uint256 rebateAmount = 0;
for (uint256 index = 0; index < tokenCount; index++) {
uint256 tokenId = ERC721(cryptorchidsERC721).tokenOfOwnerByIndex(msg.sender, index);
if (redemptions[tokenId] == true) continue;
uint256 rebate = tokenRebate(tokenId);
if (rebateAmount + rebate > safeBal) break;
bool flowering = ERC721(cryptorchidsERC721).flowering(tokenId);
if (!flowering) continue;
(, uint256 plantedAt, , ) = ERC721(cryptorchidsERC721).getTokenMetadata(tokenId);
if (plantedAt < promotionStart) continue;
rebateAmount += rebate;
redemptions[tokenId] = true;
drawingEntries.push(msg.sender);
}
pot += rebateAmount;
}
/** Current rebate amount for new, mintable token. Based on CryptOrchids current price,
* the ramping rebate is intended to address the regrettable FOMO ramp pricing.
* Starts at 0.02ETH, and increases with inverse correlation to price ramp to
* offer effectively straight 0.04 ETH for seeds.
* @dev calls CryptOrchids.currentPrice and finds difference with MINT_FLOOR to return rebate.
*/
function setCurrentRebate() public {
uint256 currentPrice = ERC721(cryptorchidsERC721).currentPrice();
if (currentPrice == MINT_FLOOR) {
currentRebate = REBATE_AMOUNT;
return;
}
currentRebate = currentPrice - MINT_FLOOR;
}
/** Redeemable rebate amount for existing token. Based on the price the token was sold at,
* this prevents a seed holder from redeeming a seed for more than it was purchased for.
* @dev Copies currentPrice and returns rebate amount for tokenId
*/
function tokenRebate(uint256 tokenId) public pure returns (uint256) {
if (tokenId > 9900) {
return 1000000000000000000 - MINT_FLOOR; // 9900+: 0.960 ETH
} else if (tokenId > 9500) {
return 640000000000000000 - MINT_FLOOR; // 9500-9500: 0.60 ETH
} else if (tokenId > 7500) {
return 320000000000000000 - MINT_FLOOR; // 7500-9500: 0.28 ETH
} else if (tokenId > 3500) {
return 160000000000000000 - MINT_FLOOR; // 3500-7500: 0.12 ETH
} else if (tokenId > 1500) {
return 80000000000000000 - MINT_FLOOR; // 1500-3500: 0.04 ETH
} else if (tokenId > 500) {
return 60000000000000000 - MINT_FLOOR; // 500-1500: 0.02 ETH
} else {
return REBATE_AMOUNT; // 0 - 500 0.02 ETH
}
}
/** Current count of rebates available as determined by safeBalance and currentRebate
*/
function rebatesAvailable() public view returns (uint256) {
return SafeMath.div(safeBalance(), currentRebate);
}
/** Current amount availble for refund or to be staked in raffle.
*/
function safeBalance() internal view returns (uint256) {
return (address(this).balance).sub(pot);
}
/** Current amount availble for refund or to be staked in raffle.
*/
function drawingEntriesCount() public view returns (uint256) {
return drawingEntries.length;
}
/** Current amount availble for refund or to be staked in raffle.
*/
function addressEntriesCount() public view returns (uint256) {
uint256 count = 0;
for (uint256 index = 0; index < drawingEntries.length; index++) {
if (drawingEntries[index] == msg.sender) {
count += 1;
}
}
return count;
}
function selectWinner(uint256 userProvidedSeed) public virtual {
require(currentTime() > promotionEnd, "COC:wW:promotion running");
require(randomWinnerRequestId[0] == 0, "COC:wW:winner requested");
require(LINK.balanceOf(address(this)) >= vrfFee, "COC:sW:no LINK");
randomWinnerRequestId = requestRandomness(keyHash, vrfFee, userProvidedSeed);
}
function fulfillRandomness(bytes32 requestId, uint256 randomness) internal override {
require(requestId == randomWinnerRequestId, "COC:fR:invalid request ID");
uint256 winnerIndex = SafeMath.mod(randomness, drawingEntriesCount());
winner = drawingEntries[winnerIndex];
}
/** Winner may withdraw ether from the contract once the promotion is over.
*
*/
function withdrawWinner() public {
require(currentTime() > promotionEnd, "COC:wW:promotion running");
require(msg.sender == winner, "COC:wW:not winner");
uint256 winnings = pot;
pot = 0;
payable(winner).transfer(winnings);
}
/** Owner may reset the promotion to run again.
*
*/
function reset(uint256 newPromotionEnd) public onlyOwner {
require(currentTime() > promotionEnd, "COC:rst:promotion running");
require(pot == 0, "COC:rst:winnings unclaimed");
delete drawingEntries;
winnerRequested = false;
randomWinnerRequestId = bytes32(0);
winner = address(0);
pot = 0;
promotionEnd = newPromotionEnd;
}
/** Withdraw ether from this contract once the promotion is over.
* @dev Transfer remaining balance to owner if after promotionEnd.
*
*/
function withdrawUnclaimed() public onlyOwner {
require(currentTime() > promotionEnd, "COC:wU:promotion running");
require(pot == 0, "COC:wU:winnings unclaimed");
payable(msg.sender).transfer(address(this).balance);
}
receive() external payable {}
}
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.6 <0.9.0;
contract CurrentTime {
function currentTime() internal view virtual returns (uint256) {
return block.timestamp;
}
}
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.6 <0.9.0;
interface ERC721 {
enum Stage {Unsold, Seed, Flower, Dead}
struct CryptOrchid {
string species;
uint256 plantedAt;
uint256 waterLevel;
}
/// @dev This emits when ownership of any NFT changes by any mechanism.
/// This event emits when NFTs are created (`from` == 0) and destroyed
/// (`to` == 0). Exception: during contract creation, any number of NFTs
/// may be created and assigned without emitting Transfer. At the time of
/// any transfer, the approved address for that NFT (if any) is reset to none.
event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId);
/// @dev This emits when the approved address for an NFT is changed or
/// reaffirmed. The zero address indicates there is no approved address.
/// When a Transfer event emits, this also indicates that the approved
/// address for that NFT (if any) is reset to none.
event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId);
/// @dev This emits when an operator is enabled or disabled for an owner.
/// The operator can manage all NFTs of the owner.
event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved);
/// @notice Count all NFTs assigned to an owner
/// @dev NFTs assigned to the zero address are considered invalid, and this
/// function throws for queries about the zero address.
/// @param _owner An address for whom to query the balance
/// @return The number of NFTs owned by `_owner`, possibly zero
function balanceOf(address _owner) external view returns (uint256);
/// @notice Find the owner of an NFT
/// @dev NFTs assigned to zero address are considered invalid, and queries
/// about them do throw.
/// @param _tokenId The identifier for an NFT
/// @return The address of the owner of the NFT
function ownerOf(uint256 _tokenId) external view returns (address);
/// @notice Transfers the ownership of an NFT from one address to another address
/// @dev Throws unless `msg.sender` is the current owner, an authorized
/// operator, or the approved address for this NFT. Throws if `_from` is
/// not the current owner. Throws if `_to` is the zero address. Throws if
/// `_tokenId` is not a valid NFT. When transfer is complete, this function
/// checks if `_to` is a smart contract (code size > 0). If so, it calls
/// `onERC721Received` on `_to` and throws if the return value is not
/// `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`.
/// @param _from The current owner of the NFT
/// @param _to The new owner
/// @param _tokenId The NFT to transfer
/// @param data Additional data with no specified format, sent in call to `_to`
function safeTransferFrom(
address _from,
address _to,
uint256 _tokenId,
bytes calldata data
) external payable;
/// @notice Transfers the ownership of an NFT from one address to another address
/// @dev This works identically to the other function with an extra data parameter,
/// except this function just sets data to "".
/// @param _from The current owner of the NFT
/// @param _to The new owner
/// @param _tokenId The NFT to transfer
function safeTransferFrom(
address _from,
address _to,
uint256 _tokenId
) external payable;
/// @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE
/// TO CONFIRM THAT `_to` IS CAPABLE OF RECEIVING NFTS OR ELSE
/// THEY MAY BE PERMANENTLY LOST
/// @dev Throws unless `msg.sender` is the current owner, an authorized
/// operator, or the approved address for this NFT. Throws if `_from` is
/// not the current owner. Throws if `_to` is the zero address. Throws if
/// `_tokenId` is not a valid NFT.
/// @param _from The current owner of the NFT
/// @param _to The new owner
/// @param _tokenId The NFT to transfer
function transferFrom(
address _from,
address _to,
uint256 _tokenId
) external payable;
/// @notice Change or reaffirm the approved address for an NFT
/// @dev The zero address indicates there is no approved address.
/// Throws unless `msg.sender` is the current NFT owner, or an authorized
/// operator of the current owner.
/// @param _approved The new approved NFT controller
/// @param _tokenId The NFT to approve
function approve(address _approved, uint256 _tokenId) external payable;
/// @notice Enable or disable approval for a third party ("operator") to manage
/// all of `msg.sender`'s assets
/// @dev Emits the ApprovalForAll event. The contract MUST allow
/// multiple operators per owner.
/// @param _operator Address to add to the set of authorized operators
/// @param _approved True if the operator is approved, false to revoke approval
function setApprovalForAll(address _operator, bool _approved) external;
/// @notice Get the approved address for a single NFT
/// @dev Throws if `_tokenId` is not a valid NFT.
/// @param _tokenId The NFT to find the approved address for
/// @return The approved address for this NFT, or the zero address if there is none
function getApproved(uint256 _tokenId) external view returns (address);
/// @notice Query if an address is an authorized operator for another address
/// @param _owner The address that owns the NFTs
/// @param _operator The address that acts on behalf of the owner
/// @return True if `_operator` is an approved operator for `_owner`, false otherwise
function isApprovedForAll(address _owner, address _operator) external view returns (bool);
/**
* @dev Returns the total amount of tokens stored by the contract.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns a token ID owned by `owner` at a given `index` of its token list.
* Use along with {balanceOf} to enumerate all of ``owner``'s tokens.
*/
function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256 tokenId);
/**
* @dev Returns a token ID at a given `index` of all the tokens stored by the contract.
* Use along with {totalSupply} to enumerate all tokens.
*/
function tokenByIndex(uint256 index) external view returns (uint256);
function flowering(uint256 tokenId) external view returns (bool);
function currentPrice() external view returns (uint256 price);
function getTokenMetadata(uint256 tokenId)
external
view
returns (
string memory,
uint256,
uint256,
Stage
);
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
interface LinkTokenInterface {
function allowance(address owner, address spender) external view returns (uint256 remaining);
function approve(address spender, uint256 value) external returns (bool success);
function balanceOf(address owner) external view returns (uint256 balance);
function decimals() external view returns (uint8 decimalPlaces);
function decreaseApproval(address spender, uint256 addedValue) external returns (bool success);
function increaseApproval(address spender, uint256 subtractedValue) external;
function name() external view returns (string memory tokenName);
function symbol() external view returns (string memory tokenSymbol);
function totalSupply() external view returns (uint256 totalTokensIssued);
function transfer(address to, uint256 value) external returns (bool success);
function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool success);
function transferFrom(address from, address to, uint256 value) external returns (bool success);
}
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.8.0;
import "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor () internal {
address msgSender = _msgSender();
_owner = msgSender;
emit OwnershipTransferred(address(0), msgSender);
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
_;
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
emit OwnershipTransferred(_owner, address(0));
_owner = address(0);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
emit OwnershipTransferred(_owner, newOwner);
_owner = newOwner;
}
}
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.8.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, with an overflow flag.
*
* _Available since v3.4._
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
/**
* @dev Returns the substraction of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b > a) return (false, 0);
return (true, a - b);
}
/**
* @dev Returns the multiplication of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool, 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-contracts/pull/522
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
/**
* @dev Returns the division of two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b == 0) return (false, 0);
return (true, a / b);
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b == 0) return (false, 0);
return (true, a % b);
}
/**
* @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");
return a - b;
}
/**
* @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) {
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, reverting 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) {
require(b > 0, "SafeMath: division by zero");
return a / b;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting when dividing by zero.
*
* Counterpart to Solidity's `%` operator. 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 mod(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0, "SafeMath: modulo by zero");
return a % b;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on
* overflow (when the result is negative).
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {trySub}.
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b <= a, errorMessage);
return a - b;
}
/**
* @dev Returns the integer division of two unsigned integers, reverting with custom message on
* division by zero. The result is rounded towards zero.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryDiv}.
*
* 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, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
return a / b;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting with custom message when dividing by zero.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryMod}.
*
* Counterpart to Solidity's `%` operator. 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 mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
return a % b;
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.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 SafeMathChainlink {
/**
* @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;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* Reverts when dividing by zero.
*
* Counterpart to Solidity's `%` operator. 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 mod(uint256 a, uint256 b) internal pure returns (uint256) {
require(b != 0, "SafeMath: modulo by zero");
return a % b;
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
import "./vendor/SafeMathChainlink.sol";
import "./interfaces/LinkTokenInterface.sol";
import "./VRFRequestIDBase.sol";
/** ****************************************************************************
* @notice Interface for contracts using VRF randomness
* *****************************************************************************
* @dev PURPOSE
*
* @dev Reggie the Random Oracle (not his real job) wants to provide randomness
* @dev to Vera the verifier in such a way that Vera can be sure he's not
* @dev making his output up to suit himself. Reggie provides Vera a public key
* @dev to which he knows the secret key. Each time Vera provides a seed to
* @dev Reggie, he gives back a value which is computed completely
* @dev deterministically from the seed and the secret key.
*
* @dev Reggie provides a proof by which Vera can verify that the output was
* @dev correctly computed once Reggie tells it to her, but without that proof,
* @dev the output is indistinguishable to her from a uniform random sample
* @dev from the output space.
*
* @dev The purpose of this contract is to make it easy for unrelated contracts
* @dev to talk to Vera the verifier about the work Reggie is doing, to provide
* @dev simple access to a verifiable source of randomness.
* *****************************************************************************
* @dev USAGE
*
* @dev Calling contracts must inherit from VRFConsumerBase, and can
* @dev initialize VRFConsumerBase's attributes in their constructor as
* @dev shown:
*
* @dev contract VRFConsumer {
* @dev constuctor(<other arguments>, address _vrfCoordinator, address _link)
* @dev VRFConsumerBase(_vrfCoordinator, _link) public {
* @dev <initialization with other arguments goes here>
* @dev }
* @dev }
*
* @dev The oracle will have given you an ID for the VRF keypair they have
* @dev committed to (let's call it keyHash), and have told you the minimum LINK
* @dev price for VRF service. Make sure your contract has sufficient LINK, and
* @dev call requestRandomness(keyHash, fee, seed), where seed is the input you
* @dev want to generate randomness from.
*
* @dev Once the VRFCoordinator has received and validated the oracle's response
* @dev to your request, it will call your contract's fulfillRandomness method.
*
* @dev The randomness argument to fulfillRandomness is the actual random value
* @dev generated from your seed.
*
* @dev The requestId argument is generated from the keyHash and the seed by
* @dev makeRequestId(keyHash, seed). If your contract could have concurrent
* @dev requests open, you can use the requestId to track which seed is
* @dev associated with which randomness. See VRFRequestIDBase.sol for more
* @dev details. (See "SECURITY CONSIDERATIONS" for principles to keep in mind,
* @dev if your contract could have multiple requests in flight simultaneously.)
*
* @dev Colliding `requestId`s are cryptographically impossible as long as seeds
* @dev differ. (Which is critical to making unpredictable randomness! See the
* @dev next section.)
*
* *****************************************************************************
* @dev SECURITY CONSIDERATIONS
*
* @dev A method with the ability to call your fulfillRandomness method directly
* @dev could spoof a VRF response with any random value, so it's critical that
* @dev it cannot be directly called by anything other than this base contract
* @dev (specifically, by the VRFConsumerBase.rawFulfillRandomness method).
*
* @dev For your users to trust that your contract's random behavior is free
* @dev from malicious interference, it's best if you can write it so that all
* @dev behaviors implied by a VRF response are executed *during* your
* @dev fulfillRandomness method. If your contract must store the response (or
* @dev anything derived from it) and use it later, you must ensure that any
* @dev user-significant behavior which depends on that stored value cannot be
* @dev manipulated by a subsequent VRF request.
*
* @dev Similarly, both miners and the VRF oracle itself have some influence
* @dev over the order in which VRF responses appear on the blockchain, so if
* @dev your contract could have multiple VRF requests in flight simultaneously,
* @dev you must ensure that the order in which the VRF responses arrive cannot
* @dev be used to manipulate your contract's user-significant behavior.
*
* @dev Since the ultimate input to the VRF is mixed with the block hash of the
* @dev block in which the request is made, user-provided seeds have no impact
* @dev on its economic security properties. They are only included for API
* @dev compatability with previous versions of this contract.
*
* @dev Since the block hash of the block which contains the requestRandomness
* @dev call is mixed into the input to the VRF *last*, a sufficiently powerful
* @dev miner could, in principle, fork the blockchain to evict the block
* @dev containing the request, forcing the request to be included in a
* @dev different block with a different hash, and therefore a different input
* @dev to the VRF. However, such an attack would incur a substantial economic
* @dev cost. This cost scales with the number of blocks the VRF oracle waits
* @dev until it calls responds to a request.
*/
abstract contract VRFConsumerBase is VRFRequestIDBase {
using SafeMathChainlink for uint256;
/**
* @notice fulfillRandomness handles the VRF response. Your contract must
* @notice implement it. See "SECURITY CONSIDERATIONS" above for important
* @notice principles to keep in mind when implementing your fulfillRandomness
* @notice method.
*
* @dev VRFConsumerBase expects its subcontracts to have a method with this
* @dev signature, and will call it once it has verified the proof
* @dev associated with the randomness. (It is triggered via a call to
* @dev rawFulfillRandomness, below.)
*
* @param requestId The Id initially returned by requestRandomness
* @param randomness the VRF output
*/
function fulfillRandomness(bytes32 requestId, uint256 randomness)
internal virtual;
/**
* @notice requestRandomness initiates a request for VRF output given _seed
*
* @dev The fulfillRandomness method receives the output, once it's provided
* @dev by the Oracle, and verified by the vrfCoordinator.
*
* @dev The _keyHash must already be registered with the VRFCoordinator, and
* @dev the _fee must exceed the fee specified during registration of the
* @dev _keyHash.
*
* @dev The _seed parameter is vestigial, and is kept only for API
* @dev compatibility with older versions. It can't *hurt* to mix in some of
* @dev your own randomness, here, but it's not necessary because the VRF
* @dev oracle will mix the hash of the block containing your request into the
* @dev VRF seed it ultimately uses.
*
* @param _keyHash ID of public key against which randomness is generated
* @param _fee The amount of LINK to send with the request
* @param _seed seed mixed into the input of the VRF.
*
* @return requestId unique ID for this request
*
* @dev The returned requestId can be used to distinguish responses to
* @dev concurrent requests. It is passed as the first argument to
* @dev fulfillRandomness.
*/
function requestRandomness(bytes32 _keyHash, uint256 _fee, uint256 _seed)
internal returns (bytes32 requestId)
{
LINK.transferAndCall(vrfCoordinator, _fee, abi.encode(_keyHash, _seed));
// This is the seed passed to VRFCoordinator. The oracle will mix this with
// the hash of the block containing this request to obtain the seed/input
// which is finally passed to the VRF cryptographic machinery.
uint256 vRFSeed = makeVRFInputSeed(_keyHash, _seed, address(this), nonces[_keyHash]);
// nonces[_keyHash] must stay in sync with
// VRFCoordinator.nonces[_keyHash][this], which was incremented by the above
// successful LINK.transferAndCall (in VRFCoordinator.randomnessRequest).
// This provides protection against the user repeating their input seed,
// which would result in a predictable/duplicate output, if multiple such
// requests appeared in the same block.
nonces[_keyHash] = nonces[_keyHash].add(1);
return makeRequestId(_keyHash, vRFSeed);
}
LinkTokenInterface immutable internal LINK;
address immutable private vrfCoordinator;
// Nonces for each VRF key from which randomness has been requested.
//
// Must stay in sync with VRFCoordinator[_keyHash][this]
mapping(bytes32 /* keyHash */ => uint256 /* nonce */) private nonces;
/**
* @param _vrfCoordinator address of VRFCoordinator contract
* @param _link address of LINK token contract
*
* @dev https://docs.chain.link/docs/link-token-contracts
*/
constructor(address _vrfCoordinator, address _link) public {
vrfCoordinator = _vrfCoordinator;
LINK = LinkTokenInterface(_link);
}
// rawFulfillRandomness is called by VRFCoordinator when it receives a valid VRF
// proof. rawFulfillRandomness then calls fulfillRandomness, after validating
// the origin of the call
function rawFulfillRandomness(bytes32 requestId, uint256 randomness) external {
require(msg.sender == vrfCoordinator, "Only VRFCoordinator can fulfill");
fulfillRandomness(requestId, randomness);
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
contract VRFRequestIDBase {
/**
* @notice returns the seed which is actually input to the VRF coordinator
*
* @dev To prevent repetition of VRF output due to repetition of the
* @dev user-supplied seed, that seed is combined in a hash with the
* @dev user-specific nonce, and the address of the consuming contract. The
* @dev risk of repetition is mostly mitigated by inclusion of a blockhash in
* @dev the final seed, but the nonce does protect against repetition in
* @dev requests which are included in a single block.
*
* @param _userSeed VRF seed input provided by user
* @param _requester Address of the requesting contract
* @param _nonce User-specific nonce at the time of the request
*/
function makeVRFInputSeed(bytes32 _keyHash, uint256 _userSeed,
address _requester, uint256 _nonce)
internal pure returns (uint256)
{
return uint256(keccak256(abi.encode(_keyHash, _userSeed, _requester, _nonce)));
}
/**
* @notice Returns the id for this request
* @param _keyHash The serviceAgreement ID to be used for this request
* @param _vRFInputSeed The seed to be passed directly to the VRF
* @return The id for this request
*
* @dev Note that _vRFInputSeed is not the seed passed by the consuming
* @dev contract, but the one generated by makeVRFInputSeed
*/
function makeRequestId(
bytes32 _keyHash, uint256 _vRFInputSeed) internal pure returns (bytes32) {
return keccak256(abi.encodePacked(_keyHash, _vRFInputSeed));
}
}
{
"compilationTarget": {
"contracts/Coupon/Coupon.sol": "Coupon"
},
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs",
"useLiteralContent": true
},
"optimizer": {
"enabled": true,
"runs": 1000
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"cryptorchidsAddress","type":"address"},{"internalType":"address","name":"_VRFCoordinator","type":"address"},{"internalType":"address","name":"_LinkToken","type":"address"},{"internalType":"bytes32","name":"_keyhash","type":"bytes32"}],"stateMutability":"payable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[],"name":"LinkToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VRFCoordinator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"addressEntriesCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"checkEligibility","outputs":[{"internalType":"uint256[]","name":"eligibleTokens","type":"uint256[]"},{"internalType":"uint256","name":"rebateAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cryptorchidsERC721","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentRebate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"drawingEntriesCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"enter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pot","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"promotionEnd","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"promotionOpen","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"promotionStart","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"requestId","type":"bytes32"},{"internalType":"uint256","name":"randomness","type":"uint256"}],"name":"rawFulfillRandomness","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rebatesAvailable","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"redeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newPromotionEnd","type":"uint256"}],"name":"reset","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"userProvidedSeed","type":"uint256"}],"name":"selectWinner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"setCurrentRebate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenRebate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"winner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"winnerRequested","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdrawUnclaimed","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawWinner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]