Created
May 20, 2023 18:35
-
-
Save Sambillingham/b35b1204e7d11f3557e68cf5b92a2e7c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: MIT | |
pragma solidity ^0.8.12; | |
import "solmate/src/auth/Owned.sol"; | |
import "solmate/src/tokens/ERC1155.sol"; | |
import "solmate/src/utils/LibString.sol"; | |
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; | |
interface IERC721 { | |
function burn(uint256 tokenId) external; | |
} | |
contract HexapodComponents is ERC1155, Owned { | |
using LibString for uint256; | |
string public name = 'HOLO COMPONENTS'; | |
string public symbol = 'HHC'; | |
string baseURI = 'https://hexapod.industries/api/components/'; | |
address hexapod; | |
bool OPENEDITION_LIVE = false; | |
bool REROLL_LIVE = false; | |
uint16 MIN_ID = 1; | |
uint16 MAX_ID = 100; | |
uint256 PRICE = 0.0025 ether; | |
uint256 RECYCLE_PRICE = 0.00125 ether; | |
mapping(address => bool) public allowedAddresses; | |
mapping(uint256 => mapping(uint256 => bool)) public MintPerHoloId; | |
mapping(uint256 => bytes) public DeconstructValues; | |
error Unauthorized(); | |
error NotOpen(); | |
error InsufficientValue(); | |
error InvalidSignature(); | |
error OneTimeOnly(); | |
error LengthMismatch(); | |
constructor(address _hexapod) Owned(msg.sender) { | |
hexapod = _hexapod; | |
} | |
function flipAllowedAddress(address _address) external onlyOwner() { | |
allowedAddresses[_address] = !allowedAddresses[_address]; | |
} | |
function mintBatchExternal(address to, uint256[] memory ids, uint256[] memory amounts) external { | |
if (!allowedAddresses[msg.sender]) revert Unauthorized(); | |
_batchMint(to, ids, amounts, ''); | |
} | |
function burnBatchExternal(address from, uint256[] memory ids, uint256[] memory amounts) external { | |
if (!allowedAddresses[msg.sender]) revert Unauthorized(); | |
_batchBurn(from, ids, amounts); | |
} | |
function setURI(string calldata newBaseUri) external onlyOwner() { | |
baseURI = newBaseUri; | |
} | |
function uri(uint256 id) public view override returns (string memory) { | |
return string.concat(baseURI, id.toString()); | |
} | |
function setValues(bool _status, bool _reroll, uint16 _min, uint16 _max, uint256 _price, uint256 _rprice) external onlyOwner() { | |
OPENEDITION_LIVE = _status; | |
REROLL_LIVE = _reroll; | |
MIN_ID = _min; | |
MAX_ID = _max; | |
PRICE = _price; | |
RECYCLE_PRICE = _rprice; | |
} | |
function setDeconstructValues(uint256 _id, bytes calldata _values) external onlyOwner() { | |
DeconstructValues[_id] = _values; | |
} | |
function mintBatch(uint256 amount) payable external { | |
if (!OPENEDITION_LIVE) revert NotOpen(); | |
if (msg.value < PRICE * amount) revert InsufficientValue(); | |
internalmint(amount); | |
} | |
function mintWithSignature( | |
bytes calldata signature, | |
uint256 holoId, | |
uint256 compId | |
) external payable { | |
if (recoverSigner(msg.sender, signature, holoId, compId) != owner) revert InvalidSignature(); | |
if (MintPerHoloId[holoId][compId] == true) revert OneTimeOnly(); | |
MintPerHoloId[holoId][compId] = true; | |
_mint(msg.sender, compId, 1, ''); | |
} | |
function deconstructHolo(bytes calldata signature, uint256 holoId, uint256 reactLevel, uint256 groupId) external { | |
if (recoverSigner(msg.sender, signature, holoId, reactLevel, groupId) != owner) revert InvalidSignature(); | |
uint256[] memory amounts = new uint256[](reactLevel); | |
uint256[] memory ids = new uint256[](reactLevel); | |
for (uint256 i = 0; i < reactLevel;) { | |
ids[i] = uint8(DeconstructValues[groupId][i]); | |
amounts[i] = 1; | |
unchecked { | |
++i; | |
} | |
} | |
IERC721(hexapod).burn(holoId); | |
_batchMint(msg.sender, ids, amounts, ''); | |
} | |
function recompBatch(uint256[] memory ids, uint256[] memory amounts) external { | |
if (!REROLL_LIVE) revert NotOpen(); | |
if (ids.length != amounts.length) revert LengthMismatch(); | |
uint256 halfTotal = calcTotal(amounts) / 2; | |
_batchBurn(msg.sender, ids, amounts ); | |
internalmint(halfTotal); | |
} | |
function recycleBatch(uint256[] memory ids, uint256[] memory amounts) payable external { | |
if (!REROLL_LIVE) revert NotOpen(); | |
uint256 total = calcTotal(amounts); | |
if (msg.value < RECYCLE_PRICE * total) revert InsufficientValue(); | |
_batchBurn(msg.sender, ids, amounts ); | |
internalmint(total); | |
} | |
function internalmint(uint256 amount) internal { | |
uint256[] memory amounts = new uint256[](amount); | |
uint256[] memory ids = new uint256[](amount); | |
for (uint256 i = 0; i < amount;) { | |
ids[i] = (random(i) % (MAX_ID-MIN_ID) ) + MIN_ID; | |
amounts[i] = 1; | |
unchecked { | |
++i; | |
} | |
} | |
_batchMint(msg.sender, ids, amounts, ''); | |
} | |
function random(uint256 i) internal view returns (uint256) { | |
return uint256(keccak256(abi.encodePacked( | |
tx.origin, | |
blockhash(block.number - i), | |
block.timestamp * i | |
))); | |
} | |
function recoverSigner( | |
address _address, | |
bytes memory _signature, | |
uint256 holoId, | |
uint256 compId | |
) public pure returns (address) { | |
bytes32 messageDigest = keccak256( | |
abi.encodePacked( | |
"\x19Ethereum Signed Message:\n32", | |
keccak256(abi.encodePacked(_address, holoId, compId)) | |
) | |
); | |
return ECDSA.recover(messageDigest, _signature); | |
} | |
function recoverSigner( | |
address _address, | |
bytes memory _signature, | |
uint256 holoId, | |
uint256 reactLevel, | |
uint256 groupId | |
) public pure returns (address) { | |
bytes32 messageDigest = keccak256( | |
abi.encodePacked( | |
"\x19Ethereum Signed Message:\n32", | |
keccak256(abi.encodePacked(_address, holoId, reactLevel, groupId)) | |
) | |
); | |
return ECDSA.recover(messageDigest, _signature); | |
} | |
function calcTotal(uint256[] memory amounts) internal pure returns (uint256) { | |
uint256 total; | |
for (uint256 i = 0; i < amounts.length;) { | |
total += amounts[i]; | |
unchecked { | |
++i; | |
} | |
} | |
return total; | |
} | |
function withdraw() external onlyOwner() { | |
(bool success, ) = (msg.sender).call{ value: address(this).balance }(''); | |
require(success, "FAILED"); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment