COTI Ecosystem Growth Fund

Revolutionizing Web3 Security:
End-to-End Encryption with Trustless Confidential Compute

Web3 began with the premise of asset security and transparency; using our general-purpose secure computation network we get privacy by default.

Partners and backers

Enable Transparent Management of Confidential Data and Digital Assets with a Single Platform

Days of peeping to your own sensitive data and business financials are over. It’s time to integrate with a growing network of data sources.

Secure your personal and business financials

Use an end-to-end encrypted token standard for transfer amounts, business partners, and more.

Protect dApp’s customers by ensuring privacy compliance

Sensitive data is encrypted at all time over the network via a groundbreaking GarbledCircuit-based MPC protocol.

Offer and discover data across networks

Turn aggregatable business data to a monetizable asset

Transparent and Programmable Privacy Unlocks a New World of Use Cases

DEX

Artificial intelligence

Real-world asset management

Gaming, Gamefi and GambleFi

Decentralized social networks

Bridging

Marketplaces

Governance

Indentity dApps

Heathcare & legal

Regulated DeFi, Institution DeFi

CBDC

Programmable Privacy has Never Been Easier

							
							
					// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import "MpcCore.sol";

// The provided Solidity contract is an implementation of an ERC20 token standard with enhanced privacy features. 
// It aims to ensure the confidentiality of token transactions through encryption techniques while maintaining compatibility with the ERC20 standard.
// 
// Key Features:
// Privacy Enhancement:
// The contract utilizes encryption techniques to encrypt sensitive data such as token balances and allowances. Encryption is performed using both user-specific and system-wide encryption keys to safeguard transaction details.
// Encrypted Balances and Allowances:
// Token balances and allowances are stored in encrypted form within the contract's state variables. This ensures that sensitive information remains confidential and inaccessible to unauthorized parties.
// Integration with MPC Core:
// The contract leverages functionalities provided by an external component called MpcCore. This component likely implements cryptographic operations such as encryption, decryption, and signature verification using techniques like Multi-Party Computation (MPC).
// Token Transfer Methods:
// The contract provides multiple transfer methods, allowing token transfers in both encrypted and clear (unencrypted) forms. Transfers can occur between addresses with encrypted token values or clear token values.
// Approval Mechanism:
// An approval mechanism is implemented to allow token holders to grant spending permissions (allowances) to other addresses. Approvals are also encrypted to maintain transaction privacy.
contract PrivateERC20Contract {

    // Events are emitted for token transfers (Transfer) and approvals (Approval). These events provide transparency and allow external observers to track token movements within the contract.
    event Transfer(address indexed _from, address indexed _to, uint256 _value);
    event Transfer(address indexed _from, address indexed _to);
    event Approval(address indexed _owner, address indexed _spender, uint256 _value);
    event Approval(address indexed _owner, address indexed _spender);
    event Balance(address indexed _owner, ctUint64 _balance);
    event Allowance(address indexed _owner, ctUint64 _allowance);


    string private _name;
    string private _symbol;
    uint8 private _decimals = 5;    // Sets the number of decimal places for token amounts. Here, _decimals is 5,
                                    // allowing for transactions with precision up to 0.00001 tokens.
    uint256 private _totalSupply;  
    
    // Mapping of balances of the token holders
    // The balances are stored encrypted by the system aes key
    mapping(address => ctUint64) private balances;
    // Mapping of allowances of the token holders
    mapping(address => mapping(address => ctUint64)) private allowances;

    // Create the contract with the name and symbol. Assign the initial supply of tokens to the contract creator.
    // params: name: the name of the token
    //         symbol: the symbol of the token
    //         initialSupply: the initial supply of the token assigned to the contract creator
    constructor(string memory name_, string memory symbol_, uint64 initialSupply) {
        _name = name_;
        _symbol = symbol_;
        _totalSupply = initialSupply;
        balances[msg.sender] = MpcCore.offBoard(MpcCore.setPublic64(initialSupply));
    }

    function name() public view returns (string memory){
        return _name;
    }

    function symbol() public view returns (string memory){
        return _symbol;
    }

    function decimals() public view returns (uint8){
        return _decimals;
    }

    function totalSupply() public view returns (uint256){
        return _totalSupply;
    }

    // The function returns the encrypted account balance utilizing the user's secret key. 
    // Since the balance is initially encrypted internally using the system's AES key, the user cannot access it. 
    // Thus, the balance undergoes re-encryption using the user's secret key. 
    // As a result, the function is not designated as a "view" function.
    function balanceOf() public returns (ctUint64){
        ctUint64 balance = balances[msg.sender];
        // The balance is saved encrypted using the system key. However, to allow the user to access it, the balance needs to be re-encrypted using the user key. 
        // Therefore, we decrypt the balance (onBoard) and then encrypt it again using the user key (offBoardToUser).
        gtUint64 balanceGt = MpcCore.onBoard(balance);
        ctUint64 userBalance = MpcCore.offBoardToUser(balanceGt, msg.sender);
        emit Balance(msg.sender, userBalance);
        return userBalance;
    }

    // Transfers the amount of tokens given inside the IT (encrypted and signed value) to address _to
    // params: _to: the address to transfer to
    //         _itCT: the encrypted value of the amount to transfer
    //         _itSignature: the signature of the amount to transfer
    //         revealRes: indicates if we should reveal the result of the transfer
    // returns: In case revealRes is true, returns the result of the transfer. In case revealRes is false, always returns true
    function transfer(address _to, ctUint64 _itCT, bytes calldata _itSignature, bool revealRes) public returns (bool success){
        // Create IT from ciphertext and signature
        itUint64 memory it;
        it.ciphertext = _itCT;
        it.signature = _itSignature;
        // Verify the IT and transfer the value
        gtBool result = contractTransfer(_to, MpcCore.validateCiphertext(it));
        if (revealRes){
            return MpcCore.decrypt(result);
        } else {
            return true;
        }
    }

    // Transfers the amount of tokens to address _to
    // params: _to: the address to transfer to
    //         _value: the value of the amount to transfer
    //         revealRes: indicates if we should reveal the result of the transfer
    // returns: In case revealRes is true, returns the result of the transfer. In case revealRes is false, always returns true
    function transfer(address _to, uint64 _value, bool revealRes) public returns (bool success){
        gtBool result = contractTransferClear(_to, _value);

        if (revealRes){
            return MpcCore.decrypt(result);
        } else {
            return true;
        }
    }

    // Transfers the amount of tokens given inside the encrypted value to address _to
    // params: _to: the address to transfer to
    //         _value: the encrypted value of the amount to transfer
    // returns: The encrypted result of the transfer.
    function contractTransfer(address _to, gtUint64 _value) public returns (gtBool success){
        (gtUint64 fromBalance, gtUint64 toBalance) = getBalances(msg.sender, _to);
        (gtUint64 newFromBalance, gtUint64 newToBalance, gtBool result) = MpcCore.transfer(fromBalance, toBalance, _value);

        emit Transfer(msg.sender, _to);
        setNewBalances(msg.sender, _to, newFromBalance, newToBalance);

        return result;
    }

    // Transfers the amount of tokens to address _to
    // params: _to: the address to transfer to
    //         _value: the value of the amount to transfer
    // returns: The encrypted result of the transfer.
    function contractTransferClear(address _to, uint64 _value) public returns (gtBool success){
        (gtUint64 fromBalance, gtUint64 toBalance) = getBalances(msg.sender, _to);
        (gtUint64 newFromBalance, gtUint64 newToBalance, gtBool result) = MpcCore.transfer(fromBalance, toBalance, _value);

        emit Transfer(msg.sender, _to, _value);
        setNewBalances(msg.sender, _to, newFromBalance, newToBalance);

        return result;
    }

    // Transfers the amount of tokens given inside the IT (encrypted and signed value) from address _from to address _to
    // params: _from: the address to transfer from
    //         __to: the address to transfer to
    //         _itCT: the encrypted value of the amount to transfer
    //         _itSignature: the signature of the amount to transfer
    //         revealRes: indicates if we should reveal the result of the transfer
    // returns: In case revealRes is true, returns the result of the transfer. In case revealRes is false, always returns true
    function transferFrom(address _from, address _to, ctUint64 _itCT, bytes calldata _itSignature, bool revealRes) public returns (bool success){
        // Create IT from ciphertext and signature
        itUint64 memory it;
        it.ciphertext = _itCT;
        it.signature = _itSignature;
        // Verify the IT and transfer the value
        gtBool result = contractTransferFrom(_from, _to, MpcCore.validateCiphertext(it));
        if (revealRes){
            return MpcCore.decrypt(result);
        } else {
            return true;
        }
    }

    // Transfers the amount of tokens from address _from to address _to
    // params: _from: the address to transfer from
    //         __to: the address to transfer to
    //         _value: the value of the amount to transfer
    //         revealRes: indicates if we should reveal the result of the transfer
    // returns: In case revealRes is true, returns the result of the transfer. In case revealRes is false, always returns true
    function transferFrom(address _from, address _to, uint64 _value, bool revealRes) public returns (bool success){
        gtBool result = contractTransferFromClear(_from, _to, _value);
        if (revealRes){
            return MpcCore.decrypt(result);
        } else {
            return true;
        }
    }

    // Transfers the amount of tokens given inside the encrypted value from address _from to address _to
    // params: _from: the address to transfer from
    //         _to: the address to transfer to
    //         _value: the encrypted value of the amount to transfer
    // returns: The encrypted result of the transfer.
    function contractTransferFrom(address _from, address _to, gtUint64 _value) public returns (gtBool success){
        (gtUint64 fromBalance, gtUint64 toBalance) = getBalances(_from, _to);
        gtUint64 allowance = MpcCore.onBoard(getGTAllowance(_from, msg.sender));
        (gtUint64 newFromBalance, gtUint64 newToBalance, gtBool result, gtUint64 newAllowance) = MpcCore.transferWithAllowance(fromBalance, toBalance, _value, allowance);

        setApproveValue(_from, msg.sender, MpcCore.offBoard(newAllowance));
        emit Transfer(_from, _to);
        setNewBalances(_from, _to, newFromBalance, newToBalance);

        return result;
    }

    // Transfers the amount of tokens from address _from to address _to
    // params: _from: the address to transfer from
    //         _to: the address to transfer to
    //         _value: the value of the amount to transfer
    // returns: The encrypted result of the transfer.
    function contractTransferFromClear(address _from, address _to, uint64 _value) public returns (gtBool success){
        (gtUint64 fromBalance, gtUint64 toBalance) = getBalances(_from, _to);
        gtUint64 allowance = MpcCore.onBoard(getGTAllowance(_from, msg.sender));
        (gtUint64 newFromBalance, gtUint64 newToBalance, gtBool result, gtUint64 newAllowance) = MpcCore.transferWithAllowance(fromBalance, toBalance, _value, allowance);

        setApproveValue(_from, msg.sender, MpcCore.offBoard(newAllowance));
        emit Transfer(_from, _to, _value);
        setNewBalances(_from, _to, newFromBalance, newToBalance);

        return result;
    }

    // Returns the encrypted balances of the two addresses
    function getBalances(address _from, address _to) private returns (gtUint64, gtUint64){
        ctUint64 fromBalance = balances[_from];
        ctUint64 toBalance = balances[_to];

        gtUint64 gtFromBalance;
        gtUint64 gtToBalance;
        if (ctUint64.unwrap(fromBalance) == 0){// 0 means that no allowance has been set
            gtFromBalance = MpcCore.setPublic64(0);
        } else {
            gtFromBalance = MpcCore.onBoard(fromBalance);
        }

        if (ctUint64.unwrap(toBalance) == 0){// 0 means that no allowance has been set
            gtToBalance = MpcCore.setPublic64(0);
        } else {
            gtToBalance = MpcCore.onBoard(toBalance);
        }

        return (gtFromBalance, gtToBalance);
    }

    // Sets the new encrypted balances of the two addresses
    function setNewBalances(address _from, address _to, gtUint64 newFromBalance, gtUint64 newToBalance) private {
        // Convert the gtUInt64 to ctUint64 and store it in the balances mapping
        balances[_from] = MpcCore.offBoard(newFromBalance);
        balances[_to] = MpcCore.offBoard(newToBalance);
    }

    // Sets the new allowance given inside the IT (encrypted and signed value) of the spender
    function approve(address _spender, ctUint64 _itCT, bytes calldata _itSignature) public returns (bool success){
        // Create IT using the given CT and signature
        itUint64 memory it;
        it.ciphertext = _itCT;
        it.signature = _itSignature;
        return approve(_spender, MpcCore.validateCiphertext(it));
    }

    // Sets the new encrypted allowance of the spender
    function approve(address _spender, gtUint64 _value) public returns (bool success){
        address owner = msg.sender;
        setApproveValue(owner, _spender, MpcCore.offBoard(_value));
        emit Approval(owner, _spender);
        return true;
    }

    // Sets the new allowance of the spender
    function approveClear(address _spender, uint64 _value) public returns (bool success){
        address owner = msg.sender;
        gtUint64 gt = MpcCore.setPublic64(_value);
        setApproveValue(owner, _spender, MpcCore.offBoard(gt));
        emit Approval(owner, _spender, _value);
        return true;
    }

    // Returns the encrypted allowance of the spender. The encryption is done using the msg.sender aes key
    function allowance(address _owner, address _spender) public returns (ctUint64 remaining){
        require(_owner == msg.sender || _spender == msg.sender);
            
        ctUint64 remainingCt = getGTAllowance(_owner, _spender);
        gtUint64 remainingGt = MpcCore.onBoard(remainingCt);
        ctUint64 allowance = MpcCore.offBoardToUser(remainingGt, msg.sender);
        emit Allowance(msg.sender, allowance);

        return allowance;
    }

    // Returns the encrypted allowance of the spender. The encryption is done using the system aes key
    function getGTAllowance(address _owner, address _spender) private returns (ctUint64 remaining){
        // ctUint64 zero = ctUint64.wrap(0);
        if (ctUint64.unwrap(allowances[_owner][_spender]) == 0) {// 0 means that no allowance has been set
            gtUint64 zero = MpcCore.setPublic64(0);
            return MpcCore.offBoard(zero);
        } else {
            return allowances[_owner][_spender];
        }
    }

    // Sets the new encrypted allowance of the spender
    function setApproveValue(address _owner, address _spender, ctUint64 _value) private {
        allowances[_owner][_spender] = _value;
    }

}				
			
							
							
					// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import "MpcCore.sol";

contract ConfidentialIdentityRegistry{
    uint constant MAX_IDENTIFIERS_LENGTH = 20;

    address private _owner;

    // A mapping from wallet to registrarId
    mapping(address => uint) public registrars;

    // A mapping from wallet to an identity.
    mapping(address => Identity) internal identities;

    struct Identity {
        uint registrarId;
        mapping(string => ctUint64) identifiers;
        string[] identifierList;
    }

    mapping(address => mapping(address => mapping(string => bool))) permissions; // users => contracts => identifiers[]

    error InvalidOwner(address owner);
    error UnauthorizedAccount(address account);

    event NewRegistrar(address wallet, uint registrarId);
    event RemoveRegistrar(address wallet);
    event NewDid(address wallet);
    event RemoveDid(address wallet);
    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
    event Identifier(address indexed _reader, string _identifier, ctUint64 _value);

    constructor(address initialOwner){
        if (initialOwner == address(0)) {
            revert InvalidOwner(address(0));
        }
        _transferOwnership(initialOwner);
    }

    function addRegistrar(address wallet, uint registrarId) public onlyOwner {
        require(registrarId > 0, "registrarId needs to be > 0");
        registrars[wallet] = registrarId;
        emit NewRegistrar(wallet, registrarId);
    }

    function removeRegistrar(address wallet) public onlyOwner {
        require(registrars[wallet] > 0, "wallet is not registrar");
        registrars[wallet] = 0;
        emit RemoveRegistrar(wallet);
    }

    // Add user
    function addDid(address wallet) public onlyOwner {
        require(
            identities[wallet].registrarId == 0,
            "This wallet is already registered"
        );
        Identity storage newIdentity = identities[wallet];
        newIdentity.registrarId = registrars[msg.sender];
        emit NewDid(wallet);
    }

    function removeDid(
        address wallet
    ) public onlyExistingWallet(wallet) onlyRegistrarOf(wallet) {
        string[] memory identifierList_ = identities[wallet].identifierList;
        uint identifierLength = identifierList_.length;
        for (uint i; i < identifierLength; i++) {
            identities[wallet].identifiers[identifierList_[i]] = MpcCore
                .offBoard(MpcCore.setPublic64(0));
        }
        delete identities[wallet];
        emit RemoveDid(wallet);
    }

    // Set user's identifiers
    function setIdentifier(
        address wallet,
        string calldata identifier,
        ctUint64 value,
        bytes calldata signature
    ) public {
        itUint64 memory it;
        it.ciphertext = value;
        it.signature = signature;
        setIdentifier(wallet, identifier, MpcCore.validateCiphertext(it));
    }

    function setIdentifier(
        address wallet,
        string memory identifier,
        gtUint64 value
    ) internal onlyExistingWallet(wallet) onlyRegistrarOf(wallet) {
        identities[wallet].identifiers[identifier] = MpcCore.offBoard(value);
        string[] memory identifierList_ = identities[wallet].identifierList;
        uint identifierLength = identifierList_.length;
        for (uint i; i < identifierLength; i++) {
            if (
                keccak256(bytes(identities[wallet].identifierList[i])) ==
                keccak256(bytes(identifier))
            ) return;
        }
        require(
            identifierLength + 1 <= MAX_IDENTIFIERS_LENGTH,
            "Too many identifiers"
        );
        identities[wallet].identifierList.push(identifier);
    }

    function removeIdentifier(
        address wallet,
        string memory identifier
    ) internal onlyExistingWallet(wallet) onlyRegistrarOf(wallet) {
        string[] memory identifierList_ = identities[wallet].identifierList;
        uint identifierLength = identifierList_.length;
        for (uint i; i < identifierLength; i++) {
            if (
                keccak256(bytes(identities[wallet].identifierList[i])) ==
                keccak256(bytes(identifier))
            ) {
                identities[wallet].identifierList[i] = identities[wallet]
                    .identifierList[identifierLength - 1];
                identities[wallet].identifierList.pop();
                return;
            }
        }
        require(false, "Identifier not found");
    }

    // User handling permission permission
    function grantAccess(
        address allowed,
        string[] calldata identifiers
    ) public {
        for (uint i = 0; i < identifiers.length; i++) {
            permissions[msg.sender][allowed][identifiers[i]] = true;
        }
    }

    function revokeAccess(
        address allowed,
        string[] calldata identifiers
    ) public {
        for (uint i = 0; i < identifiers.length; i++) {
            permissions[msg.sender][allowed][identifiers[i]] = false;
        }
    }

    function getRegistrar(address wallet) public view returns (uint) {
        return identities[wallet].registrarId;
    }

    function getIdentifier(
        address wallet,
        string calldata identifier
    )
        public
        onlyExistingWallet(wallet)
        onlyAllowed(wallet, identifier)

        returns (ctUint64)
    {
        ctUint64 value = identities[wallet].identifiers[identifier];
        gtUint64 gtValue = MpcCore.onBoard(value);
        ctUint64 ctValue = MpcCore.offBoardToUser(gtValue, msg.sender);
        emit Identifier(msg.sender, identifier, ctValue);
        return ctValue;
    }


    // ACL
    modifier onlyExistingWallet(address wallet) {
        require(
            identities[wallet].registrarId > 0,
            "This wallet isn't registered"
        );
        _;
    }

    modifier onlyRegistrar() {
        require(registrars[msg.sender] > 0, "You're not a registrar");
        _;
    }

    modifier onlyRegistrarOf(address wallet) {
        uint registrarId = registrars[msg.sender];
        require(
            identities[wallet].registrarId == registrarId,
            "You're not managing this identity"
        );
        _;
    }

    modifier onlyAllowed(address wallet, string memory identifier) {
        require(
            owner() == msg.sender ||
                permissions[wallet][msg.sender][identifier],
            "User didn't give you permission to access this identifier."
        );
        _;
    }

    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    function owner() public view returns (address) {
        return _owner;
    }

    function _checkOwner() internal view {
        if (owner() != msg.sender) {
            revert UnauthorizedAccount(msg.sender);
        }
    }

    function transferOwnership(address newOwner) public onlyOwner {
        if (newOwner == address(0)) {
            revert InvalidOwner(address(0));
        }
        _transferOwnership(newOwner);
    }

    function _transferOwnership(address newOwner) internal {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}
				
			
							
							
					// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

/**
 * @title ConfidentialAuction
 * @dev This contract is for conducting an auction with encrypted bids.
 *
 * Initialization:
 * The contract is initialized with a beneficiary, a token contract, a bidding time, and a stoppable flag.
 * The beneficiary is the address that will receive the highest bid at the end of the auction.
 * The token contract is an instance of `PrivateERC20Contract` which is used for encrypted bids.
 * The bidding time determines when the auction ends.
 * The stoppable flag indicates whether the auction can be manually stopped by the contract owner.
 *
 * Functions:
 * - bid: Allows a user to place a bid. The bid is encrypted and validated. If the bid is higher than the current highest bid,
       it becomes the new highest bid. The tokens corresponding to the bid are transferred from the bidder to the contract.
 * - getBid: Allows a user to retrieve their bid.
 * - stop: Allows the contract owner to manually stop the auction if it is stoppable.
 * - doIHaveHighestBid: Allows a user to check if they have the highest bid after the auction has ended.
 * - claim: Allows the highest bidder to claim the auction object after the auction has ended.
 * - auctionEnd: Transfers the highest bid amount to the beneficiary.
 * - withdraw: Allows a bidder to withdraw their bid once the auction has ended and if they are not the highest bidder.
 *
 * Modifiers:
 * The contract includes modifiers to restrict function calls to before or after the auction end time, and to the contract owner.
 *
 */

import {PrivateERC20Contract} from "PrivateERC20Contract.sol";
import "MpcCore.sol";

contract ConfidentialAuction {
    uint public endTime;

    address public beneficiary;

    // Current highest bid.
    ctUint64 internal highestBid;

    // Mapping from bidder to their bid value.
    mapping(address => ctUint64) internal bids;

    // Number of bid
    uint public bidCounter;

    // The token contract used for encrypted bids.
    PrivateERC20Contract public tokenContract;

    // Whether the auction object has been claimed.
    ctBool internal 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);
    event Bid(address indexed _reader, ctUint64 _value);
    event IsHighestBidder(address indexed _reader, ctBool _value);

    constructor(
        address _beneficiary,
        PrivateERC20Contract _tokenContract,
        uint biddingTime,
        bool isStoppable
    ) {
        beneficiary = _beneficiary;
        tokenContract = _tokenContract;
        endTime = block.timestamp + biddingTime;
        objectClaimed = MpcCore.offBoard(MpcCore.setPublic(false));
        tokenTransferred = false;
        bidCounter = 0;
        stoppable = isStoppable;
        contractOwner = msg.sender;
    }

    function bid(
        ctUint64 _itCT,
        bytes calldata _itSignature
    ) public onlyBeforeEnd {
        ctUint64 existingBid = bids[msg.sender];

        itUint64 memory it;
        it.ciphertext = _itCT;
        it.signature = _itSignature;
        gtUint64 gtBid = MpcCore.validateCiphertext(it);

        if (ctUint64.unwrap(existingBid) == 0) {
            bidCounter++;
            bids[msg.sender] = MpcCore.offBoard(gtBid);
            tokenContract.contractTransferFrom(
                msg.sender,
                address(this),
                gtBid
            );
        } else if (
            MpcCore.decrypt(
                MpcCore.ge(
                    MpcCore.onBoard(existingBid),
                    MpcCore.onBoard(highestBid)
                )
            )
        ) {
            bids[msg.sender] = MpcCore.offBoard(gtBid);
            gtUint64 toTransfer = MpcCore.sub(
                gtBid,
                MpcCore.onBoard(existingBid)
            );
            tokenContract.contractTransferFrom(
                msg.sender,
                address(this),
                toTransfer
            );
        }
        ctUint64 currentBid = bids[msg.sender];
        if (
            ctUint64.unwrap(highestBid) == 0 ||
            MpcCore.decrypt(
                MpcCore.ge(
                    MpcCore.onBoard(existingBid),
                    MpcCore.onBoard(highestBid)
                )
            )
        ) {
            highestBid = currentBid;
        }
    }

    function getBid() public returns (ctUint64) {
        gtUint64 bidGt = MpcCore.onBoard(bids[msg.sender]);
        ctUint64 bidCt = MpcCore.offBoardToUser(bidGt, msg.sender);
        emit Bid(msg.sender, bidCt);
        return bidCt;
    }

    function stop() public onlyContractOwner {
        require(stoppable);
        manuallyStopped = true;
    }

    function doIHaveHighestBid() public onlyAfterEnd returns (ctBool) {
        gtBool isHighest = MpcCore.setPublic(false);
        if (
            ctUint64.unwrap(highestBid) != 0 &&
            ctUint64.unwrap(bids[msg.sender]) != 0
        ) {
            isHighest = MpcCore.ge(
                MpcCore.onBoard(bids[msg.sender]),
                MpcCore.onBoard(highestBid)
            );
        }
        ctBool isHighestCt = MpcCore.offBoardToUser(isHighest, msg.sender);
        emit IsHighestBidder(msg.sender, isHighestCt);
        return isHighestCt;
    }

    function claim() public onlyAfterEnd {
        gtBool isHighest = MpcCore.ge(
            MpcCore.onBoard(bids[msg.sender]),
            MpcCore.onBoard(highestBid)
        );
        gtBool canClaim = MpcCore.and(
            MpcCore.not(MpcCore.onBoard(objectClaimed)),
            isHighest
        );
        if (MpcCore.decrypt(canClaim)) {
            objectClaimed = MpcCore.offBoard(MpcCore.setPublic(true));
            bids[msg.sender] = MpcCore.offBoardToUser(
                MpcCore.setPublic64(0),
                msg.sender
            );
            emit Winner(msg.sender);
        }
    }

    function auctionEnd() public onlyAfterEnd {
        require(!tokenTransferred);

        tokenTransferred = true;
        tokenContract.contractTransfer(
            beneficiary,
            MpcCore.onBoard(highestBid)
        );
    }

    // Withdraw a bid from the auction to the caller once the auction has stopped.
    function withdraw() public onlyAfterEnd {
        gtUint64 bidValue = MpcCore.onBoard(bids[msg.sender]);
        gtBool isHighestBid = MpcCore.ge(bidValue, MpcCore.onBoard(highestBid));
        gtBool canWithdraw = MpcCore.not(
            MpcCore.and(
                isHighestBid,
                MpcCore.not(MpcCore.onBoard(objectClaimed))
            )
        );
        if (MpcCore.decrypt(canWithdraw)) {
            bids[msg.sender] = MpcCore.offBoardToUser(
                MpcCore.setPublic64(0),
                msg.sender
            );
            tokenContract.contractTransfer(msg.sender, bidValue);
        }
    }

    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);
        _;
    }
}
				
			

Integrate with programmable privacy on leading chains

In the spotlight

Decades of Pursuing Digital Confidentiality

Avishay Yanai

Co-Founder & CEO

Meital Levy

Co-Founder & CTO

Advisory

Prof. Mike Rosulek

OSU

Shahaf Bar-Geffen

CEO @ COTI

Dr. Nir Halwani

CTO @ Frequents

Prof. Yehuda Lindell

CEO @ Unbound (now Coinbase)