Philipp Keinberger
NftMarketplace
This contract is an nft marketplace, where users can list (sell) and buy nfts using eth and erc20 tokens. Payment tokens (e.g. erc20-tokens, accepted by the marketplace as payment for nfts) can be added and removed through access- restricted functions, favourably controlled by a governor contract (e.g. dao) to allow for decentralized governance of the marketplace. The contract is designed to be upgradeable.
This contract implements the IERC721 and IERC20 Openzeppelin interfaces for the ERC721 and ERC20 token standards. The Marketplace implements Chainlink price feeds to retrieve prices of listed erc20 payment tokens. This contract inherits from Openzeppelins OwnableUpgradeable contract in order to allow owner features, while still keeping upgradeablity functionality. The Marketplace is designed to be deployed through a proxy contract to allow for future upgrades of the contract.
function addPaymentToken(address tokenAddress, address priceFeedAddress, uint8 decimals) external nonpayable
Function for adding a payment token (erc20) as payment method for nft purchases using erc20 tokens
This function reverts if the market is CLOSED or the caller is not the owner of the marketplace. Checking if the tokenAddress indeed implements the IERC20 interface is not provided since the function can only be called by the owner, while the owner should be trustworthy enough to check for that beforehand. Main reason for that is gas savings. This function emits the {PaymentTokenAdded} event.
Name | Type | Description |
---|---|---|
tokenAddress | address | Is the address of the erc20 contract |
priceFeedAddress | address | Is the address of the chainlink price feed for the erc20 |
decimals | uint8 | Is the amount of decimals returned by the chainlink price feed |
function addPaymentTokenAtListing(address nftAddr, uint256 tokenId, address paymentTokenAddress) external nonpayable
Function for adding a payment token to a listing
This function reverts if the market is not OPEN, the caller is not the owner of tokenId
at nftAddr
, or the nft is not listed on the marketplace. This function emits the {NftPaymentTokenAdded} event.
Name | Type | Description |
---|---|---|
nftAddr | address | Is the address of the nft contract |
tokenId | uint256 | Is the id of the nft |
paymentTokenAddress | address | is the address of the payment token to be added |
function buyNftErc20(address nftAddr, uint256 tokenId, uint256 paymentTokenIndex) external nonpayable
Function for buying an nft on the marketplace with an erc20 (payment) token.
This function reverts if the market is not OPEN, the nft is not listed on the marketplace or the marketplace, the marketplace is not approved to spend the nft or the approved token amount by buyer is smaller than the amount of tokens required to pay for the nft. The amount of tokens needed of paymentToken at index paymentTokenIndex
is retrieved from the getTokenAmountFromEthAmount function, which converts the price (eth in wei) to the token amount (in wei) using Chainlink price feeds. This implementation will transfer the nft to the buyer directly, while also transferring the amount of tokens paid directly to the seller. If the transfer of the erc20 tokens fails, the function is reverted (nft will not be transferred to buyer). This function emits the {NftBought} event.
Name | Type | Description |
---|---|---|
nftAddr | address | Is the address of the nft contract |
tokenId | uint256 | Is the id of the nft |
paymentTokenIndex | uint256 | Is the index of the paymentToken in the Listing.paymentTokenAddresses array |
function buyNftEth(address nftAddr, uint256 tokenId) external payable
Function for buying an nft on the marketplace with eth
This function reverts if the market is not OPEN, the nft is not listed on the marketplace, the marketplace is not approved to transfer the nft or the amount of eth sent to the marketplace is smaller than the price of the nft. This implementation will transfer the nft to the buyer directly, while granting the seller address the right to withdraw the eth amount sent by the buyer to the marketplace by calling the withdrawFunds function. Checking the amount of eligible funds for withdrawal can be done by calling getEligibleFunds. This function emits the {NftBought} event.
Name | Type | Description |
---|---|---|
nftAddr | address | Is the address of the nft contract |
tokenId | uint256 | Is the id of the nft |
function cancelListing(address nftAddr, uint256 tokenId) external nonpayable
Function for cancelling a listing on the marketplace
This function reverts if the market is not OPEN, the caller is not the owner of tokenId
at nftAddr
, or the nft is not listed on the marketplace. This implementation only deletes the listing from the mapping. Sellers have to revoke approval rights for their nft on their own or through a frontend application. This function emits the {NftDelisted} event.
Name | Type | Description |
---|---|---|
nftAddr | address | Is the address of the nft contract |
tokenId | uint256 | Is the id of the nft |
function getEligibleFunds(address addr) external view returns (uint256)
Function for looking up the amount of eligible funds that can be withdrawn
Name | Type | Description |
---|---|---|
addr | address | Is the address to be looked up |
Name | Type | Description |
---|---|---|
_0 | uint256 | Eligible funds of addr for withdrawal from marketplace |
function getListing(address nftAddr, uint256 tokenId) external view returns (struct NftMarketplace.Listing)
This function returns the current Listing of tokenId
at nftAddr
(if existing)
Name | Type | Description |
---|---|---|
nftAddr | address | Is the address of the nft contract |
tokenId | uint256 | Is the id of the nft |
Name | Type | Description |
---|---|---|
_0 | NftMarketplace.Listing | Listing of tokenId at nftAddr |
function getPaymentToken(address addr) external view returns (struct NftMarketplace.PaymentToken)
Function for looking up payment token of marketplace
Name | Type | Description |
---|---|---|
addr | address | Is the contract address of the payment token |
Name | Type | Description |
---|---|---|
_0 | NftMarketplace.PaymentToken | PaymentToken of addr |
function getState() external view returns (enum NftMarketplace.MarketState)
This function returns the current MarketState of the marketplace
Name | Type | Description |
---|---|---|
_0 | enum NftMarketplace.MarketState | State of the marketplace |
function getTokenAmountFromEthAmount(uint256 ethAmount, address tokenAddress) external view returns (uint256)
Function for converting ethAmount
to amount of tokens using Chainlink price feeds
This function reverts if the tokenAddress
is not listed as a paymentToken. This implementation returns the token amount in wei (18 decimals).
Name | Type | Description |
---|---|---|
ethAmount | uint256 | Amount of eth (in wei) to be converted |
tokenAddress | address | Is the address of the erc20 token |
Name | Type | Description |
---|---|---|
_0 | uint256 | Token amount (in wei) |
function getVersion() external pure returns (uint8)
Function for retrieving version of marketplace
Name | Type | Description |
---|---|---|
_0 | uint8 | Version |
function initialize() external nonpayable
Initializer function which replaces constructor for upgradeability functionality. Sets the msg.sender as owner
function listNft(address nftAddr, uint256 tokenId, uint256 nftPrice, address[] allowedPaymentTokens) external nonpayable
Function for listing an nft on the marketplace
This function reverts if the market is not OPEN, the caller is not the owner of tokenId
at nftAddr
, or the marketplace is not approved to transfer the nft. The function also reverts if allowedPaymentTokens
contains an erc20-token, which is not added as a paymentToken on the marketplace. If allowedPaymentTokens
are not specified, the nft will only be able to be sold using the buyNftEth function. This implementation still lets sellers hold their nft until the item actually gets sold. The buyNft functions will check for allowance to spend the nft still being present when called. This function emits the {NftListed} event.
Name | Type | Description |
---|---|---|
nftAddr | address | Is the address of the nft contract |
tokenId | uint256 | Is the token id of the nft |
nftPrice | uint256 | Is the price set by msg.sender for the listing |
allowedPaymentTokens | address[] | Are payment tokens allowed as payment methods for the nft (optional) |
function owner() external view returns (address)
Returns the address of the current owner.
Name | Type | Description |
---|---|---|
_0 | address | undefined |
function removePaymentToken(address tokenAddress) external nonpayable
Function for removing a payment token from the contract
This function reverts if the market is CLOSED or the caller is not the owner of the marketplace. This function emits the {PaymentTokenRemoved} event.
Name | Type | Description |
---|---|---|
tokenAddress | address | Is the address of the payment token (erc20) to be removed |
function removePaymentTokenAtListing(address nftAddr, uint256 tokenId, uint256 index) external nonpayable
Function for removing a payment token to a listing
This function reverts if the market is not OPEN, the caller is not the owner of tokenId
at nftAddr
, or the nft is not listed on the marketplace. This function emits the {NftPaymentTokenRemoved} event.
Name | Type | Description |
---|---|---|
nftAddr | address | Is the address of the nft contract |
tokenId | uint256 | Is the id of the nft |
index | uint256 | is the index of the payment token to be removed |
function renounceOwnership() external nonpayable
Leaves the contract without owner. It will not be possible to call onlyOwner
functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner.
function setState(enum NftMarketplace.MarketState newState) external nonpayable
Function for setting the state of the marketplace
This function can only be called by the owner
Name | Type | Description |
---|---|---|
newState | enum NftMarketplace.MarketState | Is the new value for the state |
function transferOwnership(address newOwner) external nonpayable
Transfers ownership of the contract to a new account (newOwner
). Can only be called by the current owner.
Name | Type | Description |
---|---|---|
newOwner | address | undefined |
function updateListingPrice(address nftAddr, uint256 tokenId, uint256 newPrice) external nonpayable
Function for updating the price of the listing on the marketplace
This function reverts if the market is not OPEN, the caller is not the owner of tokenId
at nftAddr
, or the nft is not listed on the marketplace. This function emits the {NftPriceUpdated} event.
Name | Type | Description |
---|---|---|
nftAddr | address | Is the address of the nft contract |
tokenId | uint256 | Is the id of the nft |
newPrice | uint256 | Is the new price for the nft |
function withdrawFunds() external nonpayable
Function for withdrawing eth from the marketplace, if eligible funds is greater than zero (only after purchases with eth)
This function reverts if the market is CLOSED or if there are no eligible funds of the caller to withdraw.
event Initialized(uint8 version)
Name | Type | Description |
---|---|---|
version | uint8 | undefined |
event NftBought(address nftAddr, uint256 tokenId, address indexed buyer, uint256 indexed price)
Event emitted when an nft is bought
Name | Type | Description |
---|---|---|
nftAddr | address | undefined |
tokenId | uint256 | undefined |
buyer indexed |
address | undefined |
price indexed |
uint256 | undefined |
event NftDelisted(address indexed nftAddr, uint256 indexed tokenId)
Event emitted when an nft is delisted by the seller
Name | Type | Description |
---|---|---|
nftAddr indexed |
address | undefined |
tokenId indexed |
uint256 | undefined |
event NftListed(address indexed seller, address indexed nftAddr, uint256 indexed tokenId, uint256 price, address[] tokensForPayment)
Event emitted when a new nft is listed on the market
Name | Type | Description |
---|---|---|
seller indexed |
address | undefined |
nftAddr indexed |
address | undefined |
tokenId indexed |
uint256 | undefined |
price | uint256 | undefined |
tokensForPayment | address[] | undefined |
event NftPaymentTokenAdded(address indexed nftAddr, uint256 indexed tokenId, address indexed paymentTokenAddress)
Event emitted when seller adds an erc20 token accepted as payment for the nft
Name | Type | Description |
---|---|---|
nftAddr indexed |
address | undefined |
tokenId indexed |
uint256 | undefined |
paymentTokenAddress indexed |
address | undefined |
event NftPaymentTokenRemoved(address indexed nftAddr, uint256 indexed tokenId, address indexed paymentTokenAddress)
Event emitted when seller removes an erc20 token previously accepted as payment for the nft
Name | Type | Description |
---|---|---|
nftAddr indexed |
address | undefined |
tokenId indexed |
uint256 | undefined |
paymentTokenAddress indexed |
address | undefined |
event NftPriceUpdated(address indexed nftAddr, uint256 indexed tokenId, uint256 indexed price)
Event emitted when seller updates the price of an nft
Name | Type | Description |
---|---|---|
nftAddr indexed |
address | undefined |
tokenId indexed |
uint256 | undefined |
price indexed |
uint256 | undefined |
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner)
Name | Type | Description |
---|---|---|
previousOwner indexed |
address | undefined |
newOwner indexed |
address | undefined |
event PaymentTokenAdded(address tokenAddress)
Event emitted when a new payment token gets added to the market
Name | Type | Description |
---|---|---|
tokenAddress | address | undefined |
event PaymentTokenRemoved(address tokenAddress)
Event emitted when a payment token is removed from the market
Name | Type | Description |
---|---|---|
tokenAddress | address | undefined |
error NftMarketplace__AlreadyListed(address nftAddress, uint256 tokenId)
Thrown when tokenId
of nftAddress
is already listed on market
Name | Type | Description |
---|---|---|
nftAddress | address | undefined |
tokenId | uint256 | undefined |
error NftMarketplace__EthTransferFailed()
Thrown when eth transfer failed
error NftMarketplace__IndexOutOfBounds()
Thrown when index does not exist in an array
error NftMarketplace__NftNotListed(address nftAddress, uint256 tokenId)
Thrown when tokenId
of nftAddress
is not listed on market
Name | Type | Description |
---|---|---|
nftAddress | address | undefined |
tokenId | uint256 | undefined |
error NftMarketplace__NoEligibleFunds()
Thrown when caller has no eligible funds for withdrawal
error NftMarketplace__NotApprovedForNft(address nftAddress, uint256 tokenId)
Thrown when market is not approved to transfer tokenId
of nftAddress
Name | Type | Description |
---|---|---|
nftAddress | address | undefined |
tokenId | uint256 | undefined |
error NftMarketplace__NotEnoughAllowance()
Thrown when allowance of market is less than required
error NftMarketplace__NotEnoughFunds()
Thrown when caller does not send enough eth to market
error NftMarketplace__NotOwnerOfNft(address nftAddress, uint256 tokenId)
Thrown when caller is not owner of tokenId
at nftAddress
Name | Type | Description |
---|---|---|
nftAddress | address | undefined |
tokenId | uint256 | undefined |
error NftMarketplace__PriceMustBeAboveZero()
Thrown when price is below or equal to zero
error NftMarketplace__StateIs(uint256 state)
Thrown when state of contract is not equal to the one specified
Name | Type | Description |
---|---|---|
state | uint256 | undefined |
error NftMarketplace__StateIsNot(uint256 state)
Thrown when state of contract is equal to the one specified
Name | Type | Description |
---|---|---|
state | uint256 | undefined |
error NftMarketplace__TokenNotListed(address tokenAddress)
Thrown when the token (erc20) is not listed as payment token
Name | Type | Description |
---|---|---|
tokenAddress | address | undefined |
error NftMarketplace__TokenTransferFailed(address tokenAddress)
Thrown when erc20 token transfer failed
Name | Type | Description |
---|---|---|
tokenAddress | address | undefined |