Poking around in the world of NFTs you will primarily come into contact with NFTs on Ethereum Virtual Machine (EVM) based blockchains. Now that Opensea Solana has integrated NFTs on its trading platform or well-known marketplaces such as NBATopshot have been implemented on Flow, it is worth to take a closer look at both of them. Not at least in order to avoid expensive mistakes, caused by bad decisions for a certain technology.
To get a practical understanding of both Blockchains, we have deployed the identical implementation of a rudimentary NFT marketplace including the implementation of the associated NFT smart contracts on each of them. The experiences and lessons learned are shared with you in this blog series.
In this part, you will learn how Flow supports the low-threshold entry into blockchain development.
Table of Contents:
- Introduction to Flow
- Flow Concepts
- Summary Findings
1. Introduction to Flow
Flow is a Proof-of-Stake blockchain designed to be the foundation of decentralized, blockchain based games, apps, and digital assets. It was developed by Dapper Labs as an alternative to Ethereum due to the network congestion caused by their NFT platform CryptoKitties. To improve network performance, Flow separates the jobs of a validator node into the four roles Collection, Consensus, Execution and Verification.
Each role comes with trade-offs with either Security, Decentralization or Scalability. Focusing on scalability for Execution Nodes while focusing on decentralization and security for Verification and Consensus Nodes supposedly circumvents the scalability trilemma in Flow.
Cadence is Flows own high-level resource-oriented programming language allowing for a new form of ownership defined by three rules: Each resource exists in exactly one place at any given time. Ownership of a resource is defined by where it is stored and the access to methods on a resource is limited to the owner.
Interactions with a Smart Contract are separated into State Queries (Scripts) and Transactions. A script cannot perform any writes to the blockchain and can only read the current state of the blockchain without requiring permission from any account.
Transactions are code submitted to the blockchain that mutates the state of user accounts and smart contracts signed by one or more accounts. Transactions are split into the phases prepare, pre, execute and post to improve readability and safety.
The user wallet controls access to a user's account, representing the record on the blockchain that stores the digital assets owned by a single user. The application client (Flow Marketplace) connects to the user's wallet in order to send transactions to the blockchain. The wallet has final control over any transactions that interact with the user's account.
2. Flow Concepts
Objects are stored under paths in an account's storage. Paths consist of a domain and an identifier: /domain/identifier. The three valid domains are storage, private, and public. The path associated with a smart contract uses the identifier defined within the contract to store objects on the account. The objects are stored in the storage in their capabilities in the public and private domain.
The account storage is limited by its storage capacity, which is calculated from the amount of FLOW stored in the account's main FLOW token vault. If a transaction requires more storage than the storage capacity, the transaction fails.
Capability-based access control
Capabilities are used to allow access to certain fields and functions of a stored object to specific users or even anyone else. An account requires a valid capability to access another account's stored objects. Capabilities created using a public path (public domain) are public and can be accessed by any account. Capabilities created using a private path (private domain) can only be obtained from authorized accounts.
Once a capability is created and obtained, it can be borrowed to get a reference to the stored object.
Transactions in Flow are signed by different roles, which can involve one or more accounts.
The proposer and authorizer have to sign the transaction payload. The proposer is the account that specifies a proposal key, which includes the accounts sequence number to prevent transaction replay attacks. The authorizer are zero or more accounts authorizing the transaction to mutate their state. The payload and the payload signature form the authorization envelope that needs to be signed by the payer. The payer is the account paying for the transaction fees.
A transaction can declare all signer roles to be only one account. An example for this would be minting an NFT on our Marketplace, which is currently only signed by the admin account who has deployed the contracts. Destroying or sending an NFT, instead requires the owner as the authorizer and currently uses the custodial wallet provider as the payer and proposer on the testnet.
Flow supports Wallets to be managed in two ways: custodial or non-custodial mode.
Non-custodial wallets require the owner to know and store their wallet information themselves, whereas custodial wallets depend on external wallet providers such as Blocto or Ledger. Blocto, for example, manages your keys for you and merely requires a registration via email. The following summarizes the key differences between both modes:
- Requires knowledge of wallet details such as the private key and the address
- In order to sign transactions, an authorization function following Flow's requirements needs to be defined explicitly
- Non-custodial wallets grant the user more options regarding contract deployment compared to when taking advantage of wallet providers
- Detailed wallet information enables account management via Flow CLI
- No need to know/store your wallet's information
- No need to define and provide an authorization function explicitly in order to sign transactions
- Requires registration with wallet provider; details dependent on provider
- Account management only possible via transactions (e.g. deployment of contracts)
As alluded to in previous sections, contracts can be deployed in two ways:
Either via transactions, where access to the signer's account object allows mutation of its contracts or via the Flow CLI. The latter requires a configuration in a flow.json file, which in turn requires full knowledge over the wallets.
Networks and Contract-Updatability
Due to the fact that deployed contracts are saved in the storage of a user it's not possible to deploy the same contract multiple times with the same account. Therefore it's necessary to delete an old contract before redeploying it. This may seem easier than it actually is on Flow. Currently it is required to contact the Flow support team in order to deploy and delete contracts on the mainnet. As such it is recommended to thoroughly test a contract on the testnet before deciding to deploy it on the mainnet. Whereas on the testnet it is a bit easier. Deployment can be directly executed without the need of contacting someone. Deletion may still cause problems depending on the way the account is handled. If it is a custodial account like Blocto it may not be possible to delete an existing account because the deletion request might be regarded as malicious and therefore gets rejected. The only solution would be to create a new account. A non-custodial account does not face this problem as every request gets directly signed with this account without interference of another party. As such updating a contract on the testnet may only be possible with a non-custodial account.
In addition to the restrictions stated above there is one additional requirement for updating an existing contract. The new version of the contract must support the existing saved data and should therefore not differ too much from the previous version.
The prototype supports a dashboard, which shows all NFTs that have been minted and their respective owners.
After authentication with a wallet provider, the dashboard only shows the user's private page This page lists all NFTs in the user's collection, and they can be opened in a detailed view, which allows the user to transfer and delete the NFT.
The minting of new NFTs with the admin's immediate authorization is supported as well.
The Flow command-line interpreter features several management options regarding Flow accounts, contracts, networks and deployments. It is configured via a flow.json file, which specifies network addresses, account names and keys (for non-custodial accounts), contract locations and deployment configurations.
FCL JS' main use cases are the configuration of blockchain & wallet provider end points, the dispatching of transactions and queries and the management of (custodial) user authentication and authorizations.
4. Summary Findings
We have compiled the most important findings and experiences from our example implementation in the following two tables. We have contrasted these with the more developed and widespread Ethereum world. It should be noted that these are experiences from the first half of 2022.
|Developer Documentation||Extensive documentation and few community created tutorials||Extensive documentation and community created tutorials|
|Development Community||Smaller Community||Many third party tutorials and forums|
|Development Tools||Limited but under development: Flow Playground, Cadence IDE extensions||Larger choice of tools: IDEs, frameworks, languages,|
|Contract Security Analysis||No tools found||
Various security analysis tools: Mythril, MythX, Echidna ...
Contract auditing firms available
|Smart Contract Language||Cadence||Solidity, Vyper, Yul|
|Smart Contract Type||Stateful, Resource-oriented||Stateful|
|Converting Contracts from Solidity||Requires some changess but also enables different designs||-|
|Subjective Assessment||Lower barriers of entry||De facto standard for smart contract development|