Skip to content

Instantly share code, notes, and snippets.

@bmeredith
Forked from ebrahimasifismail/Context.sol
Last active May 31, 2021 18:18
Show Gist options
  • Save bmeredith/703571357ce58434ef6ada32b621d076 to your computer and use it in GitHub Desktop.
Save bmeredith/703571357ce58434ef6ada32b621d076 to your computer and use it in GitHub Desktop.
Sample Contracts
pragma solidity ^0.5.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;
}
}
pragma solidity ^0.5.0;
import "./ERC721Tradable.sol";
import "./Ownable.sol";
/**
* @title Creature
* Creature - a contract for my non-fungible creatures.
*/
contract Creature is ERC721Tradable {
constructor(address _proxyRegistryAddress) ERC721Tradable("Creature", "OSC", _proxyRegistryAddress) public { }
function baseTokenURI() public view returns (string memory) {
return "https://creatures-api.opensea.io/api/creature/";
}
function contractURI() public view returns (string memory) {
return "https://creatures-api.opensea.io/contract/opensea-creatures";
}
}
pragma solidity ^0.5.11;
import "./ERC1155Tradable.sol";
/**
* @title CreatureAccessory
* CreatureAccessory - a contract for Creature Accessory semi-fungible tokens.
*/
contract CreatureAccessory is ERC1155Tradable {
constructor(address _proxyRegistryAddress) ERC1155Tradable(
"OpenSea Creature Accessory",
"OSCA",
_proxyRegistryAddress
) public {
_setBaseMetadataURI("https://creatures-api.opensea.io/api/accessory/");
}
function contractURI() public view returns (string memory) {
return "https://creatures-api.opensea.io/contract/opensea-erc1155";
}
}
pragma solidity ^0.5.11;
import "openzeppelin-solidity/contracts/ownership/Ownable.sol";
import "openzeppelin-solidity/contracts/utils/ReentrancyGuard.sol";
import "./IFactory.sol";
import "./ERC1155Tradable.sol";
import "./Strings.sol";
/**
* @title CreatureAccessoryFactory
* CreatureAccessory - a factory contract for Creature Accessory semi-fungible
* tokens.
*/
contract CreatureAccessoryFactory is IFactory, Ownable, ReentrancyGuard {
using Strings for string;
using SafeMath for uint256;
address public proxyRegistryAddress;
address public nftAddress;
address public lootBoxAddress;
string constant internal baseMetadataURI = "https://creatures-api.opensea.io/api/";
uint256 constant UINT256_MAX = ~uint256(0);
/**
* Optionally set this to a small integer to enforce limited existence per option/token ID
* (Otherwise rely on sell orders on OpenSea, which can only be made by the factory owner.)
*/
uint256 constant SUPPLY_PER_TOKEN_ID = UINT256_MAX;
// The number of creature accessories (not creature accessory rarity classes!)
uint256 constant NUM_ITEM_OPTIONS = 6;
/**
* Three different options for minting CreatureAccessories (basic, premium, and gold).
*/
uint256 constant public BASIC_LOOTBOX = NUM_ITEM_OPTIONS + 0;
uint256 constant public PREMIUM_LOOTBOX = NUM_ITEM_OPTIONS + 1;
uint256 constant public GOLD_LOOTBOX = NUM_ITEM_OPTIONS + 2;
uint256 constant public NUM_LOOTBOX_OPTIONS = 3;
uint256 constant public NUM_OPTIONS = NUM_ITEM_OPTIONS + NUM_LOOTBOX_OPTIONS;
constructor(
address _proxyRegistryAddress,
address _nftAddress,
address _lootBoxAddress
) public {
proxyRegistryAddress = _proxyRegistryAddress;
nftAddress = _nftAddress;
lootBoxAddress = _lootBoxAddress;
}
/////
// FACTORY INTERFACE METHODS
/////
function name() external view returns (string memory) {
return "OpenSea Creature Accessory Pre-Sale";
}
function symbol() external view returns (string memory) {
return "OSCAP";
}
function supportsFactoryInterface() external view returns (bool) {
return true;
}
function factorySchemaName() external view returns (string memory) {
return "ERC1155";
}
function numOptions() external view returns (uint256) {
return NUM_LOOTBOX_OPTIONS + NUM_ITEM_OPTIONS;
}
function uri(uint256 _optionId) external view returns (string memory) {
return Strings.strConcat(
baseMetadataURI,
"factory/",
Strings.uint2str(_optionId)
);
}
function canMint(uint256 _optionId, uint256 _amount) external view returns (bool) {
return _canMint(msg.sender, _optionId, _amount);
}
function mint(uint256 _optionId, address _toAddress, uint256 _amount, bytes calldata _data) external nonReentrant() {
return _mint(_optionId, _toAddress, _amount, _data);
}
/**
* @dev Main minting logic implemented here!
*/
function _mint(
uint256 _option,
address _toAddress,
uint256 _amount,
bytes memory _data
) internal {
require(_canMint(msg.sender, _option, _amount), "CreatureAccessoryFactory#_mint: CANNOT_MINT_MORE");
if (_option < NUM_ITEM_OPTIONS) {
require(
_isOwnerOrProxy(msg.sender) || msg.sender == lootBoxAddress,
"Caller cannot mint accessories"
);
// Items are pre-mined (by the owner), so transfer them (We are an
// operator for the owner).
ERC1155Tradable items = ERC1155Tradable(nftAddress);
// Option is used as a token ID here
items.safeTransferFrom(owner(), _toAddress, _option, _amount, _data);
} else if (_option < NUM_OPTIONS) {
require(_isOwnerOrProxy(msg.sender), "Caller cannot mint boxes");
uint256 lootBoxOption = _option - NUM_ITEM_OPTIONS;
// LootBoxes are not premined, so we need to create or mint them.
// lootBoxOption is used as a token ID here.
_createOrMint(lootBoxAddress, _toAddress, lootBoxOption, _amount, _data);
} else {
revert("Unknown _option");
}
}
/*
* Note: make sure code that calls this is non-reentrant.
* Note: this is the token _id *within* the ERC1155 contract, not the option
* id from this contract.
*/
function _createOrMint (address _erc1155Address, address _to, uint256 _id, uint256 _amount, bytes memory _data)
internal {
ERC1155Tradable tradable = ERC1155Tradable(_erc1155Address);
// Lazily create the token
if (! tradable.exists(_id)) {
tradable.create(_to, _id, _amount, "", _data);
} else {
tradable.mint(_to, _id, _amount, _data);
}
}
/**
* Get the factory's ownership of Option.
* Should be the amount it can still mint.
* NOTE: Called by `canMint`
*/
function balanceOf(
address _owner,
uint256 _optionId
) public view returns (uint256) {
if (_optionId < NUM_ITEM_OPTIONS) {
if (!_isOwnerOrProxy(_owner) && _owner != lootBoxAddress) {
// Only the factory's owner or owner's proxy,
// or the lootbox can have supply
return 0;
}
// The pre-minted balance belongs to the address that minted this contract
ERC1155Tradable lootBox = ERC1155Tradable(nftAddress);
// OptionId is used as a token ID here
uint256 currentSupply = lootBox.balanceOf(owner(), _optionId);
return currentSupply;
} else {
if (!_isOwnerOrProxy(_owner)) {
// Only the factory owner or owner's proxy can have supply
return 0;
}
// We explicitly calculate the token ID here
uint256 tokenId = (_optionId - NUM_ITEM_OPTIONS);
ERC1155Tradable lootBox = ERC1155Tradable(lootBoxAddress);
uint256 currentSupply = lootBox.totalSupply(tokenId);
// We can mint up to a balance of SUPPLY_PER_TOKEN_ID
return SUPPLY_PER_TOKEN_ID.sub(currentSupply);
}
}
function _canMint(
address _fromAddress,
uint256 _optionId,
uint256 _amount
) internal view returns (bool) {
return _amount > 0 && balanceOf(_fromAddress, _optionId) >= _amount;
}
function _isOwnerOrProxy(
address _address
) internal view returns (bool) {
ProxyRegistry proxyRegistry = ProxyRegistry(proxyRegistryAddress);
return owner() == _address || address(proxyRegistry.proxies(owner())) == _address;
}
}
pragma solidity ^0.5.11;
import "openzeppelin-solidity/contracts/utils/ReentrancyGuard.sol";
import "./ERC1155Tradable.sol";
import "./LootBoxRandomness.sol";
/**
* @title CreatureAccessoryLootBox
* CreatureAccessoryLootBox - a randomized and openable lootbox of Creature
* Accessories.
*/
contract CreatureAccessoryLootBox is ERC1155Tradable, ReentrancyGuard {
using LootBoxRandomness for LootBoxRandomness.LootBoxRandomnessState;
LootBoxRandomness.LootBoxRandomnessState state;
mapping (uint256 => uint256) tokenSupply;
/**
* @dev Example constructor. Sets minimal configuration.
* @param _proxyRegistryAddress The address of the OpenSea/Wyvern proxy registry
* On Rinkeby: "0xf57b2c51ded3a29e6891aba85459d600256cf317"
* On mainnet: "0xa5409ec958c83c3f309868babaca7c86dcb077c1"
*/
constructor(address _proxyRegistryAddress)
ERC1155Tradable(
"OpenSea Creature Accessory Loot Box",
"OSCALOOT",
_proxyRegistryAddress
)
public {
}
function setState(
address _factoryAddress,
uint256 _numOptions,
uint256 _numClasses,
uint256 _seed
) public onlyOwner {
LootBoxRandomness.initState(state, _factoryAddress, _numOptions, _numClasses, _seed);
}
function setTokenIdsForClass(
uint256 _classId,
uint256[] memory _tokenIds
) public onlyOwner {
LootBoxRandomness.setTokenIdsForClass(state, _classId, _tokenIds);
}
function setOptionSettings(
uint256 _option,
uint256 _maxQuantityPerOpen,
uint16[] memory _classProbabilities,
uint16[] memory _guarantees
) public onlyOwner {
LootBoxRandomness.setOptionSettings(state, _option, _maxQuantityPerOpen, _classProbabilities, _guarantees);
}
///////
// MAIN FUNCTIONS
//////
function unpack(
uint256 _optionId,
address _toAddress,
uint256 _amount
) external {
// This will underflow if msg.sender does not own enough tokens.
_burn(msg.sender, _optionId, _amount);
// Mint nfts contained by LootBox
LootBoxRandomness._mint(state, _optionId, _toAddress, _amount, "", address(this));
}
/**
* @dev Mint the token/option id.
*/
function mint(
address _to,
uint256 _optionId,
uint256 _amount,
bytes memory _data
) public nonReentrant {
require(_isOwnerOrProxy(msg.sender), "Lootbox: owner or proxy only");
require(_optionId < state.numOptions, "Lootbox: Invalid Option");
// Option ID is used as a token ID here
_mint(_to, _optionId, _amount, _data);
}
/**
* @dev track the number of tokens minted.
*/
function _mint(
address _to,
uint256 _id,
uint256 _quantity,
bytes memory _data
) internal {
tokenSupply[_id] = tokenSupply[_id].add(_quantity);
super._mint(_to, _id, _quantity, _data);
}
function _isOwnerOrProxy(
address _address
) internal view returns (bool) {
ProxyRegistry proxyRegistry = ProxyRegistry(proxyRegistryAddress);
return owner() == _address || address(proxyRegistry.proxies(owner())) == _address;
}
}
pragma solidity ^0.5.0;
import "openzeppelin-solidity/contracts/ownership/Ownable.sol";
import "./Factory.sol";
import "./Creature.sol";
import "./CreatureLootBox.sol";
import "./Strings.sol";
contract CreatureFactory is Factory, Ownable {
using Strings for string;
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
address public proxyRegistryAddress;
address public nftAddress;
address public lootBoxNftAddress;
string public baseURI = "https://creatures-api.opensea.io/api/factory/";
/**
* Enforce the existence of only 100 OpenSea creatures.
*/
uint256 CREATURE_SUPPLY = 100;
/**
* Three different options for minting Creatures (basic, premium, and gold).
*/
uint256 NUM_OPTIONS = 3;
uint256 SINGLE_CREATURE_OPTION = 0;
uint256 MULTIPLE_CREATURE_OPTION = 1;
uint256 LOOTBOX_OPTION = 2;
uint256 NUM_CREATURES_IN_MULTIPLE_CREATURE_OPTION = 4;
constructor(address _proxyRegistryAddress, address _nftAddress) public {
proxyRegistryAddress = _proxyRegistryAddress;
nftAddress = _nftAddress;
lootBoxNftAddress = address(new CreatureLootBox(_proxyRegistryAddress, address(this)));
fireTransferEvents(address(0), owner());
}
function name() external view returns (string memory) {
return "OpenSeaCreature Item Sale";
}
function symbol() external view returns (string memory) {
return "CPF";
}
function supportsFactoryInterface() public view returns (bool) {
return true;
}
function numOptions() public view returns (uint256) {
return NUM_OPTIONS;
}
function transferOwnership(address newOwner) public onlyOwner {
address _prevOwner = owner();
super.transferOwnership(newOwner);
fireTransferEvents(_prevOwner, newOwner);
}
function fireTransferEvents(address _from, address _to) private {
for (uint256 i = 0; i < NUM_OPTIONS; i++) {
emit Transfer(_from, _to, i);
}
}
function mint(uint256 _optionId, address _toAddress) public {
// Must be sent from the owner proxy or owner.
ProxyRegistry proxyRegistry = ProxyRegistry(proxyRegistryAddress);
assert(address(proxyRegistry.proxies(owner())) == msg.sender || owner() == msg.sender || msg.sender == lootBoxNftAddress);
require(canMint(_optionId));
Creature openSeaCreature = Creature(nftAddress);
if (_optionId == SINGLE_CREATURE_OPTION) {
openSeaCreature.mintTo(_toAddress);
} else if (_optionId == MULTIPLE_CREATURE_OPTION) {
for (uint256 i = 0; i < NUM_CREATURES_IN_MULTIPLE_CREATURE_OPTION; i++) {
openSeaCreature.mintTo(_toAddress);
}
} else if (_optionId == LOOTBOX_OPTION) {
CreatureLootBox openSeaCreatureLootBox = CreatureLootBox(lootBoxNftAddress);
openSeaCreatureLootBox.mintTo(_toAddress);
}
}
function canMint(uint256 _optionId) public view returns (bool) {
if (_optionId >= NUM_OPTIONS) {
return false;
}
Creature openSeaCreature = Creature(nftAddress);
uint256 creatureSupply = openSeaCreature.totalSupply();
uint256 numItemsAllocated = 0;
if (_optionId == SINGLE_CREATURE_OPTION) {
numItemsAllocated = 1;
} else if (_optionId == MULTIPLE_CREATURE_OPTION) {
numItemsAllocated = NUM_CREATURES_IN_MULTIPLE_CREATURE_OPTION;
} else if (_optionId == LOOTBOX_OPTION) {
CreatureLootBox openSeaCreatureLootBox = CreatureLootBox(lootBoxNftAddress);
numItemsAllocated = openSeaCreatureLootBox.itemsPerLootbox();
}
return creatureSupply < (CREATURE_SUPPLY - numItemsAllocated);
}
function tokenURI(uint256 _optionId) external view returns (string memory) {
return Strings.strConcat(
baseURI,
Strings.uint2str(_optionId)
);
}
/**
* Hack to get things to work automatically on OpenSea.
* Use transferFrom so the frontend doesn't have to worry about different method names.
*/
function transferFrom(address _from, address _to, uint256 _tokenId) public {
mint(_tokenId, _to);
}
/**
* Hack to get things to work automatically on OpenSea.
* Use isApprovedForAll so the frontend doesn't have to worry about different method names.
*/
function isApprovedForAll(
address _owner,
address _operator
)
public
view
returns (bool)
{
if (owner() == _owner && _owner == _operator) {
return true;
}
ProxyRegistry proxyRegistry = ProxyRegistry(proxyRegistryAddress);
if (owner() == _owner && address(proxyRegistry.proxies(_owner)) == _operator) {
return true;
}
return false;
}
/**
* Hack to get things to work automatically on OpenSea.
* Use isApprovedForAll so the frontend doesn't have to worry about different method names.
*/
function ownerOf(uint256 _tokenId) public view returns (address _owner) {
return owner();
}
}
pragma solidity ^0.5.0;
import "./ERC721Tradable.sol";
import "./Creature.sol";
import "./Factory.sol";
import "openzeppelin-solidity/contracts/ownership/Ownable.sol";
/**
* @title CreatureLootBox
*
* CreatureLootBox - a tradeable loot box of Creatures.
*/
contract CreatureLootBox is ERC721Tradable {
uint256 NUM_CREATURES_PER_BOX = 3;
uint256 OPTION_ID = 0;
address factoryAddress;
constructor(address _proxyRegistryAddress, address _factoryAddress) ERC721Tradable("CreatureLootBox", "LOOTBOX", _proxyRegistryAddress) public {
factoryAddress = _factoryAddress;
}
function unpack(uint256 _tokenId) public {
require(ownerOf(_tokenId) == msg.sender);
// Insert custom logic for configuring the item here.
for (uint256 i = 0; i < NUM_CREATURES_PER_BOX; i++) {
// Mint the ERC721 item(s).
Factory factory = Factory(factoryAddress);
factory.mint(OPTION_ID, msg.sender);
}
// Burn the presale item.
_burn(msg.sender, _tokenId);
}
function baseTokenURI() public view returns (string memory) {
return "creatures-api.opensea.io/api/box/";
}
function itemsPerLootbox() public view returns (uint256) {
return NUM_CREATURES_PER_BOX;
}
}
pragma solidity ^0.5.12;
import "./Ownable.sol";
import 'multi-token-standard/contracts/tokens/ERC1155/ERC1155.sol';
import 'multi-token-standard/contracts/tokens/ERC1155/ERC1155Metadata.sol';
import 'multi-token-standard/contracts/tokens/ERC1155/ERC1155MintBurn.sol';
import "./Strings.sol";
contract OwnableDelegateProxy { }
contract ProxyRegistry {
mapping(address => OwnableDelegateProxy) public proxies;
}
/**
* @title ERC1155Tradable
* ERC1155Tradable - ERC1155 contract that whitelists an operator address, has create and mint functionality, and supports useful standards from OpenZeppelin,
like _exists(), name(), symbol(), and totalSupply()
*/
contract ERC1155Tradable is ERC1155, ERC1155MintBurn, ERC1155Metadata, Ownable {
using Strings for string;
address proxyRegistryAddress;
mapping (uint256 => address) public creators;
mapping (uint256 => uint256) public tokenSupply;
mapping (uint256 => string) customUri;
// Contract name
string public name;
// Contract symbol
string public symbol;
/**
* @dev Require msg.sender to be the creator of the token id
*/
modifier creatorOnly(uint256 _id) {
require(creators[_id] == msg.sender, "ERC1155Tradable#creatorOnly: ONLY_CREATOR_ALLOWED");
_;
}
/**
* @dev Require msg.sender to own more than 0 of the token id
*/
modifier ownersOnly(uint256 _id) {
require(balances[msg.sender][_id] > 0, "ERC1155Tradable#ownersOnly: ONLY_OWNERS_ALLOWED");
_;
}
constructor(
string memory _name,
string memory _symbol,
address _proxyRegistryAddress
) public {
name = _name;
symbol = _symbol;
proxyRegistryAddress = _proxyRegistryAddress;
}
function uri(
uint256 _id
) public view returns (string memory) {
require(_exists(_id), "ERC1155Tradable#uri: NONEXISTENT_TOKEN");
// We have to convert string to bytes to check for existence
bytes memory customUriBytes = bytes(customUri[_id]);
if (customUriBytes.length > 0) {
return customUri[_id];
} else {
return Strings.strConcat(
baseMetadataURI,
Strings.uint2str(_id)
);
}
}
/**
* @dev Returns the total quantity for a token ID
* @param _id uint256 ID of the token to query
* @return amount of token in existence
*/
function totalSupply(
uint256 _id
) public view returns (uint256) {
return tokenSupply[_id];
}
/**
* @dev Will update the base URL of token's URI
* @param _newBaseMetadataURI New base URL of token's URI
*/
function setBaseMetadataURI(
string memory _newBaseMetadataURI
) public onlyOwner {
_setBaseMetadataURI(_newBaseMetadataURI);
}
/**
* @dev Will update the base URI for the token
* @param _tokenId The token to upddate. msg.sender must be its creator.
* @param _newURI New URI for the token.
*/
function setCustomURI(
uint256 _tokenId,
string memory _newURI
) public creatorOnly(_tokenId) {
customUri[_tokenId] = _newURI;
emit URI(_newURI, _tokenId);
}
/**
* @dev Creates a new token type and assigns _initialSupply to an address
* NOTE: remove onlyOwner if you want third parties to create new tokens on
* your contract (which may change your IDs)
* NOTE: The token id must be passed. This allows lazy creation of tokens or
* creating NFTs by setting the id's high bits with the method
* described in ERC1155 or to use ids representing values other than
* successive small integers. If you wish to create ids as successive
* small integers you can either subclass this class to count onchain
* or maintain the offchain cache of identifiers recommended in
* ERC1155 and calculate successive ids from that.
* @param _initialOwner address of the first owner of the token
* @param _id The id of the token to create (must not currenty exist).
* @param _initialSupply amount to supply the first owner
* @param _uri Optional URI for this token type
* @param _data Data to pass if receiver is contract
* @return The newly created token ID
*/
function create(
address _initialOwner,
uint256 _id,
uint256 _initialSupply,
string memory _uri,
bytes memory _data
) public onlyOwner returns (uint256) {
require(!_exists(_id), "token _id already exists");
creators[_id] = msg.sender;
if (bytes(_uri).length > 0) {
customUri[_id] = _uri;
emit URI(_uri, _id);
}
_mint(_initialOwner, _id, _initialSupply, _data);
tokenSupply[_id] = _initialSupply;
return _id;
}
/**
* @dev Mints some amount of tokens to an address
* @param _to Address of the future owner of the token
* @param _id Token ID to mint
* @param _quantity Amount of tokens to mint
* @param _data Data to pass if receiver is contract
*/
function mint(
address _to,
uint256 _id,
uint256 _quantity,
bytes memory _data
) public creatorOnly(_id) {
_mint(_to, _id, _quantity, _data);
tokenSupply[_id] = tokenSupply[_id].add(_quantity);
}
/**
* @dev Mint tokens for each id in _ids
* @param _to The address to mint tokens to
* @param _ids Array of ids to mint
* @param _quantities Array of amounts of tokens to mint per id
* @param _data Data to pass if receiver is contract
*/
function batchMint(
address _to,
uint256[] memory _ids,
uint256[] memory _quantities,
bytes memory _data
) public {
for (uint256 i = 0; i < _ids.length; i++) {
uint256 _id = _ids[i];
require(creators[_id] == msg.sender, "ERC1155Tradable#batchMint: ONLY_CREATOR_ALLOWED");
uint256 quantity = _quantities[i];
tokenSupply[_id] = tokenSupply[_id].add(quantity);
}
_batchMint(_to, _ids, _quantities, _data);
}
/**
* @dev Change the creator address for given tokens
* @param _to Address of the new creator
* @param _ids Array of Token IDs to change creator
*/
function setCreator(
address _to,
uint256[] memory _ids
) public {
require(_to != address(0), "ERC1155Tradable#setCreator: INVALID_ADDRESS.");
for (uint256 i = 0; i < _ids.length; i++) {
uint256 id = _ids[i];
_setCreator(_to, id);
}
}
/**
* Override isApprovedForAll to whitelist user's OpenSea proxy accounts to enable gas-free listings.
*/
function isApprovedForAll(
address _owner,
address _operator
) public view returns (bool isOperator) {
// Whitelist OpenSea proxy contract for easy trading.
ProxyRegistry proxyRegistry = ProxyRegistry(proxyRegistryAddress);
if (address(proxyRegistry.proxies(_owner)) == _operator) {
return true;
}
return ERC1155.isApprovedForAll(_owner, _operator);
}
/**
* @dev Change the creator address for given token
* @param _to Address of the new creator
* @param _id Token IDs to change creator of
*/
function _setCreator(address _to, uint256 _id) internal creatorOnly(_id)
{
creators[_id] = _to;
}
/**
* @dev Returns whether the specified token exists by checking to see if it has a creator
* @param _id uint256 ID of the token to query the existence of
* @return bool whether the token exists
*/
function _exists(
uint256 _id
) internal view returns (bool) {
return creators[_id] != address(0);
}
function exists(
uint256 _id
) external view returns (bool) {
return _exists(_id);
}
}
pragma solidity ^0.5.0;
import 'https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v2.3.0/contracts/token/ERC721/ERC721Full.sol';
import './Ownable.sol';
import './Strings.sol';
contract OwnableDelegateProxy { }
contract ProxyRegistry {
mapping(address => OwnableDelegateProxy) public proxies;
}
/**
* @title ERC721Tradable
* ERC721Tradable - ERC721 contract that whitelists a trading address, and has minting functionality.
*/
contract ERC721Tradable is ERC721Full, Ownable {
using Strings for string;
address proxyRegistryAddress;
uint256 private _currentTokenId = 0;
constructor(string memory _name, string memory _symbol, address _proxyRegistryAddress) ERC721Full(_name, _symbol) public {
proxyRegistryAddress = _proxyRegistryAddress;
}
/**
* @dev Mints a token to an address with a tokenURI.
* @param _to address of the future owner of the token
*/
function mintTo(address _to) public onlyOwner {
uint256 newTokenId = _getNextTokenId();
_mint(_to, newTokenId);
_incrementTokenId();
}
/**
* @dev calculates the next token ID based on value of _currentTokenId
* @return uint256 for the next token ID
*/
function _getNextTokenId() private view returns (uint256) {
return _currentTokenId.add(1);
}
/**
* @dev increments the value of _currentTokenId
*/
function _incrementTokenId() private {
_currentTokenId++;
}
function baseTokenURI() public view returns (string memory) {
return "";
}
function tokenURI(uint256 _tokenId) external view returns (string memory) {
return Strings.strConcat(
baseTokenURI(),
Strings.uint2str(_tokenId)
);
}
/**
* Override isApprovedForAll to whitelist user's OpenSea proxy accounts to enable gas-less listings.
*/
function isApprovedForAll(
address owner,
address operator
)
public
view
returns (bool)
{
// Whitelist OpenSea proxy contract for easy trading.
ProxyRegistry proxyRegistry = ProxyRegistry(proxyRegistryAddress);
if (address(proxyRegistry.proxies(owner)) == operator) {
return true;
}
return super.isApprovedForAll(owner, operator);
}
}
pragma solidity ^0.5.0;
/**
* This is a generic factory contract that can be used to mint tokens. The configuration
* for minting is specified by an _optionId, which can be used to delineate various
* ways of minting.
*/
interface Factory {
/**
* Returns the name of this factory.
*/
function name() external view returns (string memory);
/**
* Returns the symbol for this factory.
*/
function symbol() external view returns (string memory);
/**
* Number of options the factory supports.
*/
function numOptions() external view returns (uint256);
/**
* @dev Returns whether the option ID can be minted. Can return false if the developer wishes to
* restrict a total supply per option ID (or overall).
*/
function canMint(uint256 _optionId) external view returns (bool);
/**
* @dev Returns a URL specifying some metadata about the option. This metadata can be of the
* same structure as the ERC721 metadata.
*/
function tokenURI(uint256 _optionId) external view returns (string memory);
/**
* Indicates that this is a factory contract. Ideally would use EIP 165 supportsInterface()
*/
function supportsFactoryInterface() external view returns (bool);
/**
* @dev Mints asset(s) in accordance to a specific address with a particular "option". This should be
* callable only by the contract owner or the owner's Wyvern Proxy (later universal login will solve this).
* Options should also be delineated 0 - (numOptions() - 1) for convenient indexing.
* @param _optionId the option id
* @param _toAddress address of the future owner of the asset(s)
*/
function mint(uint256 _optionId, address _toAddress) external;
}
pragma solidity ^0.5.0;
/**
* This is a generic factory contract that can be used to mint tokens. The configuration
* for minting is specified by an _optionId, which can be used to delineate various
* ways of minting.
*/
interface IFactory {
/**
* Returns the name of this factory.
*/
function name() external view returns (string memory);
/**
* Returns the symbol for this factory.
*/
function symbol() external view returns (string memory);
/**
* Number of options the factory supports.
*/
function numOptions() external view returns (uint256);
/**
* @dev Returns whether the option ID can be minted. Can return false if the developer wishes to
* restrict a total supply per option ID (or overall).
*/
function canMint(uint256 _optionId, uint256 _amount) external view returns (bool);
/**
* @dev Returns a URL specifying some metadata about the option. This metadata can be of the
* same structure as the ERC1155 metadata.
*/
function uri(uint256 _optionId) external view returns (string memory);
/**
* Indicates that this is a factory contract. Ideally would use EIP 165 supportsInterface()
*/
function supportsFactoryInterface() external view returns (bool);
/**
* Indicates the Wyvern schema name for assets in this lootbox, e.g. "ERC1155"
*/
function factorySchemaName() external view returns (string memory);
/**
* @dev Mints asset(s) in accordance to a specific address with a particular "option". This should be
* callable only by the contract owner or the owner's Wyvern Proxy (later universal login will solve this).
* Options should also be delineated 0 - (numOptions() - 1) for convenient indexing.
* @param _optionId the option id
* @param _toAddress address of the future owner of the asset(s)
* @param _amount amount of the option to mint
* @param _data Extra data to pass during safeTransferFrom
*/
function mint(uint256 _optionId, address _toAddress, uint256 _amount, bytes calldata _data) external;
///////
// Get things to work on OpenSea with mock methods below
///////
//function safeTransferFrom(address _from, address _to, uint256 _optionId, uint256 _amount, bytes calldata _data) external;
function balanceOf(address _owner, uint256 _optionId) external view returns (uint256);
//function isApprovedForAll(address _owner, address _operator) external view returns (bool);
}
pragma solidity ^0.5.11;
import ./SafeMath.sol";
/*
DESIGN NOTES:
- We assume Class 0 is common!
- Because this is a library we use a state struct rather than member
variables. This struct is passes as the first argument to any functions that
need it. This can make some function signatures look strange.
- Because this is a library we cannot call owner(). We could include an owner
field in the state struct, but this would add maintenance overhead for
users of this library who have to make sure they change that field when
changing the owner() of the contract that uses this library. We therefore
append an _owner parameter to the argument list of functions that need to
access owner(), which makes some function signatures (particularly _mint)
look weird but is better than hiding a dependency on an easily broken
state field.
- We also cannot call onlyOwner or whenNotPaused. Users of this library should
not expose any of the methods in this library, and should wrap any code that
uses methods that set, reset, or open anything in onlyOwner().
Code that calls _mint should also be wrapped in nonReentrant() and should
ensure perform the equivalent checks to _canMint() in
CreatureAccessoryFactory.
*/
contract Factory {
function mint(uint256 _optionId, address _toAddress, uint256 _amount, bytes calldata _data) external;
function balanceOf(address _owner, uint256 _optionId) public view returns (uint256);
}
/**
* @title LootBoxRandomness
* LootBoxRandomness- support for a randomized and openable lootbox.
*/
library LootBoxRandomness {
using SafeMath for uint256;
// Event for logging lootbox opens
event LootBoxOpened(uint256 indexed optionId, address indexed buyer, uint256 boxesPurchased, uint256 itemsMinted);
event Warning(string message, address account);
uint256 constant INVERSE_BASIS_POINT = 10000;
// NOTE: Price of the lootbox is set via sell orders on OpenSea
struct OptionSettings {
// Number of items to send per open.
// Set to 0 to disable this Option.
uint256 maxQuantityPerOpen;
// Probability in basis points (out of 10,000) of receiving each class (descending)
uint16[] classProbabilities;
// Whether to enable `guarantees` below
bool hasGuaranteedClasses;
// Number of items you're guaranteed to get, for each class
uint16[] guarantees;
}
struct LootBoxRandomnessState {
address factoryAddress;
uint256 numOptions;
uint256 numClasses;
mapping (uint256 => OptionSettings) optionToSettings;
mapping (uint256 => uint256[]) classToTokenIds;
uint256 seed;
}
//////
// INITIALIZATION FUNCTIONS FOR OWNER
//////
/**
* @dev Set up the fields of the state that should have initial values.
*/
function initState(
LootBoxRandomnessState storage _state,
address _factoryAddress,
uint256 _numOptions,
uint256 _numClasses,
uint256 _seed
) public {
_state.factoryAddress = _factoryAddress;
_state.numOptions = _numOptions;
_state.numClasses = _numClasses;
_state.seed = _seed;
}
/**
* @dev If the tokens for some class are pre-minted and owned by the
* contract owner, they can be used for a given class by setting them here
*/
function setClassForTokenId(
LootBoxRandomnessState storage _state,
uint256 _tokenId,
uint256 _classId
) public {
require(_classId < _state.numClasses, "_class out of range");
_addTokenIdToClass(_state, _classId, _tokenId);
}
/**
* @dev Alternate way to add token ids to a class
* Note: resets the full list for the class instead of adding each token id
*/
function setTokenIdsForClass(
LootBoxRandomnessState storage _state,
uint256 _classId,
uint256[] memory _tokenIds
) public {
require(_classId < _state.numClasses, "_class out of range");
_state.classToTokenIds[_classId] = _tokenIds;
}
/**
* @dev Remove all token ids for a given class, causing it to fall back to
* creating/minting into the nft address
*/
function resetClass(
LootBoxRandomnessState storage _state,
uint256 _classId
) public {require(
_classId < _state.numClasses, "_class out of range");
delete _state.classToTokenIds[_classId];
}
/**
* @dev Set token IDs for each rarity class. Bulk version of `setTokenIdForClass`
* @param _tokenIds List of token IDs to set for each class, specified above in order
*/
//Requires ABIEncoderV2
/*function setTokenIdsForClasses(
LootBoxRandomnessState storage _state,
uint256[][] memory _tokenIds
) public {
require(_tokenIds.length == _state.numClasses, "wrong _tokenIds length");
for (uint256 i = 0; i < _tokenIds.length; i++) {
setTokenIdsForClass(_state, i, _tokenIds[i]);
}
}*/
/**
* @dev Set the settings for a particular lootbox option
* @param _option The Option to set settings for
* @param _maxQuantityPerOpen Maximum number of items to mint per open.
* Set to 0 to disable this option.
* @param _classProbabilities Array of probabilities (basis points, so integers out of 10,000)
* of receiving each class (the index in the array).
* Should add up to 10k and be descending in value.
* @param _guarantees Array of the number of guaranteed items received for each class
* (the index in the array).
*/
function setOptionSettings(
LootBoxRandomnessState storage _state,
uint256 _option,
uint256 _maxQuantityPerOpen,
uint16[] memory _classProbabilities,
uint16[] memory _guarantees
) public {
require(_option < _state.numOptions, "_option out of range");
// Allow us to skip guarantees and save gas at mint time
// if there are no classes with guarantees
bool hasGuaranteedClasses = false;
for (uint256 i = 0; i < _guarantees.length; i++) {
if (_guarantees[i] > 0) {
hasGuaranteedClasses = true;
}
}
OptionSettings memory settings = OptionSettings({
maxQuantityPerOpen: _maxQuantityPerOpen,
classProbabilities: _classProbabilities,
hasGuaranteedClasses: hasGuaranteedClasses,
guarantees: _guarantees
});
_state.optionToSettings[uint256(_option)] = settings;
}
/**
* @dev Improve pseudorandom number generator by letting the owner set the seed manually,
* making attacks more difficult
* @param _newSeed The new seed to use for the next transaction
*/
function setSeed(
LootBoxRandomnessState storage _state,
uint256 _newSeed
) public {
_state.seed = _newSeed;
}
///////
// MAIN FUNCTIONS
//////
/**
* @dev Main minting logic for lootboxes
* This is called via safeTransferFrom when CreatureAccessoryLootBox extends
* CreatureAccessoryFactory.
* NOTE: prices and fees are determined by the sell order on OpenSea.
* WARNING: Make sure msg.sender can mint!
*/
function _mint(
LootBoxRandomnessState storage _state,
uint256 _optionId,
address _toAddress,
uint256 _amount,
bytes memory /* _data */,
address _owner
) internal {
require(_optionId < _state.numOptions, "_option out of range");
// Load settings for this box option
OptionSettings memory settings = _state.optionToSettings[_optionId];
require(settings.maxQuantityPerOpen > 0, "LootBoxRandomness#_mint: OPTION_NOT_ALLOWED");
uint256 totalMinted = 0;
// Iterate over the quantity of boxes specified
for (uint256 i = 0; i < _amount; i++) {
// Iterate over the box's set quantity
uint256 quantitySent = 0;
if (settings.hasGuaranteedClasses) {
// Process guaranteed token ids
for (uint256 classId = 0; classId < settings.guarantees.length; classId++) {
uint256 quantityOfGuaranteed = settings.guarantees[classId];
if(quantityOfGuaranteed > 0) {
_sendTokenWithClass(_state, classId, _toAddress, quantityOfGuaranteed, _owner);
quantitySent += quantityOfGuaranteed;
}
}
}
// Process non-guaranteed ids
while (quantitySent < settings.maxQuantityPerOpen) {
uint256 quantityOfRandomized = 1;
uint256 class = _pickRandomClass(_state, settings.classProbabilities);
_sendTokenWithClass(_state, class, _toAddress, quantityOfRandomized, _owner);
quantitySent += quantityOfRandomized;
}
totalMinted += quantitySent;
}
// Event emissions
emit LootBoxOpened(_optionId, _toAddress, _amount, totalMinted);
}
/////
// HELPER FUNCTIONS
/////
// Returns the tokenId sent to _toAddress
function _sendTokenWithClass(
LootBoxRandomnessState storage _state,
uint256 _classId,
address _toAddress,
uint256 _amount,
address _owner
) internal returns (uint256) {
require(_classId < _state.numClasses, "_class out of range");
Factory factory = Factory(_state.factoryAddress);
uint256 tokenId = _pickRandomAvailableTokenIdForClass(_state, _classId, _amount, _owner);
// This may mint, create or transfer. We don't handle that here.
// We use tokenId as an option ID here.
factory.mint(tokenId, _toAddress, _amount, "");
return tokenId;
}
function _pickRandomClass(
LootBoxRandomnessState storage _state,
uint16[] memory _classProbabilities
) internal returns (uint256) {
uint16 value = uint16(_random(_state).mod(INVERSE_BASIS_POINT));
// Start at top class (length - 1)
// skip common (0), we default to it
for (uint256 i = _classProbabilities.length - 1; i > 0; i--) {
uint16 probability = _classProbabilities[i];
if (value < probability) {
return i;
} else {
value = value - probability;
}
}
//FIXME: assumes zero is common!
return 0;
}
function _pickRandomAvailableTokenIdForClass(
LootBoxRandomnessState storage _state,
uint256 _classId,
uint256 _minAmount,
address _owner
) internal returns (uint256) {
require(_classId < _state.numClasses, "_class out of range");
uint256[] memory tokenIds = _state.classToTokenIds[_classId];
require(tokenIds.length > 0, "No token ids for _classId");
uint256 randIndex = _random(_state).mod(tokenIds.length);
// Make sure owner() owns or can mint enough
Factory factory = Factory(_state.factoryAddress);
for (uint256 i = randIndex; i < randIndex + tokenIds.length; i++) {
uint256 tokenId = tokenIds[i % tokenIds.length];
// We use tokenId as an option id here
if (factory.balanceOf(_owner, tokenId) >= _minAmount) {
return tokenId;
}
}
revert("LootBoxRandomness#_pickRandomAvailableTokenIdForClass: NOT_ENOUGH_TOKENS_FOR_CLASS");
}
/**
* @dev Pseudo-random number generator
* NOTE: to improve randomness, generate it with an oracle
*/
function _random(LootBoxRandomnessState storage _state) internal returns (uint256) {
uint256 randomNumber = uint256(keccak256(abi.encodePacked(blockhash(block.number - 1), msg.sender, _state.seed)));
_state.seed = randomNumber;
return randomNumber;
}
function _addTokenIdToClass(LootBoxRandomnessState storage _state, uint256 _classId, uint256 _tokenId) internal {
// This is called by code that has already checked this, sometimes in a
// loop, so don't pay the gas cost of checking this here.
//require(_classId < _state.numClasses, "_class out of range");
_state.classToTokenIds[_classId].push(_tokenId);
}
}
pragma solidity >=0.4.21 <0.6.0;
contract Migrations {
address public owner;
uint public last_completed_migration;
constructor() public {
owner = msg.sender;
}
modifier restricted() {
if (msg.sender == owner) _;
}
function setCompleted(uint completed) public restricted {
last_completed_migration = completed;
}
function upgrade(address new_address) public restricted {
Migrations upgraded = Migrations(new_address);
upgraded.setCompleted(last_completed_migration);
}
}
pragma solidity ^0.5.0;
/**
* @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.
*/
contract Ownable {
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 = msg.sender;
_owner = msgSender;
emit OwnershipTransferred(address(0), msgSender);
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view returns (address) {
return _owner;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(_owner == msg.sender, "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 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 onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
emit OwnershipTransferred(_owner, newOwner);
_owner = newOwner;
}
}
pragma solidity ^0.5.0;
library Strings {
// via https://github.com/oraclize/ethereum-api/blob/master/oraclizeAPI_0.5.sol
function strConcat(string memory _a, string memory _b, string memory _c, string memory _d, string memory _e) internal pure returns (string memory) {
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;
for (uint i = 0; i < _ba.length; i++) babcde[k++] = _ba[i];
for (uint i = 0; i < _bb.length; i++) babcde[k++] = _bb[i];
for (uint i = 0; i < _bc.length; i++) babcde[k++] = _bc[i];
for (uint i = 0; i < _bd.length; i++) babcde[k++] = _bd[i];
for (uint i = 0; i < _be.length; i++) babcde[k++] = _be[i];
return string(babcde);
}
function strConcat(string memory _a, string memory _b, string memory _c, string memory _d) internal pure returns (string memory) {
return strConcat(_a, _b, _c, _d, "");
}
function strConcat(string memory _a, string memory _b, string memory _c) internal pure returns (string memory) {
return strConcat(_a, _b, _c, "", "");
}
function strConcat(string memory _a, string memory _b) internal pure returns (string memory) {
return strConcat(_a, _b, "", "", "");
}
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.4.21 <0.6.0;
contract Test_Token {
string public name = "Test Token";
string public symbol = "TST";
string public standard = "Test Token v1.0";
uint256 public totalSupply;
event Transfer(
address indexed _from,
address indexed _to,
uint256 _value
);
event TransferFromApp(
address indexed _from,
address indexed _to,
uint256 _value,
uint256 _token
);
event TransferFuture(
address indexed _from,
address indexed _to,
uint256 _value,
uint256 token_code
);
event Approval(
address indexed _owner,
address indexed _spender,
uint256 _value
);
mapping(address => uint256) public balanceOf;
mapping(address => mapping(address => uint256)) public allowance;
constructor (uint256 _initialSupply) public {
balanceOf[msg.sender] = _initialSupply;
totalSupply = _initialSupply;
}
function testtokenbalance (address _enquire) public view returns(uint) {
return balanceOf[_enquire];
}
function transfer(address _to, uint256 _value) public returns (bool success) {
require(balanceOf[msg.sender] >= _value);
balanceOf[msg.sender] -= _value;
balanceOf[_to] += _value;
emit Transfer(msg.sender, _to, _value);
return true;
}
function _transfer(address _to, uint256 _value, uint _token) public returns (bool success) {
require(balanceOf[msg.sender] >= _value);
balanceOf[msg.sender] -= _value;
balanceOf[_to] += _value;
emit TransferFromApp(msg.sender, _to, _value, _token);
return true;
}
function transfer_future(address _to, uint256 _value, uint256 token_code) public returns (bool success) {
require(balanceOf[msg.sender] >= _value);
balanceOf[msg.sender] -= _value;
balanceOf[_to] += _value;
emit TransferFuture(msg.sender, _to, _value, token_code);
return true;
}
function approve(address _spender, uint256 _value) public returns (bool success) {
allowance[msg.sender][_spender] = _value;
emit Approval(msg.sender, _spender, _value);
return true;
}
function getMsgSender() public view returns (address sender) {
return msg.sender;
}
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) {
require(_value <= balanceOf[_from]);
require(_value <= allowance[_from][msg.sender]);
balanceOf[_from] -= _value;
balanceOf[_to] += _value;
allowance[_from][msg.sender] -= _value;
emit Transfer(_from, _to, _value);
return true;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment