Skip to content

Commit

Permalink
Fix stucked auction
Browse files Browse the repository at this point in the history
  • Loading branch information
orionstardust committed Jan 23, 2024
1 parent e3fa31a commit 0a44f7c
Show file tree
Hide file tree
Showing 4 changed files with 202 additions and 23 deletions.
89 changes: 66 additions & 23 deletions contracts/facets/GBMFacet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import "../interfaces/Ownable.sol";
import "../libraries/AppStorage.sol";
import "../libraries/LibDiamond.sol";
import "../libraries/LibSignature.sol";
import "../libraries/LibAddress.sol";

import "../interfaces/IERC2981.sol";
import "../interfaces/IMultiRoyalty.sol";
Expand Down Expand Up @@ -57,6 +58,15 @@ contract GBMFacet is IGBM, IERC1155TokenReceiver, IERC721TokenReceiver, Modifier
) internal {
Auction storage a = s.auctions[_auctionID];
if (msg.sender == a.owner) revert("OwnerBidNotAllowed");
if (LibAddress.isContract(msg.sender)) {
// check bidder is contract and support receiver functions
if (
!LibAddress.functionExists(msg.sender, "onERC1155Received(address,address,uint256,uint256,bytes)") &&
!LibAddress.functionExists(msg.sender, "onERC721Received(address,address,uint256,bytes)")
) {
revert("UnableToReceiveTokens");
}
}
if (a.info.startTime > block.timestamp) revert("AuctionNotStarted");
//verify existence
if (a.owner == address(0)) revert("NoAuction");
Expand Down Expand Up @@ -351,19 +361,7 @@ contract GBMFacet is IGBM, IERC1155TokenReceiver, IERC721TokenReceiver, Modifier
uint256 tid = a.info.tokenID;
uint256 tam = a.info.tokenAmount;
a.claimed = true;
// case where no bids have been made
if (a.highestBid == 0) {
// Transfer the token to the owner/canceller
if (a.info.tokenKind == ERC721) {
_sendTokens(ca, a.owner, ERC721, tid, 1);
//update storage
s.erc721AuctionExists[ca][tid] = false;
}
if (a.info.tokenKind == ERC1155) {
_sendTokens(ca, a.owner, ERC1155, tid, tam);
}
emit AuctionCancelled(_auctionID, tid);
}

//if it has a bid
if (a.highestBid > 0) {
//make sure auction has ended
Expand All @@ -385,19 +383,64 @@ contract GBMFacet is IGBM, IERC1155TokenReceiver, IERC721TokenReceiver, Modifier
emit Auction_BidRemoved(_auctionID, a.highestBidder, a.highestBid);

_settleFees(a.highestBid);
}

// Transfer the token back to the owner/canceller
if (a.info.tokenKind == ERC721) {
_sendTokens(ca, a.owner, ERC721, tid, 1);
//update storage
s.erc721AuctionExists[ca][tid] = false;
}
if (a.info.tokenKind == ERC1155) {
_sendTokens(ca, a.owner, ERC1155, tid, tam);
}
// Transfer the token back to the owner/canceller
if (a.info.tokenKind == ERC721) {
_sendTokens(ca, a.owner, ERC721, tid, 1);
//update storage
s.erc721AuctionExists[ca][tid] = false;
}
if (a.info.tokenKind == ERC1155) {
_sendTokens(ca, a.owner, ERC1155, tid, tam);
}

emit AuctionCancelled(_auctionID, tid);
}

/// @notice Return the GHST to the bidder (minus the auction fee) and NFT to owner
/// @param _auctionID The auction to close
function closeAuction(uint256 _auctionID) external onlyOwner {
Auction storage a = s.auctions[_auctionID];
//verify existence
if (a.owner == address(0)) revert("NoAuction");
//check if not claimed
if (a.claimed == true) revert("AuctionClaimed");

emit AuctionCancelled(_auctionID, tid);
address ca = a.tokenContract;
uint256 tid = a.info.tokenID;
uint256 tam = a.info.tokenAmount;
a.claimed = true;

//if it has a bid
if (a.highestBid > 0) {
//make sure auction has ended
if (a.info.endTime > block.timestamp) revert("AuctionNotEnded");

//Fees of pixelcraft,GBM,DAO and rarityFarming
uint256 _auctionFees = (a.highestBid * 4) / 100;

//Refund lastHighestBidder's bid minus auction fees
uint256 ownerShare = a.highestBid - _auctionFees;
IERC20(s.GHST).transfer(a.highestBidder, ownerShare);

//emit bidRemoval event
emit Auction_BidRemoved(_auctionID, a.highestBidder, a.highestBid);

_settleFees(a.highestBid);
}

// Transfer the token back to the owner/canceller
if (a.info.tokenKind == ERC721) {
_sendTokens(ca, a.owner, ERC721, tid, 1);
//update storage
s.erc721AuctionExists[ca][tid] = false;
}
if (a.info.tokenKind == ERC1155) {
_sendTokens(ca, a.owner, ERC1155, tid, tam);
}

emit AuctionCancelled(_auctionID, tid);
}

function _settleFeesWithRoyalty(
Expand Down
29 changes: 29 additions & 0 deletions contracts/libraries/LibAddress.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

library LibAddress {
function isContract(address _account) internal view returns (bool) {
if (_account == address(0)) {
return false;
}

uint256 size;
assembly {
size := extcodesize(_account)
}
return size > 0;
}

function functionExists(address _contract, string memory _func) internal view returns (bool) {
bytes4 selector = bytes4(keccak256(bytes(_func)));
bytes memory bytecode = _contract.code;

// Check if the bytecode contains the function selector
for (uint i = 0; i < bytecode.length - 3; i++) {
if (bytecode[i] == selector[0] && bytecode[i + 1] == selector[1] && bytecode[i + 2] == selector[2] && bytecode[i + 3] == selector[3]) {
return true;
}
}
return false;
}
}
45 changes: 45 additions & 0 deletions scripts/gbmBaazaar/upgrade-closeAuction.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
//@ts-ignore
import { run, ethers } from "hardhat";
import {
convertFacetAndSelectorsToString,
DeployUpgradeTaskArgs,
FacetsAndAddSelectors,
} from "../../tasks/deployUpgrade";
import { maticGBMDiamond } from "../constants";

export async function deployUpgrade() {
const facets: FacetsAndAddSelectors[] = [
{
facetName: "GBMFacet",
addSelectors: [
"function closeAuction(uint256 _auctionID) external"
],
removeSelectors: [],
},
];

const joined = convertFacetAndSelectorsToString(facets);

const args: DeployUpgradeTaskArgs = {
diamondUpgrader: "0x585E06CA576D0565a035301819FD2cfD7104c1E8",
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) {
deployUpgrade()
.then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});
}
62 changes: 62 additions & 0 deletions test/closeAuctionTests.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import {BigNumberish} from "ethers";
import { ethers, network } from "hardhat";
import { impersonate } from "../scripts/helperFunctions";
import { deployUpgrade } from "../scripts/gbmBaazaar/upgrade-closeAuction";
import {ERC1155Generic, ERC20Generic, GBMFacet} from "../typechain";
import {ghstAddress, maticGBMDiamond} from "../scripts/constants";
import { expect } from "chai";

// constants for testing
let auctionID = "19516";
// let auctionID = "19518";

let gbmFacet: GBMFacet;
let diamondOwner: string;

let auctionOwner: string;
let stuckedBidder: string;
let bidAmount: BigNumberish;
let tokenID: BigNumberish;
let tokenContract: string;
let token: ERC1155Generic;
let ghst: ERC20Generic;

describe("Test Close Auction", async function () {
before(async function () {
this.timeout(300000);
console.log("deploying upgrades ");
await deployUpgrade();

diamondOwner = await (await ethers.getContractAt("OwnershipFacet", maticGBMDiamond)).owner()
gbmFacet = (await ethers.getContractAt(
"GBMFacet",
maticGBMDiamond
)) as GBMFacet;
gbmFacet = await impersonate(diamondOwner, gbmFacet, ethers, network);
ghst = await ethers.getContractAt("ERC20Generic", ghstAddress);
});

it("Force close stucked auctions", async function () {
auctionOwner = await (await gbmFacet.getAuctionInfo(auctionID)).owner;
const auction = await gbmFacet.getAuctionInfo(auctionID)
tokenID = auction.info.tokenID;
stuckedBidder = auction.highestBidder;
bidAmount = auction.highestBid;
tokenContract = auction.tokenContract;
token = (await ethers.getContractAt(
"ERC1155Generic",
tokenContract
)) as ERC1155Generic;

const balanceBefore = await token.balanceOf(auctionOwner, tokenID);
const ghstBalanceBefore = await ghst.balanceOf(stuckedBidder);

await (await gbmFacet.closeAuction(auctionID)).wait();

const balanceAfter = await token.balanceOf(auctionOwner, tokenID);
const ghstBalanceAfter = await ghst.balanceOf(stuckedBidder);

expect(balanceAfter).equal(balanceBefore.add(1));
expect(ghstBalanceAfter.sub(ghstBalanceBefore)).equal(bidAmount.mul(96).div(100));
});
});

0 comments on commit 0a44f7c

Please sign in to comment.