diff --git a/.gitignore b/.gitignore index afc76bb..e26c153 100644 --- a/.gitignore +++ b/.gitignore @@ -44,4 +44,5 @@ typechain-types #Hardhat files cache artifacts +.prettierrc diff --git a/contracts/Escrow.sol b/contracts/Escrow.sol index d6990b4..f98b1e7 100644 --- a/contracts/Escrow.sol +++ b/contracts/Escrow.sol @@ -10,5 +10,43 @@ interface IERC721 { } contract Escrow { + address public nftAddress; //stores smart contract of NFT + address payable public seller; //person who lists the Real estate NFT + address public lender; //address of the lender to lends payment + address public inspector; + modifier onlySeller() { + require(msg.sender == seller, "Only seller can use this"); + _; + } + + mapping(uint256 => bool) public isListed; + mapping(uint256 => uint256) public purchasePrice; + mapping(uint256 => uint256) public escrowAmount; + mapping(uint256 => address) public buyer; + + constructor( + address _nftAddress, + address payable _seller, + address _inspector, + address _lender + ) { + nftAddress = _nftAddress; + seller = _seller; + lender = _lender; + inspector = _inspector; + } + + function list( + uint256 _nftID, + address _buyer, + uint256 _purchasePrice, + uint256 _escrowAmount + ) public payable onlySeller { + IERC721(nftAddress).transferFrom(msg.sender, address(this), _nftID); + isListed[_nftID] = true; + purchasePrice[_nftID] = _purchasePrice; + buyer[_nftID] = _buyer; + escrowAmount[_nftID] = _escrowAmount; + } } diff --git a/contracts/RealEstate.sol b/contracts/RealEstate.sol index 882434b..c5ffcde 100644 --- a/contracts/RealEstate.sol +++ b/contracts/RealEstate.sol @@ -1,6 +1,27 @@ //SPDX-License-Identifier: Unlicense pragma solidity ^0.8.0; -contract RealEstate { +import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol"; +import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; +import "@openzeppelin/contracts/utils/Counters.sol"; +contract RealEstate is ERC721URIStorage { + using Counters for Counters.Counter; + Counters.Counter private _tokenIds; + + constructor() ERC721("Real Estate", "RET") {} + + function mint(string memory tokenURI) public returns (uint256) { + _tokenIds.increment(); + + uint256 newItemId = _tokenIds.current(); + _mint(msg.sender, newItemId); + _setTokenURI(newItemId, tokenURI); + + return newItemId; + } + + function totalSupply() public view returns (uint256) { + return _tokenIds.current(); + } } diff --git a/test/Escrow.js b/test/Escrow.js index 9b84e1a..b32eee5 100644 --- a/test/Escrow.js +++ b/test/Escrow.js @@ -1,10 +1,90 @@ -const { expect } = require('chai'); -const { ethers } = require('hardhat'); +const { expect } = require("chai") +const { ethers } = require("hardhat") const tokens = (n) => { - return ethers.utils.parseUnits(n.toString(), 'ether') + return ethers.utils.parseUnits(n.toString(), "ether") } -describe('Escrow', () => { +describe("Escrow", () => { + let buyer, seller + let realEstate, escrow + //create the following set up for each test + beforeEach(async () => { + //create dummy accounts for test + ;[buyer, seller, inspector, lender] = await ethers.getSigners() + + //deploy realestate + const RealEstate = await ethers.getContractFactory("RealEstate") + realEstate = await RealEstate.deploy() + + //mint + let transaction = await realEstate + .connect(seller) + .mint( + "https://ipfs.io/ipfs/QmQVcpsjrA6cr1iJjZAodYwmPekYgbnXGo4DFubJiLc2EB/1.json" + ) + await transaction.wait() + + //deploy escrow + const Escrow = await ethers.getContractFactory("Escrow") + escrow = await Escrow.deploy( + realEstate.address, + seller.address, + inspector.address, + lender.address + ) + + //approve property + transaction = await realEstate + .connect(seller) + .approve(escrow.address, 1) + await transaction.wait() + + //list property + transaction = await escrow + .connect(seller) + .list(1, buyer.address, tokens(10), tokens(5)) + await transaction.wait + }) + + describe("Deployment", () => { + it("Returns NFT address", async () => { + const result = await escrow.nftAddress() + expect(result).to.be.equal(realEstate.address) + }) + it("Returns Seller", async () => { + const result = await escrow.seller() + expect(result).to.be.equal(seller.address) + }) + it("Returns Inspector", async () => { + const result = await escrow.inspector() + expect(result).to.be.equal(inspector.address) + }) + it("Returns Lender", async () => { + const result = await escrow.lender() + expect(result).to.be.equal(lender.address) + }) + }) + + describe("Listing", () => { + it("Updates ownership", async () => { + expect(await realEstate.ownerOf(1)).to.be.equal(escrow.address) + }) + it("Updates as listed", async () => { + expect(await realEstate.ownerOf(1)).to.be.equal(escrow.address) + }) + it("Returns buyer", async () => { + const result = await escrow.buyer(1) + expect(result).to.be.equal(buyer.address) + }) + it("Returns purchase price", async () => { + const result = await escrow.purchasePrice(1) + expect(result).to.be.equal(tokens(10)) + }) + it("Returns escrow amount", async () => { + const result = await escrow.escrowAmount(1) + expect(result).to.be.equal(tokens(5)) + }) + }) })