文件 1 的 1:BMCMissionToMars.sol
pragma solidity ^0.8.12;
interface callableNFT {
function transferFrom(address from, address to, uint256 tokenID) external;
function safeTransferFrom(address from, address to, uint256 tokenID) external;
function ownerOf(uint256 tokenId) external view returns (address);
}
contract BMCMissionToMars {
event OwnerUpdated(address indexed user, address indexed newOwner);
callableNFT public og;
callableNFT public ultra;
callableNFT public droid;
callableNFT public alpha;
callableNFT public beta;
callableNFT public gamma;
struct units {
uint256[] stakedOGs;
uint256[] stakedULTRAs;
uint256[] stakedDROIDs;
uint256[] stakedALPHAs;
uint256[] stakedBETAs;
uint256[] stakedGAMMAs;
}
struct tokenData {
uint64 timestamp;
address realOwner;
}
address public owner;
bool public depositPaused;
uint256 private locked = 1;
mapping(address => units) private _staker;
mapping(address => mapping(uint256 => tokenData)) private _tokenData;
constructor(address _og, address _ultra, address _droid) {
og = callableNFT(_og);
ultra = callableNFT(_ultra);
droid = callableNFT(_droid);
owner = _msgSender();
emit OwnerUpdated(address(0), owner);
pauseDeposits(true);
}
modifier onlyOwner() {
require(_msgSender() == owner, "Non Owner");
_;
}
modifier nonReentrant() {
require(locked == 1, "No Reentry");
locked = 2;
_;
locked = 1;
}
function _msgSender() internal view returns (address) {
return msg.sender;
}
function multiDeposit(address[] memory _contractAddresses, uint256 [][] memory tokenIDs) public nonReentrant {
require(!depositPaused, "Deposits Paused");
uint256 iterations = tokenIDs.length;
require(_contractAddresses.length == iterations && iterations > 0 && iterations < 7, "Invalid Parameters");
for (uint256 i; i < iterations; ) {
_deposit(_contractAddresses[i], tokenIDs[i]);
unchecked {
++i;
}
}
}
function multiWithdraw(address[] memory _contractAddresses, uint256 [][] memory tokenIDs) public nonReentrant {
uint256 iterations = tokenIDs.length;
require(_contractAddresses.length == iterations && iterations > 0 && iterations < 7, "Invalid Parameters");
for (uint256 i; i < iterations; ) {
_withdraw(_contractAddresses[i], tokenIDs[i]);
unchecked {
++i;
}
}
}
function _deposit(address _contractAddress, uint256[] memory tokenIds) internal {
require(isValidContract(_contractAddress), "Unknown contract");
uint256 tokens = tokenIds.length;
require(tokens > 0, "No Tokens Passed");
units storage currentAddress = _staker[_msgSender()];
callableNFT depositAddress = callableNFT(_contractAddress);
uint256 currentToken;
for (uint256 i; i < tokens; ) {
currentToken = tokenIds[i++];
require(depositAddress.ownerOf(currentToken) == _msgSender(), "Not the owner");
depositAddress.safeTransferFrom(_msgSender(), address(this), currentToken);
_tokenData[_contractAddress][currentToken].realOwner = _msgSender();
_tokenData[_contractAddress][currentToken].timestamp = uint64(block.timestamp);
if (depositAddress == og) {
currentAddress.stakedOGs.push(currentToken);
continue;
}
if (depositAddress == ultra) {
currentAddress.stakedULTRAs.push(currentToken);
continue;
}
if (depositAddress == droid) {
currentAddress.stakedDROIDs.push(currentToken);
continue;
}
if (depositAddress == alpha) {
currentAddress.stakedALPHAs.push(currentToken);
continue;
}
if (depositAddress == beta) {
currentAddress.stakedBETAs.push(currentToken);
continue;
}
if (depositAddress == gamma) {
currentAddress.stakedGAMMAs.push(currentToken);
}
}
}
function _withdraw(address _contractAddress, uint256[] memory tokenIds) internal {
require(isValidContract(_contractAddress), "Unknown contract");
uint256 tokens = tokenIds.length;
require(tokens > 0, "No Tokens Passed");
units storage currentAddress = _staker[_msgSender()];
callableNFT withdrawAddress = callableNFT(_contractAddress);
uint256 currentToken;
for (uint256 i; i < tokens; ) {
currentToken = tokenIds[i++];
require(withdrawAddress.ownerOf(currentToken) == address(this), "Contract Not Owner");
delete _tokenData[_contractAddress][currentToken];
if (withdrawAddress == og){
currentAddress.stakedOGs = _OrganizeArrayEntries(currentAddress.stakedOGs, currentToken);
currentAddress.stakedOGs.pop();
withdrawAddress.safeTransferFrom(address(this), _msgSender(), currentToken);
continue;
}
if (withdrawAddress == ultra){
currentAddress.stakedULTRAs = _OrganizeArrayEntries(currentAddress.stakedULTRAs, currentToken);
currentAddress.stakedULTRAs.pop();
withdrawAddress.safeTransferFrom(address(this), _msgSender(), currentToken);
continue;
}
if (withdrawAddress == droid){
currentAddress.stakedDROIDs = _OrganizeArrayEntries(currentAddress.stakedDROIDs, currentToken);
currentAddress.stakedDROIDs.pop();
withdrawAddress.safeTransferFrom(address(this), _msgSender(), currentToken);
continue;
}
if (withdrawAddress == alpha){
currentAddress.stakedALPHAs = _OrganizeArrayEntries(currentAddress.stakedALPHAs, currentToken);
currentAddress.stakedALPHAs.pop();
withdrawAddress.safeTransferFrom(address(this), _msgSender(), currentToken);
continue;
}
if (withdrawAddress == beta){
currentAddress.stakedBETAs = _OrganizeArrayEntries(currentAddress.stakedBETAs, currentToken);
currentAddress.stakedBETAs.pop();
withdrawAddress.safeTransferFrom(address(this), _msgSender(), currentToken);
continue;
}
if (withdrawAddress == gamma){
currentAddress.stakedGAMMAs = _OrganizeArrayEntries(currentAddress.stakedGAMMAs, currentToken);
currentAddress.stakedGAMMAs.pop();
withdrawAddress.safeTransferFrom(address(this), _msgSender(), currentToken);
}
}
}
function isValidContract(address _contract) public view returns (bool) {
if (_contract == address (0)) return false;
callableNFT _callableContract = callableNFT(_contract);
if (_callableContract == og ||
_callableContract == ultra ||
_callableContract == droid ||
_callableContract == alpha ||
_callableContract == beta ||
_callableContract == gamma) return true;
return false;
}
function _OrganizeArrayEntries(uint256[] memory _list, uint256 tokenId) internal pure returns (uint256[] memory) {
uint256 arrayIndex;
uint256 arrayLength = _list.length;
uint256 lastArrayIndex = arrayLength - 1;
unchecked {
for(uint256 i; i < arrayLength; ) {
if (_list[i++] == tokenId) {
arrayIndex = i;
break;
}
}
}
require(arrayIndex != 0, "Caller Not Token Owner");
unchecked {
arrayIndex--;
}
if (arrayIndex != lastArrayIndex) {
_list[arrayIndex] = _list[lastArrayIndex];
_list[lastArrayIndex] = tokenId;
}
return _list;
}
function ownerOf(address _contractAddress, uint256 tokenId) public view returns (address) {
return _tokenData[_contractAddress][tokenId].realOwner;
}
function timestampOf(address _contractAddress, uint256 tokenId) public view returns (uint256) {
return _tokenData[_contractAddress][tokenId].timestamp;
}
function getStakedOGs(address _address) public view returns (uint256[] memory){
return _staker[_address].stakedOGs;
}
function getStakedULTRAs(address _address) public view returns (uint256[] memory){
return _staker[_address].stakedULTRAs;
}
function getStakedDROIDs(address _address) public view returns (uint256[] memory){
return _staker[_address].stakedDROIDs;
}
function getStakedALPHAs(address _address) public view returns (uint256[] memory){
return _staker[_address].stakedALPHAs;
}
function getStakedBETAs(address _address) public view returns (uint256[] memory){
return _staker[_address].stakedBETAs;
}
function getStakedGAMMAs(address _address) public view returns (uint256[] memory){
return _staker[_address].stakedGAMMAs;
}
function setOGContract(address _newAddress) public onlyOwner {
og = callableNFT(_newAddress);
}
function setULTRAContract(address _newAddress) public onlyOwner {
ultra = callableNFT(_newAddress);
}
function setDROIDContract(address _newAddress) public onlyOwner {
droid = callableNFT(_newAddress);
}
function setALPHAContract(address _newAddress) public onlyOwner {
alpha = callableNFT(_newAddress);
}
function setBETAContract(address _newAddress) public onlyOwner {
beta = callableNFT(_newAddress);
}
function setGAMMAContract(address _newAddress) public onlyOwner {
gamma = callableNFT(_newAddress);
}
function pauseDeposits(bool _state) public onlyOwner {
depositPaused = _state;
}
function emergencyWithdraw(address _contractAddress, uint256[] memory tokenIds) public onlyOwner {
pauseDeposits(true);
uint256 tokens = tokenIds.length;
callableNFT withdrawAddress = callableNFT(_contractAddress);
uint256 currentToken;
for (uint256 i; i < tokens; ) {
currentToken = tokenIds[i++];
address receiver = _tokenData[_contractAddress][currentToken].realOwner;
if (receiver != address(0) && withdrawAddress.ownerOf(currentToken) == address(this)) {
withdrawAddress.transferFrom(address(this), receiver, currentToken);
delete _tokenData[_contractAddress][currentToken];
}
}
}
function onERC721Received(address, address, uint256, bytes calldata) external pure returns(bytes4){
return bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"));
}
}
{
"compilationTarget": {
"BMCMissionToMars.sol": "BMCMissionToMars"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 2000
},
"remappings": []
}