How to combine ERC20 tokens and NFTs in a single smart contract?

I’m working on a project where users can create unique ideas as NFTs and receive funding through ERC20 tokens. I’m stuck on how to implement this in a single contract. Here’s what I’ve tried:

  1. Created three separate contracts: main.sol, NFT.sol, and ERC20.sol.
  2. In main.sol, I import the other two contracts and create instances of them.
  3. NFT.sol handles the NFT creation and includes a fund() function.
  4. ERC20.sol manages token transfers and has a fundIdea() function.

Is this the right approach? Or is there a better way to combine ERC20 and ERC721 functionality in one contract? I’m worried about potential issues with function naming conflicts. Any advice on structuring this would be super helpful!

// Simplified example of what I'm trying to achieve
contract IdeasFunding {
    // NFT functions
    function createIdea(string memory tokenURI) public {
        // Mint NFT
    }

    // ERC20 functions
    function fundIdea(uint256 ideaId, uint256 amount) public {
        // Transfer tokens to idea creator
    }
}

How can I make this work without running into conflicts between ERC20 and ERC721 standards?

hey there creativePainter45! i’m curious about your project, it sounds really interesting! :thinking: have you considered using OpenZeppelin’s ERC1155 standard instead? it lets you combine fungible and non-fungible tokens in one contract, which might be perfect for what youre trying to do.

something like this could work:

import '@openzeppelin/contracts/token/ERC1155/ERC1155.sol';

contract IdeasFunding is ERC1155 {
    constructor() ERC1155('https://yourapi.com/tokens/{id}.json') {}

    function createIdea(uint256 ideaId) public {
        _mint(msg.sender, ideaId, 1, '');
    }

    function fundIdea(uint256 ideaId, uint256 amount) public {
        _mint(msg.sender, 0, amount, '');
        safeTransferFrom(msg.sender, ownerOf(ideaId), 0, amount, '');
    }
}

this way, you could use token ID 0 for your fungible funding tokens, and other IDs for your unique ideas. what do you think about this approach? would it work for your use case?

I’ve tackled a similar challenge in one of my projects. Instead of separate contracts, I found it more efficient to use a single contract that inherits from both ERC721 and ERC20. This approach reduces gas costs and simplifies management.

Here’s a basic structure I used:

import '@openzeppelin/contracts/token/ERC721/ERC721.sol';
import '@openzeppelin/contracts/token/ERC20/ERC20.sol';

contract IdeasFunding is ERC721, ERC20 {
    constructor() ERC721('Ideas', 'IDEA') ERC20('Funding', 'FUND') {}

    function createIdea(string memory tokenURI) public {
        // Mint NFT logic
    }

    function fundIdea(uint256 ideaId, uint256 amount) public {
        // Transfer tokens logic
    }
}

This setup avoids naming conflicts and keeps everything in one place. Just ensure you implement all required functions for both standards. OpenZeppelin’s contracts are robust and help streamline the process.