Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: add buy now for in gbm facet #25

Draft
wants to merge 5 commits into
base: master
Choose a base branch
from
Draft
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
26 changes: 21 additions & 5 deletions contracts/facets/GBMFacet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,21 @@ contract GBMFacet is IGBM, IERC1155TokenReceiver, IERC721TokenReceiver, Modifier
/// @param _auctionID The auctionId of the auction to complete
//No change necessary for this function code, but it use overriden internal and hence need overriding too in the diamond
function buyNow(uint256 _auctionID) public {
_buyNowImplementation(_auctionID, msg.sender);
}

/// @notice Attribute a token to a specified recipient and distribute the proceeds to the owner of this contract.
/// @param _auctionID The auctionId of the auction to complete
/// @param _recipient The address of the recipient who will receive the NFT
function buyNowFor(uint256 _auctionID, address _recipient) public {
require(_recipient != address(0), "Invalid recipient address");
_buyNowImplementation(_auctionID, _recipient);
}

/// @dev Internal function to handle the logic of buying an auction item.
/// @param _auctionID The ID of the auction.
/// @param _recipient The address of the recipient of the NFT.
function _buyNowImplementation(uint256 _auctionID, address _recipient) internal {
_validateAuctionExistence(_auctionID);

Auction storage a = s.auctions[_auctionID];
Expand All @@ -160,25 +175,26 @@ contract GBMFacet is IGBM, IERC1155TokenReceiver, IERC721TokenReceiver, Modifier
address tokenContract = a.tokenContract;
if (s.contractBiddingAllowed[tokenContract] == false) revert("BiddingNotAllowed");

//Prevents re-entrancy
// Prevents re-entrancy
a.claimed = true;

//Transfer the money of the buyer to the GBM Diamond
// Transfer the money of the buyer to the GBM Diamond
IERC20(s.GHST).transferFrom(msg.sender, address(this), ae1bnp);

//Refund the highest bidder
// Refund the highest bidder
if (a.highestBid > 0) {
IERC20(s.GHST).transfer(a.highestBidder, a.highestBid + a.dueIncentives);
//emit incentive event and bidRemoval event
emit Auction_IncentivePaid(_auctionID, a.highestBidder, a.dueIncentives);
emit Auction_BidRemoved(_auctionID, a.highestBidder, a.highestBid);
}

emit Auction_BoughtNow(_auctionID, msg.sender);
emit Auction_BoughtNow(_auctionID, _recipient);

_calculateRoyaltyAndSend(_auctionID, msg.sender, ae1bnp, a.dueIncentives);
_calculateRoyaltyAndSend(_auctionID, _recipient, ae1bnp, a.dueIncentives);
}


/// @notice Allow/disallow bidding and claiming for a whole token contract address.
/// @param _contract The token contract the auctionned token belong to
/// @param _value True if bidding/claiming should be allowed.
Expand Down
46 changes: 46 additions & 0 deletions scripts/gbmBaazaar/upgrade-buyNowFor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
//@ts-ignore
import { run, ethers, network } from "hardhat";
import {
convertFacetAndSelectorsToString,
DeployUpgradeTaskArgs,
FacetsAndAddSelectors,
} from "../../tasks/deployUpgrade";
import { gasPrice, impersonate } from "../helperFunctions";
import { maticGBMDiamond, maticGBMDiamondUpgrader } from "../constants";

export async function upgradeBuyNowFor() {
const facets: FacetsAndAddSelectors[] = [
{
facetName: "GBMFacet",
addSelectors: [
`function buyNowFor(uint256 _auctionID, address _recepient) public`,
],
removeSelectors: [],
},
];

const joined = convertFacetAndSelectorsToString(facets);

const args: DeployUpgradeTaskArgs = {
diamondUpgrader: maticGBMDiamondUpgrader,
diamondAddress: maticGBMDiamond,
facetsAndAddSelectors: joined,
useLedger: true,
useMultisig: false,
initAddress: ethers.constants.AddressZero,
initCalldata: "0x",
};

await run("deployUpgrade", args);
}

// We recommend this pattern to be able to use async/await everywhere
// and properly handle errors.
if (require.main === module) {
upgradeBuyNowFor()
.then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});
}
97 changes: 94 additions & 3 deletions test/buyNowAndStartBidPriceTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
//@ts-ignore
import { ethers, network } from "hardhat";
import { expect } from "chai";
import { upgradeBuyNow } from "../scripts/gbmBaazaar/upgrade-buyNow";
import { impersonate } from "../scripts/helperFunctions";
import {
ERC20Generic,
Expand All @@ -17,6 +16,7 @@ import {
gotchiDiamondAddress,
maticGBMDiamond,
} from "../scripts/constants";
import { upgradeBuyNowFor } from "../scripts/gbmBaazaar/upgrade-buyNowFor";

describe("Testing start bid price and buy now logic", async function () {
this.timeout(30000000);
Expand All @@ -33,6 +33,7 @@ describe("Testing start bid price and buy now logic", async function () {
let auctionId: any;
let gotchiHolder: any;
let bidder: any;

const gotchiId = 13230;
const auctionPresetId = 1;
const backendSigner = new ethers.Wallet(process.env.SECRET);
Expand All @@ -45,20 +46,24 @@ describe("Testing start bid price and buy now logic", async function () {
.mul(70)
.div(100)
.add(ethers.utils.parseEther("1"));

const auctionInfoData = {
// startTime: Math.floor(Date.now() / 1000 + 200),
// endTime: Math.floor(Date.now() / 1000) + 8640,
tokenAmount: 1,
tokenKind: "0x73ad2146", //ERC721
tokenID: gotchiId,
category: 3,
buyItNowPrice: buyItNowPrice,
startingBid: startBidPrice,
buyItNowPrice: buyItNowPrice,
};

let auctionInfo;
const ghstHolderAddress = "0x434b09Cf6864451606F27eD34609e35ef5D38c50";
let ghstHolder;

before(async function () {
await upgradeBuyNow();
await upgradeBuyNowFor();

const ownershipFacet = (await ethers.getContractAt(
"OwnershipFacet",
Expand All @@ -77,11 +82,29 @@ describe("Testing start bid price and buy now logic", async function () {
gotchiDiamondAddress
)) as ERC721Generic;

ghstHolder = await ethers.getSigner(ghstHolderAddress);
const ghstHolderBalance = await ghstERC20.balanceOf(ghstHolderAddress);

console.log("GHST Holder Balance: ", ghstHolderBalance.toString());
await network.provider.request({
method: "hardhat_impersonateAccount",
params: [ghstHolderAddress],
});
await ghstERC20
.connect(ghstHolder)
.transfer(gotchiHolderAddress, ethers.utils.parseEther("100"));
await ghstERC20
.connect(ghstHolder)
.transfer(bidderAddress, ethers.utils.parseEther("100"));

console.log("HERE WORKED");

await network.provider.request({
method: "hardhat_impersonateAccount",
params: [bidderAddress],
});
bidder = await ethers.getSigner(bidderAddress);

await network.provider.request({
method: "hardhat_impersonateAccount",
params: [gotchiHolderAddress],
Expand Down Expand Up @@ -188,6 +211,7 @@ describe("Testing start bid price and buy now logic", async function () {
const auctionOwnerGhstBalanceBefore = await ghstERC20.balanceOf(
gotchiHolderAddress
);

const receipt = await (await gbmFacetWithBidder.claim(auctionId)).wait();
const event = receipt!.events!.find(
(e: any) => e.event === "Auction_ItemClaimed"
Expand Down Expand Up @@ -368,6 +392,7 @@ describe("Testing start bid price and buy now logic", async function () {
const auctionOwnerGhstBalanceBefore = await ghstERC20.balanceOf(
gotchiHolderAddress
);

const receipt = await (await gbmFacetWithBidder.buyNow(auctionId)).wait();
const event = receipt!.events!.find(
(e: any) => e.event === "Auction_BoughtNow"
Expand All @@ -380,6 +405,7 @@ describe("Testing start bid price and buy now logic", async function () {
const auctionOwnerGhstBalanceAfter = await ghstERC20.balanceOf(
gotchiHolderAddress
);

expect(
auctionOwnerGhstBalanceAfter.sub(auctionOwnerGhstBalanceBefore)
).to.equal(buyItNowPriceLow.mul(96).div(100));
Expand Down Expand Up @@ -476,4 +502,69 @@ describe("Testing start bid price and buy now logic", async function () {
);
});
});

describe("Testing buy now logic with specified recipient (buyNowFor)", async function () {
before(async function () {
// Reset the environment
await ethers.provider.send("evm_revert", [snapshot]);
snapshot = await ethers.provider.send("evm_snapshot", []);

// Define auction info with a buy it now price
auctionInfo = {
...auctionInfoData,
startTime: Math.floor(Date.now() / 1000) + 200,
endTime: Math.floor(Date.now() / 1000) + 8640,
startingBid: startBidPrice,
buyItNowPrice: buyItNowPrice,
};

// Create the auction
const receipt = await (
await gbmFacetWithGotchiHolder.createAuction(
auctionInfo,
gotchiDiamondAddress,
auctionPresetId
)
).wait();

// Extract auction ID from the creation event
const createEvent = receipt.events.find(
(e) => e.event === "Auction_Initialized"
);
auctionId = createEvent.args._auctionID;

// wait for auction started
await ethers.provider.send("evm_increaseTime", [500]);
await ethers.provider.send("evm_mine", []);
});
it("Should revert if the recipient address is invalid", async function () {
await expect(
gbmFacetWithBidder.buyNowFor(auctionId, ethers.constants.AddressZero)
).to.be.revertedWith("Invalid recipient address");
});
it("Should allow buying an NFT for a specified recipient", async function () {
const recipient = "0xAd0CEb6Dc055477b8a737B630D6210EFa76a2265";

const auctionOwnerGhstBalanceBefore = await ghstERC20.balanceOf(
gotchiHolderAddress
);

// Ensure the recipient can receive the NFT
await expect(gbmFacetWithBidder.buyNowFor(auctionId, recipient))
.to.emit(gbmFacetWithBidder, "Auction_BoughtNow")
.withArgs(auctionId, recipient);

// Check that the recipient now owns the NFT
const newOwner = await gotchiDiamond.ownerOf(gotchiId);
expect(newOwner).to.equal(recipient);

// Check if funds were correctly transferred
const auctionOwnerGhstBalanceAfter = await ghstERC20.balanceOf(
gotchiHolderAddress
);
expect(
auctionOwnerGhstBalanceAfter.sub(auctionOwnerGhstBalanceBefore)
).to.equal(buyItNowPrice.mul(96).div(100).add(startBidPrice.mul(4).div(100))); // assuming the buy now price is taken at 96%
});
});
});
Loading