[Ethereum] ethers.js (node.js) call solidity function that is payable

ethers.jsjavascriptnodejssoliditytransactions

I understand that you can send ethereum to a smart contract, although when you do this with sendTransaction it doesn't seem that you specify a function on the smart contract when you do this. I don't quite understand how this is useful.
However what I can't find out how to do, is to send ethereum to a function that is set as payable.
I'm using ethers.js and can create a contract, and call functions that are viewable (read only) no problem, but I cant work out how to send ethereum with the transaction to a specific function

export const testContract = async (address, abi) => {
  const wei = Utils.parseEther("0.1")
  const url = "http://localhost:8545"
  const provider = new Providers.JsonRpcProvider(url)
    // Load the wallet to deploy the contract with
  const privateKey =
    "0x123"
  const wallet = new Wallet(privateKey, provider)

  var contract = new Contract(address, abi, wallet)

  const price = await contract.retrievePrice()
  console.log("price " + price) //logs the price set in the constructor when the contract was made (WORKS)
  const testAddress = await contract.isUser(
    "0x456"
  )
  console.log("testAddress ", testAddress) //checks if the given address is a user on the contract (WORKS)

  const gasPrice = await provider.getGasPrice()
  console.log("gas price: ", gasPrice.toString()) //returns the price of gas from the network (WORKS)
  try {
    const addToUsers = await contract.requestAccess({ //call function to request access, from the current wallet (REVERTS)
      value: wei
    })
    console.log("result of sending transaction ", addToUsers)
  } catch (error) {
    console.log("error.... ", error) //fires as the contract reverted the payment
  }
}

Any help as to why calling contract.requestAccess is reverting on me? I can't quite work out how to call a specific function and send Ether.
Thanks!

Response to comment

Ok right, so the function in the solidity contract looks like:

  function requestAccess() payable {
    require(msg.value == price, "Incorrect sum sent to contract");
    _addUser(msg.sender);
  }

I commented out the require, to try that but still reverts. _addUser is from a contract mine inherits from, and looks like

  function _addUser(address account) internal {
    users.add(account);
    emit UserAdded(account);
  }

users is Roles.Role private users; and sits in the parent contract

contract Users {
  using Roles for Roles.Role;

which imports from openzeppelin "openzeppelin-solidity/contracts/access/Roles.sol"

Best Answer

You may notice in the comments, I was unable to work out what wasn't working for me, but not a fan of "it works, thanks" answers which don't help others. So I have put a working example up on gists for anyone who is looking for this. Just need to make some changes to be specific to your situation, but should be relatively straight forward. https://gist.github.com/amlwwalker/89bc2c5a2b631527bb7def922b4c8306