const { ethers } = require("hardhat")
const { time } = require("@nomicfoundation/hardhat-network-helpers");
describe("Escrow", function () {
let Escrow;
let escrow;
let PropertyToken;
let propertyToken;
let owner;
let inspector;
let seller;
let buyer;
let tenant;
const TOKEN_ID = 1;
const PRICE_FOR_RENT = ethers.utils.parseEther("0.1");
const PRICE_FOR_BUY = ethers.utils.parseEther("1");
const ESCROW_AMOUNT = ethers.utils.parseEther("0.5");
beforeEach(async function () {
[owner, inspector, seller, buyer, tenant] = await ethers.getSigners();
// Deploy PropertyToken with the initial owner
PropertyToken = await ethers.getContractFactory("PropertyToken");
propertyToken = await PropertyToken.deploy(owner.address);
await propertyToken.deployed();
// Mint a token to the seller
await propertyToken.connect(owner).safeMint(seller.address, "Token URI");
// Deploy Escrow with the correct arguments
Escrow = await ethers.getContractFactory("Escrow");
escrow = await Escrow.deploy(propertyToken.address, inspector.address);
await escrow.deployed();
// Approve the escrow contract to transfer the NFT
await propertyToken.connect(seller).approve(escrow.address, TOKEN_ID);
});
describe("Deployment", function () {
it("Should set the right PTK address", async function () {
expect(await escrow.PTKaddress()).to.equal(propertyToken.address);
});
it("Should set the right inspector", async function () {
expect(await escrow.inspector()).to.equal(inspector.address);
});
});
describe("Listing Property", function () {
it("Should list a property", async function () {
await escrow.connect(seller).listProperty(TOKEN_ID, PRICE_FOR_RENT, PRICE_FOR_BUY, ESCROW_AMOUNT);
expect(await escrow.getSeller(TOKEN_ID)).to.equal(seller.address);
});
it("Should not allow listing with zero prices", async function () {
await expect(escrow.connect(seller).listProperty(TOKEN_ID, 0, PRICE_FOR_BUY, ESCROW_AMOUNT)).to.be.revertedWith("Enter a Amount greater than 0");
await expect(escrow.connect(seller).listProperty(TOKEN_ID, PRICE_FOR_RENT, 0, ESCROW_AMOUNT)).to.be.revertedWith("Enter a Amount greater than 0");
});
});
describe("Depositing Earnest", function () {
beforeEach(async function () {
await escrow.connect(seller).listProperty(TOKEN_ID, PRICE_FOR_RENT, PRICE_FOR_BUY, ESCROW_AMOUNT);
});
it("Should allow depositing earnest for buying", async function () {
await expect(escrow.connect(buyer).depositEarnest(TOKEN_ID, false, { value: ESCROW_AMOUNT })).to.not.be.reverted;
});
it("Should allow depositing earnest for renting", async function () {
await expect(escrow.connect(tenant).depositEarnest(TOKEN_ID, true, { value: PRICE_FOR_RENT })).to.not.be.reverted;
});
it("Should not allow depositing if property is not listed", async function () {
await expect(escrow.connect(buyer).depositEarnest(TOKEN_ID + 1, false, { value: ESCROW_AMOUNT })).to.be.revertedWith("Property is already sold");
});
});
describe("Executing Buy", function () {
beforeEach(async function () {
await escrow.connect(seller).listProperty(TOKEN_ID, PRICE_FOR_RENT, PRICE_FOR_BUY, ESCROW_AMOUNT);
await escrow.connect(buyer).depositEarnest(TOKEN_ID, false, { value: ESCROW_AMOUNT });
await escrow.connect(inspector).approveInspection(TOKEN_ID);
await propertyToken.connect(seller).transferFrom(seller.address, escrow.address, TOKEN_ID);
await buyer.sendTransaction({
to: escrow.address,
value: PRICE_FOR_BUY
});
});
it("Should execute buying", async function () {
await expect(escrow.connect(buyer).executeBuying(TOKEN_ID))
.to.emit(escrow, "PurchaisedPropertySuccess")
.withArgs(TOKEN_ID, buyer.address, seller.address);
});
it("Should not allow buying without inspection", async function () {
await escrow.connect(seller).listProperty(TOKEN_ID + 1, PRICE_FOR_RENT, PRICE_FOR_BUY, ESCROW_AMOUNT);
await escrow.connect(buyer).depositEarnest(TOKEN_ID + 1, false, { value: ESCROW_AMOUNT });
await expect(escrow.connect(buyer).executeBuying(TOKEN_ID + 1)).to.be.revertedWith("Inspection Isn't passed");
});
});
describe("Executing Rent", function () {
beforeEach(async function () {
await escrow.connect(seller).listProperty(TOKEN_ID, PRICE_FOR_RENT, PRICE_FOR_BUY, ESCROW_AMOUNT);
await escrow.connect(tenant).depositEarnest(TOKEN_ID, true, { value: PRICE_FOR_RENT });
await escrow.connect(inspector).approveInspection(TOKEN_ID);
await propertyToken.connect(seller).transferFrom(seller.address, escrow.address, TOKEN_ID);
});
it("Should execute renting", async function () {
await expect(escrow.connect(tenant).executeRent(TOKEN_ID, 7))
.to.emit(escrow, "RentedPropertySuccess")
.withArgs(TOKEN_ID, tenant.address, seller.address, 2); // 2 is rentForweek
});
it("Should not allow renting without earnest", async function () {
await escrow.connect(seller).listProperty(TOKEN_ID + 1, PRICE_FOR_RENT, PRICE_FOR_BUY, ESCROW_AMOUNT);
await escrow.connect(inspector).approveInspection(TOKEN_ID + 1);
await expect(escrow.connect(tenant).executeRent(TOKEN_ID + 1, 7)).to.be.revertedWith("Have to deposit Earnest first");
});
});
describe("Chainlink Automation", function () {
beforeEach(async function () {
await escrow.connect(seller).listProperty(TOKEN_ID, PRICE_FOR_RENT, PRICE_FOR_BUY, ESCROW_AMOUNT);
await escrow.connect(tenant).depositEarnest(TOKEN_ID, true, { value: PRICE_FOR_RENT });
await escrow.connect(inspector).approveInspection(TOKEN_ID);
await propertyToken.connect(seller).transferFrom(seller.address, escrow.address, TOKEN_ID);
await escrow.connect(tenant).executeRent(TOKEN_ID, 7);
});
it("Should check upkeep", async function () {
await time.increase(8 * 24 * 60 * 60); // Increase time by 8 days
const [upkeepNeeded, performData] = await escrow.checkUpkeep("0x");
expect(upkeepNeeded).to.be.true;
});
it("Should perform upkeep", async function () {
await time.increase(8 * 24 * 60 * 60); // Increase time by 8 days
const [, performData] = await escrow.checkUpkeep("0x");
await expect(escrow.performUpkeep(performData)).to.emit(escrow, "returnRentedProperty");
});
it("Should not need upkeep before rental period ends", async function () {
const [upkeepNeeded] = await escrow.checkUpkeep("0x");
expect(upkeepNeeded).to.be.false;
});
});
});
``` is my test file for contract ```//SPDX-License-Identifier:MIT
pragma solidity ^0.8.20;
import {PropertyToken} from "./ERC-721/PropertyToken.sol";
import {AutomationCompatibleInterface} from "@chainlink/contracts/src/v0.8/automation/AutomationCompatible.sol";
contract Escrow is AutomationCompatibleInterface{
address public PTKaddress;
address public inspector;
PropertyToken public PTKcontract;
uint rentFordays=1;
uint rentForweek=2;
uint rentFormonths=3;
event returnRentedProperty(
uint indexed nftId ,
address indexed tenant,
uint rentPaid
);
event PurchaisedPropertySuccess(
uint indexed nftId ,
address indexed buyer,
address indexed seller
);
event RentedPropertySuccess(
uint indexed nftId ,
address indexed tenant,
address indexed owner,
uint rent
);
constructor(address _PTKaddress, address _inspector)
{
PTKaddress=_PTKaddress;
inspector=_inspector;
PTKcontract = PropertyToken(_PTKaddress);
}
modifier onlyInspector(){
require(msg.sender==inspector,"Only inspector can call this function");
_;
}
mapping(uint=>bool)isListed;
mapping(uint=>address)tenant;
mapping(uint=>uint)returnTime;
mapping(address=>mapping(uint=>uint))rentDuration;
mapping(uint=>address)sellers;
mapping(uint=>uint)escrowAmount;
mapping(uint=>uint)priceForRent;
mapping(uint=>uint)priceForBuy;
mapping(uint=>bool)isInspectionPassed;
mapping(uint=> mapping(address=>bool))approval;
uint[] public activeTokensOnRent;
function listProperty(uint nftId,uint _priceForRent,uint _priceForBuy,uint _escrowAmt) public
{
require(_priceForRent>0,"Enter a Amount greater than 0");
require(_priceForBuy>0,"Enter a Amount greater than 0");
require(_escrowAmt>0,"Enter a Amount greater than 0");
isListed[nftId] = true;
sellers[nftId]=msg.sender;
priceForRent[nftId] = _priceForRent;
priceForBuy[nftId] = _priceForBuy;
escrowAmount[nftId] = _escrowAmt;
}
function getTotalSupply() public view returns(uint){
return PTKcontract.totalSupply();
}
function getSeller(uint nftId) public view returns(address)
{
return sellers[nftId];
}
function approveInspection(uint nftId) public onlyInspector{
isInspectionPassed[nftId]=true;
}
function getInspectionStatus(uint nftId) public view returns(bool){
return isInspectionPassed[nftId];
}
function depositEarnest(uint nftId,bool rent) public payable
{
require(isListed[nftId],"Property is already sold");
require(tenant[nftId]==address(0),"Property is on Rent");
if(!rent)
require(msg.value>=escrowAmount[nftId],"Amount should be greater than/equal to escrow amount");
else
{
require(msg.value>=priceForRent[nftId],"Amount should be greater than/equal to escrow amount");
tenant[nftId]=msg.sender;
}
}
function approveSale(uint nftId) public {
require(approval[nftId][msg.sender]==false,"ALready Approved");
approval[nftId][msg.sender]=true;
}
function executeBuying(uint nftId) public {
uint supply = getTotalSupply();
require(nftId<=supply,"Property doesn't exists");
require(isInspectionPassed[nftId]==true,"Inspection Isn't passed");
require(address(this).balance>=priceForBuy[nftId],"Insufficient balance");
address seller = sellers[nftId];
uint amount = escrowAmount[nftId];
isListed[nftId]=false;
(bool success,)=payable(seller).call{value:amount}("Amount transfered");
PTKcontract.transferFrom(address(this),msg.sender,nftId);
require(success,"Transfer to seller failed");
emit PurchaisedPropertySuccess(nftId,msg.sender,seller);
}
function executeRent(uint nftId,uint duration) public {
uint supply = getTotalSupply();
require(nftId<=supply,"Property doesn't exists");
require(tenant[nftId]==msg.sender,"Have to deposit Earnest first");
require(isInspectionPassed[nftId]==true,"Inspection Isn't passed");
require(address(this).balance>=priceForRent[nftId],"Insufficient balance");
address owner = sellers[nftId];
uint amount = priceForRent[nftId];
uint rent;
if(duration<7)
rent=rentFordays;
else if(duration>=7 && duration<30)
rent=rentForweek;
else
rent=rentFormonths;
tenant[nftId]=msg.sender;
returnTime[nftId]=block.timestamp+duration;
rentDuration[msg.sender][nftId] = duration;
(bool success,)=payable(owner).call{value:amount}("Amount transfered");
PTKcontract.transferFrom(address(this),msg.sender,nftId);
activeTokensOnRent.push(nftId);
require(success,"Transfer to owner failed");
emit RentedPropertySuccess(nftId,msg.sender,owner,rent);
}
function getTenant(uint nftId) public view returns(address){
return tenant[nftId];
}
function returnRentedproperty(uint nftId) internal{
require(tenant[nftId]!=address(0),"Property is not on rent");
uint rent;
address owner = sellers[nftId];
address currentTenant = getTenant(nftId);
uint duration = rentDuration[currentTenant][nftId];
if(duration<7)
rent=rentFordays;
else if(duration>=7 && duration<30)
rent=rentForweek;
else
rent=rentFormonths;
uint amountToReturn = priceForRent[nftId]-rent;
PTKcontract.transferFrom(currentTenant ,owner,nftId);
(bool success,)=payable(currentTenant ).call{value:amountToReturn}("amount transferred to tenant");
tenant[nftId]=address(0);
returnTime[nftId] = 0;
for(uint i=0;i<activeTokensOnRent.length;i++)
{
if(activeTokensOnRent[i]==nftId)
{
activeTokensOnRent[i] = activeTokensOnRent[activeTokensOnRent.length-1];
activeTokensOnRent.pop();
break;
}
}
require(success,"Transfer to owner failed");
emit returnRentedProperty(nftId,currentTenant,rent);
}
function checkUpkeep(bytes calldata checkdata) external view override returns (bool upkeepNeeded, bytes memory performData) {
uint[] memory tokensToreturn = new uint[](activeTokensOnRent.length);
uint count = 0;
for(uint i=0;i<activeTokensOnRent.length;i++)
{
uint nftID = activeTokensOnRent[i];
if(tenant[nftID]!=address(0) && block.timestamp>=returnTime[nftID])
{
tokensToreturn[count] = nftID;
count++;
}
}
uint [] memory propertyToReturn = new uint[](count);
for(uint i=0;i<count;i++) propertyToReturn[i]=tokensToreturn[i];
upkeepNeeded = count>0;
performData=abi.encode(propertyToReturn);
}
function performUpkeep(bytes calldata performData) external override {
(uint[] memory propertyToReturn) = abi.decode(performData,(uint[]));
for(uint i=0;i<propertyToReturn.length;i++) returnRentedproperty(propertyToReturn[i]);
}
}``` getting error while testing TypeError: Cannot read properties of undefined (reading 'parseEther'). Give me solution and also any further modification needed or not. Thank you in advance
Add a comment
|
2 Answers
ethers.utils.parseEther()
is deprecated in newer versions (i.e., v6
) of the Ethers library.
You need to use ethers.parseEther()
instead for compatibility with the latest version.
Try
const PRICE_FOR_RENT = ethers.parseEther("0.1");
https://stackoverflow.com/questions/77007626/const-amount-ethers-utils-parseether1