3

For reference, I am using Solidity to develop a smart contract for my company. I created a smart contract and attempted to use Truffle and Ganache to unit test it. However, I'm having a bit of an issue with my smart contract returning Error: VM Exception while processing transaction: revert when I try to unit test it with Truffle. After testing my code a lot, I have managed to cut down the smart contract to the following code, which still produces the error.

pragma solidity ^0.4.22;

contract Purchase {

 address public buyer;
 address public seller;
 address public companyEscrow;
 uint private moneyInEscrow = 0;

 modifier onlyCompanyEscrow {
    require(
        msg.sender == companyEscrow,
        "Only the escrow account of the company can call this function."
    );
    _;
 }

 modifier onlyBuyer {
    require(
        msg.sender == buyer,
        "Only the buyer can call this function."
    );
    _;
 }

 constructor (address addressSeller, address addressCompanyEscrow) public payable {
    buyer = msg.sender;
    seller = addressSeller;
    companyEscrow = addressCompanyEscrow;
 }

 function sendFundsToCompany ()
      public
      payable
      onlyBuyer
      returns (bool completed)
  {
      moneyInEscrow = msg.value;
      companyEscrow.transfer(moneyInEscrow);
      return true;
  }


  function sendFundsToSeller ()
      public
      payable
      onlyCompanyEscrow
      returns (bool completed)
  {
      seller.transfer(moneyInEscrow);
      moneyInEscrow = 0;
      return true;
  }
}

The function sendFundsToCompany() is supposed to be executed first and then afterwards, the function sendFundsToSeller() is supposed to be executed. I cut down my unit testing to the following Truffle unit test, which still produces the error:

var Web3Beta = require('web3')
var web3beta = new Web3Beta()
var Purchase = artifacts.require('Purchase')

contract('Purchase', function ([buyer, seller, companyEscrow] {

  var purchase = await Purchase.new(seller, companyEscrow)

  it('Should send funds to seller', async function () {
    var sellerInitialBalance = web3.eth.getBalance(seller).toNumber()
    var companyEscrowInitialBalance = web3.eth.getBalance(companyEscrow).toNumber()

    await purchase.sendFundsToCompany({ value: web3beta.utils.toWei('3', 'ether'), gas: "6600000" })
    await purchase.sendFundsToSeller({ from: companyEscrow, gas: "6600000" })

    assert.isAbove(web3.eth.getBalance(seller).toNumber(), sellerInitialBalance)
    assert.isBelow(web3.eth.getBalance(companyEscrow).toNumber(), companyEscrowInitialBalance)
  })
})

I have combed through the Ethereum StackExchange, the Truffle help boards, and the Solidity documentation. However, the bug still eludes me. After looking through similar questions on the Ethereum StackExchange, I performed the following actions:

  • I made sure both functions have the 'payable' modifier.
  • I explicitly sent the functions a large gas limit.
  • I deleted the /builds folder and recompiled everything.
  • I ended the current deployment and started a new instance with 'truffle develop'.

Unfortunately, doing these things didn't resolve my problem. I'm at a bit of a loss as to what the problem is. I'm new to Solidity so it's probably something basic; however, I can't seem to figure out what it is.

For reference, my version of Truffle is 4.1.13 and my version of Ganache is 6.1.6 (ganache-core = 2.1.5). Also, I'm running 'truffle develop' and performing my unit tests in two separate command prompts - I run 'truffle develop' in one prompt and only after do I perform the unit tests in the other command prompt.

I would greatly appreciate any help or guidance you can provide me. Thank you in advance!

  • 1
    Have you tried running that in Remix ? Because there everything works fine for me, can you confirm? I suppose it's in the tests somewere. Which of the transaction calls exactly causes the error ? – Nikita Fuchs Jul 12 '18 at 19:31
2

There may be other issues, but this is certainly one:

function sendFundsToCompany ()
    public
    payable
    onlyBuyer
    returns (bool completed)
{
    moneyInEscrow = msg.value;
    companyEscrow.transfer(moneyInEscrow);
    return true;
}

If you send this function 1 wei, then moneyInEscrow == 1, and that 1 wei is transferred away to companyEscrow. So the contract balance remains at 0.

function sendFundsToSeller ()
    public
    payable
    onlyCompanyEscrow
    returns (bool completed)
{
    seller.transfer(moneyInEscrow);
    moneyInEscrow = 0;
    return true;
}

If you then call this function, an attempt is made to send moneyInEscrow (1) wei to seller. But the contract balance is 0, so this transfer will fail.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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