0

I am building an app where I'd like a purchaser to be able to seek a refund from the contract. Essentially I am trying to transfer eth from a contract to a wallet. When I get to the point of issuing a refund, the transaction in MetaMask shows that my wallet is transferring to the contract, not vice versa as I'd like. I'm using web3 and solidity. Here is my js function that is called from the account seeking refund:

window.resellTicket = async function () {    
// send a refund from contract to reseller
try {
  // Call resell method from contract
  const resell = TicketEvent.methods.resellTicket();
  await resell.send({'value': web3.utils.toHex(web3.utils.toWei('.1234', "ether"))});

} catch (err) {
  console.log(err);
}     
load();
}

The resellTicket method in my contract:

function resellTicket() public payable {
  msg.sender.transfer(ticketPrice);
  isHoldingValidTicket[msg.sender] = false;
  increaseInventory();
}

What I see in MetaMask: enter image description here

I've also tried hard coding the contract address as from: contract_address in my resellTicket js function in which case I get this error: Error: Returned error: Error: WalletMiddleware - Invalid "from" address.

I'm totally stuck here, any guidance would be appreciated!

2 Answers 2

1

I cannot understand why the user would need or want to send ETH along when requesting a refund. This also means your resell function should not be payable.

Now, to answer the question (even though it is very old, might still help someone), there are several possible causes to this reject, from the code your showed:

  1. You should not convert the wei amount to hex, this will have unexpected results, and could also cause the revert in some cases. The value returned by web3.utils.toWei is perfectly fine as it is.
  2. ticketPrice should be defined somewhere in your contract
  3. increaseInventory() might be the culprit
  4. contract might not have enough ETH

Using Remix and its step by step debugger will help identify the precise location of the revert.

Finally, and this is the most important part, which hopefully will help other readers avoid this class of mistake:

This resell function is vulnerable to a very basic attack, even if you add require(isHoldingValidTicket[msg.sender]); at the very beginning or as a modifier, as you should anyway.

  msg.sender.transfer(ticketPrice);
  isHoldingValidTicket[msg.sender] = false;
  increaseInventory();

The first line sends ETH to the msg.sender, which might be a malicious smart contract. Its fallback would trigger and could potentially call resell again, and get another refund, and again and again until out of gas or drained all the ETH. While it is true that transfer should protect you from that by forwarding only very little gas (2300), limitations like that can sometimes be circumvented, e.g. by using other vulnerabilities, causing great harm; while move a line of code during development is cheap, and in this case just good practice that can completely void a whole class of attacks.

You should always follow the Checks-Effects-Interactions pattern, and send the ETH last.

If you have several external interactions in the same function, be very careful how they are ordered and what correlation they have.

0

Contracts can't send transactions, only accounts can. What you'll have to do is call resellTicket function from the account that wants the refund.

7
  • Thanks for chiming in, the resellTicket function is already being called from the account that wants the refund.
    – gffbss
    Nov 18, 2018 at 3:02
  • Then what's the issue? That function is issuing the refund already, no need to do anything else
    – natewelch_
    Nov 18, 2018 at 3:47
  • The issue is that the transaction fails.
    – gffbss
    Nov 18, 2018 at 4:05
  • What error are you getting?
    – natewelch_
    Nov 18, 2018 at 13:48
  • Error: Transaction has been reverted by the EVM
    – gffbss
    Nov 18, 2018 at 18:04

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.