ETH Price: $2,261.40 (-0.62%)

Transaction Decoder

Block:
16215077 at Dec-19-2022 12:12:11 AM +UTC
Transaction Fee:
0.000644628766125024 ETH $1.46
Gas Used:
51,231 Gas / 12.582787104 Gwei

Account State Difference:

  Address   Before After State Difference Code
0x44092046...DBc039456
(Prometheans: Deployer)
0.260332068815710125 Eth
Nonce: 33
0.259687440049585101 Eth
Nonce: 34
0.000644628766125024
(beaverbuild)
117.445377225183380376 Eth117.445479687183380376 Eth0.000102462
0xDaB66b4c...47635ECf8

Execution Trace

Proxy.fdd198c3( )
  • JollySwap.setRandomness( randomness=96563109460535109062060297287341467736967471803462889339984880090995856282807 )
    File 1 of 2: Proxy
    // SPDX-License-Identifier: MIT
    pragma solidity 0.8.7;
    /// @dev Proxy for NFT Factory
    contract Proxy {
        // Storage for this proxy
        bytes32 private constant IMPLEMENTATION_SLOT = bytes32(0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc);
        bytes32 private constant ADMIN_SLOT          = bytes32(0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103);
        constructor(address impl) {
            require(impl != address(0));
            _setSlotValue(IMPLEMENTATION_SLOT, bytes32(uint256(uint160(impl))));
            _setSlotValue(ADMIN_SLOT, bytes32(uint256(uint160(msg.sender))));
        }
        function setImplementation(address newImpl) public {
            require(msg.sender == _getAddress(ADMIN_SLOT));
            _setSlotValue(IMPLEMENTATION_SLOT, bytes32(uint256(uint160(newImpl))));
        }
        
        function setAdmin(address newAdmin) public {
            require(msg.sender == _getAddress(ADMIN_SLOT));
            _setSlotValue(ADMIN_SLOT, bytes32(uint256(uint160(newAdmin))));
        }
        
        function implementation() public view returns (address impl) {
            impl = address(uint160(uint256(_getSlotValue(IMPLEMENTATION_SLOT))));
        }
        function _getAddress(bytes32 key) internal view returns (address add) {
            add = address(uint160(uint256(_getSlotValue(key))));
        }
        function _getSlotValue(bytes32 slot_) internal view returns (bytes32 value_) {
            assembly {
                value_ := sload(slot_)
            }
        }
        function _setSlotValue(bytes32 slot_, bytes32 value_) internal {
            assembly {
                sstore(slot_, value_)
            }
        }
        /**
         * @dev Delegates the current call to `implementation`.
         *
         * This function does not return to its internall call site, it will return directly to the external caller.
         */
        function _delegate(address implementation__) internal virtual {
            assembly {
                // Copy msg.data. We take full control of memory in this inline assembly
                // block because it will not return to Solidity code. We overwrite the
                // Solidity scratch pad at memory position 0.
                calldatacopy(0, 0, calldatasize())
                // Call the implementation.
                // out and outsize are 0 because we don't know the size yet.
                let result := delegatecall(gas(), implementation__, 0, calldatasize(), 0, 0)
                // Copy the returned data.
                returndatacopy(0, 0, returndatasize())
                switch result
                // delegatecall returns 0 on error.
                case 0 {
                    revert(0, returndatasize())
                }
                default {
                    return(0, returndatasize())
                }
            }
        }
        receive() external payable {}
        /**
         * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other
         * function in the contract matches the call data.
         */
        fallback() external payable virtual {
            _delegate(_getAddress(IMPLEMENTATION_SLOT));
        }
    }
    

    File 2 of 2: JollySwap
    // SPDX-License-Identifier: AGPL-3.0-only
    pragma solidity 0.8.7;
    contract JollySwap {
        bytes32 private constant ADMIN_SLOT = bytes32(0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103);
        uint256 private constant ONE_PERCENT = type(uint256).max / 100;
        /*//////////////////////////////////////////////////////////////
                                     EVENTS
        //////////////////////////////////////////////////////////////*/
        event Transfer(address indexed from, address indexed to, uint256 indexed id);
        event Approval(address indexed owner, address indexed spender, uint256 indexed id);
        event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
        event Minted(address indexed owner, uint256 id);
        event Burned(address indexed owner, uint256 id);
        /*//////////////////////////////////////////////////////////////
                          ERC721 BALANCE/OWNER STORAGE
        //////////////////////////////////////////////////////////////*/
        
        string public name;
        string public symbol;
        uint256 public totalSupply;
        uint256 public randmness;
        mapping(uint256 => TokenData) internal tokens;
        mapping(address => UserData)  internal users;
        mapping(address => bool)                     public minters;
        mapping(uint256 => address)                  public getApproved;
        mapping(address => mapping(address => bool)) public isApprovedForAll;
        struct TokenData {
            address owner;
        }
        struct UserData {
            uint128 balance;
            uint128 minted;
        }
        /*//////////////////////////////////////////////////////////////
                        CONSTRUCTOR & MODIFIERS
        //////////////////////////////////////////////////////////////*/
        function initialize(string memory _name, string memory _symbol) external {
            require(msg.sender == owner(), "NOT AUTHORIZED");
            name = _name;
            symbol = _symbol;
        }
        /*//////////////////////////////////////////////////////////////
                             VIEW FUNCTIONS
        //////////////////////////////////////////////////////////////*/
        function balanceOf(address owner_) public view virtual returns (uint256) {
            require(owner_ != address(0), "ZERO_ADDRESS");
            return users[owner_].balance;
        }
        function minted(address owner_) public view returns (uint256) {
            return users[owner_].minted;
        }
        function rarity(uint256 id) public view returns (uint256) {
            if (randmness == 0) return 0;
            uint256 rdn =  uint256(keccak256(abi.encodePacked(id, randmness)));
            if (rdn > ONE_PERCENT * 98) return 3;
            if (rdn > ONE_PERCENT * 80) return 2;
            return 1;
        }
        function owner() public view returns (address owner_) {
            return _getAddress(ADMIN_SLOT);
        }
        function ownerOf(uint256 id) public view returns (address owner_) {
            require((owner_ = tokens[id].owner) != address(0), "NOT_MINTED");
        }
        function tokenURI(uint256 id) public view virtual returns (string memory) {
            return string(abi.encodePacked("https://northpole-qa.jollyswap.xyz/nft/hohoho/", _toString(id), "/", _toString(rarity(id)), ".json"));
        }
        /*//////////////////////////////////////////////////////////////
                                  MINTING LOGIC
        //////////////////////////////////////////////////////////////*/
        function mint(address receiver) external {  
            require(minters[msg.sender], "NOT MINTER");
            emit Minted(receiver, ++totalSupply);
            _safeMint(receiver, totalSupply);
        }
        function burn(address owner_, uint256 id) external {  
            require(minters[msg.sender],   "NOT MINTER");
            require(ownerOf(id) == owner_, "NOT OWNER");
            emit Burned(owner_, id);
            _burn(id);
        }
        /*//////////////////////////////////////////////////////////////
                                  ADMIN LOGIC
        //////////////////////////////////////////////////////////////*/
        function withdraw(address destination, uint256 amount) external {
            require(msg.sender == owner(), "NOT_ADMIN");
            (bool success, ) = destination.call{value: amount}("");
            require(success, "TRANSFER FAILED");
        }
        function addMinter(address minter_, bool allowed) external {
            require(msg.sender == owner(), "NOT_ADMIN");
            minters[minter_] = allowed;
        }
        function setRandomness(uint256 randomness) external {
            require(msg.sender == owner(), "NOT_ADMIN");
            randmness = randomness;
        }
        /*//////////////////////////////////////////////////////////////
                                  ERC721 LOGIC
        //////////////////////////////////////////////////////////////*/
        function approve(address spender, uint256 id) public virtual {
            address owner_ = tokens[id].owner;
            require(msg.sender == owner_ || isApprovedForAll[owner_][msg.sender], "NOT_AUTHORIZED");
            getApproved[id] = spender;
            emit Approval(owner_, spender, id);
        }
        function setApprovalForAll(address operator, bool approved) public virtual {
            isApprovedForAll[msg.sender][operator] = approved;
            emit ApprovalForAll(msg.sender, operator, approved);
        }
        function transferFrom(
            address from,
            address to,
            uint256 id
        ) public virtual {
            require(from == tokens[id].owner, "WRONG_FROM");
            require(to != address(0), "INVALID_RECIPIENT");
            require(
                msg.sender == from || isApprovedForAll[from][msg.sender] || msg.sender == getApproved[id],
                "NOT_AUTHORIZED"
            );
            // Underflow of the sender's balance is impossible because we check for
            // ownership above and the recipient's balance can't realistically overflow.
            unchecked {
                users[from].balance--;
                users[to].balance++;
            }
            tokens[id].owner = to;
            delete getApproved[id];
            emit Transfer(from, to, id);
        }
        function safeTransferFrom(
            address from,
            address to,
            uint256 id
        ) public virtual {
            transferFrom(from, to, id);
            require(
                to.code.length == 0 ||
                    ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, "") ==
                    ERC721TokenReceiver.onERC721Received.selector,
                "UNSAFE_RECIPIENT"
            );
        }
        function safeTransferFrom(
            address from,
            address to,
            uint256 id,
            bytes calldata data
        ) public virtual {
            transferFrom(from, to, id);
            require(
                to.code.length == 0 ||
                    ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, data) ==
                    ERC721TokenReceiver.onERC721Received.selector,
                "UNSAFE_RECIPIENT"
            );
        }
        /*//////////////////////////////////////////////////////////////
                                  ERC165 LOGIC
        //////////////////////////////////////////////////////////////*/
        function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
            return
                interfaceId == 0x01ffc9a7 || // ERC165 Interface ID for ERC165
                interfaceId == 0x80ac58cd || // ERC165 Interface ID for ERC721
                interfaceId == 0x5b5e139f; // ERC165 Interface ID for ERC721Metadata
        }
        /*//////////////////////////////////////////////////////////////
                            INTERNAL MINT/BURN LOGIC
        //////////////////////////////////////////////////////////////*/
        function _mint(address to, uint256 id) internal virtual {
            require(to != address(0), "INVALID_RECIPIENT");
            require(tokens[id].owner == address(0), "ALREADY_MINTED");
            // Counter overflow is incredibly unrealistic.
            unchecked {
                users[to].minted++;
                users[to].balance++;
            }
            tokens[id].owner = to;
            emit Transfer(address(0), to, id);
        }
        function _burn(uint256 id) internal virtual {
            address owner_ = tokens[id].owner;
            require(owner_ != address(0), "NOT_MINTED");
            // Ownership check above ensures no underflow.
            unchecked {
                users[owner_].balance--;
            }
            tokens[id].owner = address(0);
            delete getApproved[id];
            emit Transfer(owner_, address(0), id);
        }
        /*//////////////////////////////////////////////////////////////
                            INTERNAL SAFE MINT LOGIC
        //////////////////////////////////////////////////////////////*/
        function _safeMint(address to, uint256 id) internal virtual {
            _mint(to, id);
            require(
                to.code.length == 0 ||
                    ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, "") ==
                    ERC721TokenReceiver.onERC721Received.selector,
                "UNSAFE_RECIPIENT"
            );
        }
        function _safeMint(
            address to,
            uint256 id,
            bytes memory data
        ) internal virtual {
            _mint(to, id);
            require(
                to.code.length == 0 ||
                    ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, data) ==
                    ERC721TokenReceiver.onERC721Received.selector,
                "UNSAFE_RECIPIENT"
            );
        }
        /*//////////////////////////////////////////////////////////////
                            INTERNAL UTILITIES
        //////////////////////////////////////////////////////////////*/
        function _toString(uint256 value) internal pure returns (string memory) {
            if (value == 0) {
                return "0";
            }
            uint256 temp = value;
            uint256 digits;
            while (temp != 0) {
                digits++;
                temp /= 10;
            }
            bytes memory buffer = new bytes(digits);
            while (value != 0) {
                digits -= 1;
                buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
                value /= 10;
            }
            return string(buffer);
        }
        function _getAddress(bytes32 key) internal view returns (address add) {
            add = address(uint160(uint256(_getSlotValue(key))));
        }
        function _getSlotValue(bytes32 slot_) internal view returns (bytes32 value_) {
            assembly {
                value_ := sload(slot_)
            }
        }
    }
    abstract contract ERC721TokenReceiver {
        function onERC721Received(
            address,
            address,
            uint256,
            bytes calldata
        ) external virtual returns (bytes4) {
            return ERC721TokenReceiver.onERC721Received.selector;
        }
    }