Platform: Code4rena
Start Date: 06/12/2022
End Date: 09/12/2022
Period: 3 days
Status: Completed
Pot Size: $36,500 USDC
Participants: 119
Reporter: itsmetechjay
Judge: berndartmueller
Id: 189
League: ETH
bin2chen | 1/119 | $4,376.54 | 5 | 3 | 0 | 2 | 0 | 0 | 0 | 0 |
pauliax | 2/119 | $3,356.54 | 4 | 3 | 0 | 1 | 0 | 0 | 0 | 0 |
csanuragjain | 3/119 | $2,997.84 | 3 | 0 | 0 | 3 | 1 | 0 | 0 | 0 |
stealthyz | 4/119 | $2,864.75 | 1 | 0 | 0 | 1 | 1 | 0 | 0 | 0 |
RaymondFam | 5/119 | $1,805.27 | 4 | 0 | 0 | 2 | 0 | Grade A | Grade B | 0 |
hansfriese | 6/119 | $1,765.14 | 9 | 2 | 0 | 6 | 0 | Grade B | 0 | 0 |
HollaDieWaldfee | 7/119 | $1,530.63 | 7 | 2 | 0 | 4 | 0 | Grade A | 0 | 0 |
adriro | 8/119 | $1,010.70 | 7 | 1 | 0 | 4 | 0 | Grade B | Grade B | 0 |
Josiah | 9/119 | $991.64 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 0 |
0xA5DF | 10/119 | $656.69 | 5 | 1 | 0 | 3 | 0 | Grade B | 0 | 0 |
Auditor per page
The C4audit output for the contest can be found here.
Note for C4 wardens: Anything included in the C4udit output is considered a publicly known issue and is ineligible for awards.
Escher Escher is a decentralized curated marketplace for editioned artwork
Contracts For Escher721, Sale contracts, and URI delegates, we inherit from the openzeppelen-contracts-upgradeable version of OpenZeppelin's libraries to keep deploy costs low, and the contracts aren't actually upgradeable
This is a minimal curated registry of onchain addresses which are the creators onboarded to Escher. Users can be added as a Curator
or a Creator
. Curators are able to onboard creators to the smart contract system. All assigned roles are ERC1155 soulbound tokens.
Each contract must declare a URI delegate which handles all token metadata.
This is the core creator contract implementation for Escher. It is built on top the OpenZepplin ERC721 contracts. Each contract is fully owned by the creators. Escher must be careful to not lose their keys or to add backup admins.
This is the factory contract where all onboarded artists are able to mint their own Escher Edition
contract. Each contract is a minimal proxy to keep is cheap and easy to make your own contract. While the Factory uses proxies, nothing in it is upgradeable.
This is the factory contract where fixed price sale proxies are created. The protocol controls a feeReceiver
variable which is the address that receives 5% of all sales. The other function is creating the proxy. Variables and how the creation flow works will be covered below in Sales Patterns
This is the core contract for fixed price and fixed supply sales. Inside this contract there are two public functions. One to cancel the sale which is controlled by the creator and the other to purchase an edition.
This is the factory contract where open edition sale proxies are created. The protocol controls a feeReceiver
variable which is the address that receives 5% of all sales. The other function is creating the proxy. Variables and how the creation flow works will be covered below in Sales Patterns
This is the core contract for fixed price and uncapped supply sales. Inside this contract there are two public functions.
This is the factory contract where LPDA sale proxies are created. The protocol controls a feeReceiver
variable which is the address that receives 5% of all sales. The other function is creating the proxy. Variables and how the creation flow works will be covered below in Sales Patterns
This is the core contract for LPDA sales. Each contract is a proxy to the implementation of LPDAs.
File | SLOC | Description and Coverage | Libraries |
---|---|---|---|
Contracts (12) | |||
src/uris/Unique.sol | 9 | Metadata Contract, 0.00% | @openzeppelin/* |
src/uris/Base.sol | 15 | Metadata Contract, 0.00% | @openzeppelin-upgradeable/* |
src/uris/Generative.sol 🧮 | 20 | Metadata Contract, 0.00% | |
src/Escher721Factory.sol 🌀 | 28 | Token Factory, 0.00% | @openzeppelin/* |
src/minters/FixedPriceFactory.sol 🌀 | 31 | Sale Factory, 100.00% | @openzeppelin/* |
src/minters/OpenEditionFactory.sol 🌀 | 31 | Sale Factory, 100.00% | @openzeppelin/* |
src/minters/LPDAFactory.sol 🌀 | 35 | Sale Factory, 100.00% | @openzeppelin/* |
src/Escher.sol 🧮 | 48 | Manages roles, 80.00% | @openzeppelin/* |
src/Escher721.sol 🧮 | 64 | ERC721 Token, 15.38% | @openzeppelin-upgradeable/* |
src/minters/FixedPrice.sol 💰 💣 📤 | 66 | Sale Contract, 82.61% | @openzeppelin-upgradeable/* |
src/minters/OpenEdition.sol 💰 💣 📤 | 81 | Sale Contract, 81.48% | @openzeppelin-upgradeable/* |
src/minters/LPDA.sol 💰 📤 | 106 | Sale Contract, 91.11% | @openzeppelin-upgradeable/* |
Total (over 12 files): | 534 | 72.67% |
File | SLOC | Description and Coverage | Libraries |
---|---|---|---|
Interfaces (4) | |||
src/interfaces/ISaleFactory.sol | 4 | - | |
src/interfaces/ITokenUriDelegate.sol | 6 | - | |
src/interfaces/ISale.sol 💰 | 8 | - | |
src/interfaces/IEscher721.sol | 10 | - | @openzeppelin/* |
Total (over 4 files): | 28 | - |
Here we will cover the flow from start to finish for both fixed price and open edition sales. Sales require that the default royalties for a contract has been set at minimum. This is how we decide where payments go.
setTokenURI
with the token ID and the URI (arweave recommended)setTokenRoyalty
with the following variables:id
: the token ID of the salereceiver
: the address to receive paymntsfeeNumerator
: the desired royalty %createFixedSale
in the FixedPriceSaleFactory
contract. This will create the proxy sale contract. The artist must provide the following variables:edition
: the contract address of their Escher Edition proxyid
: the id of the token to sellprice
: the price in ether of each editionsaleTime
: the starting time in unix of the saleamount
: the amount of editions to sellgrantRole
in the creators Escher Edition contract. This will allow the proxy contract to mint the tokens. The following variables must be provided:role
: the bytes32 MINTER_ROLE
which can be found in the artist contractaccount
: the address of the sale proxy contractsetTokenURI
with the token ID and the URI (arweave recommended)setTokenRoyalty
with the following variables:id
: the token ID of the salereceiver
: the address to receive paymntsfeeNumerator
: the desired royalty %createOpenEdition
in the OpenEditionSaleFactory
contract. This will create the proxy sale contract. The artist must provide the following variables:edition
: the contract address of their Escher Edition proxyid
: the id of the token to sellprice
: the price in ether of each editionsaleTime
: the starting time in unix of the saleendTime
: the ending time in unix of the salegrantRole
in the creators Escher Edition contract. This will allow the proxy contract to mint the tokens. The following variables must be provided:role
: the bytes32 MINTER_ROLE
which can be found in the artist contractaccount
: the address of the sale proxy contractfinalize
to get their Ethereum.setTokenURI
with the token ID and the URI (arweave recommended)setTokenRoyalty
with the following variables:id
: the token ID of the salereceiver
: the address to receive paymntsfeeNumerator
: the desired royalty %createLPDASale
in the LPDAFactory
contract. This will create the proxy sale contract. The artist must provide the following variables:currentId
: the starting id of the token to sellfinalId
: the ending id of the token to selledition
: the contract address of their Escher Edition proxystartPrice
: the starting price of the LDPAfinalPrice
: the ending price of the LDPAdropPerSecond
: price decrease per secondendTime
: the ending time in unix of the salesaleReceiver
: the account to send proceeds from the sale tostartTime
: the starting time in unix of the salegrantRole
in the creators Escher Edition contract. This will allow the proxy contract to mint the tokens. The following variables must be provided:role
: the bytes32 MINTER_ROLE
which can be found in the artist contractaccount
: the address of the sale proxy contractrefund
to get their Ether refunds based on their purchase price and lowest sale price.Describe any novel or unique curve logic or mathematical models implemented in the contracts
Sponsor, please confirm/edit the information below.
- If you have a public code repo, please share it here: - How many contracts are in scope?: 13 - Total SLoC for these contracts?: 525 - How many external imports are there?: 10 - How many separate interfaces and struct definitions are there for the contracts within scope?: 5 - Does most of your code generally use composition or inheritance?: composition - How many external calls?: 0 - What is the overall line coverage percentage provided by your tests?: 100% - Is there a need to understand a separate part of the codebase / get context in order to audit this part of the protocol?: false - Please describe required context: - Does it use an oracle?: false - Does the token conform to the ERC20 standard?: No token - Are there any novel or unique curve logic or mathematical models?: No - Does it use a timelock function?: No - Is it an NFT?: ERC721 are part of it - Does it have an AMM?: No - Is it a fork of a popular project?: false - Does it use rollups?: false - Is it multi-chain?: false - Does it use a side-chain?: false
In one command
rm -Rf 2022-12-escher || true && git clone https://github.com/code-423n4/2022-12-escher.git && cd 2022-12-escher && npm ci && git submodule update --init --recursive && foundryup && forge test --gas-report
Install linting and formatting
npm ci
Install git submodules
git submodule update --init --recursive
Run tests
forge test
Run Slither
Make sure you're running the latest version of slither v0.9.1
slither .