Source

NFT20Pair.sol

pragma solidity ^0.6.0;

// ERC721
import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";

// ERC1155
import "@openzeppelin/contracts/token/ERC1155/ERC1155Receiver.sol";
import "@openzeppelin/contracts/token/ERC1155/IERC1155.sol";

import "./ERC20.sol";

import "@openzeppelin/contracts/utils/EnumerableSet.sol";

interface IFactory {
    function fee() external view returns (uint256);

    function flashLoansEnabled() external view returns (bool);
}

interface IFlashLoanReceiver {
    function executeOperation(
        uint256[] calldata _ids,
        uint256[] calldata _amounts,
        address initiator,
        bytes calldata params
    ) external returns (bool);
}

contract NFT20Pair is ERC20, IERC721Receiver, ERC1155Receiver {
    address public factory;
    address public nftAddress;
    uint256 public nftType;
    uint256 public nftValue;

    mapping(uint256 => uint256) public track1155;

    using EnumerableSet for EnumerableSet.UintSet;
    EnumerableSet.UintSet lockedNfts;

    event Withdraw(uint256[] indexed _tokenIds, uint256[] indexed amounts);

    // create new token
    constructor() public {}

    function init(
        string memory _name,
        string memory _symbol,
        address _nftAddress,
        uint256 _nftType
    ) public payable {
        require(factory == address(0)); //Watch out TEST this is so we can init several time
        factory = msg.sender;
        nftType = _nftType;
        name = _name;
        symbol = _symbol;
        decimals = 18;
        nftAddress = _nftAddress;
        nftValue = 100 * 10**18;
    }

    modifier flashloansEnabled() {
        require(
            IFactory(factory).flashLoansEnabled(),
            "flashloans not allowed"
        );
        _;
    }

    function getInfos()
        public
        view
        returns (
            uint256 _type,
            string memory _name,
            string memory _symbol,
            uint256 _supply
        )
    {
        _type = nftType;
        _name = name;
        _symbol = symbol;
        _supply = totalSupply.div(nftValue);
    }

    // withdraw nft and burn tokens
    function withdraw(
        uint256[] calldata _tokenIds,
        uint256[] calldata amounts,
        address recipient
    ) external {
        if (nftType == 1155) {
            if (_tokenIds.length == 1) {
                _burn(msg.sender, nftValue.mul(amounts[0]));
                _withdraw1155(
                    address(this),
                    recipient,
                    _tokenIds[0],
                    amounts[0]
                );
            } else {
                _batchWithdraw1155(
                    address(this),
                    recipient,
                    _tokenIds,
                    amounts
                );
            }
        } else if (nftType == 721) {
            _burn(msg.sender, nftValue.mul(_tokenIds.length));
            for (uint256 i = 0; i < _tokenIds.length; i++) {
                _withdraw721(address(this), recipient, _tokenIds[i]);
            }
        }

        emit Withdraw(_tokenIds, amounts);
    }

    function _withdraw1155(
        address _from,
        address _to,
        uint256 _tokenId,
        uint256 value
    ) internal {
        IERC1155(nftAddress).safeTransferFrom(_from, _to, _tokenId, value, "");
    }

    function _batchWithdraw1155(
        address _from,
        address _to,
        uint256[] memory ids,
        uint256[] memory amounts
    ) internal {
        uint256 qty = 0;
        for (uint256 i = 0; i < ids.length; i++) {
            qty = qty + amounts[i];
        }
        // burn tokens
        _burn(msg.sender, nftValue.mul(qty));

        IERC1155(nftAddress).safeBatchTransferFrom(
            _from,
            _to,
            ids,
            amounts,
            "0x0"
        );
    }

    function multi721Deposit(uint256[] memory _ids, address _referral) public {
        uint256 fee = IFactory(factory).fee();

        for (uint256 i = 0; i < _ids.length; i++) {
            IERC721(nftAddress).transferFrom(
                msg.sender,
                address(this),
                _ids[i]
            );
        }

        address referral = _referral == address(0x0) ? factory : _referral;

        _mint(
            msg.sender,
            (nftValue.mul(_ids.length)).mul(uint256(100).sub(fee)).div(100)
        );
        _mint(referral, (nftValue.mul(_ids.length)).mul(fee).div(100));
    }

    function swap721(uint256 _in, uint256 _out) external {
        IERC721(nftAddress).transferFrom(msg.sender, address(this), _in);
        IERC721(nftAddress).safeTransferFrom(address(this), msg.sender, _out);
    }

    function swap1155(
        uint256[] calldata in_ids,
        uint256[] calldata in_amounts,
        uint256[] calldata out_ids,
        uint256[] calldata out_amounts
    ) external {
        uint256 ins;
        uint256 outs;

        for (uint256 i = 0; i < out_ids.length; i++) {
            ins = ins.add(in_amounts[i]);
            outs = outs.add(out_amounts[i]);
        }

        require(ins == outs, "Need to swap same amount of NFTs");

        IERC1155(nftAddress).safeBatchTransferFrom(
            address(this),
            msg.sender,
            out_ids,
            out_amounts,
            "0x0"
        );
        IERC1155(nftAddress).safeBatchTransferFrom(
            msg.sender,
            address(this),
            in_ids,
            in_amounts,
            "INTERNAL"
        );
    }

    function _withdraw721(
        address _from,
        address _to,
        uint256 _tokenId
    ) internal {
        // lockedNfts.remove(_tokenId);
        IERC721(nftAddress).safeTransferFrom(_from, _to, _tokenId);
    }

    function onERC721Received(
        address operator,
        address,
        uint256,
        bytes memory data
    ) public virtual override returns (bytes4) {
        require(nftAddress == msg.sender, "forbidden");
        uint256 fee = IFactory(factory).fee();

        address referral =
            bytesToAddress(data) == address(0x0)
                ? factory
                : bytesToAddress(data);

        _mint(referral, nftValue.mul(fee).div(100));
        _mint(operator, nftValue.mul(uint256(100).sub(fee)).div(100));
        return this.onERC721Received.selector;
    }

    function onERC1155Received(
        address operator,
        address,
        uint256,
        uint256 value,
        bytes memory data
    ) public virtual override returns (bytes4) {
        require(nftAddress == msg.sender, "forbidden");
        if (keccak256(data) != keccak256("INTERNAL")) {
            uint256 fee = IFactory(factory).fee();

            address referral =
                bytesToAddress(data) == address(0x0)
                    ? factory
                    : bytesToAddress(data);

            _mint(referral, (nftValue.mul(value)).mul(fee).div(100));
            _mint(
                operator,
                (nftValue.mul(value)).mul(uint256(100).sub(fee)).div(100)
            );
        }
        return this.onERC1155Received.selector;
    }

    function onERC1155BatchReceived(
        address operator,
        address,
        uint256[] memory ids,
        uint256[] memory values,
        bytes memory data
    ) public virtual override returns (bytes4) {
        require(nftAddress == msg.sender, "forbidden");
        if (keccak256(data) != keccak256("INTERNAL")) {
            uint256 qty = 0;

            for (uint256 i = 0; i < ids.length; i++) {
                qty = qty + values[i];
            }
            uint256 fee = IFactory(factory).fee();

            address referral =
                bytesToAddress(data) == address(0x0)
                    ? factory
                    : bytesToAddress(data);

            _mint(
                operator,
                (nftValue.mul(qty)).mul(uint256(100).sub(fee)).div(100)
            );
            _mint(referral, (nftValue.mul(qty)).mul(fee).div(100));
        }
        return this.onERC1155BatchReceived.selector;
    }

    // set new params
    function setParams(
        uint256 _nftType,
        string calldata _name,
        string calldata _symbol,
        uint256 _nftValue
    ) external {
        require(msg.sender == factory, "!authorized");
        nftType = _nftType;
        name = _name;
        symbol = _symbol;
        nftValue = _nftValue;
    }

    function bytesToAddress(bytes memory b) public view returns (address) {
        uint256 result = 0;
        for (uint256 i = b.length - 1; i + 1 > 0; i--) {
            uint256 c = uint256(uint8(b[i]));

            uint256 to_inc = c * (16**((b.length - i - 1) * 2));
            result += to_inc;
        }
        return address(result);
    }

    function flashLoan(
        uint256[] calldata _ids,
        uint256[] calldata _amounts,
        address _operator,
        bytes calldata _params
    ) external flashloansEnabled() {
        require(_ids.length < 80, "To many NFTs");

        if (nftType == 1155) {
            IERC1155(nftAddress).safeBatchTransferFrom(
                address(this),
                _operator,
                _ids,
                _amounts,
                "0x0"
            );
        } else {
            for (uint8 index; index < _ids.length; index++) {
                IERC721(nftAddress).safeTransferFrom(
                    address(this),
                    _operator,
                    _ids[index]
                );
            }
        }
        require(
            IFlashLoanReceiver(_operator).executeOperation(
                _ids,
                _amounts,
                msg.sender,
                _params
            ),
            "Execution Failed"
        );

        if (nftType == 1155) {
            IERC1155(nftAddress).safeBatchTransferFrom(
                _operator,
                address(this),
                _ids,
                _amounts,
                "INTERNAL"
            );
        } else {
            for (uint8 index; index < _ids.length; index++) {
                IERC721(nftAddress).transferFrom(
                    _operator,
                    address(this),
                    _ids[index]
                );
            }
        }
    }
}

Last updated