2

I've made an ERC20 token (TaylorSwiftCoin, aka SWFT), and I'm attempting to make a very basic smart contract. I'm running this on the Dune TestNet, and I simply want this smart contract to take 100 of these SWFT coins, and in return, display a message (this is just as a proof of concept for a project).

My code is as follows:

pragma solidity ^0.8.0;

import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol";

contract PurchaseTicket {
    IERC20 public constant token = IERC20(0xfd3a409a40A00E99AAbE072e304a540aa25Fd4e9);
    uint256 public constant ticketPrice = 100;
    string public constant successMessage = "Transaction successful. The following is your ticket number: 34824312.";
    address public owner;

    constructor() {
        owner = msg.sender;
    }

    function purchase() public payable returns (string memory) {
        require(token.transferFrom(msg.sender, address(this), ticketPrice), "Token transfer failed.");
        return successMessage;
    }

    function withdrawTokens() public payable {
        require(msg.sender == owner, "Only the owner can withdraw tokens.");
        uint256 contractBalance = token.balanceOf(address(this));
        require(token.transfer(owner, contractBalance), "Token withdrawal failed.");
    }
}

The problem is that the purchase() function always gives this error:

Gas estimation errored with the following message (see below). The transaction execution will likely fail. Do you want to force sending? Returned error: {"jsonrpc":"2.0","error":"Execution reverted","id":422342247361384}

and if I force send the transaction, I get the error: false Transaction mined but execution failed.

The withdrawTokens() function works however, and gives no such error. And I have been approving the contract using the ERC20 token's approve() function.

Does anyone have any insight into why this is happening, and if so, how to fix it?

3
  • 1
    Have you provided approval to this smart contract to spend the users SWFT token?
    – Sanjay S B
    Commented Apr 17, 2023 at 4:16
  • 1
    Yes, I think I am. I'm going to the deployed contract of the SWFT token, and putting in the contract address and 100 SWFT tokens as the parameters to the approve function. I then approve it in Metamask. Is that how you're supposed to do it?
    – Henry
    Commented Apr 17, 2023 at 4:36
  • Consider adding a check to ensure that the PurchaseTicket contract has the expected allowance before trying to call transferFrom: require(token.allowance(msg.sender, address(this)) >= ticketPrice)
    – Rohan Nero
    Commented Apr 17, 2023 at 5:06

3 Answers 3

1

Your require statement should check the balance of msg.sender and then perform the transfer on the next line after it passes that check.

4
  • 1
    I changed the function to this, but it still gets the same exact error. require(token.balanceOf(msg.sender) >= 100); token.transferFrom(msg.sender, address(this), ticketPrice);
    – Henry
    Commented Apr 17, 2023 at 3:47
  • It must be your deployment. Commented Apr 17, 2023 at 9:20
  • Do you know how I can see the successMessage as output once the transaction goes through? It's supposed to be returned by the function, but I never see it.
    – Henry
    Commented Apr 17, 2023 at 23:50
  • The decoded output is just " - "
    – Henry
    Commented Apr 18, 2023 at 0:28
1

This should work fine

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol";

contract PurchaseTicket {
    IERC20 public constant token = IERC20(0xfd3a409a40A00E99AAbE072e304a540aa25Fd4e9);
    uint256 public constant ticketPrice = 100;
    string public constant successMessage = "Transaction successful. The following is your ticket number: 34824312.";
    address public owner;

    constructor() {
        owner = msg.sender;
    }

    function purchase() public payable returns (string memory) {
        require(token.balanceOf(msg.sender) >= ticketPrice, "Token transfer failed.");
        token.transferFrom(msg.sender, address(this), ticketPrice);
        return successMessage;
    }

    function withdrawTokens() public payable {
        require(msg.sender == owner, "Only the owner can withdraw tokens.");
        uint256 contractBalance = token.balanceOf(address(this));
        require(token.transfer(owner, contractBalance), "Token withdrawal failed.");
    }
}

Require condition should actually be used for validation You can perform transaction in body of that function

enter image description here

Here working fine for me If you're getting the same error than it means you're not approving right amount of tokens. Make sure you are approving correct tokens

i.e if you wanna approve 100 tokens than you should pass the value after multiplying it with decimal In my case Decimal of token was 18 so put 18 Zeros ahead of 100 as 10000000000000000000

3
  • Thank you so much for the response! I got it working, and now it takes the SWFT tokens from my wallet. The only issue now is that I can't see the successMessage when the purchase() transaction goes through. How do I see the successMessage once the purchase() transaction goes through?
    – Henry
    Commented Apr 17, 2023 at 23:48
  • The decoded output is just " - "
    – Henry
    Commented Apr 18, 2023 at 0:28
  • can you share the output image in the question? Commented Apr 18, 2023 at 6:15
1

I tested your contract and it seems fine. But I still encountered the error you mentioned. The issue with my deployment was that I forgot to update the token address in the PurchaseTicket contract.

IERC20 public constant token = IERC20(0xfd3a409a40A00E99AAbE072e304a540aa25Fd4e9);

I was using your address instead of the one I deployed. Check if this is the reason for your error too.

The second might be, as everyone mentioned, the approval. But I guess in this case if you encounter a failed transaction, you would have seen the error message in the relevant explorer. So I am not 100% sure if that was the issue.

3
  • Thank you very much for the response! I was approving the wrong coin, not the actual SWFT coin at the address I had in the contract. So now I got it working, and it takes the SWFT tokens from my wallet. The only issue now is that I can't see the successMessage when the purchase() transaction goes through. How do I see the successMessage once the purchase() transaction goes through?
    – Henry
    Commented Apr 17, 2023 at 23:49
  • The decoded output is just " - "
    – Henry
    Commented Apr 18, 2023 at 0:28
  • @Henry Your purchase function is a state-changing function (not a view or pure function). This means that it will never return anything externally. You can try using events in this case. Commented Apr 18, 2023 at 5:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.