Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions broadcast/MarketPlace.s.sol/11155111/run-1742339819.json

Large diffs are not rendered by default.

46 changes: 46 additions & 0 deletions broadcast/MarketPlace.s.sol/11155111/run-1742415480.json

Large diffs are not rendered by default.

46 changes: 46 additions & 0 deletions broadcast/MarketPlace.s.sol/11155111/run-1742422433.json

Large diffs are not rendered by default.

46 changes: 46 additions & 0 deletions broadcast/MarketPlace.s.sol/11155111/run-latest.json

Large diffs are not rendered by default.

57 changes: 45 additions & 12 deletions src/MarketPlace.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ contract MarketPlace is ERC721URIStorage {

constructor() ERC721("CarMarketplace", "CARS") {
owner = msg.sender;
_nextTokenId = 1;
}

// events

struct CarInfo {
uint id;
string make;
string model;
uint256 year;
Expand All @@ -33,8 +33,9 @@ contract MarketPlace is ERC721URIStorage {
uint256 public dealerCount = 0;
uint256 public carCount = 0;
uint256 public dealerRegistrationFee = 0.01 ether;
uint256 public platformFee = 0.001 ether;

mapping(address => uint[]) public carsByDealer;
mapping(address => CarInfo[]) public carsByDealer;
mapping(address => CarInfo[]) public carBought;
mapping(uint256 => CarInfo) public carById;
mapping(address => Dealer) public dealers;
Expand Down Expand Up @@ -65,7 +66,8 @@ contract MarketPlace is ERC721URIStorage {

dealers[msg.sender] = Dealer(_email, _name, block.timestamp, true);
isRegistered[msg.sender] = true;

dealerCount++;
emit Events.DealerRegistered(msg.sender, _name, block.timestamp);
emit Events.DealerRegistered(msg.sender, _name, block.timestamp);
}

Expand All @@ -84,6 +86,7 @@ contract MarketPlace is ERC721URIStorage {
_setTokenURI(newCarId, _tokenURI);

carById[newCarId] = CarInfo(
_nextTokenId,
_make,
_model,
_year,
Expand All @@ -93,15 +96,20 @@ contract MarketPlace is ERC721URIStorage {
false
);

carsByDealer[msg.sender].push(newCarId);
carsByDealer[msg.sender].push(
CarInfo(_nextTokenId,_make, _model, _year, _vin, _price, msg.sender, false)
);

carCount++;
emit Events.CarMinted(msg.sender, _model, _make, _price);

emit Events.CarMinted(msg.sender, _model, _make, _price);
return newCarId;
}

// list car After minting as nft

function listCar(uint _carId, uint _price) external {
function listCar(uint _carId, uint _price) external onlyRegisteredDealer {
require(ownerOf(_carId) == msg.sender, "Not the car owner");
carById[_carId].price = _price;
carById[_carId].forSale = true;
Expand All @@ -112,33 +120,58 @@ contract MarketPlace is ERC721URIStorage {
function buyCar(uint _carId) external payable {
CarInfo storage car = carById[_carId];
require(car.forSale, "Car not Listed");
require(msg.value >= car.price, "Insufficient Funds");
require(msg.value >= car.price + platformFee, "Insufficient Funds");

address seller = ownerOf(_carId);
require(seller != address(0), "Invalid seller address");

_transfer(seller, msg.sender, _carId);
car.forSale = false;
car.dealer = msg.sender;

payable(seller).transfer(msg.value);
(bool success, ) = payable(seller).call{value: car.price}("");
require(success, "Transfer failed");

(bool successPlatformFee, ) = payable(owner).call{value: platformFee}(
""
);
require(successPlatformFee, "Transfer failed");

carBought[msg.sender].push(car);
emit Events.CarSold(_carId, seller, msg.sender, car.price);
}

function getDealerCars(
address _dealer
) external view returns (uint256[] memory) {
) external view returns (CarInfo[] memory) {
return carsByDealer[_dealer];
}

function updateCarPrice(uint256 _tokenId, uint256 _newPrice) external {
require(ownerOf(_tokenId) == msg.sender, "Not the car owner");
carById[_tokenId].price = _newPrice;
function updateCarPrice(uint256 _carId, uint256 _newPrice) external {
require(ownerOf(_carId) == msg.sender, "Not the car owner");
carById[_carId].price = _newPrice;
}

function getAllCarsBought(
address _user
) public view returns (CarInfo[] memory) {
return carBought[_user];
}

function delistCar(uint _carId) external {
require(ownerOf(_carId) == msg.sender, "Not the car owner");
carById[_carId].forSale = false;
}

function getDealerCarCount(
address _dealer
) external view returns (uint256) {
return carsByDealer[_dealer].length;
}

function getTokenURI(
uint256 _tokenId
) external view returns (string memory) {
return tokenURI(_tokenId);
}
}
199 changes: 189 additions & 10 deletions test/MarketPlace.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,207 @@ import {Test, console} from "forge-std/Test.sol";
import {MarketPlace} from "../src/MarketPlace.sol";

contract CounterTest is Test {
MarketPlace public marketplace;
address deployer=address(0xd65944287EB2685c345057F6a4A48d619bA6f7cf);
uint256 dealerRegistrationFee = 1 ether;
event CarSold(
uint256 indexed carId,
address indexed seller,
address indexed buyer,
uint256 price
);

struct CarInfo {
string make;
string model;
uint256 year;
string vin;
uint256 price;
address dealer;
bool forSale;
}
MarketPlace public marketplace;
address deployer = address(0xd65944287EB2685c345057F6a4A48d619bA6f7cf);
uint256 dealerRegistrationFee = 1 ether;
address buyer = address(0x456);
uint256 platformFee = 0.1 ether;

function setUp() public {
vm.prank(deployer);
marketplace = new MarketPlace();
marketplace = new MarketPlace();
vm.deal(deployer, 100 ether);
vm.deal(buyer, 100 ether);
}

function test_DeployerIsOwner() public view{
assertEq(marketplace.owner(), deployer,"Deployer should be the owner");
function test_DeployerIsOwner() public view {
assertEq(marketplace.owner(), deployer, "Deployer should be the owner");
}

function test_registerDealer() public {
vm.prank(deployer);
vm.deal(deployer, dealerRegistrationFee);

marketplace.registerDealer{value: dealerRegistrationFee}("dealer@example.com", "Dealer Name");
(string memory email, string memory name, uint256 registrationTime, bool isActive) = marketplace.dealers(deployer);
marketplace.registerDealer{value: dealerRegistrationFee}(
"dealer@example.com",
"James"
);
(string memory email, string memory name, , bool isActive) = marketplace
.dealers(deployer);
assertEq(email, "dealer@example.com", "Email should match");
assertEq(name, "Dealer Name", "Name should match");
assertEq(name, "James", "Name should match");
assertTrue(isActive, "Dealer should be active");
assertTrue(marketplace.isRegistered(deployer), "Dealer should be registered");
assertTrue(
marketplace.isRegistered(deployer),
"Dealer should be registered"
);
}

function test_mintNft() public {
vm.prank(deployer);
vm.deal(deployer, dealerRegistrationFee);
marketplace.registerDealer{value: dealerRegistrationFee}(
"dealer@example.com",
"James"
);
vm.prank(deployer);
marketplace.mintNft(
"tesla",
"2016",
2015,
"0345673",
1 ether,
"ffkkfjfjf"
);
(, , , , , uint256 price, , bool isAvailable) = marketplace.carById(1);
assertEq(price, 1 ether);
assertEq(isAvailable, false);
}

function test_listCar() public {
vm.prank(deployer);
vm.deal(deployer, dealerRegistrationFee);
marketplace.registerDealer{value: dealerRegistrationFee}(
"dealer@example.com",
"James"
);
vm.prank(deployer);
marketplace.mintNft(
"tesla",
"2016",
2015,
"0345673",
1 ether,
"ffkkfjfjf"
);

vm.prank(deployer);
marketplace.listCar(1, 2 ether);
(,, , , , uint256 price, , bool isAvailable) = marketplace.carById(1);
assertEq(isAvailable, true);
assertEq(price, 2 ether);
}

function _registerDealerAndMintCar() internal returns (uint256 carId) {
vm.prank(deployer);
marketplace.registerDealer{value: dealerRegistrationFee}(
"dealer@example.com",
"James"
);

// Mint a car
vm.prank(deployer);
carId = marketplace.mintNft(
"tesla",
"model3",
2015,
"0345673",
1 ether,
"ffkkfjfjf"
);
}

function test_buyCar_success() public {
uint256 carId = _registerDealerAndMintCar();

// List the car for sale
vm.prank(deployer);
marketplace.updateCarPrice(carId, 1 ether);

// Buy the car
uint256 totalCost = 1 ether + platformFee;

// Expect the CarSold event
emit CarSold(carId, deployer, buyer, 1 ether);
vm.prank(deployer);
marketplace.listCar(1, 1 ether);

vm.prank(buyer);
marketplace.buyCar{value: totalCost}(carId);

// Verify state changes
(,, , , , uint256 price, address dealer, bool forSale) = marketplace
.carById(carId);
assertEq(price, 1 ether, "Price should remain unchanged");
assertEq(dealer, buyer, "Buyer should be the new dealer");
assertFalse(forSale, "Car should no longer be for sale");

// Verify ownership transfer
address owner = marketplace.ownerOf(carId);
assertEq(owner, buyer, "Buyer should own the car");

// Verify carBought array
MarketPlace.CarInfo[] memory carsBought = marketplace.getAllCarsBought(
buyer
);
assertEq(carsBought.length, 1, "Buyer should have 1 car bought");
assertEq(carsBought[0].make, "tesla", "Car make should match");
}

function test_buyCar_notListed() public {
uint256 carId = _registerDealerAndMintCar();
vm.prank(buyer);
vm.expectRevert("Car not Listed");
marketplace.buyCar{value: 1 ether + platformFee}(carId);
}

function test_updateCarPrice() public {
uint256 carId = _registerDealerAndMintCar();

vm.prank(deployer);
marketplace.updateCarPrice(carId, 2 ether);

(, , , , , uint256 price, , ) = marketplace.carById(carId);
assertEq(price, 2 ether, "Price should be updated to 2 ether");
}

function test_updateCarPrice_nonOwner() public {
uint256 carId = _registerDealerAndMintCar();

vm.prank(buyer);
vm.expectRevert("Not the car owner");
marketplace.updateCarPrice(carId, 2 ether);
}

function test_getAllCarsBought() public {
uint256 carId = _registerDealerAndMintCar();

vm.prank(deployer);
marketplace.listCar(1, 1 ether);

// Buy the car
uint256 totalCost = 1 ether + platformFee;
vm.prank(buyer);
marketplace.buyCar{value: totalCost}(1);

// Verify the cars bought by the buyer
MarketPlace.CarInfo[] memory carsBought = marketplace.getAllCarsBought(
buyer
);
assertEq(carsBought.length, 1, "Buyer should have 1 car bought");
assertEq(carsBought[0].make, "tesla", "Car make should match");
}

function test_getDealerCars() public {
uint256 carId = _registerDealerAndMintCar();
MarketPlace.CarInfo[] memory dealerCars = marketplace.getDealerCars(deployer);
assertEq(dealerCars.length, 1, "Dealer should have 1 car");
}
}

Loading