This document delves into the advantages of implementing an Offchain Marketplace contract for the Decentraland Marketplace. By leveraging off-chain trade signing and on-chain execution, the proposed system introduces a more efficient, scalable, and cost-effective way to conduct digital asset transactions.
The Decentraland Marketplace currently operates through a series of smart contracts that facilitate various marketplace functionalities, such as creating and executing orders and bids for NFTs, as well as conducting primary sales of wearables.
This contract enables users to list NFTs for sale and execute sales. Users can create orders for their assets, allowing others to buy them. A similar version of this contract is deployed on Polygon for assets in that chain.
The Bid contract allows users to place and accept bids on NFTs. This is useful for users who want to make offers for assets that aren’t currently listed for sale. The contract also exists on Polygon.
This contract enables primary sales of Decentraland wearables, particularly useful for creators who release new collections of digital assets. The contract only exists on Polygon.
One of the main challenges with the current smart contract architecture in Decentraland is that every transaction requires users to interact directly with the blockchain, incurring gas fees for each action. Whether a user is listing an NFT for sale, placing a bid, or purchasing an item, they must submit an on-chain transaction, paying Ethereum or Polygon gas fees in the process. This can be an expensive and cumbersome process, especially on Ethereum during periods of high network congestion.
In contrast, other marketplaces such as OpenSea have implemented off-chain signing mechanisms for creating orders and bids. Rather than paying gas fees each time a user interacts with the platform, users simply sign an off-chain message with their wallets, signaling their intent to list, bid, or purchase an asset. The trade is only executed on-chain once a counterparty is ready to complete it, resulting in just one final on-chain transaction—saving significant gas fees for both buyers and sellers.
Additionally, Decentraland's current contracts lack some common features typically found in web2 marketplaces (such as Amazon), including:
These limitations hinder the marketplace's flexibility and user experience.
The marketplace smart contracts found in the Offchain Marketplace GitHub repository implement a flexible and efficient system for handling digital asset trades on Ethereum and Polygon. The contracts aim to enhance Decentraland's existing Marketplace functionality, enabling users to perform complex asset exchanges through trades while minimizing on-chain transaction costs.
At the heart of the system is the ability to define Trade
structures that contain
all the necessary conditions for asset swaps between users. Instead of requiring every trade
action to be carried out on-chain, resulting in higher transaction costs, trades are created
off-chain and only executed on-chain when needed. This allows users to sign a trade agreement
with their wallets off-chain and incur no transaction fees before execution.
This process is made possible through the accept(Trade[] _trades)
function, which
is the main entry point for executing trades. This function accepts an array of
Trade
objects and executes them sequentially, if all specified conditions are
met.
Trades are designed to be versatile, supporting a wide range of asset exchanges and custom conditions. Each trade consists of the following critical components:
Signature
A trade becomes valid once it has been signed by the creator. The signature verifies the authenticity of the trade and ensures that it was indeed signed by the creator. This is essential for confirming the identity of the party offering the trade and is used to validate the trade's data during execution.
Checks
Trades incorporate multiple layers of verification to ensure they can be executed correctly. These checks include:
Expiration Date
Specifies when the trade can no longer be executed. Once the expiration date is reached, the trade becomes invalid and cannot be used.
Effective Date
Determines when the trade becomes active and can be executed. This allows for trades to be scheduled for future activation.
Contract Signature Index
A value stored in the smart contract that must be used when signing trades. The contract owner can update this value to invalidate all previous trade signatures created with an old index.
Signer Signature Index
Similar to the contract signature index but specific to each signer. The signer can update this value to invalidate all previously signed trades with an outdated index.
Allowed Executors
Defines a list of specific addresses authorized to execute the trade. If no list is provided, the trade is open to be executed by anyone.
External Checks
A set of additional verifications performed through external smart contracts. These checks add a custom layer of validation, such as confirming ownership, balance, or other on-chain conditions.
Assets Involved
Trades specify the assets that will be exchanged when the trade is executed. These assets can include ERC721 tokens, ERC20 tokens, and Collection Items.
Assets to be Received:
Lists the assets that the trade creator (signer) will receive from the counterparty.
Assets to be Sent:
Lists the assets that the trade creator will give in exchange.
The system supports multiple combinations of assets, providing flexibility for diverse asset swaps within a single trade.
Off-Chain Creation and Signing:
The Signer defines a Trade on the frontend and signs it using their wallet. This process creates a cryptographically secure agreement that cannot be tampered with after signing.
Storage and Presentation:
Once the Trade is signed, the Trade data and its corresponding signature are stored on a server for future use. The signed Trade is then made available to all users on the frontend or to a limited group of users, depending on the Trade's availability or specific restrictions.
On-Chain Execution via accept(Trade[] _trades)
:
When a user is interested in executing the Trade, they call the
accept(Trade[] _trades)
function on-chain, submitting the stored Trade data
and signature. This triggers the on-chain validation, where the smart contract checks the
Trade's conditions. Once all checks are satisfied, the Trade is executed, and the assets
are swapped on-chain.
Lower Gas Costs:
By moving the creation and signing of trades off-chain, users avoid paying transaction fees until the trade is actually executed. This significantly reduces gas costs, especially for trades that are negotiated but never finalized.
Flexibility:
Built to support multiple new features and advanced use cases that will add plenty of value to the Decentraland Marketplace.
A user wants to list an ERC721 token for sale in exchange for a specific amount of an ERC20 token.
Purpose: This feature allows users to list their assets for sale on the marketplace, where anyone can purchase them by meeting the trade requirements.
A user wants to acquire a specific ERC721 token and offers a certain amount of ERC20 tokens as payment.
Purpose: This allows buyers to make offers on assets they want to purchase, even if the assets are not actively listed for sale. The bid invites the asset owner to accept the buyer's offer.
A user wants to sell an ERC721 token for a certain amount of ERC20 tokens but restricts the sale to specific addresses.
Purpose: This feature is useful for restricted or exclusive sales, allowing sellers to target specific groups of users.
Auctions allow multiple bids for a specific asset or collection of assets.
Purpose: This provides a flexible way to run decentralized auctions while ensuring that bids that are outbid are invalidated once the auction is over.
Trade ID for Auctions
The Trade ID is a unique identifier used to link trades within the same operation and is crucial to the auction process. It consists of:
As long as these values remain the same, the Trade ID will be identical across trades. This allows all bids in an auction, though independently signed, to be associated through the same Trade ID.
When the seller accepts the winning bid, the Trade ID is marked as "used" in the contract, automatically invalidating all other auction bids.
This mechanism saves auction participants from having to manually cancel their bids for an expired auction, reducing gas fees and preventing unintended trade execution.
Creating Auctions
Since all bids are linked by the same salt and the same asset(s), once the seller accepts and executes a bid, the Trade ID is marked as consumed. This ensures that no other bids can be executed in the future, providing security for bidders by guaranteeing that their signed trades cannot be misused after the auction ends.
A public order allows a user to sell multiple items in one transaction. The seller can bundle several supported assets, specifying a single amount of ERC20 tokens to receive in exchange.
Purpose: This feature is ideal for batch sales or promotions.
A bidder offers to acquire several assets in exchange for a specific amount of ERC20 tokens.
Purpose: This feature allows users to bid on multiple items at once, simplifying bulk transactions in cases where a buyer wants to acquire a set of assets for a single price.
Asset swaps enable users to trade one type of asset for another, even if they are not ERC721 and ERC20 tokens.
Purpose: This feature facilitates flexible trades between different asset types supported by the marketplace, beyond just ERC721 and ERC20 combinations.
Hot Sales offer time-limited discounts on assets.
Purpose: This feature allows sellers to run promotions or flash sales, adjusting prices dynamically for a limited period.
Discounts can be applied to individual trades or using broader mechanisms like Coupons.
Purpose: Discounts make it possible to adjust pricing strategies, either for individual items or entire collections, enhancing marketing flexibility and sales incentives.
Revenue sharing allows sellers to distribute the proceeds from a trade between multiple addresses.
Purpose: This feature facilitates distributing trade proceeds to multiple beneficiaries, supporting use cases like charity donations or revenue sharing among partners.
The shopping cart feature enables users to bundle multiple trades into a single transaction.
Purpose: This feature streamlines the purchasing process for users, making it easier to handle multiple transactions efficiently.
External checks validate trade eligibility by querying external smart contracts.
Purpose: External checks enhance trade security and eligibility by integrating additional criteria based on external contract data.
USD pegged MANA trades allow users to price assets in USD, with the payment being made in MANA.
Purpose: This feature enables asset pricing in USD, simplifying pricing for users and ensuring that the payment amount in MANA adjusts with the current exchange rate.
In summary, the off-chain marketplace contracts for Decentraland provide a powerful, flexible framework for facilitating asset exchanges in a decentralized, trustless environment. By combining off-chain signing with on-chain execution, the system significantly reduces gas costs, supports complex trade conditions, and enhances the overall user experience for trading in Decentraland.