Files
fhevm-solidity/examples/BlindAuction.sol
Joseph-André Turk 535b055fc8 Updated Solidity version to ^0.8.20 and OpenZeppelin Contracts to ^5.0.1
updated to ethermint node

updated node dev version

removed parallel flag from hardhat test

reput inband test for ci

setup evm version to Paris to avoid PUSH0 error and updated hardhat version

removed utils.ts.new file

synced package.json and package-lock.json

prettier
2024-01-09 11:05:38 +01:00

154 lines
5.1 KiB
Solidity

// SPDX-License-Identifier: BSD-3-Clause-Clear
pragma solidity ^0.8.20;
import "../lib/TFHE.sol";
import "../abstracts/Reencrypt.sol";
import "./EncryptedERC20.sol";
contract BlindAuction is Reencrypt {
uint public endTime;
address public beneficiary;
// Current highest bid.
euint32 internal highestBid;
// Mapping from bidder to their bid value.
mapping(address => euint32) public bids;
// Number of bid
uint public bidCounter;
// The token contract used for encrypted bids.
EncryptedERC20 public tokenContract;
// Whether the auction object has been claimed.
ebool public objectClaimed;
// If the token has been transferred to the beneficiary
bool public tokenTransferred;
bool public stoppable;
bool public manuallyStopped = false;
// The owner of the contract.
address public contractOwner;
// The function has been called too early.
// Try again at `time`.
error TooEarly(uint time);
// The function has been called too late.
// It cannot be called after `time`.
error TooLate(uint time);
event Winner(address who);
constructor(address _beneficiary, EncryptedERC20 _tokenContract, uint biddingTime, bool isStoppable) {
beneficiary = _beneficiary;
tokenContract = _tokenContract;
endTime = block.timestamp + biddingTime;
objectClaimed = TFHE.asEbool(false);
tokenTransferred = false;
bidCounter = 0;
stoppable = isStoppable;
contractOwner = msg.sender;
}
// Bid an `encryptedValue`.
function bid(bytes calldata encryptedValue) public onlyBeforeEnd {
euint32 value = TFHE.asEuint32(encryptedValue);
euint32 existingBid = bids[msg.sender];
if (TFHE.isInitialized(existingBid)) {
ebool isHigher = TFHE.lt(existingBid, value);
// Update bid with value
bids[msg.sender] = TFHE.cmux(isHigher, value, existingBid);
// Transfer only the difference between existing and value
euint32 toTransfer = value - existingBid;
// Transfer only if bid is higher
euint32 amount = TFHE.cmux(isHigher, toTransfer, TFHE.asEuint32(0));
tokenContract.transferFrom(msg.sender, address(this), amount);
} else {
bidCounter++;
bids[msg.sender] = value;
tokenContract.transferFrom(msg.sender, address(this), value);
}
euint32 currentBid = bids[msg.sender];
if (!TFHE.isInitialized(highestBid)) {
highestBid = currentBid;
} else {
highestBid = TFHE.cmux(TFHE.lt(highestBid, currentBid), currentBid, highestBid);
}
}
function getBid(
bytes32 publicKey,
bytes calldata signature
) public view onlySignedPublicKey(publicKey, signature) returns (bytes memory) {
return TFHE.reencrypt(bids[msg.sender], publicKey, 0);
}
// Returns the user bid
function stop() public onlyContractOwner {
require(stoppable);
manuallyStopped = true;
}
// Returns an encrypted value of 0 or 1 under the caller's public key, indicating
// if the caller has the highest bid.
function doIHaveHighestBid(
bytes32 publicKey,
bytes calldata signature
) public view onlyAfterEnd onlySignedPublicKey(publicKey, signature) returns (bytes memory) {
if (TFHE.isInitialized(highestBid) && TFHE.isInitialized(bids[msg.sender])) {
return TFHE.reencrypt(TFHE.le(highestBid, bids[msg.sender]), publicKey);
} else {
return TFHE.reencrypt(TFHE.asEuint32(0), publicKey);
}
}
// Claim the object. Succeeds only if the caller has the highest bid.
function claim() public onlyAfterEnd {
ebool canClaim = TFHE.and(TFHE.le(highestBid, bids[msg.sender]), TFHE.not(objectClaimed));
objectClaimed = canClaim;
bids[msg.sender] = TFHE.cmux(canClaim, TFHE.asEuint32(0), bids[msg.sender]);
// emit Winner(msg.sender);
}
// Transfer token to beneficiary
function auctionEnd() public onlyAfterEnd {
require(!tokenTransferred);
tokenTransferred = true;
tokenContract.transfer(beneficiary, highestBid);
}
// Withdraw a bid from the auction to the caller once the auction has stopped.
function withdraw() public onlyAfterEnd {
euint32 bidValue = bids[msg.sender];
ebool isHighestBid = TFHE.eq(bidValue, highestBid);
ebool canWithdraw = TFHE.not(TFHE.and(isHighestBid, TFHE.not(objectClaimed)));
tokenContract.transfer(msg.sender, TFHE.cmux(canWithdraw, bidValue, TFHE.asEuint32(0)));
bids[msg.sender] = TFHE.cmux(canWithdraw, TFHE.asEuint32(0), bids[msg.sender]);
}
modifier onlyBeforeEnd() {
if (block.timestamp >= endTime || manuallyStopped == true) revert TooLate(endTime);
_;
}
modifier onlyAfterEnd() {
if (block.timestamp <= endTime && manuallyStopped == false) revert TooEarly(endTime);
_;
}
modifier onlyContractOwner() {
require(msg.sender == contractOwner);
_;
}
}