-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 40e75e9
Showing
41 changed files
with
16,661 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
PRIVATE_KEY= | ||
INFURA_API_KEY= | ||
ETHERSCAN_API_KEY= | ||
MAX_SLOT= | ||
MAX_NFTS_PER_SLOT= | ||
ROYALTY_FEE_BPS= | ||
DAO_ADDRESS= | ||
SUPPORTED_BID_TOKENS= | ||
ROYALTIES_REGISTRY= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
on: [push] | ||
jobs: | ||
main_job: | ||
runs-on: ubuntu-latest | ||
name: Solidity Security | ||
steps: | ||
- name: Checkout | ||
uses: actions/checkout@v2 | ||
- name: Setup Node.js | ||
uses: actions/setup-node@v2 | ||
with: | ||
node-version: '14' | ||
- name: Install dependencies | ||
run: yarn | ||
- name: Configure Hardhat | ||
env: | ||
HARDHAT_CONFIG : ${{secrets.HARDHAT_CONFIG}} | ||
run: echo "$HARDHAT_CONFIG" > hardhat.config.js | ||
- name: Compile Contracts | ||
run: yarn compile | ||
- name: Slither Static Analysis | ||
uses: luisfontes19/[email protected] | ||
with: | ||
slither-version: '0.8.2' | ||
run-npm-install: true | ||
high-threshold: 1 | ||
medium-threshold: 1 | ||
low-threshold: 1 | ||
optimization-threshold: 1 | ||
informative-threshold: 10 | ||
projectPath: "." |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
node_modules | ||
.envrc | ||
.env | ||
.DS_Store | ||
coverage | ||
coverage.json | ||
.openzeppelin | ||
|
||
deployments/ganache | ||
deployments/rinkeby | ||
deployments/ropsten | ||
deployments/mainnet | ||
|
||
#Hardhat files | ||
cache | ||
artifacts | ||
.vscode | ||
.solhint.json | ||
.prettierrc | ||
arguments.js |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
## Auctions specs/stages | ||
|
||
### 1. Create an auction with specified configuration | ||
|
||
- The auction is opened for deposits until the *startTime* timestamp is reached | ||
- The depositor can deposit NFTs into each defined slot, up to the slot limit | ||
- The depositor can withdraw NFTs before the auction has started | ||
- The auction can be cancelled before the *startTime* timestamp | ||
- If the auction has started and there are no deposited NFTs, the auction becomes void and does not accept deposits | ||
|
||
### 2. Auction start | ||
|
||
- Users are allowed to to bid to the auction (with ERC20 token or ETH) | ||
- There is no restriction on the bid amount until all slots have been filled | ||
- Once there are more bids than slots, every next bid should be higher than the next winning bid | ||
- Each user is allowed to withdraw his bid if it is a non winning bid | ||
- Users are allowed to bid until the *endTime* timestamp is reached | ||
|
||
### 3. Auction end | ||
|
||
- When the *endTime* timestamp is reached, the *finalizeAuction* function should be called. It will check which slots have been won, assign the winners and the bid amounts | ||
- Once the auction is finalized, the revenue for each slot should be captured. Without this step, the auctioneer wouldn’t be able to collect his winnings and the bidders wouldn’t be able to withdraw their NFTs | ||
- In the case of auction with little amount of slots, all slots revenue can be captured in a batch transaction *captureSlotRevenueRange* | ||
|
||
### 4. Capture revenue | ||
|
||
- When the revenue has been captured, the winners are allowed to withdraw the NFTs they’ve won. This is done by calling the *claimERC721Rewards*. There could be a case, where there are more NFTs in a slot and one transaction could not be enough (due to gas limitations). In this case the function should be called multiple times with the remaining amounts. | ||
- In the case there is a slot which hasn’t been won by anyone (either because the reserve price hasn't been met or there weren't enough bids), the depositor can withdraw his NFTs with the *withdrawERC721FromNonWinningSlot* function. It has the same mechanics as *claimERC721Rewards* | ||
- To collect the revenue from the auctions, *distributeCapturedAuctionRevenue* should be called for each slot. | ||
|
||
### Functions related to each stage: | ||
|
||
- **Create** - *createAuction* | ||
- **Cancel** - *cancelAuction*, *withdrawDepositedERC721* | ||
- **Deposit** - *depositERC721*, *batchDepositToAuction* | ||
- **Bidding** - *ethBid*, *erc20Bid*, *withdrawEthBid*, *withdrawERC20Bid* | ||
- **Finalize** - *finalizeAuction*, *captureSlotRevenue*, *captureSlotRevenueRange*, *claimERC721Rewards*, *withdrawERC721FromNonWinningSlot* | ||
- **Revenue distribution** - *distributeCapturedAuctionRevenue*, *distributeSecondarySaleFees*, *distributeRoyalties* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
# UniverseXYZ ERC721 Auctions | ||
|
||
The repository contains ERC721 Auctions smart contracts written for UniverseXYZ. Credit to [UniverseXYZ](https://universe.xyz). | ||
|
||
### Build the project | ||
|
||
Run: | ||
|
||
``` | ||
$ yarn | ||
$ cp .envrc.example .envrc | ||
$ source .envrc | ||
$ yarn compile | ||
``` | ||
|
||
### Run Tests | ||
|
||
``` | ||
$ npx hardhat test | ||
``` | ||
|
||
### Deploy to Ganache | ||
|
||
``` | ||
$ ./start_ganache.sh | ||
$ yarn deploy ganache | ||
``` | ||
|
||
### Deploy to live networks | ||
|
||
Edit .envrc.example then copy it to .envrc | ||
|
||
``` | ||
$ cp .envrc.example .envrc | ||
$ source .envrc | ||
``` | ||
|
||
Make sure to update the enviroment variables with suitable values. | ||
|
||
Now enable the env vars using [direnv](https://direnv.net/docs/installation.html) | ||
|
||
``` | ||
$ eval "$(direnv hook bash)" | ||
$ direnv allow | ||
``` | ||
|
||
Deploy to a network: | ||
|
||
``` | ||
$ yarn deploy rinkeby | ||
``` | ||
|
||
### Verify smart contract on etherscan | ||
|
||
To verify the deployed contract run: | ||
|
||
``` | ||
$ yarn etherscan-verify rinkeby --address | ||
``` | ||
|
||
### Gas cost estimation | ||
|
||
To get a gas estimation for deployment of contracts and functions calls, the `REPORT_GAS` env variable must be set to true. To estimate with certaing gas price update the hardhat.config.js file. Gas estimation happens during test, only functions specified in tests will get an estimation. run with: | ||
|
||
``` | ||
$ yarn test | ||
``` | ||
|
||
### Rinkeby deployments | ||
|
||
UniverseAuctionHouse - https://rinkeby.etherscan.io/address/0x2345164eFfE24EA125ECD0ec9C7539D5422c367f | ||
|
||
UniverseERC721Factory - https://rinkeby.etherscan.io/address/0x26E84797880B6435861E8730171B75e6257bCBa0 | ||
|
||
UniverseERC721 - https://rinkeby.etherscan.io/address/0xF7B12892699D6c94E83d864805A381548cfB2A29 | ||
|
||
UniverseERC721Core - https://rinkeby.etherscan.io/address/0xfD7D165344a04241AB3Cd07d021eEC17F03ADc51 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity 0.8.11; | ||
|
||
import "@openzeppelin/contracts/utils/introspection/ERC165Storage.sol"; | ||
import "./interfaces/IERC2981Royalties.sol"; | ||
|
||
/// @dev This is a contract used to add ERC2981 support to ERC721 and 1155 | ||
abstract contract ERC2981Royalties is ERC165Storage, IERC2981Royalties { | ||
struct RoyaltyInfo { | ||
address recipient; | ||
uint24 amount; | ||
} | ||
|
||
mapping(uint256 => RoyaltyInfo) internal _royalties; | ||
|
||
bytes4 private constant _INTERFACE_ID_ERC2981 = 0x2a55205a; | ||
|
||
constructor() { | ||
_registerInterface(_INTERFACE_ID_ERC2981); | ||
} | ||
|
||
/// @dev Sets token royalties | ||
/// @param tokenId the token id fir which we register the royalties | ||
/// @param recipient recipient of the royalties | ||
/// @param value percentage (using 2 decimals - 10000 = 100, 0 = 0) | ||
function _setTokenRoyalty( | ||
uint256 tokenId, | ||
address recipient, | ||
uint256 value | ||
) internal { | ||
require(value <= 10000, "ERC2981Royalties: Too high"); | ||
_royalties[tokenId] = RoyaltyInfo(recipient, uint24(value)); | ||
} | ||
|
||
function royaltyInfo(uint256 tokenId, uint256 value) | ||
external | ||
view | ||
override | ||
returns (address receiver, uint256 royaltyAmount) | ||
{ | ||
RoyaltyInfo memory royalties = _royalties[tokenId]; | ||
receiver = royalties.recipient; | ||
royaltyAmount = (value * royalties.amount) / 10000; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
//SPDX-License-Identifier: MIT | ||
pragma solidity 0.8.11; | ||
|
||
import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; | ||
import "./interfaces/IERC721Consumable.sol"; | ||
|
||
abstract contract ERC721Consumable is IERC721Consumable, ERC721 { | ||
|
||
// Mapping from token ID to consumer address | ||
mapping (uint256 => address) _tokenConsumers; | ||
|
||
/** | ||
* @dev See {IERC721Consumable-consumerOf} | ||
*/ | ||
function consumerOf(uint256 _tokenId) view external returns (address) { | ||
require(_exists(_tokenId), "ERC721Consumable: consumer query for nonexistent token"); | ||
return _tokenConsumers[_tokenId]; | ||
} | ||
|
||
/** | ||
* @dev See {IERC721Consumable-changeConsumer} | ||
*/ | ||
function changeConsumer(address _consumer, uint256 _tokenId) external { | ||
address owner = this.ownerOf(_tokenId); | ||
require(msg.sender == owner || msg.sender == getApproved(_tokenId) || | ||
isApprovedForAll(owner, msg.sender), | ||
"ERC721Consumable: changeConsumer caller is not owner nor approved"); | ||
_changeConsumer(owner, _consumer, _tokenId); | ||
} | ||
|
||
/** | ||
* @dev Changes the consumer | ||
* Requirement: `tokenId` must exist | ||
*/ | ||
function _changeConsumer(address _owner, address _consumer, uint256 _tokenId) internal { | ||
_tokenConsumers[_tokenId] = _consumer; | ||
emit ConsumerChanged(_owner, _consumer, _tokenId); | ||
} | ||
|
||
/** | ||
* @dev See {IERC165-supportsInterface}. | ||
*/ | ||
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721) returns (bool) { | ||
return interfaceId == type(IERC721Consumable).interfaceId || super.supportsInterface(interfaceId); | ||
} | ||
|
||
function _beforeTokenTransfer(address _from, address _to, uint256 _tokenId) internal virtual override (ERC721) { | ||
super._beforeTokenTransfer(_from, _to, _tokenId); | ||
|
||
_changeConsumer(_from, address(0), _tokenId); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity 0.8.11; | ||
|
||
import "@openzeppelin/contracts/utils/introspection/ERC165Storage.sol"; | ||
|
||
contract HasSecondarySaleFees is ERC165Storage { | ||
struct Fee { | ||
address payable recipient; | ||
uint96 value; | ||
} | ||
|
||
// id => fees | ||
mapping (uint256 => Fee[]) public fees; | ||
event SecondarySaleFees(uint256 tokenId, address[] recipients, uint[] bps); | ||
|
||
/* | ||
* bytes4(keccak256('getFeeBps(uint256)')) == 0x0ebd4c7f | ||
* bytes4(keccak256('getFeeRecipients(uint256)')) == 0xb9c4d9fb | ||
* | ||
* => 0x0ebd4c7f ^ 0xb9c4d9fb == 0xb7799584 | ||
*/ | ||
bytes4 private constant _INTERFACE_ID_FEES = 0xb7799584; | ||
constructor() { | ||
_registerInterface(_INTERFACE_ID_FEES); | ||
} | ||
|
||
function getFeeRecipients(uint256 id) external view returns (address payable[] memory) { | ||
Fee[] memory _fees = fees[id]; | ||
address payable[] memory result = new address payable[](_fees.length); | ||
for (uint i = 0; i < _fees.length; i++) { | ||
result[i] = _fees[i].recipient; | ||
} | ||
return result; | ||
} | ||
|
||
function getFeeBps(uint256 id) external view returns (uint[] memory) { | ||
Fee[] memory _fees = fees[id]; | ||
uint[] memory result = new uint[](_fees.length); | ||
for (uint i = 0; i < _fees.length; i++) { | ||
result[i] = _fees[i].value; | ||
} | ||
return result; | ||
} | ||
|
||
} |
Oops, something went wrong.