Search code examples
javascriptonclicksolidityweb3jserc20

Web3 Token Holder Requirement to Show Image


Is it possible, in Web3, to call a function which would require the user to first hold an ERC20 token before an image/text is visible? This would be similar to a password requirement, but instead of typing a password for the function to take effect, they would simply have to hold at least 1 ERC20 token. Now, in solidity I've been able to write a function that simply returns a text line if msg.sender has at least one ERC20. I want to do this but in web3 that would reveal a .jpg image of instructions:

function Reveal()override public view returns (string memory) {
    require(ERC20Token(0xB0Bd09D....).balanceOf(msg.sender) >= 1 wei, "Error");
     return 'Thank you for collecting  an ERC20Token, the instructions will be sent out shortly';
}

On a website I have a .jpg image that has instructions written on it for the msg.sender, but only want them to have this image visible to viewers that hold a token. I have a button labeled "Reveal" with an OnClick that would fire something like this:

//sender presses "reveal" button, function checks if sender has at least 1 ERC20Token. If true, then "Instructions" image is made visible. If not, textbox appears.

 contract.methods.reveal.call()({ 
if(ERC20Token(0xB0Bd09D....).balanceOf(msg.sender) >= 1 wei); {
document.getElementById("instructions").style.visibility="visible";
} else{
              //Tell viewer that they require ERC20 token
              buttonx.innerHTML = " You require at least 1 ERC20Token to proceed";

I'm probably going about this wrong in Solidity, but trying to figure it out. So far I've been using Metamask and selecting the current users account with window.web3.currentProvider.selectedAddress which I should incorporate as well?


Solution

  • A) It is matter of taste but would it not be better to rename Reveal() to hasERC20() and return "bool"? Also for me it seems that "require" validation is a bit unnecessary in this situation so Solidity code could look like:

    function hasERC20() public view returns (bool memory) {  
        return (ERC20Token(0xB0Bd09D....).balanceOf(msg.sender) >= 1);  
    }
    

    B) You don't have to use ERC20Token() for the second time because it is already in Solidity code so the code could look like:

    const msgSenderHasERC20 = await contract.methods.hasERC20().call();
    
    if (msgSenderHasERC20){
        document.getElementById("instructionsHasERC20_true").style.visibility="visible";
        document.getElementById("instructionsHasERC20_false").style.visibility="hidden";
    } else {
        document.getElementById("instructionsHasERC20_true").style.visibility="hidden";
        document.getElementById("instructionsHasERC20_false").style.visibility="visible";   
    }  
    

    C) You should not use "window.web3.currentProvider.selectedAddress" because it is DEPRECATED. Use ethereum.request({ method: 'eth_accounts' }) instead. The "currently selected" address is the first item in the array returned by eth_accounts.