How to calculate rate for an ERC20 exchange for a token with 0 decimals?

I have an ERC20 token and an exchange contract modeled after the Ethereum Tutorial

I’m confused about how to correctly calculate the rate for the exchange.

MyToken has 50 trillion tokens and I want that displayed where 1 = “1”, 500 = “500” etc. so I’ve called _setupDecimals(0) in the constructor of MyToken.

I want 1 ETH to equal 2 billion MyTokens so I set the rate to be 2 billion.

However, this is showing transaction balance exceeded errors when I call eth_sendTransaction.

What is the best way to calculate the rate for this setup?

:1234: Code to reproduce

pragma solidity ^0.6.2;

import "@openzeppelin/contracts-ethereum-package/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts-ethereum-package/contracts/math/SafeMath.sol";
import "hardhat/console.sol";

contract MyTokenExchange {
  using SafeMath for uint256;

  uint256 public rate;
  IERC20 public token;

  constructor(IERC20 _token) public {
    // two billion
    rate = 2000000000;
    token = _token;

  receive() external payable {
    uint256 tokens = msg.value.mul(rate);
    token.transfer(msg.sender, tokens);

// test
  it("allows purchasing MyTokens", async function () {
    const params = [
        from: this.signers.admin.address,
        to: this.mytokenexchange.address,
        value: `0x${(1).toString(16)}`, // Is this equivalent of 1 ETH?

    const transactionHash = await ethers.provider.send("eth_sendTransaction", params);

    expect(await this.mytoken.balanceOf(this.signers.admin.address)).to.equal(2000000000);

:computer: Environment

"ethereum-waffle": "^3.4.0",
"ethers": "^5.4.0",
"hardhat": "^2.4.1",