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

(WIP) Party Favors #48

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
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
122 changes: 122 additions & 0 deletions contracts/IPartyBid.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.5;

interface IPartyBid {
// ============ Enums ============

// State Transitions:
// (1) AUCTION_ACTIVE on deploy
// (2) AUCTION_WON or AUCTION_LOST on finalize()
enum PartyStatus {AUCTION_ACTIVE, AUCTION_WON, AUCTION_LOST}

// ============ Structs ============

struct Contribution {
uint256 amount;
uint256 previousTotalContributedToParty;
}

// ============ Public Storage Variables ============

// market wrapper contract exposing interface for
// market auctioning the NFT
function marketWrapper() external view returns(address);

// NFT contract
function nftContract() external view returns(address);

// Fractionalized NFT vault responsible for post-auction value capture
function tokenVault() external view returns(address);

// ID of auction within market contract
function auctionId() external view returns(uint256);

// ID of token within NFT contract
function tokenId() external view returns(uint256);

// ERC-20 symbol for fractional tokens
function symbol() external view returns(string memory);

// ERC-20 name for fractional tokens
function name() external view returns(string memory);

// state of the contract
function partyStatus() external view returns(PartyStatus);

// total ETH deposited by all contributors
function totalContributedToParty() external view returns(uint256);

// the total spent by PartyBid on the auction;
// 0 if the NFT is lost; highest bid + 5% PartyDAO fee if NFT is won
function totalSpent() external view returns(uint256);

// the highest bid submitted by PartyBid
function highestBid() external view returns(uint256);

// contributor => array of Contributions
function contributions(address _contributor) external view returns(Contribution[] memory);

// contributor => total amount contributed
function totalContributed(address _contributor) external view returns(uint256);

// contributor => true if contribution has been claimed
function claimed(address _contributor) external view returns(bool);


// ======== Initializer =========

function initialize(
address _marketWrapper,
address _nftContract,
uint256 _tokenId,
uint256 _auctionId,
string memory _name,
string memory _symbol
) external;

// ======== External: Contribute =========

/**
* @notice Contribute to the PartyBid's treasury
* while the auction is still open
* @dev Emits a Contributed event upon success; callable by anyone
*/
function contribute() external payable;

// ======== External: Bid =========

/**
* @notice Submit a bid to the Market
* @dev Reverts if insufficient funds to place the bid and pay PartyDAO fees,
* or if any external auction checks fail (including if PartyBid is current high bidder)
* Emits a Bid event upon success.
* Callable by any contributor
*/
function bid() external;

// ======== External: Finalize =========

/**
* @notice Finalize the state of the auction
* @dev Emits a Finalized event upon success; callable by anyone
*/
function finalize() external;

// ======== External: Claim =========

/**
* @notice Claim the tokens and excess ETH owed
* to a single contributor after the auction has ended
* @dev Emits a Claimed event upon success
* callable by anyone (doesn't have to be the contributor)
* @param _contributor the address of the contributor
*/
function claim(address _contributor) external;

// ======== Public: Utility Calculations =========

/**
* @notice Convert ETH value to equivalent token amount
*/
function valueToTokens(uint256 _value) external pure returns (uint256 _tokens);
}
34 changes: 34 additions & 0 deletions contracts/IPartyBidFactory.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.5;

interface IPartyBidFactory {
// ============ Public Immutable Variables ============

// PartyBid logic contract address
function logic() external view returns(address);

// PartyDAO multisig contract address
function partyDAOMultisig() external view returns(address);

// token vault factory contract address
function tokenVaultFactory() external view returns(address);

// weth contract address
function weth() external view returns(address);

// ============ Public Storage Variables ============

// PartyBid proxy => block number deployed at
function deployedAt(address) external view returns(uint256);

//======== Deploy function =========

function startParty(
address _marketWrapper,
address _nftContract,
uint256 _tokenId,
uint256 _auctionId,
string memory _name,
string memory _symbol
) external returns (address partyBidProxy);
}
94 changes: 94 additions & 0 deletions contracts/party-favors/DynamicPartyGated.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.5;

// ============ Internal Imports ============
import {IPartyBid} from "../IPartyBid.sol";
import {IPartyBidFactory} from "../IPartyBidFactory.sol";
// ============ External Imports ============
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";

/**
* @title DynamicPartyGated
* @author Anna Carroll
* @notice Only allow contributors to a *dynamically increasing set* of parties
* to call a function with onlyContributors modifier
*/
contract DynamicPartyGated is Ownable {
//======== Immutable Storage =========

// the PartyBid Factory address
address public immutable partyBidFactory;

//======== Mutable Storage =========

// the list of PartyBids to gate contributors
address[] public parties;

//======== Modifiers =========

/**
* @notice Gate a function to only be callable by
* contributors to the specified parties
* @dev reverts if msg.sender did not contribute to any of the parties
*/
modifier onlyContributors() {
require(isContributor(msg.sender), "DynamicPartyGated:onlyContributors");
_;
}

//======== Constructor =========

/**
* @notice Supply the PartyBids for gating contributors
* @param _partyBidFactory address of the PartyBid Factory
* @param _parties array of PartyBid addresses whose contributors to restrict to
*/
constructor(address _partyBidFactory, address[] memory _parties) {
require(_parties.length > 0, "DynamicPartyGated::constructor: supply at least one party");
for (uint256 i = 0; i < _parties.length; i++) {
_addParty(_partyBidFactory, _parties[i]);
}
partyBidFactory = _partyBidFactory;
}

//======== Public Functions =========

/**
* @notice Determine whether a contributor
* participated in the specified parties
* @param _contributor address that might have contributed to parties
* @return TRUE if they contributed
*/
function isContributor(address _contributor) public view returns (bool) {
for (uint256 i = 0; i < parties.length; i++) {
if (IPartyBid(parties[i]).totalContributed(_contributor) > 0) {
return true;
}
}
return false;
}

//======== External Functions =========

/**
* @notice Add a new party to include a new set of contributors
* @dev only callable by contract owner
* @param _party address of the PartyBid
*/
function addParty(address _party) external onlyOwner {
_addParty(partyBidFactory, _party);
}

//======== Internal Functions =========

/**
* @notice Add a new party to include a new set of contributors
* @param _partyBidFactory address of the PartyBid Factory
* @param _party address of the PartyBid
*/
function _addParty(address _partyBidFactory, address _party) internal {
uint256 _deployedAtBlock = IPartyBidFactory(_partyBidFactory).deployedAt(_party);
require(_deployedAtBlock != 0, "DynamicPartyGated::_addParty: not a party");
parties.push(_party);
}
}
65 changes: 65 additions & 0 deletions contracts/party-favors/MultiplePartyGated.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.5;

// ============ Internal Imports ============
import {IPartyBid} from "../IPartyBid.sol";
import {IPartyBidFactory} from "../IPartyBidFactory.sol";

/**
* @title MultiplePartyGated
* @author Anna Carroll
* @notice Only allow contributors to a *defined set* of parties
* to call a function with onlyContributors modifier
*/
contract MultiplePartyGated {
//======== Mutable Storage =========

// the list of PartyBids to gate contributors
address[] public parties;

//======== Modifiers =========

/**
* @notice Gate a function to only be callable by
* contributors to the specified parties
* @dev reverts if msg.sender did not contribute to any of the parties
*/
modifier onlyContributors() {
require(isContributor(msg.sender), "MultiplePartyGated:onlyContributors");
_;
}

//======== Constructor =========

/**
* @notice Supply the PartyBids for gating contributors
* @param _partyBidFactory address of the PartyBid Factory
* @param _parties array of PartyBid addresses whose contributors to restrict to
*/
constructor(address _partyBidFactory, address[] memory _parties) {
require(_parties.length > 0, "MultiplePartyGated::constructor: supply at least one party");
for (uint256 i = 0; i < _parties.length; i++) {
address _party = _parties[i];
uint256 _deployedAtBlock = IPartyBidFactory(_partyBidFactory).deployedAt(_party);
require(_deployedAtBlock != 0, "MultiplePartyGated::constructor: not a party");
parties.push(_party);
}
}

//======== Public Functions =========

/**
* @notice Determine whether a contributor
* participated in the specified parties
* @param _contributor address that might have contributed to parties
* @return TRUE if they contributed
*/
function isContributor(address _contributor) public view returns (bool) {
for (uint256 i = 0; i < parties.length; i++) {
if (IPartyBid(parties[i]).totalContributed(_contributor) > 0) {
return true;
}
}
return false;
}
}
56 changes: 56 additions & 0 deletions contracts/party-favors/SinglePartyGated.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.5;

// ============ Internal Imports ============
import {IPartyBid} from "../IPartyBid.sol";
import {IPartyBidFactory} from "../IPartyBidFactory.sol";

/**
* @title SinglePartyGated
* @author Anna Carroll
* @notice Only allow contributors to a *single* party
* to call a function with onlyContributors modifier
*/
contract SinglePartyGated {
//======== Immutable Storage =========

// the PartyBid to gate contributors
address public immutable party;

//======== Modifiers =========

/**
* @notice Gate a function to only be callable by
* contributors to the specified party
* @dev reverts if msg.sender did not contribute to the party
*/
modifier onlyContributors() {
require(isContributor(msg.sender), "SinglePartyGated:onlyContributors");
_;
}

//======== Constructor =========

/**
* @notice Supply the PartyBids for gating contributors
* @param _partyBidFactory address of the PartyBid Factory
* @param _party address of the PartyBid whose contributors to restrict to
*/
constructor(address _partyBidFactory, address _party) {
uint256 _deployedAtBlock = IPartyBidFactory(_partyBidFactory).deployedAt(_party);
require(_deployedAtBlock != 0, "SinglePartyGated::constructor: not a party");
party = _party;
}

//======== Public Functions =========

/**
* @notice Determine whether a contributor
* participated in the specified parties
* @param _contributor address that might have contributed to parties
* @return TRUE if they contributed
*/
function isContributor(address _contributor) public view returns (bool) {
return IPartyBid(party).totalContributed(_contributor) > 0;
}
}