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.