// File: ERC1155.sol



// SPDX-License-Identifier: MIT

pragma solidity ^0.8;

interface iERC1155 {
    function onERC1155Received(
        address,
        address,
        uint256,
        uint256,
        bytes calldata
    ) external returns (bytes4);

    function onERC1155BatchReceived(
        address,
        address,
        uint256[] calldata,
        uint256[] calldata,
        bytes calldata
    ) external returns (bytes4);
}

// author: jolan.eth
abstract contract ERC1155 {
    mapping(uint256 => uint256) supply;
    mapping(uint256 => mapping(address => uint256)) balances;
    mapping(address => mapping(address => bool)) operatorApprovals;

    event TransferSingle(
        address indexed operator,
        address indexed from,
        address indexed to,
        uint256 id,
        uint256 value
    );
    event TransferBatch(
        address indexed operator,
        address indexed from,
        address indexed to,
        uint256[] ids,
        uint256[] values
    );
    event ApprovalForAll(
        address indexed account,
        address indexed operator,
        bool approved
    );

    function supportsInterface(bytes4 interfaceId) public pure returns (bool) {
        return interfaceId == 0xd9b67a26 || interfaceId == 0x0e89341c;
    }

    function totalSupply(uint256 id) public view returns (uint256) {
        return supply[id];
    }

    function balanceOf(address owner, uint256 id)
        public
        view
        returns (uint256)
    {
        require(
            owner != address(0),
            "ERC1155::balanceOf() - owner is address(0)"
        );
        return balances[id][owner];
    }

    function balanceOfBatch(address[] memory owners, uint256[] memory ids)
        public
        view
        returns (uint256[] memory)
    {
        require(
            owners.length == ids.length,
            "ERC1155::balanceOfBatch() - owners length don't match ids length"
        );

        uint256[] memory batchBalances = new uint256[](owners.length);

        uint256 i = 0;
        while (i < owners.length)
            batchBalances[i] = balanceOf(owners[i], ids[i++]);

        return batchBalances;
    }

    function isApprovedForAll(address owner, address operator)
        public
        view
        returns (bool)
    {
        return operatorApprovals[owner][operator];
    }

    function setApprovalForAll(address operator, bool approved) public {
        _setApprovalForAll(msg.sender, operator, approved);
    }

    function safeTransferFrom(
        address from,
        address to,
        uint256 id,
        uint256 amount,
        bytes memory data
    ) public {
        require(
            from == msg.sender || isApprovedForAll(from, msg.sender),
            "ERC1155::safeTransferFrom() - msg.sender is not owner or approved"
        );

        uint256 fromBalance = balances[id][from];
        require(
            fromBalance >= amount,
            "ERC1155::safeTransferFrom() - fromBalance is lower than amount"
        );

        unchecked {
            balances[id][from] = fromBalance - amount;
        }

        balances[id][to] += amount;

        emit TransferSingle(msg.sender, from, to, id, amount);
        _doSafeTransferAcceptanceCheck(msg.sender, from, to, id, amount, data);
    }

    function safeBatchTransferFrom(
        address from,
        address to,
        uint256[] memory ids,
        uint256[] memory amounts,
        bytes memory data
    ) public {
        require(
            from == msg.sender || isApprovedForAll(from, msg.sender),
            "ERC1155::safeBatchTransferFrom() - msg.sender is not owner or approved"
        );

        require(
            ids.length == amounts.length,
            "ERC1155::safeBatchTransferFrom() - ids.length don't match amounts.length"
        );

        require(
            to != address(0),
            "ERC1155::safeBatchTransferFrom() - to is address(0)"
        );

        address operator = msg.sender;

        uint256 i = 0;
        while (i < ids.length) {
            uint256 id = ids[i];
            uint256 amount = amounts[i];

            uint256 fromBalance = balances[id][from];
            require(
                fromBalance >= amount,
                "ERC1155::safeBatchTransferFrom() - balance is lower than amount"
            );
            unchecked {
                balances[id][from] = fromBalance - amount;
            }
            balances[id][to] += amount;
            ++i;
        }

        emit TransferBatch(operator, from, to, ids, amounts);
        _doSafeBatchTransferAcceptanceCheck(
            operator,
            from,
            to,
            ids,
            amounts,
            data
        );
    }

    function safeBatchTransferFromInternal(
        address from,
        address to,
        uint256[] memory ids,
        uint256[] memory amounts,
        bytes memory data
    ) internal {
        require(
            ids.length == amounts.length,
            "ERC1155::safeBatchTransferFrom() - ids.length don't match amounts.length"
        );

        require(
            to != address(0),
            "ERC1155::safeBatchTransferFrom() - to is address(0)"
        );

        address operator = address(this);

        uint256 i = 0;
        while (i < ids.length) {
            uint256 id = ids[i];
            uint256 amount = amounts[i];

            uint256 fromBalance = balances[id][from];
            require(
                fromBalance >= amount,
                "ERC1155::safeBatchTransferFrom() - balance is lower than amount"
            );
            unchecked {
                balances[id][from] = fromBalance - amount;
            }
            balances[id][to] += amount;
            ++i;
        }

        emit TransferBatch(operator, from, to, ids, amounts);
        _doSafeBatchTransferAcceptanceCheck(
            operator,
            from,
            to,
            ids,
            amounts,
            data
        );
    }

    function _setApprovalForAll(
        address owner,
        address operator,
        bool approved
    ) private {
        require(owner != operator, "error owner");
        operatorApprovals[owner][operator] = approved;
        emit ApprovalForAll(owner, operator, approved);
    }

    function _mint(
        address to,
        uint256 id,
        uint256 amount,
        bytes memory data
    ) internal {
        require(to != address(0), "ERC1155::_mint() - to is address(0)");

        supply[id]++;
        balances[id][to] += amount;
        emit TransferSingle(msg.sender, address(0), to, id, amount);
        _doSafeTransferAcceptanceCheck(
            msg.sender,
            address(0),
            to,
            id,
            amount,
            data
        );
    }

    function _doSafeTransferAcceptanceCheck(
        address operator,
        address from,
        address to,
        uint256 id,
        uint256 amount,
        bytes memory data
    ) private {
        uint256 size;
        assembly {
            size := extcodesize(to)
        }
        if (size > 0) {
            try
                iERC1155(to).onERC1155Received(operator, from, id, amount, data)
            returns (bytes4 response) {
                if (response != iERC1155.onERC1155Received.selector) {
                    revert(
                        "ERC1155::doSafeTransferAcceptanceCheck() - error receiver"
                    );
                }
            } catch Error(string memory reason) {
                revert(reason);
            } catch {
                revert(
                    "ERC1155::doSafeTransferAcceptanceCheck() - error receiver"
                );
            }
        }
    }

    function _doSafeBatchTransferAcceptanceCheck(
        address operator,
        address from,
        address to,
        uint256[] memory ids,
        uint256[] memory amounts,
        bytes memory data
    ) private {
        uint256 size;
        assembly {
            size := extcodesize(to)
        }
        if (size > 0) {
            try
                iERC1155(to).onERC1155BatchReceived(
                    operator,
                    from,
                    ids,
                    amounts,
                    data
                )
            returns (bytes4 response) {
                if (response != iERC1155.onERC1155BatchReceived.selector) {
                    revert(
                        "ERC1155::doSafeTransferAcceptanceCheck() - error receiver"
                    );
                }
            } catch Error(string memory reason) {
                revert(reason);
            } catch {
                revert(
                    "ERC1155::doSafeTransferAcceptanceCheck() - error receiver"
                );
            }
        }
    }
}

// File: Registry.sol



// SPDX-License-Identifier: MIT

pragma solidity ^0.8;

// author: jolan.eth
abstract contract Registry {
    struct RCSA {
        address NFTContract;
        uint256 id;
    }

    mapping(uint256 => RCSA) REKTRegistry;
    
    function getREKTRegistry(uint256 id)
    public view returns (RCSA memory) {
        RCSA storage Object = REKTRegistry[id];
        return Object;
    }

    function setRCSARegistration(uint256 tokenId, address NFTContract, uint256 id)
    internal {
        REKTRegistry[tokenId] = RCSA(
            NFTContract, id
        );
    }
}
// File: REKT.sol



// SPDX-License-Identifier: MIT

pragma solidity ^0.8;

import "./ERC1155.sol";
import "./Registry.sol";

interface iREKT {
    function exist(uint256) external view returns (bool);

    function uri(uint256) external view returns (string memory);

    function tokenURI(uint256) external view returns (string memory);

    function supportsInterface(bytes4) external view returns (bool);
}

/// RRRRRRRRRRRRRRRRR   EEEEEEEEEEEEEEEEEEEEEEKKKKKKKKK    KKKKKKKTTTTTTTTTTTTTTTTTTTTTTT
/// R::::::::::::::::R  E::::::::::::::::::::EK:::::::K    K:::::KT:::::::::::::::::::::T
/// R::::::RRRRRR:::::R E::::::::::::::::::::EK:::::::K    K:::::KT:::::::::::::::::::::T
/// RR:::::R     R:::::REE::::::EEEEEEEEE::::EK:::::::K   K::::::KT:::::TT:::::::TT:::::T
///   R::::R     R:::::R  E:::::E       EEEEEEKK::::::K  K:::::KKKTTTTTT  T:::::T  TTTTTT
///   R::::R     R:::::R  E:::::E               K:::::K K:::::K           T:::::T        
///   R::::RRRRRR:::::R   E::::::EEEEEEEEEE     K::::::K:::::K            T:::::T        
///   R:::::::::::::RR    E:::::::::::::::E     K:::::::::::K             T:::::T        
///   R::::RRRRRR:::::R   E:::::::::::::::E     K:::::::::::K             T:::::T        
///   R::::R     R:::::R  E::::::EEEEEEEEEE     K::::::K:::::K            T:::::T        
///   R::::R     R:::::R  E:::::E               K:::::K K:::::K           T:::::T        
///   R::::R     R:::::R  E:::::E       EEEEEEKK::::::K  K:::::KKK        T:::::T        
/// RR:::::R     R:::::REE::::::EEEEEEEE:::::EK:::::::K   K::::::K      TT:::::::TT      
/// R::::::R     R:::::RE::::::::::::::::::::EK:::::::K    K:::::K      T:::::::::T      
/// R::::::R     R:::::RE::::::::::::::::::::EK:::::::K    K:::::K      T:::::::::T      
/// RRRRRRRR     RRRRRRREEEEEEEEEEEEEEEEEEEEEEKKKKKKKKK    KKKKKKK      TTTTTTTTTTT      
                                                                                     
// author: jolan.eth
contract REKT is ERC1155, Registry {
    constructor() {}

    function name() public pure returns (string memory) {
        return "REKT";
    }

    function symbol() public pure returns (string memory) {
        return "RCSA";
    }

    function mintRCSA(
        address source,
        uint256 id,
        uint256 amount
    ) public {
        require(
            source != address(0),
            "REKT::mintRCSA() - source does not exist"
        );

        require(amount > 0, "REKT::mintRCSA() - amount is 0");

        uint256 tokenId = uint256(
            keccak256(abi.encodePacked(uint256(uint160(address(source))), id))
        );

        if (ERC1155.totalSupply(tokenId) == 0) {
            Registry.setRCSARegistration(tokenId, address(source), id);
        }

        ERC1155._mint(msg.sender, tokenId, amount, "");
    }

    function uri(uint256 id) public view returns (string memory) {
        require(ERC1155.totalSupply(id) > 0, "REKT::uri() - id does not exist");
        Registry.RCSA memory Entry = Registry.getREKTRegistry(id);
        iREKT Reader = iREKT(Entry.NFTContract);
        if (Reader.supportsInterface(0x80ac58cd))
            return Reader.tokenURI(Entry.id);
        if (Reader.supportsInterface(0xd9b67a26)) return Reader.uri(Entry.id);
        return "REKT";
    }

    function owner() public pure returns (address) {
        return address(0);
    }

    function encode(bytes memory data) internal pure returns (string memory) {
        uint256 len = data.length;
        if (len == 0) return "";

        uint256 encodedLen = 4 * ((len + 2) / 3);

        bytes memory result = new bytes(encodedLen + 32);

        bytes
            memory table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

        assembly {
            let tablePtr := add(table, 1)
            let resultPtr := add(result, 32)

            for {
                let i := 0
            } lt(i, len) {

            } {
                i := add(i, 3)
                let input := and(mload(add(data, i)), 0xffffff)

                let out := mload(add(tablePtr, and(shr(18, input), 0x3F)))
                out := shl(8, out)
                out := add(
                    out,
                    and(mload(add(tablePtr, and(shr(12, input), 0x3F))), 0xFF)
                )
                out := shl(8, out)
                out := add(
                    out,
                    and(mload(add(tablePtr, and(shr(6, input), 0x3F))), 0xFF)
                )
                out := shl(8, out)
                out := add(
                    out,
                    and(mload(add(tablePtr, and(input, 0x3F))), 0xFF)
                )
                out := shl(224, out)

                mstore(resultPtr, out)

                resultPtr := add(resultPtr, 4)
            }

            switch mod(len, 3)
            case 1 {
                mstore(sub(resultPtr, 2), shl(240, 0x3d3d))
            }
            case 2 {
                mstore(sub(resultPtr, 1), shl(248, 0x3d))
            }

            mstore(result, encodedLen)
        }

        return string(result);
    }

    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);
    }
}