1

I'm new to coding and solidiy - I'm trying to test a covered-call option smart contract in hardhat but keep getting a transaction reverted error when I try to test the transfer of ether into the covered call contract and I'm not sure how to solve it.

here is my smart contract:

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

contract CoveredCallContract {

    address public callWriter;
    address public callBuyer;
    uint public amount;
    uint public optionPrice;
    uint public strikePrice;
    uint public expiryDate;
    bool wasPurchased;

    constructor(uint _amount, uint _optionPrice, uint _strikePrice) {
        callWriter = msg.sender;
        amount = _amount;
        optionPrice = _optionPrice;
        strikePrice = _strikePrice;
        expiryDate = block.timestamp + 1 weeks;
    }

    // this function is how the callwriter deposits the collateral to cover the option
    function depositCollateral() public payable {
        // ensure call writier has enough money in their account
        require(msg.sender.balance >= amount, " Insufficient balance");

        payable(address(this)).transfer(amount);
    }

    // this function allows the buyer to purchase the contract and pay the premium
    function purchaseOption() external payable {
        // ensure buyer hasn't already bought the option
        require(wasPurchased == false);

        // ensure buyer sends the correct amount
        require(msg.value == optionPrice, "Incorrect purchase price");

        // set the option buyer to the callbuyer
        callBuyer = msg.sender;

        // if the buyer buys the option, the price is transfered directly to the writer
        payable(callWriter).transfer(msg.value);

        // set the wasPurchased to true one the option has been purchased
        wasPurchased = true;

    }

    // the option will be executed if the price of ETH is above the strike price 
    function executeOption() external payable {
        // ensure the buyer has purchased the option
        require(wasPurchased == true);

        // make sure it's the buyer executing the contract
        require(msg.sender == callBuyer, "Unauthorized");

        // ensure the contract has been funded by the call writer
        require(address(this).balance == amount, "Funding error");

        // ensure the amount the buyer pays at execution is equal to the strikeprice
        require(msg.value == strikePrice, "Payment error");

        // make sure the contract has not expired
        require(block.timestamp <= expiryDate, "Option has already expired");

        // if all the above hold transfer the amount to the buyer
        payable(callBuyer).transfer(address(this).balance);
    }

    // if the option is not executed the initial funds will be sent back to the call writer
    function refund() public payable {
        if(wasPurchased == false) {
            require(block.timestamp >= expiryDate, "Option has not expired yet");
        }
        payable(callWriter).transfer((address(this).balance));
    }
}

and here is my JS test:

const { expect, assert } = require("chai");
const { ethers } = require("hardhat");
const { BigNumber } = require("@ethersproject/bignumber");
const { Web3Provider } = require("@ethersproject/providers");

describe("CoveredCallContract", function () {

  let coveredCallContract;
  let callWriter;
  let callBuyer;
  const amount = ethers.utils.parseEther("1");
  const optionPrice = ethers.utils.parseEther("0.1");
  const strikePrice = ethers.utils.parseEther("1.5");

  this.beforeEach(async () => {
    [callWriter, callBuyer] = await ethers.getSigners();
    const CoveredCallContract = await ethers.getContractFactory("CoveredCallContract");
    coveredCallContract = await CoveredCallContract.deploy(amount, optionPrice, strikePrice);
    await coveredCallContract.deployed();
  });

  it("should have call writer address equal the deployer address", async () => {
    assert(await coveredCallContract.connect(callWriter))
  })

  it('should set option expiry date', async () => {
    const expiryDate = await coveredCallContract.expiryDate();
    assert(expiryDate);
  });

  it('should not have an intial ether balnce in the contract', async () => {
    const balance = await ethers.provider.getBalance(coveredCallContract.address);
    assert.equal(balance, 0);
    console.log(balance);
  });

  it('should NOT deposit collateral if writers balance is too low', async () => {
    const writerBalance = await ethers.provider.getBalance(callWriter.address);
    expect(writerBalance).to.be.greaterThan(amount);
  });
    
  it('should deposit the collateral', async () => {
    await coveredCallContract.connect(callWriter).depositCollateral({value: amount});
  });

  it('should now have an ether balance', async () => {
    const balance = await ethers.provider.getBalance(coveredCallContract.address);
    await expect(balance).to.be.equal(amount);
    console.log(balance);
  });  

  it('should NOT buy option if not paying the correct price', async () => {
    await expect(coveredCallContract.purchaseOption({value: ethers.utils.parseEther("0.2")})).to.be.revertedWith("Incorrect purchase price");
  });

  it('should purchase option', async () => {
    await coveredCallContract.purchaseOption({value: optionPrice});
  });

  it('should execute option', async () => {
    await coveredCallContract.connect(callBuyer).executeOption({value: amount});
  });

  it('should refund the writer if option not executed', async () => {
    const expiryDate = await coveredCallContract.expiryDate();
    const unixSeconds = Date.now() / 1000;
    const oneWeek = 8 * 24 * 60 * 60;
    assert.equal(expiryDate, await hre.network.provider.request({
      method: "evm_setNextBlockTimestamp",
      params: [unixSeconds + oneWeek]
    }));
    await hre.network.provider.request({ method: "evm_mine" });
    
    await coveredCallContract.refund({value: amount});
  });
})
 

I was testing to transfer eth from the call writers address to the covered calls smart contract.

I was expecting to then see the balance of the smart contract be equal to the amount deposited.

the transfer however reverted and I can't fully understand why.

a couple of the tests have not passed and I'm struggling to understand why. Any advice would be greatly appreciated.

1 Answer 1

0

You said 'the transfer however reverted'. What transfer exactly are you talking about? Is it this one that reverts?

it('should deposit the collateral', async () => {
    await coveredCallContract.connect(callWriter).depositCollateral({value: amount});
  });

Also, your function depositColateral is wrong

 function depositCollateral() public payable {
        // ensure call writier has enough money in their account
        require(msg.sender.balance >= amount, " Insufficient balance");

        payable(address(this)).transfer(amount);
    }

the function should be

 function depositCollateral() public payable {
        // ensure call writier has enough money in their account
        require(msg.value >= amount, " Insufficient balance");
    }

Your "payable(address(this)).transfer(amount);" basically transfer the eth received from the smart contract to the smart contract, which is unnecessary.

Also, the require is wrong. For exemple, with your function, if I have only one ether in my wallet, and I send it to your function depositColateral(), my balance is now 0 and the function will revert even if I provided enough ether to pass the 'amount' check. On the other hand, if I send 0 wei , my balance will be 1 eth, and the check will pass even tho I provided no fund to the function.

Does that makes sense?

2
  • hi Olivier, thanks for getting back to me so quickly - apaologies for my late response back. Your comments on the deposit collateral test made sense. I amended it and the test was successful. The following test "should now have an ether balance" however still failed with:
    – 0xJI
    Dec 1, 2022 at 17:32
  • AssertionError: expected 0 to equal 1000000000000000000. The numerical values of the given "ethers.BigNumber" and "ethers.BigNumber" inputs were compared, and they differed. + expected - actual -0 +1000000000000000000 ....I'm not quite sure why but it seems as though the deposited collateral didn't transfer to the smart contract or am I missing somthing? I think this also caused the execute option test to fail also - do you have any suggestions as to where I've gone wrong?
    – 0xJI
    Dec 1, 2022 at 17:37

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.