diff --git a/package.json b/package.json index b88ed4b6a3..8f089668be 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "scripts": { "docusaurus": "docusaurus", "start": "docusaurus start", - "build": "./scripts/import.sh && docusaurus build", + "build": "./scripts/import.sh && docusaurus build && node scripts/generate-llm-files.js", "swizzle": "docusaurus swizzle", "deploy": "docusaurus deploy", "clear": "docusaurus clear", @@ -60,7 +60,8 @@ "tailwindcss": "^3.3.5", "unist-util-visit": "^5.0.0", "webpack-merge": "5.8.0", - "zod": "^3.24.1" + "zod": "^3.24.1", + "glob": "^10.3.10" }, "devDependencies": { "@docusaurus/module-type-aliases": "^3.6.3", diff --git a/scripts/generate-llm-files.js b/scripts/generate-llm-files.js new file mode 100644 index 0000000000..eb5a120249 --- /dev/null +++ b/scripts/generate-llm-files.js @@ -0,0 +1,86 @@ +/* eslint-disable */ +const fs = require('fs'); +const path = require('path'); +const glob = require('glob'); + +// Ensure the static directory exists +const staticDir = path.join(__dirname, '..', 'static'); +if (!fs.existsSync(staticDir)) { + fs.mkdirSync(staticDir, { recursive: true }); +} + +// Create a directory for markdown files +const markdownDir = path.join(staticDir, 'markdown'); +if (!fs.existsSync(markdownDir)) { + fs.mkdirSync(markdownDir, { recursive: true }); +} + +// Find all markdown files +const files = glob.sync('./docs/**/*.md?(x)'); +const llms = []; +const fullContent = []; + +files.forEach((file) => { + const content = fs.readFileSync(file, 'utf-8'); + const relativePath = path.relative('./docs', file); + const fileDir = path.dirname(file); + + // Add to llms.txt (just the paths) + llms.push(relativePath); + + // Add to llms-full.txt (full content with separators) + fullContent.push(`\n=== ${relativePath} ===\n${content}`); + + // Create a markdown file for each page + const markdownFileName = relativePath.replace(/\.mdx?$/, '.md'); + const markdownFilePath = path.join(markdownDir, markdownFileName); + + // Ensure the directory exists + const markdownFileDir = path.dirname(markdownFilePath); + if (!fs.existsSync(markdownFileDir)) { + fs.mkdirSync(markdownFileDir, { recursive: true }); + } + + // Extract import statements to create a map of image variables to file paths + const importMap = {}; + const importRegex = /import\s+(\w+)\s+from\s+['"](.+?)['"];?/g; + let importMatch; + while ((importMatch = importRegex.exec(content)) !== null) { + const [_, varName, filePath] = importMatch; + // Handle relative paths + const fullPath = + filePath.startsWith('./') || filePath.startsWith('../') + ? path.relative(fileDir, path.resolve(fileDir, filePath)) + : filePath; + importMap[varName] = fullPath; + } + + // Process the content to handle common React/MDX components + let processedContent = content + // Convert import statements to comments + .replace( + /import\s+(.*?)\s+from\s+['"](.+?)['"];?/g, + '', + ) + // Handle image components with src + .replace( + //g, + '![$2]($1)', + ) + // Replace image variables with their file paths + .replace(/!\[(.*?)\]\((\w+)\)/g, (match, alt, varName) => { + return importMap[varName] ? `![${alt}](${importMap[varName]})` : match; + }) + // Clean up multiple newlines + .replace(/\n{3,}/g, '\n\n') + .trim(); + + // Write the processed markdown file - directly as Markdown, not wrapped in HTML + fs.writeFileSync(markdownFilePath, processedContent); +}); + +// Write the files +fs.writeFileSync(path.join(staticDir, 'llms.txt'), llms.join('\n')); +fs.writeFileSync(path.join(staticDir, 'llms-full.txt'), fullContent.join('\n')); + +console.log('✅ Generated llms.txt, llms-full.txt, and markdown files'); diff --git a/src/components/PageActionsDropdown.module.css b/src/components/PageActionsDropdown.module.css new file mode 100644 index 0000000000..b91aba8d44 --- /dev/null +++ b/src/components/PageActionsDropdown.module.css @@ -0,0 +1,91 @@ +.menuContainer { + position: relative; + display: inline-block; +} + +.menuButton { + display: inline-flex; + align-items: center; + gap: 0.5rem; + padding: 0.5rem 1rem; + font-size: 0.875rem; + font-weight: 500; + color: var(--ifm-color-primary); + background-color: transparent; + border: 1px solid var(--ifm-color-primary); + border-radius: 0.375rem; + cursor: pointer; + transition: all 0.2s ease; +} + +.menuButton:hover { + background-color: var(--ifm-color-primary); + color: white; +} + +.chevronIcon { + width: 0.75rem; + height: 0.75rem; + transition: transform 0.2s ease; +} + +.menuButton[aria-expanded='true'] .chevronIcon { + transform: rotate(180deg); +} + +.menuItems { + position: absolute; + right: 0; + z-index: 50; + margin-top: 0.5rem; + width: 16rem; + background-color: var(--ifm-background-color); + border-radius: 0.5rem; + box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), + 0 2px 4px -1px rgba(0, 0, 0, 0.06); + border: 1px solid var(--ifm-color-emphasis-200); +} + +.menuItemsContainer { + padding: 0.5rem; +} + +.menuItem { + display: flex; + align-items: flex-start; + gap: 0.75rem; + width: 100%; + padding: 0.75rem; + text-align: left; + border-radius: 0.375rem; + color: var(--ifm-color-emphasis-800); + background-color: transparent; + border: none; + cursor: pointer; + text-decoration: none; + transition: all 0.2s ease; +} + +.menuItem:hover, +.menuItemActive { + background-color: var(--ifm-color-emphasis-100); +} + +.menuIcon { + width: 1.25rem; + height: 1.25rem; + margin-top: 0.125rem; + color: var(--ifm-color-emphasis-600); +} + +.menuItemTitle { + font-size: 0.875rem; + font-weight: 500; + color: var(--ifm-color-emphasis-900); +} + +.menuItemDescription { + font-size: 0.75rem; + color: var(--ifm-color-emphasis-600); + margin-top: 0.125rem; +} diff --git a/src/components/PageActionsDropdown.tsx b/src/components/PageActionsDropdown.tsx new file mode 100644 index 0000000000..6c004ef1a8 --- /dev/null +++ b/src/components/PageActionsDropdown.tsx @@ -0,0 +1,200 @@ +import React, { useState } from 'react'; +import { createPortal } from 'react-dom'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { + faCopy, + faCode, + faRobot, + faBrain, + faChevronDown, +} from '@fortawesome/free-solid-svg-icons'; +import styles from './PageActionsDropdown.module.css'; +import BrowserOnly from '@docusaurus/BrowserOnly'; + +function PageActionsDropdownContent(): JSX.Element { + const [isOpen, setIsOpen] = useState(false); + + // Get the current path and create the markdown URL + const currentPath = window.location.pathname; + // Remove any trailing slash to match our directory structure + const cleanPath = currentPath.endsWith('/') + ? currentPath.slice(0, -1) + : currentPath; + // If we're at the root docs page (/docs), use /index.md + const mdPath = + cleanPath === '/docs' ? '/index' : cleanPath.replace('/docs', ''); + const markdownUrl = `/markdown${mdPath}.md`; + + // Create the ChatGPT and Claude URLs with the markdown URL + const fullUrl = `${window.location.origin}${markdownUrl}`; + const chatGptUrl = `https://chat.openai.com/?hints=search&q=Read%20from%20${encodeURIComponent( + fullUrl, + )}%20so%20I%20can%20ask%20questions%20about%20it.`; + const claudeUrl = `https://claude.ai/new?q=Read%20from%20${encodeURIComponent( + fullUrl, + )}%20so%20I%20can%20ask%20questions%20about%20it.`; + + const handleCopyMarkdown = async (): Promise => { + try { + // Fetch the actual Markdown file + const response = await fetch(markdownUrl); + if (!response.ok) { + throw new Error(`Failed to fetch Markdown: ${response.status}`); + } + + const markdown = await response.text(); + await navigator.clipboard.writeText(markdown); + + setIsOpen(false); // Close the dropdown after copying + } catch (err) { + console.error('Failed to copy markdown:', err); + + // Fallback to copying the article text if fetch fails + try { + const pageContent = document.querySelector('article')?.innerText ?? ''; + await navigator.clipboard.writeText(pageContent); + setIsOpen(false); + } catch (fallbackErr) { + console.error('Fallback copy failed:', fallbackErr); + } + } + }; + + // Reference to track button position for the portal + const [buttonPosition, setButtonPosition] = React.useState({ + top: 0, + right: 0, + }); + const buttonRef = React.useRef(null); + + // Update position when the button is clicked + const updatePosition = () => { + if (buttonRef.current) { + const rect = buttonRef.current.getBoundingClientRect(); + setButtonPosition({ + top: rect.bottom + window.scrollY, + right: window.innerWidth - rect.right, + }); + } + }; + + // Toggle the dropdown + const toggleDropdown = () => { + updatePosition(); + setIsOpen(!isOpen); + }; + + // Handle clicks outside to close the dropdown + React.useEffect(() => { + const handleClickOutside = (event: MouseEvent) => { + if ( + buttonRef.current && + !buttonRef.current.contains(event.target as Node) && + !(event.target as Element).closest(`.${styles.menuItems}`) + ) { + setIsOpen(false); + } + }; + + document.addEventListener('mousedown', handleClickOutside); + return () => { + document.removeEventListener('mousedown', handleClickOutside); + }; + }, []); + + return ( +
+
+ +
+ + {isOpen && + createPortal( +
+ +
, + document.body, + )} +
+ ); +} + +export default function PageActionsDropdown() { + return {() => }; +} diff --git a/src/theme/DocItem/LLMButtons/index.js b/src/theme/DocItem/LLMButtons/index.js new file mode 100644 index 0000000000..3315b3cd2c --- /dev/null +++ b/src/theme/DocItem/LLMButtons/index.js @@ -0,0 +1,50 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import styles from './styles.module.css'; + +export default function LLMButtons({ content }) { + const handleCopyMarkdown = async () => { + try { + // Get the current page content + const pageContent = document.querySelector('article')?.innerText || ''; + await navigator.clipboard.writeText(pageContent); + // You might want to add a toast notification here + console.log('Markdown copied to clipboard'); + } catch (err) { + console.error('Failed to copy markdown:', err); + } + }; + + const encodedContent = encodeURIComponent(window.location.href); + + return ( +
+ + + +
+ ); +} + +LLMButtons.propTypes = { + content: PropTypes.any, +}; diff --git a/src/theme/DocItem/LLMButtons/styles.module.css b/src/theme/DocItem/LLMButtons/styles.module.css new file mode 100644 index 0000000000..d3db5ce290 --- /dev/null +++ b/src/theme/DocItem/LLMButtons/styles.module.css @@ -0,0 +1,30 @@ +.llmButtons { + display: flex; + gap: 8px; + margin: 1rem 0; + flex-wrap: wrap; +} + +.llmButton { + display: inline-flex; + align-items: center; + justify-content: center; + padding: 8px 16px; + border-radius: 6px; + font-size: 14px; + font-weight: 500; + cursor: pointer; + transition: all 0.2s ease; + background-color: var(--ifm-color-primary); + color: white; + border: none; +} + +.llmButton:hover { + background-color: var(--ifm-color-primary-darker); + transform: translateY(-1px); +} + +.llmButton:active { + transform: translateY(0); +} diff --git a/src/theme/DocItem/index.js b/src/theme/DocItem/index.js new file mode 100644 index 0000000000..b34c1942cd --- /dev/null +++ b/src/theme/DocItem/index.js @@ -0,0 +1,6 @@ +import React from 'react'; +import DocItem from '@theme-original/DocItem'; + +export default function DocItemWrapper(props) { + return ; +} diff --git a/src/theme/TOC/index.tsx b/src/theme/TOC/index.tsx index 5c68756552..ec5632e112 100644 --- a/src/theme/TOC/index.tsx +++ b/src/theme/TOC/index.tsx @@ -5,6 +5,7 @@ import type { Props } from '@theme/TOC'; import styles from './styles.module.css'; import FeedbackFaces from '@site/src/components/feedbackFaces'; +import PageActionsDropdown from '@site/src/components/PageActionsDropdown'; // Using a custom className // This prevents TOCInline/TOCCollapsible getting highlighted by mistake @@ -15,7 +16,10 @@ export default function TOC({ className, ...props }: Props): JSX.Element { return (
-
Rate this page
+
+
Rate this page
+ +
( + from: coaPath) ?? panic("Could not borrow reference to the COA!") + } + + execute { + self.coa.deploy(code: code.decodeHex(), gasLimit: 15000000, value: EVM.Balance(attoflow: 0)) + } +} +``` + +## Step 2: Set Up Your Environment and Deploy the Contract + +To run the transactions and tests, we'll use [Overflow][overflow]. Follow these steps to set up and deploy: + +1. Initialize a Go Project: + - Open your terminal and navigate to your project's root directory. + - Run: `go mod init flow/tutorials` to create a Go module. +2. Install Overflow: + - Run: `go get github.com/bjartek/overflow/v2` to install the Overflow package. +3. Create the Task File: + - In the root directory, create a folder called `tasks`. + - Inside `tasks`, create a file named `main.go`. + - Paste the following Go code into `main.go`: + +```go +package main + +import ( + "fmt" + "io/ioutil" + "log" + . "github.com/bjartek/overflow/v2" + "github.com/fatih/color" +) + +func readJSFile(filePath string) (string, error) { + content, err := ioutil.ReadFile(filePath) + if err != nil { + return "", err + } + return string(content), nil +} + +func main() { + filePath := "bytecode/GameItem.js" + jsContent, err := readJSFile(filePath) + if err != nil { + log.Fatalf("Error reading JavaScript file: %v", err) + } + o := Overflow( + WithGlobalPrintOptions(), + WithNetwork("testnet"), + ) + + color.Red("Should be able to create a COA") + o.Tx("create_COA", + WithSigner("gamer"), + ).Print() + + color.Cyan("Deploy a Solidity contract to Random's COA") + o.Tx("deploy_sol_contract", + WithSigner("gamer"), + WithArg("code", jsContent), + WithArg("pathId", 0), + ).Print() +} +``` + +4. Run the Deployment: + - From the terminal, navigate to the root directory. + - Run: `go run ./tasks/main.go`. + - This will: + - Create a Cadence Owned Account (COA) for the "gamer" account. + - Deploy the Solidity contract using the bytecode from `GameItem.js`. +5. Verify the Deployment: + - Check the terminal output for the deployed contract address (e.g., `0xb93cB988D0722E17B67A5E169a47FB6F3A4dea1b`). + - Visit the [Flow EVM Testnet Scanner][testnet-scanner] and search for the address to confirm the deployment. + +![Remix Screenshot](imgs/remix3.png) + +Note: The "gamer" account (e.g., `0xb995271139c0126f`) is a Testnet account. The `pathId` (set to `0`) corresponds to the COA slot. If you've created multiple COAs, increment `pathId` (e.g., `1`, `2`) accordingly. + +## Step 3: Call a Function on the Deployed Contract + +Now, let's call the `awardItem` function from the deployed ERC721 contract using this Cadence script: + +1. Cadence Script Preparation: + Use the following Cadence script to call the contract function: + +```cadence +import "EVM" + +access(all) +fun main(hexEncodedAddress: String, address: Address, pathId: UInt64): [AnyStruct] { + let account = getAuthAccount(address) + let coaPath = StoragePath(identifier: address.toString().concat("EVM_").concat(pathId.toString()))! + let coa = account.storage.borrow( + from: coaPath + ) ?? panic("Could not borrow reference to the COA!") + let addressBytes = hexEncodedAddress.decodeHex().toConstantSized<[UInt8; 20]>()! + + let callResult = coa.call( + to: EVM.EVMAddress(bytes: addressBytes), + data: EVM.encodeABIWithSignature( + "awardItem(address,string)", + [EVM.addressFromString("000000000000000000000002A16A68E971e4670B"), "{name: gamerz}"] + ), + gasLimit: 15000000, + value: EVM.Balance(attoflow: 0) + ) + + return EVM.decodeABI(types: [Type()], data: callResult.data) +} +``` + +2. Update the Go File: + Open `tasks/main.go` and add the following code at the end of the `main` function (replace the `hexEncodedAddress` with your deployed contract address): + +```go +color.Cyan("Mint a game item from the Solidity contract") +o.Script("call_sol_function", + WithArg("hexEncodedAddress", "b93cB988D0722E17B67A5E169a47FB6F3A4dea1b"), + WithArg("address", "gamer"), + WithArg("pathId", 0), +).Print() +``` + +3. Run the Script: + + - In the terminal, run: `go run ./tasks/main.go` again. + - This executes the Cadence script, calling `awardItem` to mint an NFT. + +4. Check the Result: + - The terminal will display the token ID of the newly minted NFT (e.g., a UInt256 value). + - See the screenshot below for an example output: + +![Result Screenshot](imgs/remix4.png) + +The terminal output shows the unique token ID that was generated when minting the game item through the Solidity contract using Cadence. + + +The `awardItem` function is called with a test address and a string parameter. In a real-world scenario, you would replace these with actual wallet addresses and more meaningful metadata. + + +## Conclusion + +Deploying a Solidity contract within a Cadence environment on the Flow blockchain is not only feasible but also presents an exciting opportunity for you to harness the strengths of both programming languages. Throughout this guide, you've navigated the critical steps involved in the deployment process, from compiling your Solidity contract using Remix to executing transactions with Overflow and Cadence scripts. By completing this guide, you've achieved the following: + +- Deployed a Solidity contract on Flow EVM using Cadence: You compiled and deployed your Solidity contract to Flow's EVM layer via a Cadence transaction. +- Called functions from Cadence: You used a Cadence script to mint an NFT by invoking the `awardItem` function on your deployed contract. + +As blockchain technology continues to evolve, adopting these best practices is crucial for fostering a secure and trustworthy ecosystem. This empowers you to innovate while staying true to the core principles of decentralization and fairness. + +[node-npm-install]: https://docs.npmjs.com/downloading-and-installing-node-js-and-npm +[flow-cli-install]: https://developers.flow.com/tools/flow-cli/install +[remix]: https://remix.ethereum.org/ +[coa-guide]: https://developers.flow.com/evm/cadence/interacting-with-coa + +[overflow]: https://github.com/bjartek/overflow] +[testnet-scanner]: https://evm-testnet.flowscan.io/ + + +=== tutorials/native-vrf/commit-reveal-cadence.md === +--- +sidebar_position: 1 +title: Secure Randomness with Commit-Reveal in Cadence +description: Guide on implementing secure randomness in Cadence using Flow's commit-reveal scheme +keywords: + - blockchain + - randomness + - Cadence + - Flow blockchain + - commit-reveal + - secure randomness + - Random Beacon + - smart contracts + - Coin Toss + - decentralization + - fairness + - cryptography +--- + +# Secure Randomness with Commit-Reveal in Cadence + +Randomness is a critical component in blockchain applications, enabling fair and unpredictable outcomes for use cases like gaming, lotteries, and cryptographic protocols. The most basic approach to generating a random number on EVM chains is to utilize block hashes, which combines the block hash with a user-provided seed and hashes them together. The resulting hash can be used as a pseudo-random number. However, this approach has limitations: + +1. Predictability: Miners can potentially manipulate the block hash to influence the generated random number. +2. Replay attacks: In case of block reorganizations, the revealed answers will not be re-used again. + +[Chainlink VRF][chainlink-vrf] is a popular tool that improves on this by providing another approach for generating provably random values on Ethereum and other blockchains by relying on a decentralized oracle network to deliver cryptographically secure randomness from off-chain sources. However, this dependence on external oracles introduces several weaknesses, such as cost, latency, and scalability concerns. + +In contrast, Flow offers a simpler and more integrated approach with its Random Beacon contract, which provides native on-chain randomness at the protocol level, eliminating reliance on external oracles and sidestepping their associated risks. Via a commit-and-reveal scheme, Flow's protocol-native secure randomness can be used within both Cadence and Solidity smart contracts. + +## Objectives + +By the end of this guide, you will be able to: + +- Deploy a Cadence smart contract on the Flow blockchain +- Implement commit-reveal randomness to ensure fairness +- Interact with Flow's on-chain randomness features +- Build and test the Coin Toss game using Flow's Testnet + +## Prerequisites + +You'll need the following: + +- Flow Testnet Account: An account on the Flow Testnet with test FLOW tokens for deploying contracts and executing transactions (e.g., via [Flow Faucet][flow-faucet]). +- Flow CLI or Playground: The Flow CLI or Flow Playground for deploying and testing contracts (install via [Flow Docs][flow-docs]). + +## Overview + +In this guide, we will explore how to use a commit-reveal scheme in conjunction with Flow's Random Beacon to achieve secure, non-revertible randomness. This mechanism mitigates post-selection attacks, where participants attempt to manipulate or reject unfavorable random outcomes after they are revealed. + +To illustrate this concept, we will build a Coin Toss game on Flow, demonstrating how smart contracts can leverage commit-reveal randomness for fair, tamper-resistant results. + +### What is the Coin Toss Game? + +The Coin Toss Game is a decentralized betting game that showcases Flow's commit-reveal randomness. Players place bets without knowing the random outcome, ensuring fairness and resistance to manipulation. + +The game consists of two distinct phases: + +1. Commit Phase – The player places a bet by sending Flow tokens to the contract. The contract records the commitment and requests a random value from Flow's Random Beacon. The player receives a Receipt, which they will use to reveal the result later. +2. Reveal Phase – Once the random value becomes available in `RandomBeaconHistory`, the player submits their Receipt to determine the outcome: + - If the result is 0, the player wins and receives double their bet. + - If the result is 1, the player loses, and their bet remains in the contract. + +### Why Use Commit-Reveal Randomness? + +- Prevents manipulation – Players cannot selectively reveal results after seeing the randomness. +- Ensures fairness – Flow's Random Beacon provides cryptographically secure, verifiable randomness. +- Reduces reliance on external oracles – The randomness is generated natively on-chain, avoiding additional complexity, third party risk and cost. + +## Building the Coin Toss Contract + +In this section, we'll walk through constructing the `CoinToss.cdc` contract, which contains the core logic for the Coin Toss game. To function properly, the contract relies on supporting contracts and a proper deployment setup. + +This tutorial will focus specifically on writing and understanding the `CoinToss.cdc` contract, while additional setup details can be found in the [original GitHub repo][github-repo]. + +### Step 1: Defining the `CoinToss.cdc` Contract + +Let's define our `CoinToss.cdc` and bring the other supporting contracts. + +```cadence +import "Burner" +import "FungibleToken" +import "FlowToken" + +import "RandomConsumer" + +access(all) contract CoinToss { + /// The multiplier used to calculate the winnings of a successful coin toss + access(all) let multiplier: UFix64 + /// The Vault used by the contract to store funds. + access(self) let reserve: @FlowToken.Vault + /// The RandomConsumer.Consumer resource used to request & fulfill randomness + access(self) let consumer: @RandomConsumer.Consumer + + /* --- Events --- */ + access(all) event CoinFlipped(betAmount: UFix64, commitBlock: UInt64, receiptID: UInt64) + access(all) event CoinRevealed(betAmount: UFix64, winningAmount: UFix64, commitBlock: UInt64, receiptID: UInt64) +} +``` + +### Step 2: Implementing the Commit Phase With `flipCoin` + +Let's define the first step in our scheme; the commit phase. We do this through a `flipCoin` public function. In this method, the caller commits a bet. The contract takes note of the block height and bet amount, returning a `Receipt` resource which is used by the former to reveal the coin toss result and determine their winnings. + +```cadence +access(all) fun flipCoin(bet: @{FungibleToken.Vault}): @Receipt { + let request <- self.consumer.requestRandomness() + let receipt <- create Receipt( + betAmount: bet.balance, + request: <-request + ) + self.reserve.deposit(from: <-bet) + + emit CoinFlipped(betAmount: receipt.betAmount, commitBlock: receipt.getRequestBlock()!, receiptID: receipt.uuid) + + return <- receipt + } +``` + +### Step 3: Implementing the Reveal Phase With `revealCoin` + +Now we implement the reveal phase with the `revealCoin` function. Here the caller provides the Receipt given to them at commitment. The contract then "flips a coin" with `_randomCoin()` providing the Receipt's contained Request. If result is 1, user loses, but if it's 0 the user doubles their bet. Note that the caller could condition the revealing transaction, but they've already provided their bet amount so there's no loss for the contract if they do. + +```cadence +access(all) fun revealCoin(receipt: @Receipt): @{FungibleToken.Vault} { + let betAmount = receipt.betAmount + let commitBlock = receipt.getRequestBlock()! + let receiptID = receipt.uuid + + let coin = self._randomCoin(request: <-receipt.popRequest()) + + Burner.burn(<-receipt) + + // Deposit the reward into a reward vault if the coin toss was won + let reward <- FlowToken.createEmptyVault(vaultType: Type<@FlowToken.Vault>()) + if coin == 0 { + let winningsAmount = betAmount * self.multiplier + let winnings <- self.reserve.withdraw(amount: winningsAmount) + reward.deposit( + from: <-winnings + ) + } + + emit CoinRevealed(betAmount: betAmount, winningAmount: reward.balance, commitBlock: commitBlock, receiptID: receiptID) + + return <- reward + } +``` + +The final version of `CoinToss.cdc` should look like [this contract code][coin-toss-contract-code]. + +## Testing CoinToss on Flow Testnet + +To make things easy, we've already deployed the `CoinToss.cdx` contract for you at this address: [0xb6c99d7ff216a684][coin-toss-contract]. We'll walk through placing a bet and revealing the result using [run.dnz][run-dnz], a Flow-friendly tool similar to Ethereum's Remix. + +### Placing a Bet with flipCoin + +First, you'll submit a bet to the CoinToss contract by withdrawing Flow tokens and storing a receipt. Here's how to get started: + +1. Open Your Dev Environment: Head to [run.dnz][run-dnz]. +2. Enter the Transaction Code: Paste the following Cadence code into the editor: + +```cadence +import FungibleToken from 0x9a0766d93b6608b7 +import FlowToken from 0x7e60df042a9c0868 +import CoinToss from 0xb6c99d7ff216a684 + +/// Commits the defined amount of Flow as a bet to the CoinToss contract, saving the returned Receipt to storage +/// +transaction(betAmount: UFix64) { + + prepare(signer: auth(BorrowValue, SaveValue) &Account) { + // Withdraw my bet amount from my FlowToken vault + let flowVault = signer.storage.borrow(from: /storage/flowTokenVault)! + let bet <- flowVault.withdraw(amount: betAmount) + + // Commit my bet and get a receipt + let receipt <- CoinToss.flipCoin(bet: <-bet) + + // Check that I don't already have a receipt stored + if signer.storage.type(at: CoinToss.ReceiptStoragePath) != nil { + panic("Storage collision at path=".concat(CoinToss.ReceiptStoragePath.toString()).concat(" a Receipt is already stored!")) + } + + // Save that receipt to my storage + // Note: production systems would consider handling path collisions + signer.storage.save(<-receipt, to: CoinToss.ReceiptStoragePath) + } +} +``` + +3. Set Your Bet: A modal will pop up asking for the betAmount. Enter a value (e.g., 1.0 for 1 Flow token) and submit +4. Execute the Transaction: Click "Run," and a WalletConnect window will appear. Choose Blocto, sign in with your email, and hit "Approve" to send the transaction to Testnet. + +![remix5-sc](./imgs/remix5.png) + +5. Track it: You can take the transaction id to [FlowDiver][flow-diver][.io](https://testnet.flowdiver.io/tx/9c4f5436535d36a82d4ae35467b37fea8971fa0ab2409dd0d5f861f61e463d98) to have a full view of everything that's going on with this `FlipCoin` transaction. + +### Revealing the Coin Toss Result + +Let's reveal the outcome of your coin toss to see if you've won. This step uses the receipt from your bet, so ensure you're using the same account that placed the bet. Here's how to do it: + +1. Return to your Dev Environment: Open [run.dnz][run-dnz] again. +2. Enter the Reveal Code: Paste the following Cadence transaction into the editor: + +```cadence +import FlowToken from 0x7e60df042a9c0868 +import CoinToss from 0xb6c99d7ff216a684 + +/// Retrieves the saved Receipt and redeems it to reveal the coin toss result, depositing winnings with any luck +/// +transaction { + + prepare(signer: auth(BorrowValue, LoadValue) &Account) { + // Load my receipt from storage + let receipt <- signer.storage.load<@CoinToss.Receipt>(from: CoinToss.ReceiptStoragePath) + ?? panic("No Receipt found in storage at path=".concat(CoinToss.ReceiptStoragePath.toString())) + + // Reveal by redeeming my receipt - fingers crossed! + let winnings <- CoinToss.revealCoin(receipt: <-receipt) + + if winnings.balance > 0.0 { + // Deposit winnings into my FlowToken Vault + let flowVault = signer.storage.borrow<&FlowToken.Vault>(from: /storage/flowTokenVault)! + flowVault.deposit(from: <-winnings) + } else { + destroy winnings + } + } +} +``` + +After running this transaction, we reveal the result of the coin flip and it's 1! Meaning we have won nothing this time, but keep trying! + +You can find the full transaction used for this example, with its result and events, at [FlowDiver.io/tx/][flow-diver-tx]. + +## Conclusion + +The commit-reveal scheme, implemented within the context of Flow's Random Beacon, provides a robust solution for generating secure and non-revertible randomness in decentralized applications. By leveraging this mechanism, developers can ensure that their applications are: + +- Fair: Outcomes remain unbiased and unpredictable. +- Resistant to manipulation: Protects against post-selection attacks. +- Immune to replay attacks: A common pitfall in traditional random number generation on other blockchains. + +The CoinToss game serves as a practical example of these principles in action. By walking through its implementation, you've seen firsthand how straightforward yet effective this approach can be—balancing simplicity for developers with robust security for users. As blockchain technology advances, embracing such best practices is essential to creating a decentralized ecosystem that upholds fairness and integrity, empowering developers to innovate with confidence. + +This tutorial has equipped you with hands-on experience and key skills: + +- You deployed a Cadence smart contract on the Flow blockchain. +- You implemented commit-reveal randomness to ensure fairness. +- You interacted with Flow's on-chain randomness features. +- You built and tested the Coin Toss game using Flow's Testnet. + +By harnessing Flow's built-in capabilities, you can now focus on crafting engaging, user-centric experiences without grappling with the complexities or limitations of external systems. This knowledge empowers you to create secure, scalable, and fair decentralized applications. + +[chainlink-vrf]: https://docs.chain.link/vrf +[flow-faucet]: https://testnet-faucet.onflow.org/ +[flow-docs]: https://docs.onflow.org/flow-cli/install/ +[flow-diver]: https://testnet.flowdiver.io/ +[github-repo]: https://github.com/onflow/random-coin-toss +[run-dnz]: https://run.dnz.dev/ +[coin-toss-contract]: https://contractbrowser.com/A.b6c99d7ff216a684.CoinToss +[coin-toss-contract-code]: https://github.com/onflow/random-coin-toss/blob/main/contracts/CoinToss.cdc +[flow-diver-tx]: https://testnet.flowdiver.io/tx/a79fb2f947e7803eefe54e48398f6983db4e0d4d5e217d2ba94f8ebdec132957 + + +=== tutorials/flowtobooth/index.md === +--- +sidebar_position: 3 +title: FlowtoBooth +description: Learn how to build apps that showcase Flow's unique capabilities through fun benchmark applications. +keywords: + - tutorials + - guides + - learning + - flow + - evm + - smart contracts + - development + - blockchain + - benchmarks + - gas efficiency +--- + +# FlowtoBooth Tutorials + +The FlowtoBooth tutorial series teaches you how to build a fun benchmark application that showcase Flow's unique capabilities, particularly its efficient gas pricing that makes traditionally expensive operations practical and affordable. + +These tutorials are designed to inspire developers by demonstrating what's possible on Flow, though they may not always represent production best practices. + +## Image Gallery + +Learn how to store and retrieve images directly onchain: + +- [Build a Fully-Onchain Image Gallery](image-gallery.md) + +## Coming Soon + +More FlowtoBooth tutorials are in development, including: + +- Composing on the Image Gallery to mint NFTs from the gallery +- Using [Cross-VM] to allow users to mint several NFTS with one approval + +[Cross-VM]: ../cross-vm-apps/index.md + + +=== tutorials/flowtobooth/image-gallery.md === +--- +title: Build a Fully-Onchain Image Gallery +description: Learn how to store images up to approximately 32kb onchain, on Flow EVM, easily - free with the Flow wallet, or sub-cent with any other wallet. +sidebar_position: 1 +keywords: + [ + Flow, + EVM, + Flow EVM, + storage, + Solidity, + Next.js, + React, + onchain storage, + base64, + image gallery, + smart contract, + blockchain, + gas efficiency, + web3, + dapp, + tutorial, + onchain app, + ] +--- + +# Build a Fully-Onchain Image Gallery + +:::info + +The [FlowtoBooth] tutorial series teaches you how to build a **fun benchmark app** and provides inspiration for the greater scope of possibilities building on Flow thanks to gas being so much less expensive. + +It is **not a production best-practice**. While everything in these tutorials works, you'll run into the following problems at production scale: + +- RPC Providers will likely rate-limit you for reading this much data at once +- NFT marketplaces may not display the images, likely due to the above +- 256\*256 images are huge by blockchain data standards, but too small for modern devices + +::: + +If you search for resources on how to store images of any significant size onchain, you'll be told it's either prohibitively expensive or even completely impossible. The reason for this is two-fold - first the size limit for data on transactions is about 40kb. Second, saving 40kb takes almost all of the 30 million gas limit on most blockchains. + +The former constraint is immutable (though many chains are slowly increasing this limit), which limits the app to images about 256\*256 pixels in size. The latter is heavily dependent on which chain you choose. + +At current gas prices on most chains, using all 30 million gas in a block costs **several dollars** - or potentially **thousands** on ETH mainnet. At current prices on Flow, spending 30 million gas costs **less than a penny**, usually 1 or 2 tenths of a cent. + +Much more computation is available at prices you or your users will be willing to pay for regular interactions. Including, but not limited to: + +- Airdropping hundreds of NFTs with one transaction, for pennies +- Generation of large mazes +- Generating large amounts of random numbers (with free [native VRF]) +- Extensive string manipulation onchain +- Simple game AI logic + +In this tutorial, we'll build a smart contract that can store and retrieve images onchain. We'll also build a simple frontend to interact with the contract on Flow and another chain. + +![stage-1](stage-1.png) + +## Objectives + +After completing this guide, you'll be able to: + +- Construct a composable onchain image gallery that can be used permissionlessly by onchain apps and other contracts to store and retrieve images +- Build an onchain app that can interact with this contract to save and display images +- Compare the price of spending 30 million gas on Flow with the price on other chains + +## Prerequisites + +### Next.js and Modern Frontend Development + +This tutorial uses [Next.js]. You don't need to be an expert, but it's helpful to be comfortable with development using a current React framework. You'll be on your own to select and use a package manager, manage Node versions, and other frontend environment tasks. + +### Solidity + +You don't need to be an expert, but you should be comfortable writing code in [Solidity]. You can use [Hardhat], [Foundry], or even [Remix]. + +## Build an Image Gallery Contract + +Start a new smart contract project in the toolchain of your choice and install the [OpenZeppelin] contracts. + +In your project, stub out a new contract for your image gallery that inherits from the [Ownable] contract: + +```solidity +// ImageGallery.sol + +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.28; + +import "@openzeppelin/contracts/access/Ownable.sol"; + +contract ImageGallery is Ownable { + constructor(address _owner) Ownable(_owner) {} +} +``` + +We're passing the original owner of the contract as an argument in the constructor to give greater flexibility for ownership when this contract is deployed. + +### Set Up Storage for Images + +We'll store the images in a simple `struct` that holds the image as a `base64` encoded `string`and also contains a `string` for the description. Doing so allows the image to be directly used in html and makes it easier to test the contract directly with a block explorer, but has the downside of making the images 33% bigger. Another format would be more efficient. + +These will be held in array: + +```solidity +struct Image { + string description; + string base64EncodedImage; +} + +Image[] public images; +``` + +### Construct Functions to Add and Delete Images + +Next, add a function that accepts a `_description` and `_base64EncodedImage` and adds them to the array. + +```solidity +function addImage( + string memory _description, + string memory _base64EncodedImage +) public onlyOwner { + images.push(Image(_description, _base64EncodedImage)); +} +``` + +Then, add one to delete the image at a given index: + +```solidity +function deleteImage(uint256 index) public onlyOwner { + if (index >= images.length) { + revert ImageIndexOutOfBounds(index, images.length); + } + for (uint256 i = index; i < images.length - 1; i++) { + images[i] = images[i + 1]; + } + images.pop(); +} +``` + +:::warning + +If the array gets big enough that calling `deleteImage` takes more than 30 million gas, it will brick this function. A safer and more gas-efficient method is to use a `mapping` with a counter as the index, and handling for the case where an index is empty. + +We're doing it this way to provide a way to delete accidentally uploaded images without making things too complex. + +::: + +### Retrieval Functions + +Finally, add functions to get one image, get all of the images, and get the number of images in the collection. + +```solidity +function getImages() public view returns (Image[] memory) { + return images; +} + +function getImage(uint256 index) public view returns (Image memory) { + if (index >= images.length) { + revert ImageIndexOutOfBounds(index, images.length); + } + return images[index]; +} + +function getImageCount() public view returns (uint256) { + return images.length; +} +``` + +### Final Contract + +After completing the above, you'll end up with a contract similar to: + +```solidity +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.28; + +import "@openzeppelin/contracts/access/Ownable.sol"; + +contract ImageGallery is Ownable { + struct Image { + string description; + string base64EncodedImage; + } + + Image[] public images; + + error ImageIndexOutOfBounds(uint256 index, uint256 length); + + constructor(address _owner) Ownable(_owner) {} + + function addImage( + string memory _description, + string memory _base64EncodedImage + ) public onlyOwner { + images.push(Image(_description, _base64EncodedImage)); + } + + function deleteImage(uint256 index) public onlyOwner { + if (index >= images.length) { + revert ImageIndexOutOfBounds(index, images.length); + } + for (uint256 i = index; i < images.length - 1; i++) { + images[i] = images[i + 1]; + } + images.pop(); + } + + function getImages() public view returns (Image[] memory) { + return images; + } + + function getImage(uint256 index) public view returns (Image memory) { + if (index >= images.length) { + revert ImageIndexOutOfBounds(index, images.length); + } + return images[index]; + } + + function getImageCount() public view returns (uint256) { + return images.length; + } +} + +``` + +### Create a Factory + +The image gallery contract you've just constructed is intended to be a utility for other contracts and apps to use freely. You don't want just one gallery for everyone, you need to give the ability for any app or contract to create and deploy private galleries freely. + +Build a factory to deploy image galleries: + +```solidity +pragma solidity ^0.8.28; + +import "@openzeppelin/contracts/access/Ownable.sol"; +import "./ImageGallery.sol"; + +contract ImageGalleryFactory { + event ImageGalleryCreated(address indexed owner, address gallery); + + function createImageGallery(address _owner) public { + ImageGallery gallery = new ImageGallery(_owner); + emit ImageGalleryCreated(_owner, address(gallery)); + } +} +``` + +### Tracking Factories + +Some app designs may need multiple galleries for each user. For example, you might want to be able to give users the ability to collect images in separate galleries for separate topics, dates, or events, similar to how many photo apps work on smartphones. + +To facilitate this feature, update your contract to keep track of which galleries have been created by which users. You'll end up with: + +```solidity +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.28; + +import "@openzeppelin/contracts/access/Ownable.sol"; +import "./ImageGallery.sol"; + +contract ImageGalleryFactory { + event ImageGalleryCreated(address indexed owner, address gallery); + + mapping(address => address[]) userToGalleries; + + function createImageGallery(address _owner) public { + ImageGallery gallery = new ImageGallery(_owner); + emit ImageGalleryCreated(_owner, address(gallery)); + userToGalleries[_owner].push(address(gallery)); + } + + function getGalleries( + address _owner + ) public view returns (address[] memory) { + return userToGalleries[_owner]; + } +} +``` + +### Testing the Factory + +Write appropriate unit tests, then deploy and verify the factory on Flow Testnet. + +If you need help, check out: + +- Deploy and Verify with [Hardhat] +- Deploy and Verify with [Foundry] +- Deploy and Verify with [Remix] + +Navigate to [evm-testnet.flowscan.io], search for your contract, and navigate to the `contracts` tab, then `Read/Write contract`. You'll see something similar to: + +![Factory on Flowscan](factory-on-flowscan.png) + +`Connect` your wallet. Use the [Flow Wallet] if you want automatically sponsored gas on both mainnet and testnet, or use the [Flow Faucet] to grab some testnet funds if you prefer to use another wallet. + +Expand the `createImageGallery` function, click the `self` button, and then `Write` the function. + +![createImageGallery](create-image-gallery.png) + +Approve the transaction and wait for it to complete. Then, call `getGalleries` for your address to find the address of the gallery you've created. + +### Testing the Image Gallery + +Search for the address of your image gallery contract. It `won't` be verified, but if you're using our exact contract, you will see a message from Flowscan that a verified contract with the same bytecode was found in the Blockscout DB. Click the provided link to complete the verification process. + +:::info + +The easiest way to get an ABI for the image gallery is to deploy one. You can do that now if you like. + +::: + +If you're following along, but used your own contract, simply deploy and verify one copy of the contract directly, refresh the page, then complete the above. + +You could test `addImage` with a random string, but it's better to use a base64-encoded image. Search for and navigate to one of the many online tools that will base64 encode images. + +:::danger + +Most sites of this nature are free tools created by helpful programmers and are funded with ads, donations, or the generosity of the creator. But you never know who made them or what they're caching. + +**Never** upload or convert sensitive data on a free site. + +::: + +Use the tool to convert an image that is ~30kb or smaller. Copy the string and paste it into the field in `addImage`. You can also add a `description`, but the bytes used will count towards the ~40kb limit. + +![addImage](add-image.png) + +Click `Write` and approve the transaction. Take note of the cost! You've saved an image onchain forever for just a little bit of gas! + +Once the transaction goes through, call `getImage` with `0` as the index to retrieve your description and base64-encoded image. + +Paste your image string as the `src` for an `img` tag in an html snippet to confirm it worked. + +```html +
+ +
+``` + +## Building the Frontend + +Now that your contracts are sorted and working, it's time to build an app to interact with it. We'll use [Next.js] for this, but the components we provide will be adaptable to other React frameworks. + +Run: + +```bash +npx create-next-app +``` + +We're using the default options. + +Next, install [rainbowkit], [wagmi], and their related dependencies: + +```bash +npm install @rainbow-me/rainbowkit wagmi viem@2.x @tanstack/react-query +``` + +### Provider Setup + +Add a file called `providers` inside the `app` folder. In it, add your config and providers for [wagmi] and [rainbowkit]. You'll need to [add the Flow Wallet] as a custom wallet. It's not included by default because it has special features that aren't compatible with other blockchains. + +```tsx +'use client'; + +import { connectorsForWallets } from '@rainbow-me/rainbowkit'; +import { Wallet, getWalletConnectConnector } from '@rainbow-me/rainbowkit'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { createConfig, WagmiProvider } from 'wagmi'; +import { RainbowKitProvider } from '@rainbow-me/rainbowkit'; +import { flowTestnet } from 'viem/chains'; +import { http } from 'wagmi'; + +const projectId = '51407fcf066d74968d9a1a4c6da0d994'; // Replace with your actual project ID + +export interface MyWalletOptions { + projectId: string; +} + +const flowWallet = ({ projectId }: MyWalletOptions): Wallet => ({ + id: 'flow-wallet', + name: 'Flow Wallet', + iconUrl: 'https://lilico.app/logo_mobile.png', + iconBackground: '#41CC5D', + downloadUrls: { + android: + 'https://play.google.com/store/apps/details?id=com.flowfoundation.wallet', + ios: 'https://apps.apple.com/ca/app/flow-wallet-nfts-and-crypto/id6478996750', + chrome: + 'https://chromewebstore.google.com/detail/flow-wallet/hpclkefagolihohboafpheddmmgdffjm', + qrCode: 'https://link.lilico.app', + }, + mobile: { + getUri: (uri: string) => uri, + }, + qrCode: { + getUri: (uri: string) => uri, + instructions: { + learnMoreUrl: 'https://wallet.flow.com', + steps: [ + { + description: + 'We recommend putting Flow Wallet on your home screen for faster access to your wallet.', + step: 'install', + title: 'Open the Flow Wallet app', + }, + { + description: + 'You can find the scan button on home page, a connection prompt will appear for you to connect your wallet.', + step: 'scan', + title: 'Tap the scan button', + }, + ], + }, + }, + extension: { + instructions: { + learnMoreUrl: 'https://wallet.flow.com', + steps: [ + { + description: + 'We recommend pinning Flow Wallet to your taskbar for quicker access to your wallet.', + step: 'install', + title: 'Install the Flow Wallet extension', + }, + { + description: + 'Be sure to back up your wallet using a secure method. Never share your secret phrase with anyone.', + step: 'create', + title: 'Create or Import a Wallet', + }, + { + description: + 'Once you set up your wallet, click below to refresh the browser and load up the extension.', + step: 'refresh', + title: 'Refresh your browser', + }, + ], + }, + }, + createConnector: getWalletConnectConnector({ projectId }), +}); + +const connectors = connectorsForWallets( + [ + { + groupName: 'Recommended', + wallets: [flowWallet], + }, + ], + { + appName: 'Onchain Image Gallery', + projectId: projectId, + }, +); + +const wagmiConfig = createConfig({ + connectors, + chains: [flowTestnet], + ssr: true, + transports: { + [flowTestnet.id]: http(), + }, +}); + +export default function Providers({ children }: { children: React.ReactNode }) { + const queryClient = new QueryClient(); + + return ( + + + {children} + + + ); +} +``` + +### Add the Connect Button + +Open `page.tsx` and clear out the default content. Replace it with a message about what your app does and add the [rainbowkit] `Connect` button. Don't forget to import rainbowkit's css file and the `ConnectButton` component: + +```tsx +import '@rainbow-me/rainbowkit/styles.css'; + +import { ConnectButton } from '@rainbow-me/rainbowkit'; + +export default function Home() { + return ( +
+
+

Image Gallery

+

+ A decentralized image gallery built on Flow blockchain. All images + saved directly onchain. +

+

+ A fun benchmark, not best practice for production! +

+

+ Free with gas sponsored by Flow with the Flow wallet. Sub-cent to save + an image with other wallets. +

+ +
+
+ ); +} +``` + +Test the app and make sure you can connect your wallet. + +### Import Your Contracts + +Next, you'll need to get your contract ABI and address into your frontend. If you're using Hardhat, you can use the artifacts produced by the Ignition deployment process. If you're using Foundry or Remix, you can adapt this process to the format of artifacts produced by those toolchains. + +:::tip + +If you didn't deploy the Image Gallery contract, do so now to generate an artifact containing the ABI. + +::: + +Add a folder in `app` called `contracts`. Copy the following files from your smart contract project, located in the `ignition` and `ignition/deployments/chain-545` folders: + +- `deployed_addresses.json` +- `ImageGallery#ImageGallery.json` +- `ImageGalleryFactory#ImageGalleryFactory.json` + +Additionally, add a file called `contracts.ts`. In it, create a hook to provide the ABI and addresses of your contracts conveniently: + +```tsx +import { useMemo } from 'react'; +import { Abi } from 'viem'; + +import imageGalleryFactory from './ImageGalleryFactory#ImageGalleryFactory.json'; +import imageGallery from './ImageGallery#ImageGallery.json'; +import addresses from './deployed_addresses.json'; + +export default function useContracts() { + return useMemo(() => { + return { + imageGalleryFactory: { + address: addresses[ + 'ImageGalleryFactory#ImageGalleryFactory' + ] as `0x${string}`, + abi: imageGalleryFactory.abi as Abi, + }, + imageGallery: { + abi: imageGallery.abi as Abi, + }, + }; + }, []); +} +``` + +:::info + +Note that we're **not** including an `address` for the `imageGallery` itself. We'll need to set this dynamically as users might have more than one gallery. + +::: + +### Add Content + +You can use a few strategies to organize the components that interact with the blockchain. One is to create a centralized component that stores all of the state related to smart contracts and uses a single instance of `useWriteContract`. Doing so makes it easier to convey the transaction lifecycle to your users, at the cost of re-fetching all the data from your RPC provider after every transaction. This becomes sub-optimal if your app interacts with many contracts, or even different read functions within the same contract. + +Add a folder in `app` called `components`, and create a file called `Content.tsx`. In it, add the following: + +- Imports for React, wagmi, your contracts, and Tanstack +- State variables for: + - When a reload is needed + - When you are waiting on a transaction response + - The list of gallery addresses for the connected wallet +- Hooks for: + - `useAccount()` + - `useQueryClient()` + - `useContracts()` + - `useWriteContract()` + - `useWaitForTransactionReceipt()` +- `useEffects` to: + - Listen for a receipt and set `reload` to true and `awaitingResponse` false + - Listen for needing a reload and invalidating the query for galleryAddresses + - Error handling + - Receipt of gallery addresses +- A `useReadContract` to fetch the list of gallery addresses for this user +- Frontend code to display the button to create a gallery if the user is signed in + +You'll end up with something similar to: + +```tsx +'use client'; + +import { useEffect, useState } from 'react'; +import { + useAccount, + useReadContract, + useWaitForTransactionReceipt, + useWriteContract, +} from 'wagmi'; +import useContracts from '../contracts/contracts'; +import { useQueryClient } from '@tanstack/react-query'; + +export default function Content() { + const [reload, setReload] = useState(false); + const [awaitingResponse, setAwaitingResponse] = useState(false); + const [galleryAddresses, setGalleryAddresses] = useState([]); + + const account = useAccount(); + const queryClient = useQueryClient(); + const { imageGalleryFactory } = useContracts(); + + const { data, writeContract, error: writeError } = useWriteContract(); + + const { data: receipt, error: receiptError } = useWaitForTransactionReceipt({ + hash: data, + }); + + useEffect(() => { + if (receipt) { + setReload(true); + setAwaitingResponse(false); + } + }, [receipt]); + + useEffect(() => { + if (reload) { + setReload(false); + queryClient.invalidateQueries({ queryKey: galleryAddressesQueryKey }); + } + }, [reload]); + + useEffect(() => { + if (writeError) { + console.error(writeError); + setAwaitingResponse(false); + } + }, [writeError]); + + useEffect(() => { + if (receiptError) { + console.error(receiptError); + setAwaitingResponse(false); + } + }, [receiptError]); + + const { data: galleryAddressesData, queryKey: galleryAddressesQueryKey } = + useReadContract({ + abi: imageGalleryFactory.abi, + address: imageGalleryFactory.address, + functionName: 'getGalleries', + args: [account.address], + }); + + useEffect(() => { + if (galleryAddressesData) { + const newAddresses = galleryAddressesData as string[]; + newAddresses.reverse(); + setGalleryAddresses(newAddresses); + } + }, [galleryAddressesData]); + + function handleCreateGallery() { + setAwaitingResponse(true); + writeContract({ + abi: imageGalleryFactory.abi, + address: imageGalleryFactory.address, + functionName: 'createImageGallery', + args: [account.address], + }); + } + + return ( +
+ {account.isConnected && ( +
+
+ +
+
+ )} +
+ ); +} +``` + +**Don't forget** to add your `` component to `page.tsx`, below the `` component. + +Test the app and make sure you can complete the transaction to create a gallery. + +### Gallery List + +Next, you'll need to display the list of a user's galleries and enable them to select which one they want to interact with. A dropdown list will serve this function well. Add a component called `AddressList.tsx`, and in it add: + +```tsx +import React, { useEffect, useState } from 'react'; + +type AddressDropdownProps = { + addresses: string[]; // Array of EVM addresses + handleSetActiveAddress: Function; +}; + +const AddressDropdown: React.FC = ({ + addresses, + handleSetActiveAddress, +}) => { + const [selectedAddress, setSelectedAddress] = useState(''); + + useEffect(() => { + if (selectedAddress) { + console.log(selectedAddress); + handleSetActiveAddress(selectedAddress); + } + }, [selectedAddress]); + + return ( +
+

Select a Gallery

+
+ +
+
+ ); +}; + +export default AddressDropdown; +``` + +This component **doesn't** interact directly with the blockchain. It accepts the array of `addresses` and a function to handle setting the `activeAddress`. + +To use it in `Content.tsx`, you'll need to add a new state variable for the `activeAddress`: + +```tsx +const [activeAddress, setActiveAddress] = useState(null); +``` + +You'll also need a handler for when the `activeAddress` is set. You can't just use the `setActiveAddress()` function because you need to tell the app to reload if the user changes which gallery is active, so that the images in that gallery are loaded. + +```tsx +function handleSetActiveAddress(address: string) { + setReload(true); + setActiveAddress(address); +} +``` + +Finally, add the new component under the ` + +
+
+ +
+ + )} + +); +``` + +Run the app, log in with your wallet **that has the gallery you created for testing** and select the gallery. + +You're now displaying an image that is stored onchain **forever**! + +## Image Uploader + +The last thing to do for this initial implementation is to add functionality so that users can upload their own images through the app and save them onchain without needing to do the base64 conversion on their own. + +For now, we'll just generate an error if the file is too big, but later on we can do that for the user as well. + +Add the `ImageUploader` component. This needs to handle uploading the image and displaying any errors. We'll keep the state for the image itself in `Content` so that it's accessible to other components: + +```tsx +import React, { useState } from 'react'; + +type ImageUploaderProps = { + setUploadedBase64Image: (base64: string) => void; // Function to set the uploaded base64 image +}; + +const ImageUploader: React.FC = ({ + setUploadedBase64Image, +}) => { + const [error, setError] = useState(null); + + const handleImageUpload = (event: React.ChangeEvent) => { + const file = event.target.files?.[0]; + + if (!file) { + setError('No file selected'); + return; + } + + if (!file.type.startsWith('image/')) { + setError('Only image files are allowed'); + return; + } + + if (file.size > 30 * 1024) { + setError('Image size must be 30KB or smaller'); + return; + } + + const reader = new FileReader(); + reader.onload = () => { + const base64 = reader.result as string; + setUploadedBase64Image(base64); + setError(null); + }; + reader.onerror = () => { + setError('Failed to read file'); + }; + reader.readAsDataURL(file); + }; + + return ( +
+
+ + + {error &&

{error}

} +
+
+ ); +}; + +export default ImageUploader; +``` + +As before, we'll need to make some updates to `Content.tsx` to complete the implementation. + +First, add a state variable for the image: + +```tsx +const [uploadedBase64Image, setUploadedBase64Image] = useState(''); +``` + +Then add the `ImageUploader` to the `return`: + +```tsx + +``` + +Later on, you'll probably want to make a component for displaying the uploaded image, but for now just add it below the uploader button component: + +```tsx +{ + uploadedBase64Image && ( +
+ Uploaded +
+ ); +} +``` + +Finally, you need to add a button and a handler to call the smart contract function to save the image onchain. + +```tsx +function handleSaveOnchain() { + // console.log(uploadedBase64Image); + setAwaitingResponse(true); + writeContract({ + abi: imageGallery.abi, + address: activeAddress as `0x${string}`, + functionName: 'addImage', + args: ['', uploadedBase64Image], + }); +} +``` + +Add the button inside the check for an `uploadedBase64Image` so that it only displays when there is an image to upload: + +```tsx +{ + uploadedBase64Image && ( +
+ Uploaded + +
+ ); +} +``` + +Test the app to save your new image, and make sure the error displays if you try to upload an image that is too large. + +## Conclusion + +In this tutorial, you built a fully functional onchain image gallery using Flow EVM. You created smart contracts that can store images directly on the blockchain and a modern React frontend that allows users to interact with these contracts. The implementation demonstrates how Flow's efficient gas pricing makes operations that would be prohibitively expensive on other chains not just possible, but practical. + +Now that you have completed the tutorial, you should be able to: + +- Construct a composable onchain image gallery that can be used permissionlessly by onchain apps and other contracts to store and retrieve images +- Build an onchain app that can interact with this contract to save and display images +- Compare the price of spending 30 million gas on Flow with the price on other chains + +Now that you've completed this tutorial, you're ready to explore more complex onchain storage patterns and build applications that take advantage of Flow's unique capabilities for storing and processing larger amounts of data than traditionally possible on other chains. + + + +[FlowtoBooth]: https://flowtobooth.vercel.app/ +[Cadence]: https://cadence-lang.org/docs +[Next.js]: https://nextjs.org/docs/app/getting-started/installation +[Solidity]: https://soliditylang.org/ +[Hardhat]: ../../evm/guides/hardhat.md +[Foundry]: ../../evm/guides/foundry.md +[Remix]: ../../evm/guides/remix.md +[native VRF]: ../../evm/guides/vrf.md +[OpenZeppelin]: https://www.openzeppelin.com/ +[Ownable]: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol +[evm-testnet.flowscan.io]: https://evm-testnet.flowscan.io/ +[Hardhat]: ../../evm/guides/hardhat.md +[Foundry]: ../../evm/guides/foundry.md +[Remix]: ../../evm/guides/remix.md +[Flow Wallet]: https://wallet.flow.com/ +[Flow Faucet]: https://faucet.flow.com/fund-account +[add the Flow Wallet]: ../../evm/guides/rainbowkit.md +[rainbowkit]: https://www.rainbowkit.com/ +[wagmi]: https://wagmi.sh/ +[viem]: https://viem.sh/ + + +=== tutorials/cross-vm-apps/vm-bridge.md === +--- +title: Cross-VM Bridge +sidebar_label: Cross-VM Bridge +sidebar_position: 7 +--- + +# Cross-VM Bridge + +Flow provides the [Cross-VM Bridge](https://www.github.com/onflow/flow-evm-bridge) which enables the movement of +fungible and non-fungible tokens between Cadence & EVM. The Cross-VM Bridge is a contract-based protocol enabling the +automated and atomic bridging of tokens from Cadence into EVM with their corresponding ERC-20 and ERC-721 token types. +In the opposite direction, it supports bridging of arbitrary ERC-20 and ERC-721 tokens from EVM to Cadence as their +corresponding FT or NFT token types. + +The Cross-VM Bridge internalizes the capabilities to deploy new token contracts in either VM state as needed, resolving +access to, and maintaining links between associated contracts. It additionally automates account and contract calls to +enforce source VM asset burn or lock, and target VM token mint or unlock. + +Developers wishing to use the Cross-VM Bridge will be required to use a Cadence transaction. Cross-VM bridging +functionality is not currently available natively in Flow EVM. By extension, this means that the EVM account bridging +from EVM to Cadence must be a [`CadenceOwnedAccount` (COA)](./interacting-with-coa.md) as this is the only EVM account +type that can be controlled from the Cadence runtime. + +This [FLIP](https://github.com/onflow/flips/pull/233) outlines the architecture and implementation of the VM bridge. +This document will focus on how to use the Cross-VM Bridge and considerations for fungible and non-fungible token +projects deploying to either Cadence or EVM. + +## Deployments + +The core bridge contracts can be found at the following addresses: + +| Contracts | Testnet | Mainnet | +| ------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- | +| All Cadence Bridge contracts | [`0xdfc20aee650fcbdf`](https://contractbrowser.com/account/0xdfc20aee650fcbdf/contracts) | [`0x1e4aa0b87d10b141`](https://contractbrowser.com/account/0x1e4aa0b87d10b141/contracts) | +| `FlowEVMBridgeFactory.sol` | [`0xf8146b4aef631853f0eb98dbe28706d029e52c52`](https://evm-testnet.flowscan.io/address/0xF8146B4aEF631853F0eB98DBE28706d029e52c52) | [`0x1c6dea788ee774cf15bcd3d7a07ede892ef0be40`](https://evm.flowscan.io/address/0x1C6dEa788Ee774CF15bCd3d7A07ede892ef0bE40) | +| `FlowEVMBridgeDeploymentRegistry.sol` | [`0x8781d15904d7e161f421400571dea24cc0db6938`](https://evm-testnet.flowscan.io/address/0x8781d15904d7e161f421400571dea24cc0db6938) | [`0x8fdec2058535a2cb25c2f8cec65e8e0d0691f7b0`](https://evm.flowscan.io/address/0x8FDEc2058535A2Cb25C2f8ceC65e8e0D0691f7B0) | +| `FlowEVMBridgedERC20Deployer.sol` | [`0x4d45CaD104A71D19991DE3489ddC5C7B284cf263`](https://evm-testnet.flowscan.io/address/0x4d45CaD104A71D19991DE3489ddC5C7B284cf263) | [`0x49631Eac7e67c417D036a4d114AD9359c93491e7`](https://evm.flowscan.io/address/0x49631Eac7e67c417D036a4d114AD9359c93491e7) | +| `FlowEVMBridgedERC721Deployer.sol` | [`0x1B852d242F9c4C4E9Bb91115276f659D1D1f7c56`](https://evm-testnet.flowscan.io/address/0x1B852d242F9c4C4E9Bb91115276f659D1D1f7c56) | [`0xe7c2B80a9de81340AE375B3a53940E9aeEAd79Df`](https://evm.flowscan.io/address/0xe7c2B80a9de81340AE375B3a53940E9aeEAd79Df) | + +And below are the bridge escrow's EVM addresses. These addresses are COAs and are stored stored in the same Flow account +as you'll find the Cadence contracts (see above). + +| Network | Address | +| ------- | ---------------------------------------------------------------------------------------------------------------------------------- | +| Testnet | [`0x0000000000000000000000023f946ffbc8829bfd`](https://evm-testnet.flowscan.io/address/0x0000000000000000000000023f946FFbc8829BFD) | +| Mainnet | [`0x00000000000000000000000249250a5c27ecab3b`](https://evm.flowscan.io/address/0x00000000000000000000000249250a5C27Ecab3B) | + +## Interacting With the Bridge + +:::info + +All bridging activity in either direction is orchestrated via Cadence on COA EVM accounts. This means that all bridging +activity must be initiated via a Cadence transaction, not an EVM transaction regardless of the directionality of the +bridge request. For more information on the interplay between Cadence and EVM, see [How Flow EVM +Works](../../evm/how-it-works.md). + +::: + +### Overview + +The Flow EVM bridge allows both fungible and non-fungible tokens to move atomically between Cadence and EVM. In the +context of EVM, fungible tokens are defined as ERC20 tokens, and non-fungible tokens as ERC721 tokens. In Cadence, +fungible tokens are defined by contracts implementing +[the `FungibleToken` interface](https://github.com/onflow/flow-ft/blob/master/contracts/FungibleToken.cdc) +and non-fungible tokens implement +[the `NonFungibleToken` interface](https://github.com/onflow/flow-nft/blob/master/contracts/NonFungibleToken.cdc). + +Like all operations on Flow, there are native fees associated with both computation and storage. To prevent spam and +sustain the bridge account's storage consumption, fees are charged for both onboarding assets and bridging assets. In +the case where storage consumption is expected, fees are charged based on the storage consumed at the current network +storage rate. + +### Onboarding + +Since a contract must define the asset in the target VM, an asset must be "onboarded" to the bridge before requests can +be fulfilled. + +Moving from Cadence to EVM, onboarding can occur on the fly, deploying a template contract in the same transaction as +the asset is bridged to EVM if the transaction so specifies. + +Moving from EVM to Cadence, however, requires that onboarding occur in a separate transaction due to the fact that a +Cadence contract is initialized at the end of a transaction and isn't available in the runtime until after the +transaction has executed. + +Below are transactions relevant to onboarding assets: + +
+onboard_by_type.cdc + +```cadence onboard_by_type.cdc +!from https://www.github.com/onflow/flow-evm-bridge/blob/main/cadence/transactions/bridge/onboarding/onboard_by_type.cdc +``` + +
+ +
+onboard_by_evm_address.cdc + +```cadence onboard_by_evm_address.cdc +!from https://www.github.com/onflow/flow-evm-bridge/blob/main/cadence/transactions/bridge/onboarding/onboard_by_evm_address.cdc +``` + +
+ +### Bridging + +Once an asset has been onboarded, either by its Cadence type or EVM contract address, it can be bridged in either +direction, referred to by its Cadence type. For Cadence-native assets, this is simply its native type. For EVM-native +assets, this is in most cases a templated Cadence contract deployed to the bridge account, the name of which is derived +from the EVM contract address. For instance, an ERC721 contract at address `0x1234` would be onboarded to the bridge as +`EVMVMBridgedNFT_0x1234`, making its type identifier `A..EVMVMBridgedNFT_0x1234.NFT`. + +To get the type identifier for a given NFT, you can use the following code: + +```cadence +// Where `nft` is either a @{NonFungibleToken.NFT} or &{NonFungibleToken.NFT} +nft.getType().identifier +``` + +You may also retrieve the type associated with a given EVM contract address using the following script: + +
+ +get_associated_type.cdc + +```cadence get_associated_type.cdc +!from https://github.com/onflow/flow-evm-bridge/blob/main/cadence/scripts/bridge/get_associated_type.cdc +``` + +
+ +Alternatively, given some onboarded Cadence type, you can retrieve the associated EVM address using the following +script: + +
+ +get_associated_address.cdc + +```cadence get_associated_address.cdc +!from https://github.com/onflow/flow-evm-bridge/blob/main/cadence/scripts/bridge/get_associated_evm_address.cdc +``` + +
+ +#### NFTs + +Any Cadence NFTs bridging to EVM are escrowed in the bridge account and either minted in a bridge-deployed ERC721 +contract or transferred from escrow to the calling COA in EVM. On the return trip, NFTs are escrowed in EVM - owned by +the bridge's COA - and either unlocked from escrow if locked or minted from a bridge-owned NFT contract. + +Below are transactions relevant to bridging NFTs: + +
+ +bridge_nft_to_evm.cdc + +```cadence bridge_nft_to_evm.cdc +!from https://www.github.com/onflow/flow-evm-bridge/blob/main/cadence/transactions/bridge/nft/bridge_nft_to_evm.cdc +``` + +
+ +
+ +bridge_nft_from_evm.cdc + +```cadence bridge_nft_from_evm.cdc +!from https://www.github.com/onflow/flow-evm-bridge/blob/main/cadence/transactions/bridge/nft/bridge_nft_from_evm.cdc +``` + +
+ +#### Fungible Tokens + +Any Cadence fungible tokens bridging to EVM are escrowed in the bridge account only if they are Cadence-native. If the +bridge defines the tokens, they are burned. On the return trip the pattern is similar, with the bridge burning +bridge-defined tokens or escrowing them if they are EVM-native. In all cases, if the bridge has authority to mint on one +side, it must escrow on the other as the native VM contract is owned by an external party. + +With fungible tokens in particular, there may be some cases where the Cadence contract is not deployed to the bridge +account, but the bridge still follows a mint/burn pattern in Cadence. These cases are handled via +[`TokenHandler`](https://github.com/onflow/flow-evm-bridge/blob/main/cadence/contracts/bridge/interfaces/FlowEVMBridgeHandlerInterfaces.cdc) +implementations. Also know that moving $FLOW to EVM is built into the `EVMAddress` object so any requests bridging $FLOW +to EVM will simply leverage this interface; however, moving $FLOW from EVM to Cadence must be done through the COA +resource. + +Below are transactions relevant to bridging fungible tokens: + +
+ +bridge_tokens_to_evm.cdc + +```cadence bridge_tokens_to_evm.cdc +!from https://www.github.com/onflow/flow-evm-bridge/blob/main/cadence/transactions/bridge/tokens/bridge_tokens_to_evm.cdc +``` + +
+ +
+ +bridge_tokens_from_evm.cdc + +```cadence bridge_tokens_from_evm.cdc +!from https://www.github.com/onflow/flow-evm-bridge/blob/main/cadence/transactions/bridge/tokens/bridge_tokens_from_evm.cdc +``` + +
+ +## Prep Your Assets for Bridging + +### Context + +To maximize utility to the ecosystem, this bridge is permissionless and open to any fungible or non-fungible token as +defined by the respective Cadence standards and limited to ERC20 and ERC721 Solidity standards. Ultimately, a project +does not have to do anything for users to be able to bridge their assets between VMs. However, there are some +considerations developers may take to enhance the representation of their assets in non-native VMs. These largely relate +to asset metadata and ensuring that bridging does not compromise critical user assumptions about asset ownership. + +### EVMBridgedMetadata + +Proposed in [@onflow/flow-nft/pull/203](https://github.com/onflow/flow-nft/pull/203), the `EVMBridgedMetadata` view +presents a mechanism to both represent metadata from bridged EVM assets as well as enable Cadence-native projects to +specify the representation of their assets in EVM. Implementing this view is not required for assets to be bridged, but +the bridge does default to it when available as a way to provide projects greater control over their EVM asset +definitions within the scope of ERC20 and ERC721 standards. + +The interface for this view is as follows: + +```cadence +access(all) struct URI: MetadataViews.File { + /// The base URI prefix, if any. Not needed for all URIs, but helpful + /// for some use cases For example, updating a whole NFT collection's + /// image host easily + access(all) let baseURI: String? + /// The URI string value + /// NOTE: this is set on init as a concatenation of the baseURI and the + /// value if baseURI != nil + access(self) let value: String + + access(all) view fun uri(): String + +} + +access(all) struct EVMBridgedMetadata { + access(all) let name: String + access(all) let symbol: String + + access(all) let uri: {MetadataViews.File} +} +``` + +This uri value could be a pointer to some offchain metadata if you expect your metadata to be static. Or you could +couple the `uri()` method with the utility contract below to serialize the onchain metadata on the fly. Alternatively, +you may choose to host a metadata proxy which serves the requested token URI content. + +### SerializeMetadata + +The key consideration with respect to metadata is the distinct metadata storage patterns between ecosystem. It's +critical for NFT utility that the metadata be bridged in addition to the representation of the NFTs ownership. However, +it's commonplace for Cadence NFTs to store metadata onchain while EVM NFTs often store an onchain pointer to metadata +stored offchain. In order for Cadence NFTs to be properly represented in EVM platforms, the metadata must be bridged in +a format expected by those platforms and be done in a manner that also preserves the atomicity of bridge requests. The +path forward on this was decided to be a commitment of serialized Cadence NFT metadata into formats popular in the EVM +ecosystem. + +For assets that do not implement `EVMBridgedMetadata`, the bridge will attempt to serialize the metadata of the asset as +a JSON data URL string. This is done via the [`SerializeMetadata` +contract](https://github.com/onflow/flow-evm-bridge/blob/main/cadence/contracts/utils/SerializeMetadata.cdc) which +serializes metadata values into a JSON blob compatible with the OpenSea metadata standard. The serialized metadata is +then committed as the ERC721 `tokenURI` upon bridging Cadence-native NFTs to EVM. Since Cadence NFTs can easily update +onchain metadata either by field or by the ownership of sub-NFTs, this serialization pattern enables token URI updates +on subsequent bridge requests. + +### Opting Out + +It's also recognized that the logic of some use cases may actually be compromised by the act of bridging, particularly +in such a unique partitioned runtime environment. Such cases might include those that do not maintain ownership +assumptions implicit to ecosystem standards. + +For instance, an ERC721 implementation may reclaim a user's assets after a month of inactivity. In such a case, bridging +that ERC721 to Cadence would decouple the representation of ownership of the bridged NFT from the actual ownership in +the defining ERC721 contract after the token had been reclaimed - there would be no NFT in escrow for the bridge to +transfer on fulfillment of the NFT back to EVM. In such cases, projects may choose to opt-out of bridging, but +**importantly must do so before the asset has been onboarded to the bridge**. + +For Solidity contracts, opting out is as simple as extending the [`BridgePermissions.sol` abstract +contract](https://github.com/onflow/flow-evm-bridge/blob/main/solidity/src/interfaces/BridgePermissions.sol) which +defaults `allowsBridging()` to `false`. The bridge explicitly checks for the implementation of `IBridgePermissions` and +the value of `allowsBridging()` to validate that the contract has not opted out of bridging. + +Similarly, Cadence contracts can implement the [`IBridgePermissions.cdc` contract +interface](https://github.com/onflow/flow-evm-bridge/blob/main/cadence/contracts/bridge/interfaces/IBridgePermissions.cdc). +This contract has a single method `allowsBridging()` with a default implementation returning `false`. Again, the bridge +explicitly checks for the implementation of `IBridgePermissions` and the value of `allowsBridging()` to validate that +the contract has not opted out of bridging. Should you later choose to enable bridging, you can simply override the +default implementation and return `true`. + +In both cases, `allowsBridging()` gates onboarding to the bridge. Once onboarded - **a permissionless operation anyone +can execute** - the value of `allowsBridging()` is irrelevant and assets can move between VMs permissionlessly. + +## Under the Hood + +For an in-depth look at the high-level architecture of the bridge, see [FLIP +#237](https://github.com/onflow/flips/blob/main/application/20231222-evm-vm-bridge.md) + +### Additional Resources + +For the current state of Flow EVM across various task paths, see the following resources: + +- [Flow EVM Equivalence forum post](https://forum.flow.com/t/evm-equivalence-on-flow-proposal-and-path-forward/5478) +- [EVM Integration FLIP #223](https://github.com/onflow/flips/pull/225/files) +- [Gateway & JSON RPC FLIP #235](https://github.com/onflow/flips/pull/235) + + +=== tutorials/cross-vm-apps/introduction.md === +--- +title: Batched Tx From Scaffold +description: Learn how to use FCL with wagmi and rainbowkit to create a cross-vm app - one that is simultaneously connected to Flow EVM and Flow Cadence. +sidebar_position: 0 +keywords: + - hybrid apps + - cross-vm apps + - FCL + - wagmi + - RainbowKit + - viem + - Flow EVM + - Flow Cadence + - cross-VM + - multi-call + - batch transactions + - web3 + - dapp development + - wallet integration + - smart contracts + - blockchain development + - supercharge your EVM app with Cadence +--- + +Ever since the launch of Flow EVM, it's been possible to _supercharge_ your EVM apps by using Flow Cadence features and contracts. Some benefits, such as [native VRF] and inexpensive gas without compromising security are built in and either easy or automatic to use. Others, such as the ability to use [Cadence] to [structure and call EVM transactions], are powerful but complicated to configure and use. They also require developers to manage concurrent connections to both networks. + +[FLIP 316] improves the [Flow Client Library (FCL)] to support cross-VM functionality between Flow EVM and Flow Cadence. + +For EVM developers, this means that you can use the familiar [wagmi], [viem], and [RainbowKit] stack you're used to, add FCL, and get features like **multi-call write** with one signature for users with a Cadence-compatible [wallet]. + +In this tutorial, you'll learn how to create [Click to Mint], a simple game that allows players to mint an ERC-20 token by clicking a button. With the power of Flow, they can also click a button, and **complete 10 separate transactions with just one approval!** + +![Click to Mint](click-to-mint.png) + +:::warning + +The FCL functionality described in this tutorial is in alpha. Some steps may change. We'll keep the tutorial updated, but please [create an issue] or let us know on [Discord] if something isn't working for you. + +::: + +## Objectives + +After completing this guide, you'll be able to: + +- Build an app that seamlessly integrates Flow Cadence and Flow EVM connections +- Add Cadence features to your [Rainbowkit]/[wagmi]/[viem] app +- Utilize [Flow Client Library (FCL)] to enable multi-call contract writes to Flow EVM + +## Prerequisites + +### Next.js and Modern Frontend Development + +This tutorial uses [Next.js]. You don't need to be an expert, but it's helpful to be comfortable with development using a current React framework. You'll be on your own to select and use a package manager, manage Node versions, and other frontend environment tasks. If you don't have your own preference, you can just follow along with us and use [npm]. + +### Solidity and Cadence Smart Contract Development + +Apps using the hybrid approach can interact with both [Cadence] and [Solidity] smart contracts. You don't need to be an expert in either of these, but it's helpful to be familiar with how smart contracts work in at least one of these languages. + +### Onchain App Frontends + +We're assuming you're familiar with [wagmi], [viem], and [RainbowKit]. If you're coming from the Cadence, you might want to take a quick look at the getting started guides for these platforms. They're all excellent and will rapidly get you up to speed on how the EVM world commonly connects their apps to their contracts. + +## Getting Started + +For this tutorial, we'll be starting from a fork of the [FCL + RainbowKit + Wagmi Integration Demo] built by the team. + +Fork the repo so you can push your work freely to your own copy, then follow the setup instructions. + +## Project Overview + +Open the cross-vm app scaffold in your editor, run it, and view the site in your browser: + +```bash +npm run dev +``` + +You'll see: + +![Hybrid App Demo](hybrid-app-demo.png) + +Connect with a Cadence-compatible [wallet]. + +:::warning + +In a production app, you'll want to manage this process carefully. Non-Cadence EVM wallets may be able to connect, but they will **not** be able to use any Cadence features. + +::: + +## Send Batch Transactions + +The first demo built into this scaffold is **multi-call contract write**. + +On Flow, this isn't an unstable experimental feature - it's a demonstration of the power of EVM + Cadence. + +Click `Send Batch Transaction Example` and approve the transaction. You'll see three lines appear on the page, similar to: + +``` +{"isPending":false,"isError":false,"txId":"b3c2b8c86e68177af04324152d45d9de9c2a118ff8f090476b3a07e0c9554912","results":[{"hash":"0x46e923a08d9008632e3782ea512c4c590d4650ba58b3e8b49628f58e6adddaa9","status":"passed","errorMessage":""},{"hash":"0x52c82dc689cd5909519f8a90d0a1ec2e74192d7603fd3b5d33f7f4d54a618a84","status":"passed","errorMessage":""}]} +``` + +:::tip + +Currently, the Flow wallet sponsors all gas for all transactions signed with the wallet on both testnet **and mainnet!** + +::: + +### Cadence Parent Transaction + +The first line is the transaction id of the Flow Cadence transaction that calls **both** of the EVM transactions. Search for it in [Testnet Cadence Flowscan]. + +Cadence transactions are more complicated than those in Solidity contracts. Rather than being restricted to running functions present on the contract, they can run arbitrary code as long as the caller has access to all of the resources required by the transaction. + +You can see the code of the transaction in the `Script` tab, but we've included it here for convenience: + +```cadence +import EVM from 0x8c5303eaa26202d6 + +transaction(calls: [{String: AnyStruct}], mustPass: Bool) { + + let coa: auth(EVM.Call) &EVM.CadenceOwnedAccount + + // Borrow a reference to the EVM account that has the ability to sign transactions + prepare(signer: auth(BorrowValue) & Account) { + let storagePath = /storage/evm + self.coa = signer.storage.borrow(from: storagePath) + ?? panic("No CadenceOwnedAccount (COA) found at ".concat(storagePath.toString())) + } + + // Iterate through the list of provided EVM transactions + execute { + for i, call in calls { + let to = call["to"] as! String + let data = call["data"] as! String + let gasLimit = call["gasLimit"] as! UInt64 + let value = call["value"] as! UInt + + let result = self.coa.call( + to: EVM.addressFromString(to), + data: data.decodeHex(), + gasLimit: gasLimit, + value: EVM.Balance(attoflow: value) + ) + + if mustPass { + assert( + result.status == EVM.Status.successful, + message: "Call index ".concat(i.toString()).concat(" to ").concat(to) + .concat(" with calldata ").concat(data).concat(" failed: ") + .concat(result.errorMessage) + ) + } + } + } +``` + +In this case, it's checking that the caller of the Cadence transaction has permission to control to the EVM account, which is built in for [Cadence Owned Accounts]. The `execute` phase then iterates through the EVM transactions and uses the Cadence accounts own permissions to sign the EVM transactions. + +The loop also handles a check for the optional flag to cancel all of the transactions if any one of them fails. **In other words, you could set up a 20 transaction arbitrage attempt and unwind everything if it fails at any step!** + +### EVM Child Transactions + +The next two lines show the transaction hashes for the EVM transactions. You can view this in [Testnet EVM Flowscan] by searching for the transaction hashes, the same as any other. + +Look up both transactions. + +The first is calling the `deposit()` function to wrap FLOW and move it to EVM. + +The second is calling the ERC-20 `approve()` function to give another address the authority to spend those tokens. + +For the demo, the code for this is hard-coded into `src/app/page.tsx`: + +```tsx +const calls: EVMBatchCall[] = [ + { + // Call deposit() function (wrap FLOW) on the token contract. + address: '0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e', // Replace with your actual token contract address. + abi: [ + { + inputs: [], + name: 'deposit', + outputs: [], + stateMutability: 'payable', + type: 'function', + }, + ], + functionName: 'deposit', + args: [], // deposit takes no arguments; value is passed with the call. + }, + { + // Call approve() function (ERC20 style) on the same token contract. + address: '0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e', // Replace with your actual token contract address if needed. + abi: [ + { + inputs: [ + { name: 'spender', type: 'address' }, + { name: 'value', type: 'uint256' }, + ], + name: 'approve', + outputs: [{ name: '', type: 'bool' }], + stateMutability: 'nonpayable', + type: 'function', + }, + ], + functionName: 'approve', + args: [ + '0x2E2Ed0Cfd3AD2f1d34481277b3204d807Ca2F8c2', // Spender address. + BigInt('1000000000000000000'), // Approve 1 token (assuming 18 decimals). + ], + }, +]; +``` + +It's called with the `useBatchTransaction` hook via the `sendBatchTransaction(calls)` function. + +## Code Evaluator + +The demo also has an embedded code evaluator that you can use to experiment with snippets of code from `fcl` or `wagmi`. + +For example: + +```tsx +const user = await fcl.currentUser().snapshot(); +return user.addr; +``` + +Will return your Cadence address. This snippet: + +```tsx +const block = await fcl.block(); +return block.height; +``` + +Returns the current Cadence VM block number. + +## Calling Your Own Contract + +Next, we'll update the starter to connect to and call functions in our own contract. For this, we'll use a simple [Button Clicker Contract]. You can deploy your own copy, or use the one deployed at [`0xA7Cf2260e501952c71189D04FAd17c704DFB36e6`]. + +## Set Up Contract Imports + +:::info + +The following steps assume deployment with Hardhat Ignition. If you are using a different deployment method, import the contract address and abi as appropriate. + +::: + +In your fork of the app, add a folder called `contracts` to the `src` folder. In it, copy over ['deployed_addresses.json`] from `ignition/deployments/chain-545` in the Button Clicker repo, and `ignition/deployments/chain-545/ClickTokenModule#ClickToken.json`. + +Next, create a folder called `constants` and add a file called `contracts.ts` to it. + +In it, import the contract artifact and addresses file, and create export a constant with this information. + +```tsx +import ClickToken from '../contracts/ClickTokenModule#ClickToken.json'; +import deployedAddresses from '../contracts/deployed_addresses.json'; + +export const clickToken = { + abi: ClickToken.abi, + address: deployedAddresses['ClickTokenModule#ClickToken'] as `0x${string}`, +}; +``` + +## Build Traditional Functionality + +This isn't a wagmi tutorial, so we'll give you some components to speed up the process. Add a folder called `components` inside `src` and add the following files. + +`TheButton.tsx` + +```tsx +'use client'; + +import { useAccount } from 'wagmi'; +import { clickToken } from '../constants/contracts'; + +interface theButtonProps { + // eslint-disable-next-line + writeContract: Function; + awaitingResponse: boolean; + setAwaitingResponse: (value: boolean) => void; +} + +export default function TheButton({ + writeContract, + awaitingResponse, + setAwaitingResponse, +}: theButtonProps) { + const account = useAccount(); + + function handleClick() { + setAwaitingResponse(true); + writeContract({ + abi: clickToken.abi, + address: clickToken.address, + functionName: 'mintTo', + args: [account.address], + gas: 45000, + }); + } + + return ( + <> + {!awaitingResponse && ( + + )} + {awaitingResponse && ( + + )} + + ); +} +``` + +`TopTenDisplay.tsx` + +```tsx +import { useAccount, useReadContract } from 'wagmi'; +import { clickToken } from '../constants/contracts'; +import { useEffect, useState } from 'react'; +import { useQueryClient } from '@tanstack/react-query'; +import { formatUnits } from 'viem'; + +type scoreBoardEntry = { + user: string; + value: bigint; +}; + +interface TopTenDisplayProps { + reloadScores: boolean; + setReloadScores: (value: boolean) => void; +} + +export default function TopTenDisplay({ + reloadScores, + setReloadScores, +}: TopTenDisplayProps) { + const [scores, setScores] = useState([]); + + const account = useAccount(); + const queryClient = useQueryClient(); + + const { data: scoresData, queryKey: getAllScoresQueryKey } = useReadContract({ + abi: clickToken.abi, + address: clickToken.address as `0x${string}`, + functionName: 'getAllScores', + }); + + useEffect(() => { + if (scoresData) { + const sortedScores = scoresData as scoreBoardEntry[]; + // Sort scores in descending order + sortedScores.sort((a, b) => Number(b.value) - Number(a.value)); + + setScores(sortedScores); + } + }, [scoresData]); + + useEffect(() => { + if (reloadScores) { + console.log('Reloading scores...'); + queryClient.invalidateQueries({ queryKey: getAllScoresQueryKey }); + setReloadScores(false); + } + }, [reloadScores]); + + function renderAddress(address: string) { + return address?.slice(0, 5) + '...' + address?.slice(-3); + } + + function renderTopTen() { + if (scores.length === 0 || !account) { + return ( +
    +
  1. Loading...
  2. +
+ ); + } + // Only display the top 10 scores. If the user is in the top 10, bold the item with their score. If not, show it at the bottom with their ranking number + const topTen = scores.length > 10 ? scores.slice(0, 10) : scores; + // myRank is my address's position in the array of scores, +1. If it's not present, my rank is the length of the array + const myRank = + scores.findIndex((entry) => entry.user === account?.address) + 1 || + scores.length + 1; + + const topTenList = topTen.map((entry, index) => { + return ( +
  • + {entry.user === account.address ? ( + + {index + 1} -- {renderAddress(entry.user)} --{' '} + {formatUnits(entry.value, 18)} + + ) : ( + <> + {index + 1} -- {renderAddress(entry.user)} --{' '} + {formatUnits(entry.value, 18)} + + )} +
  • + ); + }); + + // Append my score if myRank is > 10 + if (account?.address && (myRank > 10 || myRank > scores.length)) { + topTenList.push( +
  • + + {myRank} -- {renderAddress(account.address.toString())} --{' '} + {myRank > scores.length + ? 0 + : formatUnits(scores[myRank - 1].value, 18)} + +
  • , + ); + } + + return
      {topTenList}
    ; + } + + return ( +
    +

    Top 10 Scores

    + {renderTopTen()} +
    + ); +} +``` + +`Content.tsx` + +```tsx +'use client'; + +import { useEffect, useState } from 'react'; +import TopTenDisplay from './TopTenDisplay'; +import { + useWaitForTransactionReceipt, + useWriteContract, + useAccount, +} from 'wagmi'; +import TheButton from './TheButton'; + +export default function Content() { + const [reload, setReload] = useState(false); + const [awaitingResponse, setAwaitingResponse] = useState(false); + + const account = useAccount(); + + const { data, writeContract, error: writeError } = useWriteContract(); + + const { data: receipt, error: receiptError } = useWaitForTransactionReceipt({ + hash: data, + }); + + useEffect(() => { + if (receipt) { + console.log('Transaction receipt:', receipt); + setReload(true); + setAwaitingResponse(false); + } + }, [receipt]); + + useEffect(() => { + if (writeError) { + console.error(writeError); + setAwaitingResponse(false); + } + }, [writeError]); + + useEffect(() => { + if (receiptError) { + console.error(receiptError); + setAwaitingResponse(false); + } + }, [receiptError]); + + return ( +
    + {account.address && ( +
    + +
    + )} +
    + {} +
    + ); +} +``` + +Then, import and add `` to `page.tsx`: + +```tsx +return ( + <> +
    + +
    +

    Flow Address: {flowAddress}

    +

    EVM Address: {coa?.address}

    +
    + + {

    {JSON.stringify({ isPending, isError, txId, results })}

    } + + +); +``` + +You'll now see the button and scoreboard from the contract. Test it out and earn a few points! + +![scores](scores.png) + +## Supercharge your EVM App With Cadence + +Now let's supercharge it. With the power of Cadence, you can use multi-call write and give your users way more tokens with a single click and single signature! + +For the first pass, we'll skip some organization best practices. + +Import `clickToken` into `page.tsx` and update `calls` to instead call the `mint` function from the Button Clicker contract. + +```tsx +const calls: EVMBatchCall[] = [ + { + address: clickToken.address, + abi: clickToken.abi as Abi, + functionName: 'mintTo', + args: [coa?.address], + }, +]; +``` + +Try clicking the `Send Batch Transaction Example` button again. You'll have to **manually refresh** the page when the EVM transaction hash appears to see the score update. We haven't wired in the query invalidation yet. + +Next, use some JavaScript to put 10 copies of the transaction call into the array: + +```tsx +const calls: EVMBatchCall[] = Array.from({ length: 10 }, () => ({ + address: clickToken.address, + abi: clickToken.abi as Abi, + functionName: 'mintTo', + args: [coa?.address], +})); +``` + +Click the button again and **manually** refresh page once the transaction hashes appear. + +**You just minted 10 tokens from 10 transactions with one signature!** + +## Improve the UI/UX + +While we've got the batched transactions feature working, we've got a few flaws in the user experience that we'll need to resolve, and we should make this a bit nicer looking. + +### Install Tailwind + +:::warning + +We initially tried getting an AI friend to install this for us and it got very confused. Next.js and Tailwind have both had a lot of change recently. As a result, the LLMs don't seem to have caught up just yet. + +Do this part the old-fashioned way. + +::: + +The components we borrowed already use [Tailwind], so install it: + +```bash +npm install tailwindcss @tailwindcss/postcss postcss +``` + +Then, in the root of the project, add `postcss.config.mjs` and add: + +```tsx +const config = { + plugins: { + '@tailwindcss/postcss': {}, + }, +}; +export default config; +``` + +Then, add the following to the top of `src/styles/global.css`: + +```css +@import 'tailwindcss'; +``` + +Run the app and make sure you see some styling. It won't look nice yet. We'll help you reorganize the components and hook up state monitoring, but it will be up to you to style the app how you'd like. You can check out the [reference repo] for inspiration, but it's far from perfect or beautiful. + +### Update State Display + +The first thing we'll need to fix is that the user has to refresh the window manually to see the results of the batched transaction in the scoreboard. Start by moving the functionality in `page.tsx` into a new component, called `SuperButton.tsx`. Note that we're mimicking the pattern in `TheButton.tsx` where the blockchain state is managed in `Content.tsx` and we're passing in the relevant information and functions as props: + +```tsx +'use client'; + +import { useAccount } from 'wagmi'; +import { clickToken } from '../constants/contracts'; +import { CallOutcome, EVMBatchCall } from '../hooks/useBatchTransaction'; +import { Abi } from 'viem'; + +interface SuperButtonProps { + flowAddress: string | null; + awaitingResponse: boolean; + setAwaitingResponse: (value: boolean) => void; + sendBatchTransaction: (calls: EVMBatchCall[]) => void; + isPending: boolean; + isError: boolean; + txId: string; + results: CallOutcome[]; +} + +export default function SuperButton({ + flowAddress, + awaitingResponse, + setAwaitingResponse, + sendBatchTransaction, + isPending, + isError, + txId, + results, +}: SuperButtonProps) { + const account = useAccount(); + + const calls: EVMBatchCall[] = Array.from({ length: 10 }, () => ({ + address: clickToken.address, + abi: clickToken.abi as Abi, + functionName: 'mintTo', + args: [account?.address], + })); + + function handleClick() { + setAwaitingResponse(true); + sendBatchTransaction(calls); + } + + return ( +
    +
    + With the{' '} + + Flow Wallet + + , you can sign 10 mint transactions at once! +
    + {!awaitingResponse && ( + + )} + {awaitingResponse && ( + + )} + {

    {JSON.stringify({ isPending, isError, txId, results })}

    } +
    + ); +} +``` + +You should end up with a vastly simplified `page.tsx`: + +```tsx +import Content from '../components/Content'; + +function Page() { + return ( + <> + + + ); +} + +export default Page; +``` + +Next, update `Content.tsx`. First, add the decomposition of the `useBatchTransactions` hook that used to be in `page.tsx`. You'll keep blockchain-state-related code here, in a similar pattern to `useWriteTransaction`. + +```tsx +import { useBatchTransaction } from '../hooks/useBatchTransaction'; +``` + +```tsx +const { sendBatchTransaction, isPending, isError, txId, results } = + useBatchTransaction(); +``` + +You'll also need to move the `useEffect` that subscribes to the current user on the Cadence side: + +```tsx +useEffect(() => { + const unsub = fcl.currentUser().subscribe((user: CurrentUser) => { + setFlowAddress(user.addr ?? null); + }); + return () => unsub(); +}, []); +``` + +Then, update the `useEffect` that waits for a `receipt` to also trigger if `results` is updated with the result of a batched transaction: + +```tsx +useEffect(() => { + if (receipt || results.length > 0) { + console.log('Transaction receipt:', receipt); + setReload(true); + setAwaitingResponse(false); + } +}, [receipt, results]); +``` + +Finally, reorganize the `return` into two side-by-side cards and put the new component in the right card: + +```tsx +return ( +
    +
    + +
    +

    Flow Address: {flowAddress}

    +

    EVM Address: {account?.address}

    +
    +
    +
    + {account.address && ( +
    + +
    + )} +
    +
    + +
    + {} +
    +); +``` + +### Testing + +Run the app and make sure it's working as expected, even if in a rather ugly fashion. + +### Add UI Hints + +With this kind of app, you're likely to have two types of users. Those that have upgraded to the [Flow Wallet] can take advantage of advanced features such as batched transactions, and those who haven't cannot. + +It's up to you do design a comprehensive strategy for your app, but here, we can at least let users know what's going on. Add some explainer text, and configure the button to show an appropriate message and disable itself if the wallet won't support it. + +```tsx +
    + With the Flow Wallet, you can sign 10 mint transactions at once! +
    + +``` + +### Styling + +It's up to you to make the app pretty. If you need inspiration, you can always check the [reference repo]. + +## Conclusion + +In this tutorial, you reviewed the demo starter for building hybrid applications that utilize a common EVM stack and integrate with Flow Cadence. You then added functionality to interface with another contract that mints ERC-20 tokens. Finally, you supercharged your app by using the power of Cadence for EVM multi-call contract writes. + +Now that you have completed the tutorial, you should be able to: + +- Build an app that seamlessly integrates Flow Cadence and Flow EVM connections +- Add Cadence features to your [Rainbowkit]/[wagmi]/[viem] app +- Utilize [Flow Client Library (FCL)] to enable multi-call contract writes to Flow EVM + + + +[Cadence]: https://cadence-lang.org/docs +[Next.js]: https://nextjs.org/docs/app/getting-started/installation +[npm]: https://www.npmjs.com/ +[Click to Mint]: https://clicktomint.vercel.app/ +[create an issue]: https://github.com/onflow/docs/issues/new/choose +[Cadence]: https://cadence-lang.org +[Solidity]: https://soliditylang.org/ +[native VRF]: ../../evm/guides/vrf.md +[structure and call EVM transactions]: ./batched-evm-transactions.md +[FLIP 316]: https://github.com/onflow/flips/pull/317 +[Flow Client Library (FCL)]: ../../tools/clients/fcl-js +[wagmi]: https://wagmi.sh/ +[viem]: https://viem.sh/ +[RainbowKit]: https://www.rainbowkit.com/ +[wallet]: ../../ecosystem/wallets.md +[Discord]: https://discord.com/channels/613813861610684416/1162086721471647874 +[FCL + RainbowKit + Wagmi Integration Demo]: https://github.com/jribbink/cross-vm-app +[FCL-JS]: https://github.com/onflow/fcl-js +[Testnet Cadence Flowscan]: https://testnet.flowscan.io +[Cadence Owned Accounts]: ../../build/basics/accounts.md +[Testnet EVM Flowscan]: https://evm-testnet.flowscan.io +[Button Clicker Contract]: https://github.com/briandoyle81/button-clicker-contract/blob/main/contracts/ClickToken.sol +[`0xA7Cf2260e501952c71189D04FAd17c704DFB36e6`]: https://evm-testnet.flowscan.io/address/0xA7Cf2260e501952c71189D04FAd17c704DFB36e6?tab=contract +[Tailwind]: https://tailwindcss.com/ +[reference repo]: https://github.com/briandoyle81/cross-vm-app-1/tree/main + + +=== tutorials/cross-vm-apps/interacting-with-coa.md === +--- +title: Interacting with COAs from Cadence +sidebar_label: Interacting with COAs +sidebar_position: 4 +--- + +[Cadence Owned Accounts (COAs)](../../evm/accounts.md#cadence-owned-accounts) are EVM accounts owned by a Cadence resource and +are used to interact with Flow EVM from Cadence. + +COAs expose two interfaces for interaction: one on the Cadence side and one on the EVM side. In this guide, we will +focus on how to interact with COAs with Cadence. + +In this guide we will walk through some basic examples creating and interacting with a COA in Cadence. Your specific +usage of the COA resource will depend on your own application's requirements (e.g. the COA resource may not live +directly in `/storage/evm` as in these examples, but may instead be a part of a more complex resource structure). + +## COA Interface + +To begin, we can take a look at a simplified version of the `EVM` contract, highlighting parts specific to COAs. + +You can learn more about the `EVM` contract [here](../../build/core-contracts/13-evm.md) and the full contract code can +be found on [GitHub](https://github.com/onflow/flow-go/tree/master/fvm/evm/stdlib/contract.cdc). + +```cadence EVM.cdc +access(all) +contract EVM { + //... + access(all) + resource CadenceOwnedAccount: Addressable { + /// The EVM address of the cadence owned account + /// -> could be used to query balance, code, nonce, etc. + access(all) + view fun address(): EVM.EVMAddress + + /// Get balance of the cadence owned account + /// This balance + access(all) + view fun balance(): EVM.Balance + + /// Deposits the given vault into the cadence owned account's balance + access(all) + fun deposit(from: @FlowToken.Vault) + + /// The EVM address of the cadence owned account behind an entitlement, acting as proof of access + access(EVM.Owner | EVM.Validate) + view fun protectedAddress(): EVM.EVMAddress + + /// Withdraws the balance from the cadence owned account's balance + /// Note that amounts smaller than 10nF (10e-8) can't be withdrawn + /// given that Flow Token Vaults use UFix64s to store balances. + /// If the given balance conversion to UFix64 results in + /// rounding error, this function would fail. + access(EVM.Owner | EVM.Withdraw) + fun withdraw(balance: EVM.Balance): @FlowToken.Vault + + /// Deploys a contract to the EVM environment. + /// Returns the address of the newly deployed contract + access(EVM.Owner | EVM.Deploy) + fun deploy( + code: [UInt8], + gasLimit: UInt64, + value: Balance + ): EVM.EVMAddress + + /// Calls a function with the given data. + /// The execution is limited by the given amount of gas + access(EVM.Owner | EVM.Call) + fun call( + to: EVMAddress, + data: [UInt8], + gasLimit: UInt64, + value: Balance + ): EVM.Result + } + + // Create a new CadenceOwnedAccount resource + access(all) + fun createCadenceOwnedAccount(): @EVM.CadenceOwnedAccount + // ... +} +``` + +## Importing the EVM Contract + +The `CadenceOwnedAccount` resource is a part of the `EVM` system contract, so to use any of these functions, you will +need to begin by importing the `EVM` contract into your Cadence code. + +To import the `EVM` contract into your Cadence code using the simple import syntax, you can use the following format +(learn more about configuring contracts in `flow.json` +[here](../../tools/flow-cli/flow.json/configuration.md#contracts)): + +```cadence +// This assumes you are working in the in the Flow CLI, FCL, or another tool that supports this syntax +// The contract address should be configured in your project's `flow.json` file +import "EVM" +// ... +``` + +However, if you wish to use manual address imports instead, you can use the following format: + +```cadence +// Must use the correct address based on the network you are interacting with +import EVM from 0x1234 +// ... +``` + +To find the deployment addresses of the `EVM` contract, you can refer to the [EVM contract +documentation](../../build/core-contracts/13-evm.md). + +## Creating a COA + +To create a COA, we can use the `createCadenceOwnedAccount` function from the `EVM` contract. This function takes no +arguments and returns a new `CadenceOwnedAccount` resource which represents this newly created EVM account. + +For example, we can create this COA in a transaction, saving it to the user's storage and publishing a public capability +to its reference: + +```cadence create_coa.cdc +import "EVM" + +// Note that this is a simplified example & will not handle cases where the COA already exists +transaction() { + prepare(signer: auth(SaveValue, IssueStorageCapabilityController, PublishCapability) &Account) { + let storagePath = /storage/evm + let publicPath = /public/evm + + // Create account & save to storage + let coa: @EVM.CadenceOwnedAccount <- EVM.createCadenceOwnedAccount() + signer.storage.save(<-coa, to: storagePath) + + // Publish a public capability to the COA + let cap = signer.capabilities.storage.issue<&EVM.CadenceOwnedAccount>(storagePath) + signer.capabilities.publish(cap, at: publicPath) + } +} +``` + +## Getting the EVM Address of a COA + +To get the EVM address of a COA, you can use the `address` function from the `EVM` contract. This function returns the +EVM address of the COA as an `EVM.Address` struct. This struct is used to represent addresses within Flow EVM and can +also be used to query the balance, code, nonce, etc. of an account. + +For our example, we could query the address of the COA we just created with the following script: + +```cadence get_coa_address.cdc +import "EVM" + +access(all) +fun main(address: Address): EVM.EVMAddress { + // Get the desired Flow account holding the COA in storage + let account = getAuthAccount(address) + + // Borrow a reference to the COA from the storage location we saved it to + let coa = account.storage.borrow<&EVM.CadenceOwnedAccount>( + from: /storage/evm + ) ?? panic("Could not borrow reference to the signer's CadenceOwnedAccount (COA). " + .concat("Ensure the signer account has a COA stored in the canonical /storage/evm path")) + + // Return the EVM address of the COA + return coa.address() +} +``` + +If you'd prefer the hex representation of the address, you instead return using the `EVMAddress.toString()` function: + +```cadence +return coa.address().toString() +``` + +The above will return the EVM address as a string; however note that Cadence does not prefix hex strings with `0x`. + +## Getting the Flow Balance of a COA + +Like any other Flow EVM or Cadence account, COAs possess a balance of FLOW tokens. To get the current balance of our +COA, we can use the COA's `balance` function. It will return a `EVM.Balance` struct for the account - these are used to +represent balances within Flow EVM. + +This script will query the current balance of our newly created COA: + +```cadence get_coa_balance.cdc +import "EVM" + +access(all) +fun main(address: Address): EVM.Balance { + // Get the desired Flow account holding the COA in storage + let account = getAuthAccount(address) + + // Borrow a reference to the COA from the storage location we saved it to + let coa = account.storage.borrow<&EVM.CadenceOwnedAccount>( + from: /storage/evm + ) ?? panic("Could not borrow reference to the signer's CadenceOwnedAccount (COA). " + .concat("Ensure the signer account has a COA stored in the canonical /storage/evm path")) + + // Get the current balance of this COA + return coa.balance() +} +``` + +You can also easily get the `UFix64` FLOW balance of any EVM address with this script: + +```cadence get_coa_balance_as_ufix64.cdc +import "EVM" + +access(all) +fun main(addressHex: String): UFix64 { + let addr = EVM.addressFromString(addressHex) + return addr.balance().inFLOW() +} +``` + +The above script is helpful if you already know the COA address and can provide the hex representation directly. + +## Depositing and Withdrawing Flow Tokens + +Tokens can be seamlessly transferred between the Flow EVM and Cadence environment using the `deposit` and `withdraw` +functions provided by the COA resource. Anybody with a valid reference to a COA may deposit Flow tokens into a it, +however only someone with the `Owner` or `Withdraw` entitlements can withdraw tokens. + +### Depositing Flow Tokens + +The `deposit` function takes a `FlowToken.Vault` resource as an argument, representing the tokens to deposit. It will +transfer the tokens from the vault into the COA's balance. + +This transaction will withdraw Flow tokens from a user's Cadence vault and deposit them into their COA: + +```cadence deposit_to_coa.cdc +import "EVM" +import "FungibleToken" +import "FlowToken" + +transaction(amount: UFix64) { + let coa: &EVM.CadenceOwnedAccount + let sentVault: @FlowToken.Vault + + prepare(signer: auth(BorrowValue) &Account) { + // Borrow the public capability to the COA from the desired account + // This script could be modified to deposit into any account with a `EVM.CadenceOwnedAccount` capability + self.coa = signer.capabilities.borrow<&EVM.CadenceOwnedAccount>(/public/evm) + ?? panic("Could not borrow reference to the signer's CadenceOwnedAccount (COA). " + .concat("Ensure the signer account has a COA stored in the canonical /storage/evm path")) + + // Withdraw the balance from the COA, we will use this later to deposit into the receiving account + let vaultRef = signer.storage.borrow( + from: /storage/flowTokenVault + ) ?? panic("Could not borrow reference to the owner's FlowToken Vault") + self.sentVault <- vaultRef.withdraw(amount: amount) as! @FlowToken.Vault + } + + execute { + // Deposit the withdrawn tokens into the COA + self.coa.deposit(from: <-self.sentVault) + } +} +``` + +:::info + +This is a basic example which only transfers tokens between a single user's COA & Flow account. It can be easily +modified to transfer these tokens between any arbitrary accounts. + +You can also deposit tokens directly into other types of EVM accounts using the `EVM.EVMAddress.deposit` function. See +the [EVM contract documentation](../../build/core-contracts/13-evm.md) for more information. + +::: + +### Withdrawing Flow Tokens + +The `withdraw` function takes a `EVM.Balance` struct as an argument, representing the amount of Flow tokens to withdraw, +and returns a `FlowToken.Vault` resource with the withdrawn tokens. + +We can run the following transaction to withdraw Flow tokens from a user's COA and deposit them into their Flow vault: + +```cadence withdraw_from_coa.cdc +import "EVM" +import "FungibleToken" +import "FlowToken" + +transaction(amount: UFix64) { + let sentVault: @FlowToken.Vault + let receiver: &{FungibleToken.Receiver} + + prepare(signer: auth(BorrowValue) &Account) { + // Borrow a reference to the COA from the storage location we saved it to with the `EVM.Withdraw` entitlement + let coa = signer.storage.borrow( + from: /storage/evm + ) ?? panic("Could not borrow reference to the signer's CadenceOwnedAccount (COA). " + .concat("Ensure the signer account has a COA stored in the canonical /storage/evm path")) + + // We must create a `EVM.Balance` struct to represent the amount of Flow tokens to withdraw + let withdrawBalance = EVM.Balance(attoflow: 0) + withdrawBalance.setFLOW(flow: amount) + + // Withdraw the balance from the COA, we will use this later to deposit into the receiving account + self.sentVault <- coa.withdraw(balance: withdrawBalance) as! @FlowToken.Vault + + // Borrow the public capability to the receiving account (in this case the signer's own Vault) + // This script could be modified to deposit into any account with a `FungibleToken.Receiver` capability + self.receiver = signer.capabilities.borrow<&{FungibleToken.Receiver}>(/public/flowTokenReceiver)! + } + + execute { + // Deposit the withdrawn tokens into the receiving vault + self.receiver.deposit(from: <-self.sentVault) + } +} +``` + +:::info + +This is a basic example which only transfers tokens between a single user's COA & Flow account. It can be easily +modified to transfer these tokens between any arbitrary accounts. + +::: + +## Direct Calls to Flow EVM + +To interact with smart contracts on the EVM, you can use the `call` function provided by the COA resource. This function +takes the EVM address of the contract you want to call, the data you want to send, the gas limit, and the value you want +to send. It will return a `EVM.Result` struct with the result of the call - you will need to handle this result in your +Cadence code. + +This transaction will use the signer's COA to call a contract method with the defined signature and args at a given EVM +address, executing with the provided gas limit and value: + +```cadence call.cdc +import "EVM" + +/// Calls the function with the provided signature and args at the target contract address using +/// the defined gas limit and transmitting the provided value. +transaction(evmContractHex: String, signature: String, args: [AnyStruct], gasLimit: UInt64, flowValue: UInt) { + let coa: auth(EVM.Call) &EVM.CadenceOwnedAccount + + prepare(signer: auth(BorrowValue) &Account) { + // Borrow an entitled reference to the COA from the storage location we saved it to + self.coa = signer.storage.borrow( + from: /storage/evm + ) ?? panic("Could not borrow reference to the signer's CadenceOwnedAccount (COA). " + .concat("Ensure the signer account has a COA stored in the canonical /storage/evm path")) + } + + execute { + // Deserialize the EVM address from the hex string + let contractAddress = EVM.addressFromString(evmContractHex) + // Construct the calldata from the signature and arguments + let calldata = EVM.encodeABIWithSignature( + signature, + args + ) + // Define the value as EVM.Balance struct + let value = EVM.Balance(attoflow: flowValue) + // Call the contract at the given EVM address with the given data, gas limit, and value + // These values could be configured through the transaction arguments or other means + // however, for simplicity, we will hardcode them here + let result: EVM.Result = self.coa.call( + to: contractAddress, + data: calldata, + gasLimit: gasLimit, + value: value + ) + + // Revert the transaction if the call was not successful + // Note: a failing EVM call will not automatically revert the Cadence transaction + // and it is up to the developer to use this result however it suits their application + assert( + result.status == EVM.Status.successful, + message: "EVM call to ".concat(evmContractHex) + .concat(" and signature ").concat(signature) + .concat(" failed with error code ").concat(result.errorCode.toString()) + .concat(": ").concat(result.errorMessage) + ) + } +} +``` + +:::info + +Notice that the calldata is encoded in the scope of the transaction. While developers can encode the calldata +outside the scope of the transaction and pass the encoded data as an argument, doing so compromises the +human-readability of Cadence transactions. + +It's encouraged to either define transactions for each COA call and encoded the hardcoded EVM signature and arguments, +or to pass in the human-readable arguments and signature and encode the calldata within the transaction. This ensures a +more interpretable and therefore transparent transaction. + +::: + +### Transferring FLOW in EVM + +Similar to transferring ETH and other native value in other EVMs, you'll want to call to the target EVM address with +empty calldata and providing the transfer value. + +```cadence transfer_evm_flow.cdc +import "EVM" + +/// Transfers FLOW to another EVM address from the signer's COA +/// +/// @param to: the serialized EVM address of the recipient +/// @param amount: the amount of FLOW to send +transaction(to: String, amount: UInt) { + + let recipient: EVM.EVMAddress + let recipientPreBalance: UInt + let coa: auth(EVM.Call) &EVM.CadenceOwnedAccount + + prepare(signer: auth(BorrowValue) &Account) { + self.recipient = EVM.addressFromString(to) + self.recipientPreBalance = self.recipient.balance().attoflow + self.coa = signer.storage.borrow(from: /storage/evm) + ?? panic("Could not borrow reference to the signer's CadenceOwnedAccount (COA). " + .concat("Ensure the signer account has a COA stored in the canonical /storage/evm path")) + } + + execute { + let res = self.coa.call( + to: self.recipient, + data: [], + gasLimit: 100_000, + value: EVM.Balance(attoflow: amount) + ) + + assert( + res.status == EVM.Status.successful, + message: "Failed to transfer FLOW to EVM address with error code ".concat(res.errorCode.toString()) + .concat(": ").concat(res.errorMessage) + ) + } + + post { + self.recipient.balance().attoflow == self.recipientPreBalance + amount: + "Expected final balance ".concat((self.recipientPreBalance + amount).toString()) + .concat(" but found actual balance ").concat(self.recipient.balance().attoflow.toString()) + .concat(" after deposit of ").concat(amount.toString()) + } +} +``` + +### Transfer ERC20 + +Below is an example transaction demonstrating the common ERC20 transfer. A similar pattern can be used for other +arbitrary EVM calls. + +```cadence erc20_transfer_from.cdc +import "EVM" + +/// Transfers ERC20 tokens from the signer's COA to the named recipient in the amount provided +/// +/// @param erc20AddressHex: the serialized EVM address of the ERC20 contract +/// @param to: the serialized EVM address of the recipient +/// @param amount: the amount of tokens to send +transaction(erc20AddressHex: String, to: String, amount: UInt256) { + let coa: auth(EVM.Call) &EVM.CadenceOwnedAccount + + prepare(signer: auth(BorrowValue) &Account) { + // Borrow an entitled reference to the COA from the canonical storage location + self.coa = signer.storage.borrow( + from: /storage/evm + ) ?? panic("Could not borrow reference to the signer's CadenceOwnedAccount (COA). " + .concat("Ensure the signer account has a COA stored in the canonical /storage/evm path")) + } + + execute { + // Encode the calldata for the ERC20 transfer + let calldata = EVM.encodeABIWithSignature( + "transfer(address,uint256)", // function signature + [EVM.addressFromString(to), amount] // function args + ) + // Call the contract at the given ERC20 address with encoded calldata and 0 value + let result: EVM.Result = self.coa.call( + to: EVM.addressFromString(erc20AddressHex), // deserialized address + data: calldata, // encoded calldata + gasLimit: 100_000, // 100k gas should cover most erc20 transfers + value: EVM.Balance(attoflow: UInt(0)) // no value required in most cases + ) + + // Revert the transaction if the call was not successful + // Note: a failing EVM call will not automatically revert the Cadence transaction + // and it is up to the developer to use this result however it suits their application + assert( + result.status == EVM.Status.successful, + message: "ERC20.transfer call failed with error code: ".concat(result.errorCode.toString()) + .concat(": ").concat(result.errorMessage) + ) + } +} +``` + +### Transfer ERC721 + +Following on from above, the example transaction below demonstrates a common ERC721 transfer. + +```cadence erc721_transfer.cdc +import "EVM" + +/// Transfers an ERC721 token from the signer's COA to the named recipient +/// +/// @param erc721AddressHex: the serialized EVM address of the ERC721 contract +/// @param to: the serialized EVM address of the recipient +/// @param id: the token ID to send from the signer's COA to the recipient +transaction(erc721AddressHex: String, to: String, id: UInt256) { + let coa: auth(EVM.Call) &EVM.CadenceOwnedAccount + + prepare(signer: auth(BorrowValue) &Account) { + // Borrow an entitled reference to the COA from the canonical storage location + self.coa = signer.storage.borrow( + from: /storage/evm + ) ?? panic("Could not borrow reference to the signer's CadenceOwnedAccount (COA). " + .concat("Ensure the signer account has a COA stored in the canonical /storage/evm path")) + } + + execute { + let calldata = EVM.encodeABIWithSignature( + "safeTransferFrom(address,address,uint256)", + [self.coa.address(), EVM.addressFromString(to), id] + ) + // Call the contract at the given ERC721 address with encoded calldata and 0 value + let result: EVM.Result = self.coa.call( + to: EVM.addressFromString(erc721AddressHex), // deserialized address + data: calldata // previously encoded calldata + gasLimit: 100_000, // 100k gas should cover most erc721 transfers + value: EVM.Balance(attoflow: UInt(0)) // no value required in most cases + ) + + // Revert the transaction if the call was not successful + // Note: a failing EVM call will not automatically revert the Cadence transaction + // and it is up to the developer to use this result however it suits their application + assert( + result.status == EVM.Status.successful, + message: "ERC721.safeTransferFrom call failed with error code: ".concat(result.errorCode.toString()) + .concat(": ").concat(result.errorMessage) + ) + } +} +``` + +#### Bulk Transfer ERC721 + +As covered in the [Batched EVM transactions walkthrough](./batched-evm-transactions.md), you can script multiple EVM +calls in a single Cadence transaction. Compared to the single ERC721 transfer, bulk sending multiple tokens isn't much +more code and allows for greater utility out of a single transaction. Below is an example of a bulk ERC721 token +transfer. + +```cadence erc721_bulk_transfer.cdc +import "EVM" + +/// Bulk transfers ERC721 tokens from the signer's COA to the named recipient. All tokens must be from +/// the same collection and sent to the same recipient. +/// +/// @param erc721AddressHex: the serialized EVM address of the ERC721 contract +/// @param to: the serialized EVM address of the recipient +/// @param ids: an array of IDs to send from the signer's COA to the recipient +transaction(erc721AddressHex: String, to: String, ids: [UInt256]) { + let coa: auth(EVM.Call) &EVM.CadenceOwnedAccount + + prepare(signer: auth(BorrowValue) &Account) { + // Borrow an entitled reference to the COA from the canonical storage location + self.coa = signer.storage.borrow( + from: /storage/evm + ) ?? panic("Could not borrow reference to the signer's CadenceOwnedAccount (COA). " + .concat("Ensure the signer account has a COA stored in the canonical /storage/evm path")) + } + + execute { + // Iterate over provided IDs. Note the whole transaction fails if a single transfer fails, + // so ownership validation is recommended before executing. Alternatively, you could remove + // the assertion on success below and continue iteration on call failure. + for id in ids { + let calldata = EVM.encodeABIWithSignature( + "safeTransferFrom(address,address,uint256)", + [self.coa.address(), EVM.addressFromString(to), id] + ) + // Call the contract at the given ERC721 address with encoded calldata and 0 value + let result: EVM.Result = self.coa.call( + to: EVM.addressFromString(erc721AddressHex), // deserialized address + data: calldata // previously encoded calldata + gasLimit: 100_000, // 100k gas should cover most erc721 transfers + value: EVM.Balance(attoflow: UInt(0)) // no value required in most cases + ) + + // Revert the transaction if the transfer was not successful + // Note: a failing EVM call will not automatically revert the Cadence transaction + // and it is up to the developer to use this result however it suits their application + assert( + result.status == EVM.Status.successful, + message: "ERC721.safeTransferFrom call failed on id ".concat(id.toString()) + .concat(" with error code: ").concat(result.errorCode.toString()) + .concat(": ").concat(result.errorMessage) + ) + } + } +} +``` + +## Deploying a Contract to Flow EVM + +To deploy a contract to the EVM, you can use the `deploy` function provided by the COA resource. This function takes the +contract code, gas limit, and value you want to send. It will return the EVM address of the newly deployed contract. + +This transaction will deploy a contract with the given code using the signer's COA: + +```cadence deploy_evm_contract.cdc +import "EVM" + +transaction(bytecode: String) { + let coa: auth(EVM.Deploy) &EVM.CadenceOwnedAccount + + prepare(signer: auth(BorrowValue) &Account) { + // Borrow an entitled reference to the COA from the storage location we saved it to + self.coa = signer.storage.borrow( + from: /storage/evm + ) ?? panic("Could not borrow reference to the signer's CadenceOwnedAccount (COA). " + .concat("Ensure the signer account has a COA stored in the canonical /storage/evm path")) + } + + execute { + // Deploy the contract with the given compiled bytecode, gas limit, and value + self.coa.deploy( + code: bytecode.decodeHex(), + gasLimit: 15_000_000, // can be adjusted as needed, hard coded here for simplicity + value: EVM.Balance(attoflow: 0) + ) + } +} +``` + +## More Information + +For more information about Cadence Owned Accounts, see [Flow EVM Accounts](../../evm/accounts.md). + +Other useful snippets for interacting with COAs can be found [here](https://fw-internal-doc.gitbook.io/evm). + +Check out the [Batched EVM Transactions walkthrough](./batched-evm-transactions.md) for details on transaction batching +using Cadence. + + +=== tutorials/cross-vm-apps/index.md === +--- +title: Cross-VM Apps +description: A series of tutorials on building cross-VM applications that integrate Flow EVM with Flow Cadence. +sidebar_position: 3 +keywords: + - hybrid apps + - cross-vm apps + - Flow EVM + - Flow Cadence + - tutorials + - COAs + - batched transactions + - VM bridge + - cross-VM bridge +--- + +# Cross-VM App Tutorials + +This series covers how to build cross-VM applications that integrate Flow EVM with Flow Cadence, unlocking new capabilities by combining both environments. + +## Tutorials + +- **[Batched Transactions]** - Learn how to use FCL with wagmi and RainbowKit to create a cross-VM app. +- **[Add Flow Cadence to Your wagmi App]** - Learn how to integrate Flow Cadence with your existing wagmi/RainbowKit application to enable batch transactions and other Cadence features. +- **[Interacting with COAs]** - Learn how to create and interact with Cadence Owned Accounts (COAs) to control EVM accounts from Cadence. +- **[Batched EVM Transactions]** - Discover how to batch multiple EVM transactions into a single Cadence transaction. +- **[Cross-VM Bridge]** - Explore how to bridge fungible and non-fungible tokens between Cadence and EVM environments. + +## More Coming Soon + +Stay tuned—more tutorials and advanced guides are on the way! + +[Batched Transactions]: ./introduction.md +[Interacting with COAs]: ./interacting-with-coa.md +[Batched EVM Transactions]: ./batched-evm-transactions.md +[Cross-VM Bridge]: ./vm-bridge.md +[Add Flow Cadence to Your wagmi App]: ./add-to-wagmi.md + + +=== tutorials/cross-vm-apps/direct-calls.md === +--- +title: Direct Calls from Cadence to Flow EVM +sidebar_label: Direct Calls to Flow EVM +sidebar_position: 5 +--- + +Direct calls from Cadence to Flow EVM are essential for enabling Cadence smart contracts to interact seamlessly with the EVM environment hosted on the Flow blockchain. These calls facilitate a range of functionalities including state queries and transaction initiations, allowing Cadence contracts to leverage EVM-based tools and assets. + +## Making Direct Calls + +### Accessing Flow EVM + +To interact with Flow EVM, Cadence contracts must first import `EVM` from its service address: + +```js +import EVM from +``` + +Next, create an `EVMAddress` with a sequence of 20 bytes representing the EVM address: + +```js +let addr = EVM.EVMAddress(bytes: bytes) +``` + +Once you have access to an `EVMAddress`, you can query various pieces of state information such as: + +- `balance() EVM.Balance` provides the balance of the address. It returns a balance object rather than a basic type to avoid errors when converting from flow to atto-flow. +- `nonce() UInt64` retrieves the nonce associated with the address. +- `code(): [UInt8]` fetches the code at the address; it returns the smart contract code if applicable, and is empty otherwise. + +```cadence +import EVM from + +access(all) +fun main(bytes: [UInt8; 20]): EVM.Balance { + let addr = EVM.EVMAddress(bytes: bytes) + let bal = addr.balance() + return bal +} +``` + +Alternatively, you can use the EVM contract's native deserialization to access the balance provided a hex string representing the address: + +```cadence +import EVM from + +access(all) +fun main(addressHex: String): UFix64 { + let addr = EVM.addressFromString(addressHex) + return addr.balance().inFLOW() +} +``` + +### Sending Transactions to Flow EVM + +To send transactions to Flow EVM, use the `run` function which executes RLP-encoded transactions. RLP (Recursive Length Prefix) encoding is used to efficiently encode data into a byte-array format, suitable for Ethereum-based environments. Here's an example of wrapping and sending a transaction: + +```cadence +import EVM from + +transaction(rlpEncodedTransaction: [UInt8], coinbaseBytes: [UInt8; 20]) { + + prepare(signer: &Account) { + let coinbase = EVM.EVMAddress(bytes: coinbaseBytes) + let result = EVM.run(tx: rlpEncodedTransaction, coinbase: coinbase) + assert( + runResult.status == EVM.Status.successful, + message: "tx was not executed successfully." + ) + } +} +``` + +Using `run` restricts an EVM block to a single EVM transaction, while a future `batchRun` will offer the capability to execute multiple EVM transactions in a batch. + +### Handling Transaction Responses + +Handling responses correctly is crucial to manage the state changes or errors that occur during `EVM` transactions: + +When calling `EVM.run`, it's important to understand that this method does not revert the outer Flow transaction. Developers must therefore carefully handle the response based on the `result.Status` of the EVM transaction execution. There are three main outcomes to consider: + +- `Status.invalid`: This status indicates that the transaction or call failed at the validation step, such as due to a nonce mismatch. Transactions with this status are not executed or included in a block, meaning no state change occurs. +- `Status.failed`: This status is assigned when the transaction has technically succeeded in terms of being processable, but the EVM reports an error as the outcome, such as running out of gas. Importantly, a failed transaction or call is still included in a block. Attempting to resubmit a failed transaction will result in an `invalid` status on the second try due to a now incorrect nonce. +- `Status.successful`: This status is given when the transaction or call is successfully executed and no errors are reported by the EVM. + +For scenarios where transaction validity is critical, developers may choose to use the `mustRun` variation, which reverts the transaction in the case of a validation failure, providing an added layer of error handling. + +### Understanding Gas Usage in EVM Transactions + +Direct calls to Flow EVM require gas, it's important to understand how gas usage is calculated and billed. During the execution of methods that interact with the EVM: + +- **Gas Aggregation**: The gas used by each call is aggregated throughout the transaction. +- **Gas Adjustment**: The total gas used is then adjusted based on a multiplier. This multiplier is determined by the network and can be adjusted by the service account to reflect operational costs and network conditions. +- **Payment of Gas Fees**: The adjusted total gas amount is added to the overall computation fees of the Flow transaction. These fees are paid by the transaction initiator, commonly referred to as the payer. + +## Keep Learning + +For more information and a deeper dive into the `EVMAddress`, `Result`, and `Status` objects, see [the contract here](https://github.com/onflow/flow-go/blob/master/fvm/evm/stdlib/contract.cdc). + + +=== tutorials/cross-vm-apps/batched-evm-transactions.md === +--- +title: Batched EVM Transactions Using Cadence +sidebar_label: Batched EVM Transactions +sidebar_position: 6 +--- + +Integrating Cadence into EVM applications on Flow enables developers to leverage the best of both worlds. This guide +demonstrates how to batch EVM transactions using Cadence, allowing applications to embed multiple EVM transactions in a +single Cadence transaction while conditioning final execution on the success of all EVM transactions. + +This feature can supercharge your EVM application by unlocking experiences otherwise impossible on traditional EVM +platforms. + +## Objectives + +After completing this guide, you'll be able to + +- Construct a Cadence transaction that executes several EVM transactions such that if any EVM transaction fails, the + entire set will revert +- Read and write from smart contract functions on [EVM Flowscan] +- Run a Cadence transaction from the browser using [Flow Runner] +- Install conceptual understanding of Cadence X EVM interactions +- Inspect multiple EVM transactions embedded in a Cadence transaction with [Flowscan] block explorer +- Write code that interacts with the EVM via a CadenceOwnedAccount (COA) + +## Prerequisites + +Before you dive in, make sure you have the following configured: + +- [MetaMask] installed in your browser with an active account +- [Flow Wallet extension] installed in your browser with an active account +- Both wallets funded with Testnet FLOW. See the [Faucet guide] for more information. + +## Overview + +For the purposes of demonstration, this walkthrough will focus on relatively simple EVM operations in addition to first +creating a [Cadence-controlled EVM account (COA)]. Specifically, we will: + +- Wrap FLOW as WFLOW +- Approve an ERC721 to transfer WFLOW in exchange for an NFT mint +- Mint an ERC721 token - this ERC721 has a 50% chance of failing (using [onchain VRF] to determine success) + +These operations let us focus on the **core concepts** of this guide: + +1. **Batching EVM transactions** using Cadence +2. **Conditioning execution** on the results of those EVM transactions. + +However, using these same principles, you'll have the power to address more complex use cases. For instance, replace +wrapping FLOW with a DEX swap. Or instead of minting an ERC721, purchase an NFT listing from a marketplace. Combine +these two and suddenly you can purchase NFTs with any ERC20 token, all in a single Cadence transaction, reverting +everything if a single step fails. + +The point is, while a simple use case, this guide will give you the tools to build much more complex and interesting +applications. So let's get started! + +## Components + +As mentioned in the [Overview], this guide involves three main actions: + +- Wrapping FLOW as WFLOW +- Approving an ERC721 to transfer WFLOW in exchange for an NFT mint +- Minting an ERC721 token + +Before interacting with these contracts, let's dig bit more into the components of this guide. + +### Wrap FLOW as WFLOW + +On Flow EVM, FLOW is the native currency and similar to other EVM platforms, the native currency is not accessible as an +ERC20 token. To interact with ERC20 contracts, you need to wrap FLOW as WFLOW (Wrapped FLOW). This is Flow's equivalent +of WETH on Ethereum. + +:::tip + +You can find WFLOW deployed to `0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e` on Flow [Testnet] & [Mainnet] and source +code in the [`@onflow/flow-sol-utils` repository]. + +::: + +### Approve ERC721 Transfer + +Our example `MaybeMintERC721` contract accepts WFLOW in exchange for minting an NFT. However, the contract cannot move +WFLOW without your permission. To allow the contract to move your WFLOW, you must approve the contract to transfer +enough of your WFLOW to mint the NFT. + +### Mint ERC721 Token + +Finally, we'll mint an ERC721 token using the `MaybeMintERC721` contract. This contract has a 50% chance of failing, +simulating a real-world scenario where purchasing an NFT might fail - say a listing was purchased before your +transaction was processed. + +Importantly, if this transaction fails, we want to revert the entire sequence of transactions. After all, you wrapped +FLOW to WFLOW and approved the ERC721 transfer specifically to mint this NFT. If the mint fails, you want to unwind +everything. As we'll see shortly, this is where batching EVM transactions using Cadence is extremely powerful. + +## Interacting with the Contracts + +Before taking the easy route, let's first interact with the contracts individually to better understand the process and +status quo user experience. Realistically, this is your only option for completing the whole process on other EVM +platforms. + +:::tip + +Recall in [Prerequisites] that you need to have both [MetaMask] and [Flow Wallet extension] installed and funded with +Testnet FLOW. Make sure you've done so before proceeding. + +::: + +### Using MetaMask + +#### 1. Wrap FLOW + +Our first action will be to wrap enough FLOW to cover the cost of minting the `MaybeMintERC721` token. To do this, we'll +interact with the `WFLOW` contract on Testnet. There are a number of ways we could interact with this contract - Remix +IDE, Foundry's CLI, Hardhat, etc. - but for the purposes of this guide, we'll use the [Flowscan EVM block explorer]. + +Navigate to the WFLOW Testnet contract on Flowscan: [WFLOW]. Ensure you're on the `Write Contract` tab which allows you +to interact with the contract's mutating functions. + +Before you can interact with the contract, you need to connect your MetaMask wallet to the [Flowscan EVM block +explorer]. Click the `Connect` button in the top right corner and follow the prompts to connect your MetaMask wallet. + +:::warning + +There are two **separate** block explorers for Flow - one for Cadence activity and another for EVM activity. This is +unique to Flow and is due to the fact that Cadence & EVM are separate runtimes, with EVM effectively emulated within +Cadence. This orientation - that of EVM running within Cadence - means that the Cadence-side explorer has visibility to +EVM transactions embedded within a Cadence transaction. + +Practically, this means that any transactions ran using a Flow native account can be viewed on the Cadence explorer +while any transactions run using an EVM account can be viewed on the EVM explorer. + +::: + +![Connect wallet to Flowscan](./flowscan-connect.png) + +Once connected, you should see your address in the top right corner and above the contract's functions. + +Now we can wrap FLOW. Click on the `deposit` method which will drop down an input field for the amount of FLOW you want +to wrap. The mint amount for the `MaybeMintERC721` contract is 1 whole FLOW which in EVM terms is `1e18 wei` - `wei` +being the smallest unit of an EVM's native currency (inherited from Ethereum's units - more on Ether units [here]). + +As shown below, put `1 000 000 000 000 000 000` in the input field for `deposit`. + +![Deposit 1 FLOW to WFLOW contract](./wflow-deposit.png) + +You can now click the `Write` button to submit the transaction. Once MetaMask prompts you to sign the transaction, click +`Confirm` and give it a few seconds to process. + +
    +![Confirm WFLOW deposit in MetaMask](./wflow-deposit-confirm.png) +
    + +Once confirmed, you should be able to see WFLOW balance in your tokens list in MetaMask - if not, you can click on +`Import Tokens` and paste the WFLOW contract address found on the Flowscan page and refresh your list. + +
    +![WFLOW in MetaMask](./wflow-in-metamask-tokens.png) +
    + +#### 2. Approve WFLOW Transfer + +Now that you have your WFLOW, you'll need to approve the `MaybeMintERC721` contract to transfer your WFLOW. From the +same WFLOW page in Flowscan, click on the `approve` method. This time, you'll need to input the `MaybeMintERC721` +contract address - `0x2E2Ed0Cfd3AD2f1d34481277b3204d807Ca2F8c2` - and the amount of WFLOW you want to approve - again `1 +000 000 000 000 000 000` WFLOW. + +![Approve MaybeMintERC721 for 1 WFLOW in Flowscan](./wflow-approve.png) + +Click `Write` to submit the transaction. To be clear, this does not complete a transfer, but allows the +`MaybeMintERC721` contract to transfer your WFLOW on your behalf which will execute in the next step. + +#### 3. Mint ERC721 Token + +Finally, we'll attempt to mint the ERC721 token using the `MaybeMintERC721` contract. Navigate to the `MaybeMintERC721` +contract on Flowscan: [MaybeMintERC721]. + +Again, you'll be met with the contract functions on the `Write Contract` tab. Click on the `mint` function which takes +no arguments - just click on `Write` and then `Confirm` in the resulting MetaMask window. + +This contract has a 50% chance of failing on mint using onchain randomness. If it fails, simply mint again until it +succeeds. + +On success, you can click on your NFTs in MetaMask to see your newly minted token. + +
    +![MaybeMintERC721 in MetaMask NFT list](./maybe-mint-in-metamask.png) +
    + +#### Recap + +This process is cumbersome and requires multiple transactions, each of which could fail. Given the intent of the process - +minting an NFT - if this were a case where the NFT was a limited edition or time-sensitive, you'd be left with WFLOW +wrapped and approved for transfer, but no NFT and would need to manually unwind the process. + +Or you could just use Cadence to batch these transactions and revert everything if the mint fails. Let's do that. + +### Using Flow Wallet + +Before diving into the "how", let's execute the batched version of everything we just did using Flow Wallet. This will +give you a sense of the power of Cadence and the Flow blockchain. + +The transaction below, like all Cadence transactions, is scripted, allowing us to execute a series of actions. It may +look like a lot at first, but we will break it down step by step in the following sections. + +
    + +wrap_and_mint.cdc + +```cadence +// TESTNET IMPORTS +import FungibleToken from 0x9a0766d93b6608b7 +import FlowToken from 0x7e60df042a9c0868 +import EVM from 0x8c5303eaa26202d6 + +/// This transaction demonstrates how multiple EVM calls can be batched in a single Cadence transaction via +/// CadenceOwnedAccount (COA), performing the following actions: +/// +/// 1. Configures a COA in the signer's account if needed +/// 2. Funds the signer's COA with enough FLOW to cover the WFLOW cost of minting an ERC721 token +/// 3. Wraps FLOW as WFLOW - EVM call 1 +/// 4. Approves the example MaybeMintERC721 contract which accepts WFLOW to move the mint amount - EVM call 2 +/// 5. Attempts to mint an ERC721 token - EVM call 3 +/// +/// Importantly, the transaction is reverted if any of the EVM interactions fail returning the account to the original +/// state before the transaction was executed across Cadence & EVM. +/// +/// For more context, see https://github.com/onflow/batched-evm-exec-example +/// +/// @param wflowAddressHex: The EVM address hex of the WFLOW contract as a String +/// @param maybeMintERC721AddressHex: The EVM address hex of the ERC721 contract as a String +/// +transaction(wflowAddressHex: String, maybeMintERC721AddressHex: String) { + + let coa: auth(EVM.Call) &EVM.CadenceOwnedAccount + let mintCost: UFix64 + let wflowAddress: EVM.EVMAddress + let erc721Address: EVM.EVMAddress + + prepare(signer: auth(SaveValue, BorrowValue, IssueStorageCapabilityController, PublishCapability, UnpublishCapability) &Account) { + /* COA configuration & assigment */ + // + let storagePath = /storage/evm + let publicPath = /public/evm + // Configure a COA if one is not found in storage at the default path + if signer.storage.type(at: storagePath) == nil { + // Create & save the CadenceOwnedAccount (COA) Resource + let newCOA <- EVM.createCadenceOwnedAccount() + signer.storage.save(<-newCOA, to: storagePath) + + // Unpublish any existing Capability at the public path if it exists + signer.capabilities.unpublish(publicPath) + // Issue & publish the public, unentitled COA Capability + let coaCapability = signer.capabilities.storage.issue<&EVM.CadenceOwnedAccount>(storagePath) + signer.capabilities.publish(coaCapability, at: publicPath) + } + + // Assign the COA reference to the transaction's coa field + self.coa = signer.storage.borrow(from: storagePath) + ?? panic("A CadenceOwnedAccount (COA) Resource could not be found at path ".concat(storagePath.toString()) + .concat(" - ensure the COA Resource is created and saved at this path to enable EVM interactions")) + + /* Fund COA with cost of mint */ + // + // Borrow authorized reference to signer's FlowToken Vault + let sourceVault = signer.storage.borrow( + from: /storage/flowTokenVault + ) ?? panic("The signer does not store a FlowToken Vault object at the path " + .concat("/storage/flowTokenVault. ") + .concat("The signer must initialize their account with this vault first!")) + // Withdraw from the signer's FlowToken Vault + self.mintCost = 1.0 + let fundingVault <- sourceVault.withdraw(amount: self.mintCost) as! @FlowToken.Vault + // Deposit the mint cost into the COA + self.coa.deposit(from: <-fundingVault) + + /* Set the WFLOW contract address */ + // + // View the cannonical WFLOW contract at: + // https://evm-testnet.flowscan.io/address/0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e + self.wflowAddress = EVM.addressFromString(wflowAddressHex) + + /* Assign the ERC721 EVM Address */ + // + // Deserialize the provided ERC721 hex string to an EVM address + self.erc721Address = EVM.addressFromString(maybeMintERC721AddressHex) + } + + pre { + self.coa.balance().inFLOW() >= self.mintCost: + "CadenceOwnedAccount holds insufficient FLOW balance to mint - " + .concat("Ensure COA has at least ".concat(self.mintCost.toString()).concat(" FLOW")) + } + + execute { + /* Wrap FLOW in EVM as WFLOW */ + // + // Encode calldata & set value + let depositCalldata = EVM.encodeABIWithSignature("deposit()", []) + let value = EVM.Balance(attoflow: 0) + value.setFLOW(flow: self.mintCost) + // Call the WFLOW contract, wrapping the sent FLOW + let wrapResult = self.coa.call( + to: self.wflowAddress, + data: depositCalldata, + gasLimit: 15_000_000, + value: value + ) + assert( + wrapResult.status == EVM.Status.successful, + message: "Wrapping FLOW as WFLOW failed: ".concat(wrapResult.errorMessage) + ) + + /* Approve the ERC721 address for the mint amount */ + // + // Encode calldata approve(address,uint) calldata, providing the ERC721 address & mint amount + let approveCalldata = EVM.encodeABIWithSignature( + "approve(address,uint256)", + [self.erc721Address, UInt256(1_000_000_000_000_000_000)] + ) + // Call the WFLOW contract, approving the ERC721 address to move the mint amount + let approveResult = self.coa.call( + to: self.wflowAddress, + data: approveCalldata, + gasLimit: 15_000_000, + value: EVM.Balance(attoflow: 0) + ) + assert( + approveResult.status == EVM.Status.successful, + message: "Approving ERC721 address on WFLOW contract failed: ".concat(approveResult.errorMessage) + ) + + /* Attempt to mint ERC721 */ + // + // Encode the mint() calldata + let mintCalldata = EVM.encodeABIWithSignature("mint()", []) + // Call the ERC721 contract, attempting to mint + let mintResult = self.coa.call( + to: self.erc721Address, + data: mintCalldata, + gasLimit: 15_000_000, + value: EVM.Balance(attoflow: 0) + ) + // If mint fails, all other actions in this transaction are reverted + assert( + mintResult.status == EVM.Status.successful, + message: "Minting ERC721 token failed: ".concat(mintResult.errorMessage) + ) + } +} + +``` + +
    + +You can run the transaction at the following link using the community-developed Flow Runner tool: [`wrap_and_mint.cdc`]. + +This transaction takes two arguments: + +- WFLOW contract address: `0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e` +- MaybeMintERC721 contract address: `0x2E2Ed0Cfd3AD2f1d34481277b3204d807Ca2F8c2` + +Before running, ensure that the network section - bottom right corner - displays Testnet. If not, click and select +`Testnet` as your network and refresh. Once you've confirmed you're Flow Runner is targeting Testnet, copy these +addresses and paste them into the respective fields on the Flow Runner page. Click `Run` on the top left and follow the +prompts to connect your Flow Wallet and sign the transaction. + +:::warning + +Although we are running a manual transaction for the purposes of this walkthrough, you should always be careful to +review the transaction details before signing and submitting. + +::: + +Again, since the ERC721 has a 50% chance of failing, you may need to run the transaction multiple times until it +succeeds. However note that if the mint fails, the entire transaction will revert, unwinding the wrapped FLOW and +approval. + +Again, since the ERC721 has a 50% chance of failure and the success of the transaction is conditioned on successfully +minting, your transaction may fail. If it does fail, importantly the entire transaction reverts, unwinding the wrapped +FLOW deposit and approval - the wrapping and approval transactions **do not execute** in the event of mint failure! This +is the main takeaway of this guide, that you embed a whole sequence of EVM transactions into one atomic operation using +Cadence and if the primary intent (or intents) does not execute, everything else is reverted as well. + +In our case, you'll want to submit a transaction until one succeeds. Once you submit a successful transaction, you'll +see a transaction ID with event logs in the Flow Runner output. Let's take a closer look at the transaction and its +results in the Flowscan block explorer. + +![Flow Runner output on successful transaction execution](./flow-runner-successful-output.png) + +Copy your transaction ID and go to the Flowscan Testnet Cadence block explorer: [Flowscan Cadence]. + +Pasting your transaction ID into the search bar will show you the transaction details, including the Cadence script, +execution status, and event logs. Click on the `EVM` tab to view the EVM transactions batched in the Cadence +transaction. + +![Embedded EVM transactions on Flowscan](./evm-embed-flowscan.png) + +Clicking on the transactions will open up the EVM transaction in Flowscan's EVM block explorer. If you view the EVM +transactions in order, you'll notice that they aggregate the same actions we took manually in the MetaMask section, but +this time in a single Cadence transaction! + +## Breaking it Down + +Now that we can relate to the pain of manually executing these transactions and we've seen the magic you can work with +Cadence, let's understand what's going on under the hood. + +To recap, our Cadence transaction does the following, reverting if any step fails: + +1. Wraps FLOW as WFLOW +2. Approves the `MaybeMintERC721` contract to move WFLOW +3. Attempts to mint a `MaybeMintERC721` token + +But how does our Flow account interact with EVM from the Cadence runtime? As you'll recall from the [Interacting with +COA](./interacting-with-coa.md) guide, we use a Cadence-owned account (COA) to interact with EVM contracts from Cadence. + +A COA is a [resource] providing an interface through which Cadence can interact with the EVM runtime. This is +importantly **_in addition_** to the traditional routes you'd normally access normal EVMs - e.g. via the JSON-RPC API. +And with this interface, we can take advantage of all of the benefits of Cadence - namely here scripted transactions and +conditional execution. + +So in addition to the above steps, our transaction first configures a COA in the signer's account if one doesn't already +exist. It then funds the COA with enough FLOW to cover the mint cost, sourcing funds from the signing Flow account's +Cadence Vault. Finally, it wraps FLOW as WFLOW, approves the ERC721 contract to move the mint amount, and attempts to +mint the ERC721 token. + +Let's see what each step looks like in the transaction code. + +### COA Configuration + +The first step in our transaction is to configure a COA in the signer's account if one doesn't already exist. This is +done by creating a new COA resource and saving it to the signer account's storage. A public Capability on the COA is +then issued and published on the signer's account, allowing anyone to deposit FLOW into the COA, affecting its EVM +balance. + +```cadence +/* COA configuration & assignment */ +// +let storagePath = /storage/evm +let publicPath = /public/evm +// Configure a COA if one is not found in storage at the default path +if signer.storage.type(at: storagePath) == nil { + // Create & save the CadenceOwnedAccount (COA) Resource + let newCOA <- EVM.createCadenceOwnedAccount() + signer.storage.save(<-newCOA, to: storagePath) + + // Unpublish any existing Capability at the public path if it exists + signer.capabilities.unpublish(publicPath) + // Issue & publish the public, unentitled COA Capability + let coaCapability = signer.capabilities.storage.issue<&EVM.CadenceOwnedAccount>(storagePath) + signer.capabilities.publish(coaCapability, at: publicPath) +} + +// Assign the COA reference to the transaction's coa field +self.coa = signer.storage.borrow(from: storagePath) + ?? panic("A CadenceOwnedAccount (COA) Resource could not be found at path ".concat(storagePath.toString()) + .concat(" - ensure the COA Resource is created and saved at this path to enable EVM interactions")) +``` + +At the end of this section, the transaction now has an reference authorized with the `EVM.Call` [entitlement] to use in +the `execute` block which can be used call into EVM. + +You can run a transaction that does just this step here: [`setup_coa.cdc`] + +Since you ran the all-in-one transaction previously, your account already has a COA configured in which case the linked +transaction won't do anything. You can lookup your Testnet account's EVM address with the script below to confirm you +have a COA configured. Simply input your Testnet Flow address and click `Run`. + + + +### Funding the COA + +Next, we fund the COA with enough FLOW to cover the mint cost. This is done by withdrawing FLOW from the signer's +FlowToken Vault and depositing it into the COA. + +```cadence +/* Fund COA with cost of mint */ +// +// Borrow authorized reference to signer's FlowToken Vault +let sourceVault = signer.storage.borrow( + from: /storage/flowTokenVault + ) ?? panic("The signer does not store a FlowToken Vault object at the path " + .concat("/storage/flowTokenVault. ") + .concat("The signer must initialize their account with this vault first!")) +// Withdraw from the signer's FlowToken Vault +self.mintCost = 1.0 +let fundingVault <- sourceVault.withdraw(amount: self.mintCost) as! @FlowToken.Vault +// Deposit the mint cost into the COA +self.coa.deposit(from: <-fundingVault) +``` + +Taking a look at the full transaction, we can see an explicit check that the COA has enough FLOW to cover the mint cost +before proceeding into the transaction's `execute` block. + +```cadence +pre { + self.coa.balance().inFLOW() >= self.mintCost: + "CadenceOwnedAccount holds insufficient FLOW balance to mint - " + .concat("Ensure COA has at least ".concat(self.mintCost.toString()).concat(" FLOW")) +} +``` + +This isn't absolutely necessary as successive steps would fail on this condition, but helps provide enhanced error +messages in the event of insufficient funds. + +You can run the above block in a transaction here which will move 1 FLOW from your account's Cadence FLOW balance to +your account's EVM balance, depositing it directly to your pre-configured COA: [`fund_coa.cdc`] + +After running the linked transaction, you can check your COA's FLOW balance with the script below, just enter your COA's +EVM address (which you can get from the previous script). The resulting balance should be 1.0 (unless you've funded your +COA prior to this walkthrough). + + + +### Setting our EVM Contract Targets + +The last step in our transaction's `prepare` block is to deserialize the provided WFLOW and ERC721 contract addresses +from hex strings to EVM addresses. + +```cadence +/* Set the WFLOW contract address */ +// +// View the cannonical WFLOW contract at: +// https://evm-testnet.flowscan.io/address/0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e +self.wflowAddress = EVM.addressFromString(wflowAddressHex) + +/* Assign the ERC721 EVM Address */ +// +// Deserialize the provided ERC721 hex string to an EVM address +self.erc721Address = EVM.addressFromString(maybeMintERC721AddressHex) +``` + +### Wrapping FLOW as WFLOW + +Next, we're on to the first EVM interaction - wrapping FLOW as WFLOW. This is done by encoding the `deposit()` function +call and setting the call value to the mint cost. The COA then calls the WFLOW contract with the encoded calldata, gas +limit, and value. + +```cadence +/* Wrap FLOW in EVM as WFLOW */ +// +// Encode calldata & set value +let depositCalldata = EVM.encodeABIWithSignature("deposit()", []) +let value = EVM.Balance(attoflow: 0) +value.setFLOW(flow: self.mintCost) +// Call the WFLOW contract, wrapping the sent FLOW +let wrapResult = self.coa.call( + to: self.wflowAddress, + data: depositCalldata, + gasLimit: 15_000_000, + value: value +) +assert( + wrapResult.status == EVM.Status.successful, + message: "Wrapping FLOW as WFLOW failed: ".concat(wrapResult.errorMessage) +) +``` + +Setting the value of the call transmits FLOW along with the call to the contract, accessible in solidity as `msg.value`. + +:::tip + +You'll notice a general pattern among all EVM calls in this transaction: + +1. Encoding the calldata +2. Calling the contract +3. Asserting the call was successful + +Here we're just interested in a successful call, but we could access return data if it were expected and relevant for +our Cadence transaction. This returned data is accessible from the `data` field on the `EVM.Result` object returned from +`coa.call(...)`. This data would then be decoded using `EVM.decodeABI(...)`. More on this in later guides. + +::: + +You can run the above code as a transaction here: [`wrap_flow.cdc`] + +After running the transaction, your COA should have a WFLOW balance of 1.0 WFLOW. Confirm your WFLOW balance by running +the script below, providing your Flow account address, the WFLOW address of `0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e` +and your COA's EVM address (retrieved from a previous script): + + + +Since Solidity does not support decimal precision, the returned balance will look like a large number. In the case of +WFLOW, we can recover the decimals by shifting the decimal place 18 digits to the left. Your account should have `1` +WFLOW or `1000000000000000000` as returned. + +:::warning + +Note that the number of places to shift varies by ERC20 implementation -- the default value is 18, but it's not safe to +assume this value. You can check a token's decimal places by calling `ERC20.decimals()(uint8)`. + +::: + +### Approving the ERC721 Contract + +Once the FLOW is wrapped as WFLOW, we approve the ERC721 contract to move the mint amount. This is done by encoding the +`approve(address,uint256)` calldata and calling the WFLOW contract with the encoded calldata. + +```cadence +/* Approve the ERC721 address for the mint amount */ +// +// Encode calldata approve(address,uint) calldata, providing the ERC721 address & mint amount +let approveCalldata = EVM.encodeABIWithSignature( + "approve(address,uint256)", + [self.erc721Address, UInt256(1_000_000_000_000_000_000)] + ) +// Call the WFLOW contract, approving the ERC721 address to move the mint amount +let approveResult = self.coa.call( + to: self.wflowAddress, + data: approveCalldata, + gasLimit: 15_000_000, + value: EVM.Balance(attoflow: 0) +) +assert( + approveResult.status == EVM.Status.successful, + message: "Approving ERC721 address on WFLOW contract failed: ".concat(approveResult.errorMessage) +) +``` + +You can run this approval using the transaction, passing the WFLOW address of +`0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e` and MaybeMintERC721 address of `0x2E2Ed0Cfd3AD2f1d34481277b3204d807Ca2F8c2` +: [`approve_maybe_mint_erc721.cdc`] + +The linked transaction will perform the approval step, authorizing the ERC721 to transfer WFLOW to cover the mint cost +when `mint()` is called. Confirm the contract allowance by running the script below. Pass your Flow address, WFLOW +address, ERC721 address, and your COA's EVM address. + + + +The result is the amount of your WFLOW balance the ERC721 is allowed to transfer, which after the transaction should be +`1` WFLOW, or `1000000000000000000` as returned. + +### Minting the ERC721 Token + +Finally, we attempt to mint the ERC721 token. This is done by encoding the `mint()` calldata and calling the ERC721 +contract with the encoded calldata. If the mint fails, the entire transaction is reverted. + +```cadence +/* Attempt to mint ERC721 */ +// +// Encode the mint() calldata +let mintCalldata = EVM.encodeABIWithSignature("mint()", []) +// Call the ERC721 contract, attempting to mint +let mintResult = self.coa.call( + to: self.erc721Address, + data: mintCalldata, + gasLimit: 15_000_000, + value: EVM.Balance(attoflow: 0) +) +// If mint fails, all other actions in this transaction are reverted +assert( + mintResult.status == EVM.Status.successful, + message: "Minting ERC721 token failed: ".concat(mintResult.errorMessage) +) +``` + +You can run the minting transaction here, passing the ERC721 address of `0x2E2Ed0Cfd3AD2f1d34481277b3204d807Ca2F8c2`: +[`mint.cdc`] + +Again, this transaction may fail. But if you executed all the prior stepwise transactions according to the walkthrough, +you can try again until the mint succeeds. Recall that you can view your transaction details using Cadence [Flowscan] +which will also let you view the embedded EVM transactions in the `EVM` tab. Try it out, and see if you can figure out +how to get your minted NFT's URI with the script below. + + + +### Recap + +All of the stepwise transactions you just executed are compiled in the first Cadence transaction we ran. Hopefully, +going through the process step by step illuminates the power and flexibility of Cadence, allowing you to write +transactions as simple or as complex as you want. + +While lengthy transactions can be intimidating and even a bit verbose at times, the flexibility afforded by the language +means you are only limited by your imagination. Cadence transactions allow you to support the most streamlined of +experiences, incorporating as many contracts as needed to support your use case. + +## Conclusion + +In this guide, we've demonstrated how to batch EVM transactions using Cadence, allowing you to conditionally execute +multiple EVM transactions in a single Cadence transaction. While this guide focused on relatively simple EVM operations, +the principles can be applied to much more complex and interesting applications. + +In the process, you learned how to: + +- Read and write from smart contract functions on EVM Flowscan +- Run a Cadence transaction from the browser using [Flow Runner] +- Execute batched EVM transactions via a COA in a Cadence transaction +- Condition final transaction execution on success of all EVM transactions +- Inspect multiple EVM transactions embedded in a Cadence transaction with [Flowscan] block explorer + +The biggest takeaway here isn't the specific actions taken in this walkthrough, but the overarching concept that you can +use **Cadence as an orchestration layer** to **extend existing EVM contracts**, creating unique user experiences with +the power **to differentiate your Web3 application**. + +With these basics in hand, you're ready to start building more complex applications that leverage the power of Cadence +and the Flow blockchain. How will you use these features to build Web3's next killer app? + +## Further Reading + +Now that you've experienced the power of Cadence and EVM interactions firsthand, we recommend checking out the following +guides to deepen your understanding: + +- [How Flow EVM Works] - Learn more about the Flow EVM and how it differs from traditional EVM platforms +- [Interacting with COAs] - Get a fuller picture of how Cadence interacts with EVM contracts via Cadence-owned accounts +- [Cadence Transactions] - Learn more about the Cadence transaction model + +Ready to level up your Cadence skills? Take a look at [these Cadence tutorials]. + + + +[EVM Flowscan]: https://evm.flowscan.io/ +[Flow Runner]: https://run.dnz.dev/ +[Flowscan]: https://www.flowscan.io/ +[MetaMask]: https://metamask.io/download/ +[Flow Wallet extension]: https://wallet.flow.com/download +[Faucet guide]: ../../ecosystem/faucets.md +[Cadence-controlled EVM account (COA)]: ./interacting-with-coa.md +[onchain VRF]: ../../evm/guides/vrf.md +[Overview]: #overview +[Testnet]: https://evm-testnet.flowscan.io/token/0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e?tab=contract +[Mainnet]: https://evm.flowscan.io/token/0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e?tab=contract +[`@onflow/flow-sol-utils` repository]: https://github.com/onflow/flow-sol-utils +[Prerequisites]: #prerequisites +[Flowscan EVM block explorer]: https://www.evm-testnet.flowscan.io/ +[WFLOW]: https://evm-testnet.flowscan.io/token/0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e?tab=write_contract +[here]: https://docs.soliditylang.org/en/v0.8.28/units-and-global-variables.html#ether-units +[MaybeMintERC721]: https://evm-testnet.flowscan.io/address/0x2E2Ed0Cfd3AD2f1d34481277b3204d807Ca2F8c2?tab=write_contract +[`wrap_and_mint.cdc`]: https://run.dnz.dev/snippet/c99b25e04a2d1f28 +[Flowscan Cadence]: https://testnet.flowscan.io/ +[resource]: https://cadence-lang.org/docs/solidity-to-cadence#resources +[entitlement]: https://cadence-lang.org/docs/language/access-control#entitlements +[How Flow EVM Works]: ../../evm/how-it-works.md +[Interacting with COAs]: ./interacting-with-coa.md +[Cadence Transactions]: ../../build/basics/transactions.md +[these Cadence tutorials]: https://cadence-lang.org/docs/tutorial/first-steps +[`setup_coa.cdc`]: https://run.dnz.dev/snippet/4ec75e1f4165fa05 +[`fund_coa.cdc`]: https://run.dnz.dev/snippet/0e7370601bd9123b +[`wrap_flow.cdc`]: https://run.dnz.dev/snippet/9dbfb784da5300fb +[`approve_maybe_mint_erc721.cdc`]: https://run.dnz.dev/snippet/1b503d82f9a2c5a7 +[`mint.cdc`]: https://run.dnz.dev/snippet/fd7c4dda536d006e + + +=== tutorials/cross-vm-apps/add-to-wagmi.md === +--- +title: Update Existing wagmi App +description: Learn how to integrate Flow Cadence with your existing wagmi/RainbowKit app to enable batch transactions and other Cadence features. +sidebar_position: 1 +keywords: + - hybrid apps + - cross-vm apps + - FCL + - wagmi + - RainbowKit + - Flow EVM + - Flow Cadence + - cross-VM + - multi-call + - batch transactions + - web3 + - dapp development + - wallet integration + - smart contracts + - blockchain development + - supercharge your EVM app with Cadence +--- + +# Add Flow Cadence to Your wagmi App + +This tutorial demonstrates how to enhance your existing wagmi/RainbowKit application with Flow Cadence capabilities. By integrating the Flow Client Library (FCL) with your EVM stack, you can unlock powerful features like batch transactions with a single signature. + +## Video Overview + +
    + +
    + +## Objectives + +After completing this guide, you'll be able to: + +- Add FCL to your existing wagmi/RainbowKit application +- Configure FCL to work alongside your EVM wallet connections +- Implement batch transactions that execute multiple EVM calls in a single Cadence transaction +- Display both Cadence and EVM addresses in your application + +## Prerequisites + +### Next.js and Modern Frontend Development + +This tutorial uses [Next.js]. You don't need to be an expert, but it's helpful to be comfortable with development using a current React framework. You'll be on your own to select and use a package manager, manage Node versions, and other frontend environment tasks. If you don't have your own preference, you can just follow along with us and use [npm]. + +### Solidity and Cadence Smart Contract Development + +Apps using the hybrid approach can interact with both [Cadence] and [Solidity] smart contracts. You don't need to be an expert in either of these, but it's helpful to be familiar with how smart contracts work in at least one of these languages. + +### Onchain App Frontends + +We're assuming you're familiar with [wagmi], [viem], and [RainbowKit]. If you're coming from the Cadence, you might want to take a quick look at the getting started guides for these platforms. They're all excellent and will rapidly get you up to speed on how the EVM world commonly connects their apps to their contracts. + +## Create an App + +Start by creating an app using [RainbowKit]'s scaffold: + +```bash +npm init @rainbow-me/rainbowkit@latest +``` + +## Install Required Dependencies + +Continue by adding the necessary Flow dependencies to your project: + +```bash +npm install @onflow/fcl @onflow/fcl-rainbowkit-adapter +``` + +These packages provide: + +- `@onflow/fcl`: The Flow Client Library for interacting with the Cadence VM +- `@onflow/fcl-rainbowkit-adapter`: An adapter that allows RainbowKit to work with FCL-compatible wallets + +## Step 2: Configure FCL in Your wagmi Setup + +Update your wagmi configuration (`src/wagmi.ts`) to include FCL: + +```typescript +'use client'; + +import { + flowWallet, + walletConnectWallet, +} from '@onflow/fcl-rainbowkit-adapter'; +import { connectorsForWallets } from '@rainbow-me/rainbowkit'; +import { flowTestnet } from 'wagmi/chains'; +import * as fcl from '@onflow/fcl'; +import { createConfig, http } from 'wagmi'; + +fcl.config({ + 'accessNode.api': 'https://rest-testnet.onflow.org', + 'discovery.wallet': 'https://fcl-discovery.onflow.org/mainnet/authn', + 'walletconnect.projectId': '9b70cfa398b2355a5eb9b1cf99f4a981', +}); + +const connectors = connectorsForWallets( + [ + { + groupName: 'Recommended', + wallets: [flowWallet(), walletConnectWallet], + }, + ], + { + appName: 'RainbowKit demo', + projectId: '9b70cfa398b2355a5eb9b1cf99f4a981', + }, +); + +export const config = createConfig({ + chains: [flowTestnet], + connectors, + ssr: true, + transports: { + [flowTestnet.id]: http(), + }, +}); +``` + +## Step 3: Add the Batch Transaction Utility + +Create a custom hook in `src/hooks/useBatchTransactions.ts` to handle batch transactions. This utility allows you to execute multiple EVM transactions in a single Cadence transaction: + +```typescript +import * as fcl from '@onflow/fcl'; +import { Abi, bytesToHex, encodeFunctionData, toBytes } from 'viem'; +import { useState } from 'react'; +import { useAccount } from 'wagmi'; + +// Define the interface for each EVM call. +export interface EVMBatchCall { + address: string; // The target EVM contract address (as a string) + abi: Abi; // The contract ABI fragment (as JSON) + functionName: string; // The name of the function to call + args?: readonly unknown[]; // The function arguments + gasLimit?: bigint; // The gas limit for the call + value?: bigint; // The value to send with the call +} + +export interface CallOutcome { + status: 'passed' | 'failed' | 'skipped'; + hash?: string; + errorMessage?: string; +} + +export type EvmTransactionExecutedData = { + hash: string[]; + index: string; + type: string; + payload: string[]; + errorCode: string; + errorMessage: string; + gasConsumed: string; + contractAddress: string; + logs: string[]; + blockHeight: string; + returnedData: string[]; + precompiledCalls: string[]; + stateUpdateChecksum: string; +}; + +// Helper to encode our ca lls using viem. +// Returns an array of objects with keys "address" and "data" (hex-encoded string without the "0x" prefix). +export function encodeCalls( + calls: EVMBatchCall[], +): Array> { + return calls.map((call) => { + const encodedData = encodeFunctionData({ + abi: call.abi, + functionName: call.functionName, + args: call.args, + }); + + return [ + { key: 'to', value: call.address }, + { key: 'data', value: fcl.sansPrefix(encodedData) ?? '' }, + { key: 'gasLimit', value: call.gasLimit?.toString() ?? '15000000' }, + { key: 'value', value: call.value?.toString() ?? '0' }, + ]; + }) as any; +} + +const EVM_CONTRACT_ADDRESSES = { + testnet: '0x8c5303eaa26202d6', + mainnet: '0xe467b9dd11fa00df', +}; + +// Takes a chain id and returns the cadence tx with addresses set +const getCadenceBatchTransaction = (chainId: number) => { + const isMainnet = chainId === 0x747; + const evmAddress = isMainnet + ? EVM_CONTRACT_ADDRESSES.mainnet + : EVM_CONTRACT_ADDRESSES.testnet; + + return ` +import EVM from ${evmAddress} + +transaction(calls: [{String: AnyStruct}], mustPass: Bool) { + + let coa: auth(EVM.Call) &EVM.CadenceOwnedAccount + + prepare(signer: auth(BorrowValue) & Account) { + let storagePath = /storage/evm + self.coa = signer.storage.borrow(from: storagePath) + ?? panic("No CadenceOwnedAccount (COA) found at ".concat(storagePath.toString())) + } + + execute { + for i, call in calls { + let to = call["to"] as! String + let data = call["data"] as! String + let gasLimit = call["gasLimit"] as! UInt64 + let value = call["value"] as! UInt + + let result = self.coa.call( + to: EVM.addressFromString(to), + data: data.decodeHex(), + gasLimit: gasLimit, + value: EVM.Balance(attoflow: value) + ) + + if mustPass { + assert( + result.status == EVM.Status.successful, + message: "Call index ".concat(i.toString()).concat(" to ").concat(to) + .concat(" with calldata ").concat(data).concat(" failed: ") + .concat(result.errorMessage) + ) + } + } + } +} +`; +}; + +// Custom hook that returns a function to send a batch transaction +export function useBatchTransaction() { + const { chain } = useAccount(); + + const cadenceTx = chain?.id ? getCadenceBatchTransaction(chain.id) : null; + + const [isPending, setIsPending] = useState(false); + const [isError, setIsError] = useState(false); + const [txId, setTxId] = useState(''); + const [results, setResults] = useState([]); + + async function sendBatchTransaction( + calls: EVMBatchCall[], + mustPass: boolean = true, + ) { + // Reset state + setIsPending(true); + setIsError(false); + setTxId(''); + setResults([]); + + try { + if (!cadenceTx) { + throw new Error('No current chain found'); + } + + const encodedCalls = encodeCalls(calls); + + const txId = await fcl.mutate({ + cadence: cadenceTx, + args: (arg, t) => [ + // Pass encodedCalls as an array of dictionaries with keys (String, String) + arg( + encodedCalls, + t.Array( + t.Dictionary([ + { key: t.String, value: t.String }, + { key: t.String, value: t.String }, + { key: t.String, value: t.UInt64 }, + { key: t.String, value: t.UInt }, + ] as any), + ), + ), + // Pass mustPass=true to revert the entire transaction if any call fails + arg(true, t.Bool), + ], + limit: 9999, + }); + + setTxId(txId); + + // The transaction may revert if mustPass=true and one of the calls fails, + // so we catch that error specifically. + let txResult; + try { + txResult = await fcl.tx(txId).onceExecuted(); + } catch (txError) { + // If we land here, the transaction likely reverted. + // We can return partial or "failed" outcomes for all calls. + setIsError(true); + setResults( + calls.map(() => ({ + status: 'failed' as const, + hash: undefined, + errorMessage: 'Transaction reverted', + })), + ); + setIsPending(false); + return; + } + + // Filter for TransactionExecuted events + const executedEvents = txResult.events.filter((e: any) => + e.type.includes('TransactionExecuted'), + ); + + // Build a full outcomes array for every call. + // For any call index where no event exists, mark it as "skipped". + const outcomes: CallOutcome[] = calls.map((_, index) => { + const eventData = executedEvents[index] + ?.data as EvmTransactionExecutedData; + if (eventData) { + return { + hash: bytesToHex( + Uint8Array.from( + eventData.hash.map((x: string) => parseInt(x, 10)), + ), + ), + status: eventData.errorCode === '0' ? 'passed' : 'failed', + errorMessage: eventData.errorMessage, + }; + } else { + return { + status: 'skipped', + }; + } + }); + + setResults(outcomes); + setIsPending(false); + } catch (error: any) { + setIsError(true); + setIsPending(false); + } + } + + return { sendBatchTransaction, isPending, isError, txId, results }; +} +``` + +## Step 4: Implement the UI + +Now, update your application's `page.tsx` to use the batch transaction utility. Update + +```tsx +'use client'; + +import { ConnectButton } from '@rainbow-me/rainbowkit'; +import CodeEvaluator from './code-evaluator'; +import { useAccount } from 'wagmi'; +import { useEffect, useState } from 'react'; +import * as fcl from '@onflow/fcl'; +import { CurrentUser } from '@onflow/typedefs'; +import { + EVMBatchCall, + useBatchTransaction, +} from '../hooks/useBatchTransaction'; + +function Page() { + const coa = useAccount(); + const [flowAddress, setFlowAddress] = useState(null); + const { sendBatchTransaction, isPending, isError, txId, results } = + useBatchTransaction(); + + useEffect(() => { + const unsub = fcl.currentUser().subscribe((user: CurrentUser) => { + setFlowAddress(user.addr ?? null); + }); + return () => unsub(); + }, []); + + // Define a "real" calls array to demonstrate a batch transaction. + // In this example, we call two functions on a token contract: + // 1. deposit() to wrap FLOW (e.g., WFLOW) + // 2. approve() to allow a spender to spend tokens. + const calls: EVMBatchCall[] = [ + { + // Call deposit() function (wrap FLOW) on the token contract. + address: '0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e', // Replace with your actual token contract address. + abi: [ + { + inputs: [], + name: 'deposit', + outputs: [], + stateMutability: 'payable', + type: 'function', + }, + ], + functionName: 'deposit', + args: [], // deposit takes no arguments; value is passed with the call. + }, + { + // Call approve() function (ERC20 style) on the same token contract. + address: '0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e', // Replace with your actual token contract address if needed. + abi: [ + { + inputs: [ + { name: 'spender', type: 'address' }, + { name: 'value', type: 'uint256' }, + ], + name: 'approve', + outputs: [{ name: '', type: 'bool' }], + stateMutability: 'nonpayable', + type: 'function', + }, + ], + functionName: 'approve', + args: [ + '0x2E2Ed0Cfd3AD2f1d34481277b3204d807Ca2F8c2', // Spender address. + BigInt('1000000000000000000'), // Approve 1 token (assuming 18 decimals). + ], + }, + ]; + + return ( + <> +
    + +
    +

    Flow Address: {flowAddress}

    +

    EVM Address: {coa?.address}

    +
    + + {

    {JSON.stringify({ isPending, isError, txId, results })}

    } + + + ); +} + +export default Page; +``` + +## Step 5: Test Your Application + +1. Start your development server: + + ```bash + npm run dev + ``` + +2. Connect your wallet using the RainbowKit `ConnectButton` + + - Make sure to use a Cadence-compatible wallet like Flow Wallet + +3. Click the "Send Batch Transaction" button + + - You'll be prompted to approve the Cadence transaction + - This transaction will execute multiple EVM calls in a single atomic operation + +4. Observe the results + - The Cadence transaction ID will be displayed + - The results of each EVM transaction will be shown + +## How It Works + +When you call `sendBatchTransaction`, the following happens: + +1. A Cadence transaction is created that includes all your EVM calls +2. The transaction is executed using FCL's `mutate` function +3. The Cadence transaction calls each EVM transaction in sequence +4. If any transaction fails and `mustPass` is true, the entire batch is rolled back +5. The results of each EVM transaction are returned + +This approach gives you several advantages: + +- **Atomic Operations**: All transactions succeed or fail together +- **Single Signature**: Users only need to sign one transaction +- **Gas Efficiency**: Reduced gas costs compared to separate transactions +- **Simplified UX**: Users don't need to approve multiple transactions + +## Conclusion + +You've successfully integrated Flow Cadence with your wagmi/rainbowkit application! This integration allows you to leverage the power of Cadence while maintaining the familiar EVM development experience. + +## Reference Implementation + +For a complete reference implementation, check out the [FCL + RainbowKit + wagmi Integration Demo] repository. + +[Cadence]: https://cadence-lang.org/docs +[Next.js]: https://nextjs.org/docs/app/getting-started/installation +[npm]: https://www.npmjs.com/ +[create an issue]: https://github.com/onflow/docs/issues/new/choose +[Cadence]: https://cadence-lang.org +[Solidity]: https://soliditylang.org/ +[native VRF]: ../../evm/guides/vrf.md +[structure and call EVM transactions]: ./batched-evm-transactions.md +[FLIP 316]: https://github.com/onflow/flips/pull/317 +[Flow Client Library (FCL)]: ../../tools/clients/fcl-js +[wagmi]: https://wagmi.sh/ +[viem]: https://viem.sh/ +[RainbowKit]: https://www.rainbowkit.com/ +[wallet]: ../../ecosystem/wallets.md +[Discord]: https://discord.com/channels/613813861610684416/1162086721471647874 +[FCL + RainbowKit + wagmi Integration Demo]: https://github.com/jribbink/cross-vm-app +[FCL-JS]: https://github.com/onflow/fcl-js +[Testnet Cadence Flowscan]: https://testnet.flowscan.io +[Cadence Owned Accounts]: ../../build/basics/accounts.md +[Testnet EVM Flowscan]: https://evm-testnet.flowscan.io + + +=== tutorials/ai-plus-flow/index.md === +--- +title: AI Plus Flow +description: Learn how to leverage AI tools to enhance your Flow development experience +sidebar_position: 2 +keywords: + - AI + - ChatGPT + - Cursor + - AgentKit + - Flow documentation + - Cadence documentation + - Flow development + - Flow tools + - Flow IDE + - Flow setup + - Flow configuration + - Flow AI assistance +--- + +# AI Plus Flow + +Artificial Intelligence tools can significantly enhance your Flow development experience by providing intelligent assistance, code generation, and documentation access. This tutorial series will guide you through integrating various AI tools with Flow development to boost your productivity and code quality. + +## What You'll Learn + +In this tutorial series, you'll discover how to: + +- Configure AI-powered development environments for Flow +- Access Flow documentation directly from AI assistants +- Generate Cadence and Solidity code with AI assistance +- Debug and troubleshoot Flow applications with AI support +- Leverage AI for testing and optimization +- Build AI agents that interact with Flow using AgentKit + +## Tutorials + +- [Use Flow Knowledge Base in Cursor] - Learn how to set up Cursor with Flow knowledge bases to get intelligent assistance while developing Flow applications. +- [Use Flow Knowledge Base in ChatGPT] - Create a custom GPT that understands Flow and Cadence to provide accurate answers to your development questions. +- [Flow Data Sources] - Learn about this comprehensive resource and how to integrate it with various AI platforms. +- [Eliza on Flow] - Learn how to build AI Agent on Flow with Eliza +- [Build AI Agents with AgentKit] - Learn how to create AI agents that can interact with Flow using AgentKit. + + +## Best Practices + +When using AI tools with Flow development: + +- Always verify AI-generated code against Flow documentation +- Use specific prompts that reference Flow concepts and terminology +- Combine AI assistance with your own understanding of Flow architecture +- Keep your AI tools updated with the latest Flow documentation +- Test AI-generated code thoroughly before deploying to production +- Consider the security implications of AI agents interacting with your contracts + +## Next Steps + +After completing these tutorials, you'll be equipped to leverage AI tools effectively in your Flow development workflow. Consider exploring our other tutorial series to deepen your understanding of Flow development: + +- [Cross-VM Apps][cross-vm-apps] - Build applications that integrate Flow EVM and Cadence +- [Native VRF][native-vrf] - Implement verifiable random functions in your applications +- [Token Launch][token-launch] - Create and launch tokens on Flow + +[Use Flow Knowledge Base in Cursor]: ./cursor/index.md +[Use Flow Knowledge Base in ChatGPT]: ./chatgpt/index.md +[Flow Data Sources]: ./flow-data-sources.md +[Eliza on Flow]: ./eliza/index.md +[Build AI Agents with AgentKit]: ./agentkit-flow-guide.md +[cross-vm-apps]: ../cross-vm-apps/introduction.md +[native-vrf]: ../native-vrf/index.md +[token-launch]: ../token-launch/index.md + + +=== tutorials/ai-plus-flow/flow-data-sources.md === +--- +title: Flow Data Sources +sidebar_label: Flow Data Sources +sidebar_position: 3 +keywords: + - Flow Data Sources + - AI knowledge base + - Flow documentation + - Cadence documentation + - Flow development + - Flow tools + - Flow AI assistance + - RAG + - Retrieval-Augmented Generation +--- + +# Flow Data Sources + +Flow Data Sources is a comprehensive repository that automatically aggregates and formats Flow ecosystem content into Markdown files optimized for AI ingestion. This resource serves as a centralized knowledge base for AI tools, chatbots, and RAG (Retrieval-Augmented Generation) pipelines. + +## Overview + +The repository contains Python scripts that: + +- Crawl Flow-related documentation sites, GitHub repositories, and discussions +- Convert HTML content to Markdown format +- Extract code examples from GitHub repositories +- Capture community discussions and Q&A content +- Merge all content into consolidated files for easy consumption + +## Key Features + +- **Daily Updates**: Content is automatically refreshed to ensure the latest information +- **Structured Format**: All content is converted to Markdown for consistent processing +- **Comprehensive Coverage**: Includes official documentation, code examples, and community discussions +- **Optimized for AI**: Designed specifically for AI tools, chatbots, and RAG pipelines +- **Output Options**: + - `all_merged.md`: Complete content + - `essentials_merged.md`: Streamlined version only including official documentation and sample codes. + - `cadence_docs_merged.md`: Streamlined version only including Cadence related documentation and sample codes. + +## How to Use + +Flow Data Sources can be integrated with: + +- **ChatGPT Plugins**: Enhance Q&A capabilities with Flow-specific knowledge +- **Custom Chatbots**: Power Discord/Telegram bots with accurate Flow information +- **RAG Systems**: Index content in vector databases for semantic search +- **Development Tools**: Provide context-aware assistance in IDEs like Cursor + +## Accessing the Content + +The merged documentation files are available at: + +- [All Merged Content][all-merged] +- [Essentials Only][essentials-merged] +- [Cadence Only][cadence-merged] + +For integration with AI tools like Cursor or ChatGPT, use the appropriate URL as described in the respective tutorials: + +- [Use Flow Knowledge Base in Cursor][cursor] - Learn how to set up Cursor with Flow knowledge bases +- [Use Flow Knowledge Base in ChatGPT][chatgpt] - Create a custom GPT that understands Flow and Cadence + +[all-merged]: https://github.com/onflow/Flow-Data-Sources/blob/main/merged_docs/all_merged.md +[essentials-merged]: https://github.com/onflow/Flow-Data-Sources/blob/main/merged_docs/essentials_merged.md +[cadence-merged]: https://github.com/onflow/Flow-Data-Sources/blob/main/merged_docs/cadence_docs_merged.md +[cursor]: ./cursor/index.md +[chatgpt]: ./chatgpt/index.md + + +=== tutorials/ai-plus-flow/agentkit-flow-guide.md === +--- +title: Build Custom AI Agents on Flow with AgentKit +description: Learn how to configure and deploy AI agents on the Flow testnet using AgentKit, Langchain, and the EVM-compatible Flow environment. +sidebar_label: Using AgentKit on Flow +sidebar_position: 4 +--- + +# Getting Started with AgentKit on Flow + +AgentKit is an ecosystem-agnostic modular developer toolkit that lets you rapidly build, deploy, and iterate on AI agents using pre-configured environments and ready-to-use templates. + +In this guide, you'll set up your own custom agent running on **Flow's EVM-compatible testnet**, powered by **Langchain** and **Anthropic's Claude** LLM. + +--- + +## Quickstart - Starting From Scratch + +Open your terminal and run: + +```bash +npm create onchain-agent@latest +``` + +Follow the interactive setup: + +1. Type `y` to proceed, then press **Enter**. +2. Select your framework: **Langchain** +3. Choose your network: **EVM** +4. Set the custom Chain ID: + - `545` for **Flow Testnet** + - `747` for **Flow Mainnet** +5. JSON-RPC endpoint: + ```txt + https://testnet.evm.nodes.onflow.org + ``` + +--- + +## Project Setup + +Once your scaffold is ready: + +```bash +cd onchain-agent +npm install +``` + +Now open the project in your preferred IDE (e.g. Cursor). + +### Environment Configuration + +1. Create a `.env.local` file (or edit the one generated). +2. Add your API keys (we'll use **Anthropic** here). + +> You can also use OpenAI, DeepSeek, or any other supported LLM. + +### Get Your Anthropic API Key + +- Head to [Anthropic Console](https://console.anthropic.com/dashboard) +- Create an account and **purchase credits** +- Click **Create Key**, name it, and copy the API key +- Add this to your `.env.local`: + +```env +ANTHROPIC_API_KEY=your_api_key_here +``` + +### Wallet Setup with MetaMask + +1. Add [Flow Testnet](https://developers.flow.com/evm/using) to MetaMask +2. Use the [Faucet](https://faucet.flow.com/fund-account) to fund your wallet +3. Get your private key: + - Click the `...` menu in MetaMask > **Account Details** + - Enter your password, copy the private key +4. Add it to `.env.local`: + +```env +PRIVATE_KEY=your_private_key_here +``` + +Your `.env.local` should look something like this: + +```env +PRIVATE_KEY=... +ANTHROPIC_API_KEY=... +``` + +Now run: + +```bash +mv .env.local .env +npm run dev +``` + +Visit your local server: + +``` +http://localhost:3000 +``` + +--- + +## Configure Your LLM + +If your agent doesn't respond yet — no worries! You still need to configure your **LLM and client libraries**. + +### Choose a Model + +Langchain supports many LLMs ([full list here](https://python.langchain.com/docs/integrations/llms/)). + +For this example, we'll use **Anthropic's `claude-3-5-haiku-20241022`**, a lightweight and affordable model. Alternatively, [DeepSeek](https://deepseek.com/) is highly recommended for budget-friendly usage. + +### Update `create-agent.ts` + +Change the default model from OpenAI: + +```ts +const llm = new ChatOpenAI({ model: 'gpt-4o-mini' }); +``` + +To Anthropic: + +```ts +import { ChatAnthropic } from '@langchain/anthropic'; + +const llm = new ChatAnthropic({ model: 'claude-3-5-haiku-20241022' }); +``` + +Install the package: + +```bash +npm install @langchain/anthropic +``` + +--- + +## Configure Flow and Viem Wallet + +### Update the Faucet Provider Logic + +Change this: + +```ts +const canUseFaucet = walletProvider.getNetwork().networkId == 'base-sepolia'; +``` + +To: + +```ts +const canUseFaucet = walletProvider.getNetwork().networkId == 'flow-testnet'; +``` + +### Add Flow Context Message to Agent + +This gives your agent context about the Flow testnet: + +```ts +const flowContextMessage = canUseFaucet + ? ` + You are now operating on the Flow blockchain testnet using a Viem wallet. Flow is a fast, decentralized, and + developer-friendly blockchain designed for NFTs, games, and apps. + + Key facts about Flow: + - Flow uses a proof-of-stake consensus mechanism + - The native token is FLOW + - Flow has a unique multi-role architecture for high throughput + - The testnet is EVM-compatible (works with MetaMask + Viem) + - RPC URL: https://testnet.evm.nodes.onflow.org + - Chain ID: 545 + + Your wallet address is \${await walletProvider.getAddress()}. +` + : ''; +``` + +Then inject it into the agent message modifier: + +```ts +agent = createReactAgent({ + llm, + tools, + checkpointSaver: memory, + messageModifier: ` + You are a helpful agent interacting with the Flow blockchain testnet using a Viem wallet. + Flow testnet supports EVM, so you can use Ethereum-compatible tools. + \${flowContextMessage} + + Before your first action, check the wallet details. If you see a 5XX error, ask the user to try again later. + If a task is unsupported, let the user know and point them to CDP SDK + AgentKit at: + https://docs.cdp.coinbase.com or https://developers.flow.com. + + Be concise, helpful, and avoid repeating tool descriptions unless asked. + `, +}); +``` + +--- + +## You're Done! + +You now have a working AI agent connected to Flow testnet using AgentKit! + +You can send faucet tokens to your wallet and start testing smart contract interactions or on-chain workflows. + +--- + +## Starter Project + +Want to skip the setup? + +> [Fork the Flow AgentKit Starter](https://github.com/Aliserag/flow-agentkit-starter) + +This starter includes all necessary config to start building immediately on Flow. + +--- + +## Adding AgentKit to an Existing Project + +Already have a project and want to add AgentKit? Follow these steps to integrate it into your existing codebase: + +### Install the Package + +Run this command in your project's root directory: + +```bash +npm install onchain-agent@latest +``` + +This will: + +- Download and install the latest version of the `onchain-agent` package +- Add it to the dependencies section of your `package.json` +- Update your `node_modules` folder accordingly + +### Configure Environment + +1. Create or update your `.env` file with the necessary API keys: + +```env +PRIVATE_KEY=your_wallet_private_key +ANTHROPIC_API_KEY=your_anthropic_api_key +# Or other LLM API keys +``` + +2. Configure your RPC endpoints for Flow: + +```env +FLOW_TESTNET_RPC_URL=https://testnet.evm.nodes.onflow.org +FLOW_MAINNET_RPC_URL=https://mainnet.evm.nodes.onflow.org +``` + +### Integrate AgentKit in Your Code + +Import and configure AgentKit in your application: + +```ts +// Import AgentKit components +import { createReactAgent, ChatAnthropic } from 'onchain-agent'; +import { createWalletClient, http, createPublicClient } from 'viem'; + +// Set up your Flow wallet provider +const walletClient = createWalletClient({ + transport: http('https://testnet.evm.nodes.onflow.org'), + chain: { + id: 545, // Flow Testnet + name: 'Flow Testnet', + }, + account: yourPrivateKey, +}); + +// Configure the LLM +const llm = new ChatAnthropic({ + model: 'claude-3-5-haiku-20241022', +}); + +// Create your agent +const agent = createReactAgent({ + llm, + tools: yourSelectedTools, + // Additional configuration +}); + +// Use the agent in your application +// ... +``` + +### Add Specialized Tools (Optional) + +To add specialized blockchain tools to your agent: + +```ts +import { viem, ViemToolConfig } from 'onchain-agent'; + +// Configure Viem tools for Flow +const viemTools = viem.createTools({ + chain: { + id: 545, + name: 'Flow Testnet', + }, + transport: http('https://testnet.evm.nodes.onflow.org'), +} as ViemToolConfig); + +// Add these tools to your agent +const agent = createReactAgent({ + llm, + tools: [ + ...viemTools, + // Other tools + ], +}); +``` + +--- + +## Resources + +- [AgentKit Docs](https://docs.cdp.coinbase.com/agentkit) +- [Flow EVM Guide](https://developers.flow.com/evm/using) +- [Langchain LLM Integrations](https://python.langchain.com/docs/integrations/llms/) +- [Anthropic Model Comparison](https://docs.anthropic.com/en/docs/about-claude/models/all-models#model-comparison-table) + +--- + +Happy hacking on Flow! + + +=== tutorials/ai-plus-flow/eliza/index.md === +--- +title: Eliza on Flow +description: Learn how to build AI Agent on Flow with Eliza +sidebar_position: 4 +keywords: + - AI + - AI Agent + - Eliza + - Eliza on Flow + - Flow Development + - Quickstart +--- + +# Quickstart Guide to build AI Agent on Flow with Eliza + +Eliza is a powerful framework for building AI agents that can interact with users through natural language. This tutorial will guide you through setting up and deploying an AI agent on the Flow blockchain using Eliza. You'll learn how to create intelligent agents that can understand and respond to user queries, while leveraging Flow's secure and scalable infrastructure. + +## Learning Objectives + +By the end of this tutorial, you will be able to: + +- Set up the Eliza development environment +- Configure and deploy an AI agent on Flow +- Create and customize character configurations +- Integrate different AI models with your agent +- Interact with your AI agent through a web interface +- Add and develop custom plugins for extended functionality + +## Prerequisites + +Before getting started with Eliza, ensure you have: + +- [Node.js 23+] (using [nvm] is recommended) +- [pnpm 9+] +- Git for version control +- A code editor ([VS Code], [Cursor] or [VSCodium] recommended) +- [Flow-cli] for Flow blockchain interaction. + +> **Note for Windows Users:** [WSL 2] is required. + +## Installation + +ElizaOnFlow is a Flow-dedicated Eliza wrapper, so: + +- The plugins from this repository are also compatible with the origin [Eliza]. +- You can also use any plugins from original Eliza in this repository. + +Clone the repository + +```bash +# The ElizaOnFlow is a wrapper with origin Eliza as submodule +git clone --recurse-submodules https://github.com/onflow/elizaOnFlow.git + +# Enter directory +cd elizaOnFlow + +# Please checkout the main branch which is using the latest release of origin Eliza +git checkout main +``` + +Or, If you want to use the origin Eliza, please run: + +```bash +# Eliza's characters folder is a submodule +git clone --recurse-submodules https://github.com/elizaOs/eliza.git + +# Enter directory +cd eliza + +# Checkout the latest release +git checkout $(git describe --tags --abbrev=0) +``` + +If you already cloned without submodules, please run: + +```bash +# Fetch submodules +git submodule update --init --recursive +``` + +Install dependencies + +```bash +pnpm install --no-frozen-lockfile +``` + +:::warning + +Please only use the `--no-frozen-lockfile` option when you're initially instantiating the repo or are bumping the version of a package or adding a new package to your package.json. This practice helps maintain consistency in your project's dependencies and prevents unintended changes to the lockfile. + +::: + +If you are using ElizaOnFlow, you need to install Flow Cadence contracts dependencies to ensure `*.cdc` be correctly linted by Cadence extension. + +Install Flow Cadence contracts dependencies: + +```bash +flow deps install +``` + +Build all packages: + +```bash +pnpm build +``` + +## Configure Environment + +Copy .env.example to .env and fill in the appropriate values. + +```bash +cp .env.example .env +``` + + +:::danger + +In normal development, it's a best practice to use a `.env` to protect API keys and other sensitive information. When working with crypto, it's **critical** to be disciplined and always use them, even in test projects or tutorials. If you expose a wallet key, you might lose everything in that wallet immediately, or someone might watch it for years and rug you the day you put something valuable there. + +::: + + +Edit `.env` and add your values. Do NOT add this file to version control. + +### Choose Your Model + +Eliza supports multiple AI models and you set which model to use inside the character JSON file. +But remember, once you chosed a model, you need to set up the relevant configuration. + +Check full list of supported LLMs in origin Eliza: [Models.ts] + +Suggested models: + +- Use API to access LLM providers + - OpenAI: set modelProvider as `openai`, and set `OPENAI_API_KEY` in `.env` + - Deepseek: set modelProvider as `deepseek`, and set `DEEPSEEK_API_KEY` in `.env` + - Grok: set modelProvider as `grok`, and set `GROK_API_KEY` in `.env` +- Use local inference + - Ollama: set modelProvider as `ollama`, and set `OLLAMA_MODEL` in `.env` to the model name you are using in ollama. + +> To choose model, you need to set in charactor configuration. For example: OPENAI, please set `modelProvider: "openai"` in charactor JSON file or `modelProvider: ModelProviderName.OPENAI` in `charactor.ts` + +### Setup Agent's Flow Account + +Create a new Flow account for the Agent. Learn more: [doc] + +```bash +flow accounts create +``` + +> If you are using Testnet, you can get free tokens from [Flow Faucet] + +Set Flow blockchain configuration in `.env` with new generated Flow account. + +```bash +FLOW_ADDRESS= +FLOW_PRIVATE_KEY= +FLOW_NETWORK= # Default: mainnet +FLOW_ENDPOINT_URL= # Default: +``` + +For testnet, please check Flow's [Networks] for more information. + +## Create Your First Agent + +### Create a Character File + +Check out the `deps/eliza/characters/` directory for a number of character files to try out. +Additionally you can override Eliza's `defaultCharacter` by editting `charactor.ts` which will be default used if no character json provided. + +Copy one of the example character files and make it your own + +```bash +cp characters/scooby.character.json characters/sample.character.json +``` + +📝 [Character Documentation] + +### **Start the Agent** + +Inform it which character you want to run: + +```bash +pnpm start --character="characters/sample.character.json" +``` + +Or you can use `pnpm start:debug` for more debugging logs: + +```bash +pnpm start:debug --character="characters/sample.character.json" +``` + +You can load multiple characters with a comma-separated list: + +```bash +pnpm start --characters="characters/sample.character.json, characters/scooby.character.json" +``` + +### Add / Develop Plugins + +run `npx elizaos plugins list` to get a list of available plugins or visit [Eliza Plugins Registry] + +run `npx elizaos plugins add @elizaos-plugins/plugin-NAME` to install the plugin into your instance + +To create a new plugin **for your own business**, you can refer to the [plugin development guide]. + +#### Additional Requirements + +You may need to install Sharp. If you see an error when starting up, try installing it with the following command: + +```bash +pnpm install --include=optional sharp +``` + +### **Interact with the Agent** + +Now you're ready to start a conversation with your agent. + +Open a new terminal window and run the client's http server. + +```bash +pnpm start:client +``` + +Once the client is running, you'll see a message like this: + +```bash +➜ Local: http://localhost:5173/ +``` + +Simply click the link or open your browser to `http://localhost:5173/`. You'll see the chat interface connect to the system, and you can begin interacting with your character. + +## Common Issues & Solutions + +Please check the orgin Eliza's [Common Issues & Solutions] + +## Conclusion + +In this tutorial, you've learned how to build and deploy an AI agent on the Flow blockchain using Eliza. You've gained hands-on experience with setting up the development environment, configuring agents, creating character configurations, integrating AI models, and developing custom plugins. + +The Eliza framework provides a powerful way to create intelligent agents that can understand and respond to user queries while leveraging Flow's secure and scalable infrastructure. By completing this tutorial, you now have the foundation to build more sophisticated AI agents and create unique user experiences through character customization and plugin development. + +[Node.js 23+]: https://docs.npmjs.com/downloading-and-installing-node-js-and-npm +[nvm]: https://github.com/nvm-sh/nvm +[pnpm 9+]: https://pnpm.io/installation +[VS Code]: https://code.visualstudio.com/ +[Cursor]: https://cursor.com/ +[VSCodium]: https://vscodium.com +[Flow-cli]: https://developers.flow.com/tools/flow-cli +[WSL 2]: https://learn.microsoft.com/en-us/windows/wsl/install-manual +[Eliza]: https://github.com/elizaOs/eliza +[Models.ts]: https://github.com/elizaOS/eliza/blob/main/packages/core/src/models.ts +[doc]: https://developers.flow.com/tools/flow-cli/accounts/create-accounts +[Flow Faucet]: https://faucet.flow.com/ +[Networks]: https://developers.flow.com/networks/flow-networks +[Character Documentation]: https://elizaos.github.io/eliza/docs/core/characterfile/ +[Eliza Plugins Registry]: https://elizaos.github.io/registry +[plugin development guide]: build-plugin.md +[Common Issues & Solutions]: https://elizaos.github.io/eliza/docs/quickstart/#common-issues--solutions + + +=== tutorials/ai-plus-flow/eliza/build-plugin.md === +--- +title: Eliza Plugin Guide +description: Learn how to build Eliza plugins for your AI Agent on Flow +sidebar_position: 2 +keywords: + - AI + - AI Agent + - Eliza + - Eliza on Flow + - Plugin + - Flow Development + - Quickstart +--- + +# Eliza Plugin Development Guide + +Plugins are a powerful way to extend the functionality of your Eliza AI agents. This guide will walk you through the process of creating custom plugins that can enhance your agent's capabilities, from simple utilities to complex integrations with external services. You'll learn how to leverage the plugin system to create modular and reusable components for your AI agents. + +## Learning Objectives + +By the end of this tutorial, you will be able to: + +- Create a new plugin repository from the template +- Understand the plugin development workflow +- Implement custom actions and services +- Integrate plugins with your Eliza agent +- Register and publish plugins to the Eliza Plugin Registry +- Use dependency injection for better plugin architecture + +## Prerequisites + +Before getting started with Eliza, ensure you have: + +- [Node.js 23+] (using [nvm] is recommended) +- [pnpm 9+] +- Git for version control +- A code editor ([VS Code], [Cursor] or [VSCodium] recommended) +- [Flow-cli] for Flow blockchain interaction. + +> **Note for Windows Users:** [WSL 2] is required. + +## Quickstart + +Please follow the [Quickstart Guide] to set up your development environment. + +## Plugin Development + +### Create a Plugin repository from Template + +Visit [Eliza Plugin Template] and click on the "Use this template" button to create a new repository. + +Or you can create a new empty repository and copy the files from some examples at [Eliza Plugins] organization. + +> Note: Flow's Eliza plugin template is using Dependency Injection(`@elizaos-plugins/plugin-di`), you can learn more about the Dependency Injection in the [plugin's README.md]. It allows you can use `Class` instead of `Object` for your `Actions`, `Providers`, `Services`, and etc. **If you don't want to use it, you can follow the other examples in Eliza Plugins organiazation.** + +### Add the Plugin repository to your Eliza project + +Let's say you created a repository named `username/plugin-foo`. + +Use submodules to add the plugin repository to your Eliza project. + +```bash +git submodule add https://github.com/username/plugin-foo.git packages/plugin-foo +``` + +Change the package's name in the plugin's `package.json` to `@elizaos-plugins/plugin-foo`. + +```json +{ + "name": "@elizaos-plugins/plugin-foo", +} +``` + +Add the plugin to agent's `package.json` + +```bash +pnpm add @elizaos-plugins/plugin-foo@'workspace:*' --filter ./agent +``` + +Check the `agent/package.json` to ensure the plugin is added, you should see something like this: + +```json +{ + "dependencies": { + "@elizaos-plugins/plugin-foo": "workspace:*" + } +} +``` + +### Build the Plugin + +Build the plugin using the following command: + +```bash +pnpm build --filter ./packages/plugin-foo + +# Or build all packages +pnpm build +``` + +### Add Plugin to the `character.json` you want to use + +Let's say you want to add the plugin to the `sample` character which is `characters/sample.character.json`. + +```json +{ + "name": "Sample", + "plugins": [ + "@elizaos-plugins/plugin-foo" + ] +} +``` + +:::warning + +If you are using Dependency Injection(`@elizaos-plugins/plugin-di`) in your plugin, remember to add it to the `postProcessors` field. And **`clients` field is deprecated** in the latest version of Eliza, so if you want to add clients you also need to use `plugins` field. + +::: + +```json +{ + "name": "Sample", + "plugins": [ + "@elizaos-plugins/plugin-foo", + "@elizaos-plugins/client-discord" + ], + "postProcessors": [ + "@elizaos-plugins/plugin-di" + ] +} +``` + +### Run the Eliza Agent with your Plugin + +Run the Eliza agent to test the plugin. + +```bash +pnpm start --character="characters/sample.character.json" + +# Or with more debug logs +pnpm start:debug --character="characters/sample.character.json" +``` + +### Interact with the Agent + +Now, you're ready to start a conversation with your agent. + +Open a new terminal window and run the client's http server. + +```bash +pnpm start:client +``` + +## Plugin Registration + +You need to register your plugin in the [Eliza Plugin Registry] to make it available for other users. + +Please follow the guide there, modify the [index.json] and submit a PR to the registry repository. + +## Conclusion + +In this tutorial, you've learned how to develop custom plugins for Eliza. You've gained experience with creating plugin repositories, implementing custom actions and services, integrating plugins with agents, and using dependency injection for better architecture. + +Eliza's plugin system provides a powerful way to extend the functionality of your AI agents. With the knowledge gained from this tutorial, you can now develop more sophisticated plugins, create reusable components, and share your work through the plugin registry. + +[Node.js 23+]: https://docs.npmjs.com/downloading-and-installing-node-js-and-npm +[nvm]: https://github.com/nvm-sh/nvm +[pnpm 9+]: https://pnpm.io/installation +[VS Code]: https://code.visualstudio.com/ +[Cursor]: https://cursor.com/ +[VSCodium]: https://vscodium.com +[Flow-cli]: https://developers.flow.com/tools/flow-cli +[WSL 2]: https://learn.microsoft.com/en-us/windows/wsl/install-manual +[Quickstart Guide]: ./index.md +[Eliza Plugin Template]: https://github.com/onflow/eliza-plugin-template +[Eliza Plugins]: https://github.com/elizaos-plugins +[plugin's README.md]: https://github.com/fixes-world/plugin-di +[Eliza Plugin Registry]: https://github.com/elizaos-plugins/registry +[index.json]: https://github.com/elizaos-plugins/registry/blob/main/index.json + + +=== tutorials/ai-plus-flow/cursor/index.md === +--- +title: Use Flow Knowledge Base in Cursor +sidebar_label: Use Cursor AI +sidebar_position: 1 +keywords: + - Cursor + - AI + - Flow documentation + - Cadence documentation + - Flow development + - Flow tools + - Flow IDE + - Flow setup + - Flow configuration + - Flow AI assistance +--- + +# Use Flow Knowledge Base in Cursor + +[Cursor] is an AI code editor that makes it easy to write code while building Flow apps. Let's walk through how to setup Cursor for the best possible experience when writing applications on Flow. + +
    + +
    + +## Installation + +Adding Flow docs lets you interact with our docs directly and get the most accurate answers to your questions. + +1. Go to Cursor Settings > Features > Docs and click "+ Add new doc". + +![Cursor Settings](./images//use-cursor-1.png) + +1. Set Flow Docs: + +- Enter the URL of the Flow docs: `https://developers.flow.com/tools` and press Enter. + - Note: This **will index all** the docs. We're investigating why you need `/tools` + - Cursor will automatically detect the Flow docs and index them for you. + - Ensure the name is `Flow`, and click "Confirm" to add the docs. + +![Cursor Settings](./images//use-cursor-2.png) + +1. Set Cadence Docs: + +- Click "+ Add new doc" again, now enter the URL of the Cadence docs: `https://cadence-lang.org/docs/` and press Enter. +- Same process as before, ensure the name is `Cadence`, and click "Confirm" to add the docs. + +1. Add [Flow Data Sources]: + Click "+ Add new doc" one more time and enter the URL of our massive, auto-generated file with the most current data and practices for Flow and Cadence: `https://github.com/onflow/Flow-Data-Sources/blob/main/merged_docs/all_merged.md` and press Enter. + +- Enter `Flow Data Sources`, and click "Confirm" to add the doc. +- **Caution**: This file is very large. For older development machines, you may wish to use the [essentials merged] file instead. + +1. Now wait for Cursor to index the docs. You can check the progress in the Docs section of the settings. After the indexing is complete, you can start using the docs in Cursor. + +## Using Flow Docs in Cursor + +You can then reference the Flow docs in your prompt with the `@Flow`, `@Cadence`or `@Flow Data Sources` docs. + +![Cursor Settings](./images//use-cursor-3.png) + +## Best Practices + +When using Cursor with Flow documentation: + +- Use `@Flow` when asking questions about Flow-specific concepts, tools, or ecosystem +- Use `@Cadence` when asking questions about Cadence programming language syntax or features +- Use `@Flow Data Sources` when asking about complex questions, difficult tasks, or anything that the first two sources didn't provide a satisfactory result +- Be specific in your prompts to get more accurate and relevant answers +- Combine both `@Flow` and `@Cadence` when working on cross-VM applications +- Use the documentation to verify AI-generated code and ensure best practices + +## Troubleshooting + +If you encounter any issues: + +1. Ensure all three sources are properly indexed +2. Try refreshing the documentation if answers seem outdated +3. Check your internet connection as Cursor needs to access the documentation +4. Verify the URLs are correct in your settings +5. Contact Cursor support if issues persist + +[Cursor]: https://www.cursor.com/ +[Flow Data Sources]: ../flow-data-sources.md +[essentials merged]: https://github.com/onflow/Flow-Data-Sources/blob/main/merged_docs/essentials_merged.md + + +=== tutorials/ai-plus-flow/chatgpt/index.md === +--- +title: Use Flow Knowledge Base in ChatGPT +sidebar_label: Use ChatGPT +sidebar_position: 2 +keywords: + - ChatGPT + - AI + - OpenAI + - Flow documentation + - Cadence documentation + - Flow development + - Flow tools + - Flow IDE + - Flow setup + - Flow configuration + - Flow AI assistance +--- + +# Use Flow Knowledge Base in ChatGPT + +[ChatGPT] is an AI assistant developed by [OpenAI] that can help with tasks such as writing, coding, and answering questions. It adapts to context and user input to provide relevant, conversational responses. ChatGPT can be integrated into developer tools or workflows to assist with documentation, debugging, and productivity. + +This guide walks you through creating a **Custom GPT** using ChatGPT that can reference the [Flow Data Sources] file to answer questions. + +
    + +
    + +:::warning + +You'll need a [ChatGPT Plus subscription] to use the **Custom GPT** feature. + +::: + +## 📍 Step 1: Open the "Explore GPTs" Section + +1. Log in to [ChatGPT]. +2. In the sidebar on the left, click **Explore GPTs**. + +![explore gpts](explore-gpts.png) + +--- + +## 📍 Step 2: Click "Create a GPT" + +1. In the **Explore GPTs** screen, click the **"Create"** button in the top-right corner. + +![create](create.png) + +--- + +## 📍 Step 3: Walk Through the GPT Builder + +ChatGPT will now guide you through a conversation to set up your custom GPT. First, drag and drop the [Flow Data Sources All Merged] file into the prompt. + +### Suggested Prompt + +```text +I want to make a GPT called FlowGPT that uses the linked file as it's primary source. This file changes, so it should reference the live file at least once a day: https://github.com/onflow/Flow-Data-Sources/blob/main/merged_docs/all_merged.md +``` + +--- + +## 📍 Step 4: Configure the GPT's Name and Instructions + +ChatGPT may ask you to customize or verify: + +- **Name and description** of your GPT +- **Instructions**: Tell it how to behave and what to prioritize (e.g., always reference the uploaded document) +- **Capabilities**: Enable file browsing, code interpreter, or DALL·E if needed + +We've found it helpful to suggest: + +```text +Please imagine you are a fast and smart junior developer who is eager to help and has memorized all the information in the linked file +``` + +Please let us know if you find any other useful customization prompts! + +--- + +## 📍 Step 5: Test Your GPT + +Once the GPT is built, you'll be taken to a preview chat window. Test it by asking a few questions based on your uploaded document. + +--- + +## 📍 Step 6: Save and Publish (Optional) + +When you're ready: + +- Click **"Update & Save"** to finalize +- You can choose to keep it **private** or make it **public** + +--- + +## ✅ That's it! + +You've now created a custom GPT that references your uploaded file as a primary source. You can update the file or instructions later if needed. + +[ChatGPT]: https://chatgpt.com/ +[OpenAI]: https://openai.com/ +[ChatGPT Plus subscription]: https://chat.openai.com +[Flow Data Sources]: ../flow-data-sources.md +[Flow Data Sources All Merged]: https://github.com/onflow/Flow-Data-Sources/blob/main/merged_docs/all_merged.md + + +=== tools/index.mdx === +--- +sidebar_position: 12 +title: Tools +description: Essential tools for the Flow blockchain ecosystem +--- + +import DocCardList from '@theme/DocCardList'; +import { isSamePath } from '@docusaurus/theme-common/internal'; +import { useDocsSidebar } from '@docusaurus/plugin-content-docs/client'; +import { useLocation } from '@docusaurus/router'; + + !isSamePath(item.href, useLocation().pathname)), + { + type: 'link', + label: 'Flowser', + href: 'https://flowser.dev/', + description: 'Flowser combines all the tools for local development and gives you a clear UI to inspect the local Flow network.', + customProps: { + icon: 'https://flowser.dev/icon.png', + author: { + name: 'Flowser', + profileImage: + 'https://flowser.dev/icon.png', + }, + twitterLink: 'https://twitter.com/onflowser', + githubLink: 'https://github.com/onflowser/flowser' + } + }, + { + type: 'link', + label: 'Overflow', + href: 'https://github.com/bjartek/overflow', + description: 'Overflow is a Go-based DSL for testing and running interactive stories', + customProps: { + icon: '', + author: { + name: 'bjartek', + profileImage: + 'https://avatars.githubusercontent.com/u/10621?v=4', + }, + discordLink: 'https://discord.gg/t6GEtHnWFh', + githubLink: 'https://github.com/bjartek/overflow' + } + }, +]}/> + + +=== tools/error-codes.md === +--- +title: Error Codes +sidebar_position: 7 +--- + +# Error Codes + +List of error codes returned from failing transactions and scripts. The error code has an accompanied error message that usually gives more clarification. This list is meant to give more information and helpful hints. +[Code file](https://github.com/onflow/flow-go/blob/master/fvm/errors/codes.go) + +### 1006 + +**ErrCodeInvalidProposalSignatureError** + +Example: +`...` + +### 1007 + +**ErrCodeInvalidProposalSeqNumberError** + +Example: +`[Error Code: 1007] invalid proposal key: public key 0 on account xxx has sequence number xxx, but given xxx` + +### 1008 + +**ErrCodeInvalidPayloadSignatureError** + +Example: +`[Error Code: 1008] invalid payload signature: public key 0 on account xxx does not have a valid signature: signature is not valid` + +### 1009 + +**ErrCodeInvalidEnvelopeSignatureError** + +Example: +`[Error Code: 1009] invalid envelope key: public key 1 on account xxx does not have a valid signature: signature is not valid` + +### 1051 + +**ErrCodeValueError** + +Example: +`[Error Code: 1051] invalid value (xxx): invalid encoded public key value: rlp: expected input list for flow.runtimeAccountPublicKeyWrapper...` + +### 1052 + +**ErrCodeInvalidArgumentError** + +Example: +`[Error Code: 1052] transaction arguments are invalid: (argument is not json decodable: failed to decode value: runtime error: slice bounds out of range [:2] with length 0)` + +### 1053 + +**ErrCodeInvalidAddressError** + +Example: +`...` + +### 1054 + +**ErrCodeInvalidLocationError** + +Example: +`[Error Code: 1054] location (../contracts/FungibleToken.cdc) is not a valid location: expecting an AddressLocation, but other location types are passed ../contracts/FungibleToken.cdc` + +### 1055 + +**ErrCodeAccountAuthorizationError** + +Example: +`[Error Code: 1055] authorization failed for account e85d442d61a611d8: payer account does not have sufficient signatures (1 < 1000)` + +### 1056 + +**ErrCodeOperationAuthorizationError** + +Example: +`[Error Code: 1056] (RemoveContract) is not authorized: removing contracts requires authorization from specific accounts goroutine 5688834491 [running]:` + +### 1057 + +**ErrCodeOperationNotSupportedError** + +Example: +`...` + +### 1101 + +**ErrCodeCadenceRunTimeError** + +Example: +`[Error Code: 1101] cadence runtime error Execution failed: error: pre-condition failed: Amount withdrawn must be less than or equal than the balance of the Vault` + +### 1103 + +**ErrCodeStorageCapacityExceeded** + +Example: +`[Error Code: 1103] The account with address (xxx) uses 96559611 bytes of storage which is over its capacity (96554500 bytes). Capacity can be increased by adding FLOW tokens to the account.` + +For more information refer to [Fees](../build/basics/fees.md#maximum-available-balance) + +### 1105 + +**ErrCodeEventLimitExceededError** + +Example: +`[Error Code: 1105] total event byte size (256200) exceeds limit (256000)` + +### 1106 + +**ErrCodeLedgerInteractionLimitExceededError** + +Example: +`[Error Code: 1106] max interaction with storage has exceeded the limit (used: 20276498 bytes, limit 20000000 bytes)` + +### 1107 + +**ErrCodeStateKeySizeLimitError** + +Example: +`...` + +### 1108 + +**ErrCodeStateValueSizeLimitError** + +Example: +`...` + +### 1109 + +**ErrCodeTransactionFeeDeductionFailedError** + +Example: +`[Error Code: 1109] failed to deduct 0 transaction fees from 14af75b8c487333c: Execution failed: f919ee77447b7497.FlowFees:97:24` + +### 1110 + +**ErrCodeComputationLimitExceededError** + +Example: +`[Error Code: 1110] computation exceeds limit (100)` + +### 1111 + +**ErrCodeMemoryLimitExceededError** + +Example: +`...` + +### 1112 + +**ErrCodeCouldNotDecodeExecutionParameterFromState** + +Example: +`...` + +### 1113 + +**ErrCodeScriptExecutionTimedOutError** + +Example: +`...` + +### 1114 + +**ErrCodeScriptExecutionCancelledError** + +Example: +`...` + +### 1115 + +**ErrCodeEventEncodingError** + +Example: +`...` + +### 1116 + +**ErrCodeInvalidInternalStateAccessError** + +Example: +`...` + +### 1118 + +**ErrCodeInsufficientPayerBalance** + +Example: +` [Error Code: 1118] payer ... has insufficient balance to attempt transaction execution (required balance: 0.00100000)` + +### 1201 + +**ErrCodeAccountNotFoundError** + +Example: +`[Error Code: 1201] account not found for address xxx` + +### 1202 + +**ErrCodeAccountPublicKeyNotFoundError** + +Example: +`[Error Code: 1202] account public key not found for address xxx and key index 3` + +### 1203 + +**ErrCodeAccountAlreadyExistsError** + +Example: +`...` + +### 1204 + +**ErrCodeFrozenAccountError** + +Example: +`...` + +### 1206 + +**ErrCodeAccountPublicKeyLimitError** + +Example: +`...` + +### 1251 + +**ErrCodeContractNotFoundError** + +Example: +`...` + +### 2000 + +**FailureCodeUnknownFailure** + +Example: +`...` + +### 2001 + +**FailureCodeEncodingFailure** + +Example: +`...` + +### 2002 + +**FailureCodeLedgerFailure** + +Example: +`...` + +### 2003 + +**FailureCodeStateMergeFailure** + +Example: +`...` + +### 2004 + +**FailureCodeBlockFinderFailure** + +Example: +`...` + +### 2006 + +**FailureCodeParseRestrictedModeInvalidAccessFailure** + +Example: +`...` + +### 2007 + +**FailureCodePayerBalanceCheckFailure** + +Example: +`...` + + +=== tools/wallet-provider-spec/user-signature.md === +# User Signature + +## Status + +- **Last Updated:** June 1st 2021 +- **Stable:** Yes +- **Risk of Breaking Change:** Low +- **Compatibility:** `>= @onflow/fcl@0.0.71` + +# Overview and Introduction + +**Personally sign data via FCL Compatible Wallets** + +**FCL** now incldues **`signUserMessage()`** which allows for the sending of unencrypted message data to a connected wallet provider or service to be signed with a user's private key. + +An application or service can verify a signature against a user's public key on the **Flow Blockchain**, providing proof a user controls the account's private key. + +**Use Cases** + +- **Authentication**: Cryptographically verify the ownership of a **Flow** account by signing a piece of data using a private key +- **Improved Application Login** + - **Increased security**: Arguably more secure than proof of ownership by email/password + - **Simplified UX**: No application password required + - **Increased privacy**: No email or third party authentication service needed +- **Message Validation**: Assuring that a message sent or received has not been tampered with +- **Multisig contracts** +- **Decentralised exchanges** +- **Meta transactions** + + +# Config and Authentication + +As a prerequisite, **FCL** is configured to point to the Wallet Provider's Authentication Endpoint. No additional configuration is required. + +> During development (and on mainnet) FCL can be configured to use the wallet directly by +> setting the **Wallet Discovery Url** to the wallet provider's **Authentication Endpoint** +> by configuring fcl like this `config().put("discovery.wallet", "https://my-awesome-wallet-provider.com/fcl/authenticate")`. + +Common Configuration Keys and additional info can be found here [How to Configure FCL](../clients/fcl-js/configure-fcl.md#common-configuration-keys) + +1. A user initiates authentication with the wallet provider via application UI +2. The wallet confirms a user's identity and sends back information used to configure **FCL** for future user actions in the application +3. Included in the authentication response should be the provider's [Key Services](#) including a **`user-signature`** service for use with **`signUserMessage()`** + +# User Signature Service + +A [user-signature service](https://github.com/onflow/fcl-js/blob/master/packages/fcl-core/src/normalizers/service/user-signature.js) is a standard service, with methods for **IFRAME/RPC** or **HTTP/POST**. + +The `user-signature` service receives a signable message from **FCL** and returns a standard [PollingResponse](https://github.com/onflow/fcl-js/blob/master/packages/fcl-core/src/normalizers/service/polling-response.js#L5) with an array of [CompositeSignatures](https://github.com/onflow/fcl-js/blob/master/packages/fcl-core/src/normalizers/service/composite-signature.js#L4) or `null` as the data. + +A status of **Approved** needs to have an array of composite signatures as data. + +A status of **Declined** needs to include a reason why. + +A **Pending** status needs to include an updates service and can include a local. +A service using the **`IFRAME/RPC`** method can only respond with approved or declined, as pending is not valid for iframes. + + +When `signUserMessage()` is called by the application, **FCL** uses the service method to decide how to send the signable to the wallet. + +The Wallet is responsible for prepending the signable with the correct `UserDomainTag`, hashing, and signing the message. + +# Signing Sequence + +1. Application sends message to signing service. **FCL expects a hexadecimal string** +3. Wallet/Service tags the message with required `UserDomainTag` (see below), hashes, and signs using the `signatureAlgorithm` specified on account key +2. Wallet makes available a Composite Signature consisting of `addr`, `keyId`, and `signature` **as a hex string** + +### UserDomainTag +The **`UserDomainTag`** is the prefix of all signed user space payloads. + +Before hashing and signing the message, the wallet must add a specified DOMAIN TAG. + +> currently **"FLOW-V0.0-user"** + +A domain tag is encoded as **UTF-8 bytes, right padded to a total length of 32 bytes**, prepended to the message. + +The signature can now be verified on the Flow blockchain. The following illustrates an example using `fcl.verifyUserSignatures` + +```javascript +/** + * Verify a valid signature/s for an account on Flow. + * + * @param {string} msg - A message string in hexadecimal format + * @param {Array} compSigs - An array of Composite Signatures + * @param {string} compSigs[].addr - The account address + * @param {number} compSigs[].keyId - The account keyId + * @param {string} compSigs[].signature - The signature to verify + * @return {bool} + * + * @example + * + * const isValid = await fcl.verifyUserSignatures( + * Buffer.from('FOO').toString("hex"), + * [{f_type: "CompositeSignature", f_vsn: "1.0.0", addr: "0x123", keyId: 0, signature: "abc123"}] + * ) + */ +``` + +## TL;DR Wallet Provider + +- Register with **FCL** and provide signing service endpoint. No further configuration is needed. +- On receipt of message, prompt user to approve or decline +- Prepend `UserDomainTag`, hash and sign the message with the signatureAlgorithm specified on user's key +- Return a standard `PollingResponse` with an array of `CompositeSignatures` as data or `null` and `reason` if declined + + + +=== tools/wallet-provider-spec/provable-authn.md === +# Provable Authn + +In order to improve UX/DX and encourage seamless integration with App backends and services, `fcl.authenticate` has been upgraded. + +Additional data is sent in the body of `FCL:VIEW:READY:RESPONSE`. This data includes what the wallet needs to build a message for signing with the user’s private key/s. +The signature can be returned as part of an optional `account-proof` service with the `FCL:VIEW:RESPONSE`. + +When provided by the wallet, this **signature** and additional **account-proof data** is available to the App via `fcl.currentUser` services. The service data can be used to recreate the message, and verify the signature on the Flow Blockchain. + +For example, it can be sent to the App’s backend and after validating the signature and the other account-proof data, it can safely associate the included account address to a user and log them in. + +--- + +## TL;DR Wallet Provider + +1. Wallet receives Authn `FCL:VIEW:READY:RESPONSE` request and parses out the `appIdentifier`, and `nonce`. +2. The wallet authenticates the user however they choose to do, and determines the user's account `address` +3. Wallet prepares and signs the message: + - Encodes the `appIdentifier`, `nonce`, and `address` along with the `"FCL-ACCOUNT-PROOF-V0.0"` domain separation tag, [using the encoding scheme described below](#account-proof-message-encoding). + - Signs the message with the `signatureAlgorithm` and `hashAlgorithm` specified on user's key. **It is highly recommended that the wallet display the message data and receive user approval before signing.** +4. Wallet sends back this new service and data along with the other service configuration when completing Authn. + +### Account Proof Message Encoding + +The account proof message is encoded as follows: + +```text +MESSAGE = + USER_DOMAIN_TAG || + RLP_ENCODE([ + APP_IDENTIFIER, + ADDRESS, + NONCE + ]) +``` + +with the following values: + +- `ACCOUNT_PROOF_DOMAIN_TAG` is the constant `"FCL-ACCOUNT-PROOF-V0.0"`, encoded as UTF-8 byte array and right-padded with zero bytes to a length of 32 bytes. +- `APP_IDENTIFIER` is an arbitrary length string. +- `ADDRESS` is a byte array containing the address bytes, left-padded with zero bytes to a length of 8 bytes. +- `NONCE` is an byte array with a minimum length of 32 bytes. + +`RLP_ENCODE` is a function that performs [RLP encoding](https://eth.wiki/fundamentals/rlp) and returns the encoded value as bytes. + +### JavaScript Signing Example + +```javascript +// Using WalletUtils +import {WalletUtils} from "@onflow/fcl" + +const message = WalletUtils.encodeAccountProof( + appIdentifier, // A human readable string to identify your application during signing + address, // Flow address of the user authenticating + nonce, // minimum 32-btye nonce +) + +sign(privateKey, message) + +// Without using FCL WalletUtils +const ACCOUNT_PROOF_DOMAIN_TAG = rightPaddedHexBuffer( + Buffer.from("FCL-ACCOUNT-PROOF-V0.0").toString("hex"), + 32 +) +const message = rlp([appIdentifier, address, nonce]) +const prependUserDomainTag = (message) => ACCOUNT_PROOF_DOMAIN_TAG + message + +sign(privateKey, prependUserDomainTag(message)) +``` + +```json +// Authentication Proof Service +{ + f_type: "Service", // Its a service! + f_vsn: "1.0.0", // Follows the v1.0.0 spec for the service + type: "account-proof", // the type of service it is + method: "DATA", // Its data! + uid: "awesome-wallet#account-proof", // A unique identifier for the service + data: { + f_type: "account-proof", + f_vsn: "1.0.0" + // The user's address (8 bytes, i.e 16 hex characters) + address: "0xf8d6e0586b0a20c7", + // Nonce signed by the current account-proof (minimum 32 bytes in total, i.e 64 hex characters) + nonce: "75f8587e5bd5f9dcc9909d0dae1f0ac5814458b2ae129620502cb936fde7120a", + signatures: [CompositeSignature], + } +} +``` + + +=== tools/wallet-provider-spec/index.md === +--- +title: Wallet Provider Spec +sidebar_title: Draft v4 +sidebar_position: 8 +--- + +## Status + +- **Last Updated:** June 20th 2022 +- **Stable:** Yes +- **Risk of Breaking Change:** Medium +- **Compatibility:** `>= @onflow/fcl@1.0.0-alpha.0` + +## Definitions + +This document is written with the perspective that _you_ who are reading this right now are an FCL Wallet Developer. All references to _you_ in this doc are done with this perspective in mind. + +# Overview + +Flow Client Library (FCL) approaches the idea of blockchain wallets on Flow in a different way than how wallets may be supported on other blockchains. For example, with FCL, a wallet is not necessarily limited to being a browser extension or even a native application on a users device. FCL offers wallet developers the flexibility and freedom to build many different types of applications. Since wallet applications can take on many forms, we needed to create a way for these varying applications to be able to communicate and work together. + +FCL acts in many ways as a protocol to facilitate communication and configuration between the different parties involved in a blockchain application. An _Application_ can use FCL to _authenticate_ users, and request _authorizations_ for transactions, as well as mutate and query the _Blockchain_. An application using FCL offers its _Users_ a way to connect and select any number of Wallet Providers and their Wallet Services. A selected _Wallet_ provides an Application's instance of FCL with configuration information about itself and its Wallet Services, allowing the _User_ and _Application_ to interact with them. + +In the following paragraphs we'll explore ways in which you can integrate with FCL by providing implementations of various FCL services. + +The following services will be covered: + +- Authentication (Authn) Service +- Authorization (Authz) Service +- User Signature Service +- Pre-Authz Service + +# Service Methods + +FCL Services are your way as a Wallet Provider of configuring FCL with information about what your wallet can do. FCL uses what it calls `Service Methods` to perform your supported FCL services. Service Methods are the ways FCL can talk to your wallet. Your wallet gets to decide which of these service methods each of your supported services use to communicate with you. + +Sometimes services just configure FCL and that's it. An example of this can be seen with the Authentication Service and the OpenID Service. +With those two services you are simply telling FCL "here is a bunch of info about the current user". (You will see that those two services both have a `method: "DATA"` field in them. +Currently these are the only two cases that can be a data service.) + +Other services can be a little more complex. For example, they might require a back and forth communication between FCL and the Service in question. +Ultimately we want to do this back and forth via a secure back-channel (https requests to servers), **but in some situations that isn't a viable option, so there is also a front-channel option**. +Where possible, you should aim to provide a back-channel support for services, and only fall back to a front-channel if absolutely necessary. + +Back-channel communications use `method: "HTTP/POST"`, while front-channel communications use `method: "IFRAME/RPC"`, `method: "POP/RPC"`, `method: "TAB/RPC` and `method: "EXT/RPC"`. + +| Service Method | Front | Back | +| -------------- | ----- | ---- | +| HTTP/POST | ⛔ | ✅ | +| IFRAME/RPC | ✅ | ⛔ | +| POP/RPC | ✅ | ⛔ | +| TAB/RPC | ✅ | ⛔ | +| EXT/RPC | ✅ | ⛔ | + +It's important to note that regardless of the method of communication, the data that is sent back and forth between the parties involved is the same. + +# Protocol schema definitions + +In this section we define the schema of objects used in the protocol. While they are JavaScript objects, only features supported by JSON should be used. (Meaning that conversion of an object to and from JSON should not result in any loss.) + +For the schema definition language we choose TypeScript, so that the schema closely resembles the actual type definitions one would use when making an FCL implementation. + +**Note that currently there are no official type definitions available for FCL. If you are using TypeScript, you will have to create your own type definitions (possibly based on the schema definitions presented in this document).** + +## Common definitions + +In this section we introduce some common definitions that the individual object definitions will be deriving from. + +First, let us define the kinds of FCL objects available: + +```typescript +type ObjectType = + | 'PollingResponse' + | 'Service' + | 'Identity' + | 'ServiceProvider' + | 'AuthnResponse' + | 'Signable' + | 'CompositeSignature' + | 'OpenID'; +``` + +The fields common to all FCL objects then can be defined as follows: + +```typescript +interface ObjectBase { + f_vsn: Version; + f_type: ObjectType; +} +``` + +The `f_vsn` field is usually `1.0.0` for this specification, but some exceptions will be defined by passing a different `Version` type parameter to `ObjectBase`. + +All FCL objects carry an `f_type` field so that their types can be identified at runtime. + +## FCL objects + +In this section we will define the FCL objects with each `ObjectType`. + +We also define the union of them to mean any FCL object: + +```typescript +type FclObject = + | PollingResponse + | Service + | Identity + | ServiceProvider + | AuthnResponse + | Signable + | CompositeSignature + | OpenID; +``` + +### `PollingResponse` + +```typescript +interface PollingResponse extends ObjectBase { + f_type: 'PollingResponse'; + status: 'APPROVED' | 'DECLINED' | 'PENDING' | 'REDIRECT'; + reason: string | null; + data?: FclObject; + updates?: FclObject; + local?: FclObject; +} +``` + +Each response back to FCL must be "wrapped" in a `PollingResponse`. The `status` field determines the meaning of the response: + +- An `APPROVED` status means that the request has been approved. The `data` field should be present. +- A `DECLINED` status means that the request has been declined. The `reason` field should contain a human readable reason for the refusal. +- A `PENDING` status means that the request is being processed. More `PENDING` responses may follow, but eventually a non-pending status should be returned. The `updates` and `local` fields may be present. +- The `REDIRECT` status is reserved, and should not be used by wallet services. + +In summary, zero or more `PENDING` responses should be followed by a non-pending response. It is entirely acceptable for your service to immediately return an `APPROVED` Polling Response, skipping a `PENDING` state. + +See also [PollingResponse](https://github.com/onflow/fcl-js/blob/master/packages/fcl-core/src/normalizers/service/polling-response.js). + +Here are some examples of valid `PollingResponse` objects: + +```javascript +// APPROVED +{ + f_type: "PollingResponse", + f_vsn: "1.0.0", + status: "APPROVED", + data: ___, // what the service needs to send to FCL +} + +// Declined +{ + f_type: "PollingResponse", + f_vsn: "1.0.0", + status: "DECLINED", + reason: "Declined by user." +} + +// Pending - Simple +{ + f_type: "PollingResponse", + f_vsn: "1.0.0", + status: "PENDING", + updates: { + f_type: "Service", + f_vsn: "1.0.0", + type: "back-channel-rpc", + endpoint: "https://____", // where post request will be sent + method: "HTTP/POST", + data: {}, // will be included in the request's body + params: {}, // will be included in the request's url + } +} + +// Pending - First Time with Local +{ + f_type: "PollingResponse", + f_vsn: "1.0.0", + status: "PENDING", + updates: { + f_type: "Service", + f_vsn: "1.0.0", + type: "back-channel-rpc", + endpoint: "https://____", // where post request will be sent + method: "HTTP/POST", + data: {}, // included in body of request + params: {}, // included as query params on endpoint + }, + local: { + f_type: "Service", + f_vsn: "1.0.0", + endpoint: "https://____", // the iframe that will be rendered, + method: "VIEW/IFRAME", + data: {}, // sent to frame when ready + params: {}, // included as query params on endpoint + } +} +``` + +A `PollingResponse` can alternatively be constructed using `WalletUtils` when sending `"APPROVED"` or `"DECLINED"` responses. + +```javascript +import {WalletUtils} from "@onflow/fcl" + +// Approving a PollingResponse +// Example using an AuthnResponse as the PollingResponse data +WalletUtils.approve({ + f_type: "AuthnResponse", + f_vsn: "1.0.0" + ... +}) + +// Rejecting a PollingResponse +// Supplies a reason for declining +const reason = "User declined to authenticate." +WalletUtils.decline(reason) +``` + +### `Service` + +```typescript +type ServiceType = + | 'authn' + | 'authz' + | 'user-signature' + | 'pre-authz' + | 'open-id' + | 'back-channel-rpc' + | 'authn-refresh'; + +type ServiceMethod = + | 'HTTP/POST' + | 'IFRAME/RPC' + | 'POP/RPC' + | 'TAB/RPC' + | 'EXT/RPC' + | 'DATA'; + +interface Service extends ObjectBase { + f_type: 'Service'; + type: ServiceType; + method: ServiceMethod; + uid: string; + endpoint: string; + id: string; + identity: Identity; + provider?: ServiceProvider; + data?: FclObject; +} +``` + +The meaning of the fields is as follows. + +- `type`: The type of this service. +- `method`: The service method this service uses. `DATA` means that the purpose of this service is just to provide the information in this `Service` object, and no active communication services are provided. +- `uid`: A unique identifier for the service. A common scheme for deriving this is to use `'wallet-name#${type}'`, where `${type}` refers to the type of this service. +- `endpoint`: Defines where to communicate with the service. + - When `method` is `EXT/RPC`, this can be an arbitrary unique string, and the extension will need to use it to identify its own services. A common scheme for deriving the `endpoint` is to use `'ext:${address}'`, where `${address}` refers to the wallet's address. (See `ServiceProvider` for more information.) +- `id`: The wallet's internal identifier for the user. If no other identifier is used, simply the user's flow account address can be used here. +- `identity`: Information about the identity of the user. +- `provider`: Information about the wallet. +- `data`: Additional information used with a service of type `open-id`. + +See also: + +- [authn](https://github.com/onflow/fcl-js/blob/master/packages/fcl-core/src/normalizers/service/authn.js) +- [authz](https://github.com/onflow/fcl-js/blob/master/packages/fcl-core/src/normalizers/service/authz.js) +- [user-signature](https://github.com/onflow/fcl-js/blob/master/packages/fcl-core/src/normalizers/service/user-signature.js) +- [pre-authz](https://github.com/onflow/fcl-js/blob/master/packages/fcl-core/src/normalizers/service/pre-authz.js) +- [open-id](https://github.com/onflow/fcl-js/blob/master/packages/fcl-core/src/normalizers/service/open-id.js) +- [back-channel-rpc](https://github.com/onflow/fcl-js/blob/master/packages/fcl-core/src/normalizers/service/back-channel-rpc.js) + +### `Identity` + +This object is used to define the identity of the user. + +```typescript +interface Identity extends ObjectBase { + f_type: 'Identity'; + address: string; + keyId?: number; +} +``` + +The meaning of the fields is as follows. + +- `address`: The flow account address of the user. +- `keyId`: The id of the key associated with this account that will be used for signing. + +### `ServiceProvider` + +This object is used to communicate information about a wallet. + +```typescript +interface ServiceProvider extends ObjectBase { + f_type: 'ServiceProvider'; + address: string; + name?: string; + description?: string; + icon?: string; + website?: string; + supportUrl?: string; + supportEmail?: string; +} +``` + +The meaning of the fields is as follows. + +- `address`: A flow account address owned by the wallet. It is unspecified what this will be used for. +- `name`: The name of the wallet. +- `description`: A short description for the wallet. +- `icon`: An image URL for the wallet's icon. +- `website`: The wallet's website. +- `supportUrl`: A URL the user can use to get support with the wallet. +- `supportEmail`: An e-mail address the user can use to get support with the wallet. + +### `AuthnResponse` + +This object is used to inform FCL about the services a wallet provides. + +```typescript +interface AuthnResponse extends ObjectBase { + f_type: 'AuthnResponse'; + addr: string; + services: Service[]; +} +``` + +The meaning of the fields is as follows. + +- `addr`: The flow account address of the user. +- `services`: The list of services provided by the wallet. + +### `Signable` + +```typescript +interface Signable extends ObjectBase<'1.0.1'> { + f_type: 'Signable'; + addr: string; + keyId: number; + voucher: { + cadence: string; + refBlock: string; + computeLimit: number; + arguments: { + type: string; + value: unknown; + }[]; + proposalKey: { + address: string; + keyId: number; + sequenceNum: number; + }; + payer: string; + authorizers: string[]; + }; +} +``` + +The `WalletUtils.encodeMessageFromSignable` function can be used to calculate the message that needs to be signed. + +### `CompositeSignature` + +```typescript +interface CompositeSignature extends ObjectBase { + f_type: 'CompositeSignature'; + addr: string; + keyId: number; + signature: string; +} +``` + +See also [CompositeSignature](https://github.com/onflow/fcl-js/blob/master/packages/fcl-core/src/normalizers/service/composite-signature.js). + +### `OpenID` + +TODO + +## Miscellaneous objects + +### `Message` + +```typescript +type MessageType = + | 'FCL:VIEW:READY' + | 'FCL:VIEW:READY:RESPONSE' + | 'FCL:VIEW:RESPONSE' + | 'FCL:VIEW:CLOSE'; + +type Message = { + type: MessageType; +}; +``` + +A message that indicates the status of the protocol invocation. + +This type is sometimes used as part of an _intersection type_. For example, the type `Message & PollingResponse` means a `PollingResponse` extended with the `type` field from `Message`. + +### `ExtensionServiceInitiationMessage` + +```typescript +type ExtensionServiceInitiationMessage = { + service: Service; +}; +``` + +This object is used to invoke a service when the `EXT/RPC` service method is used. + +## See also + +- [local-view](https://github.com/onflow/fcl-js/blob/master/packages/fcl-core/src/normalizers/service/local-view.js) +- [frame](https://github.com/onflow/fcl-js/blob/master/packages/fcl-core/src/normalizers/service/frame.js) + +# Service Methods + +## IFRAME/RPC (Front Channel) + +`IFRAME/RPC` is the easiest to explain, so we will start with it: + +- An iframe is rendered (comes from the `endpoint` in the service). +- The rendered iframe adds a listener and sends the `"FCL:VIEW:READY"` message. This can be simplified `WalletUtils.ready(callback)` +- FCL will send the data to be dealt with: + - Where `body` is the stuff you care about, `params` and `data` are additional information you can provide in the service object. +- The wallet sends back an `"APPROVED"` or `"DECLINED"` post message. (It will be a `f_type: "PollingResponse"`, which we will get to in a bit). This can be simplified using `WalletUtils.approve` and `WalletUtils.decline` + - If it's approved, the polling response's data field will need to be what FCL is expecting. + - If it's declined, the polling response's reason field should say why it was declined. + +```javascript +export const WalletUtils.approve = data => { + sendMsgToFCL("FCL:VIEW:RESPONSE", { + f_type: "PollingResponse", + f_vsn: "1.0.0", + status: "APPROVED", + reason: null, + data: data, + }) +} + +export const WalletUtils.decline = reason => { + sendMsgToFCL("FCL:VIEW:RESPONSE", { + f_type: "PollingResponse", + f_vsn: "1.0.0", + status: "DECLINED", + reason: reason, + data: null, + }) +} +``` + +```mermaid +graph LR + Start1(Start) + --Bot 启动--> check1[检查群内的非 Authing 用户] + --> addUser[添加 Authing 用户并消息提醒绑定手机号] + --> End1(End) +``` + +![IFRAME/RPC Diagram](https://raw.githubusercontent.com/onflow/fcl-js/master/packages/fcl-core/assets/service-method-diagrams/iframe-rpc.png) + +## POP/RPC | TAB/RPC (Front Channel) + +`POP/RPC` and `TAB/RPC` work in an almost entirely similar way to `IFRAME/RPC`, except instead of rendering the `method` in an iframe, we render it in a popup or new tab. The same communication protocol between the rendered view and FCL applies. + +![POP/RPC Diagram](https://raw.githubusercontent.com/onflow/fcl-js/master/packages/fcl-core/assets/service-method-diagrams/pop-rpc.png) + +![TAB/RPC Diagram](https://raw.githubusercontent.com/onflow/fcl-js/master/packages/fcl-core/assets/service-method-diagrams/tab-rpc.png) + +## HTTP/POST (Back Channel) + +`HTTP/POST` initially sends a post request to the `endpoint` specified in the service, which should immediately return a `f_type: "PollingResponse"`. + +Like `IFRAME/RPC`, `POP/RPC` or `TAB/RPC`, our goal is to eventually get an `APPROVED` or `DECLINED` polling response, and technically this endpoint could return one of those immediately. + +But more than likely that isn't the case and it will be in a `PENDING` state (`PENDING` is not available to `IFRAME/RPC`, `POP/RPC` or `TAB/RPC`). +When the polling response is `PENDING` it requires an `updates` field that includes a service, `BackChannelRpc`, that FCL can use to request an updated `PollingResponse` from. +FCL will use that `BackChannelRpc` to request a new `PollingResponse` which itself can be `APPROVED`, `DECLINED` or `PENDING`. +If it is `APPROVED` FCL will return, otherwise if it is `DECLINED` FCL will error. However, if it is `PENDING`, it will use the `BackChannelRpc` supplied in the new `PollingResponse` updates field. It will repeat this cycle until it is either `APPROVED` or `DECLINED`. + +There is an additional optional feature that `HTTP/POST` enables in the first `PollingResponse` that is returned. +This optional feature is the ability for FCL to render an iframe, popup or new tab, and it can be triggered by supplying a service `type: "VIEW/IFRAME"`, `type: "VIEW/POP"` or `type: "VIEW/TAB"` and the `endpoint` that the wallet wishes to render in the `local` field of the `PollingResponse`. This is a great way for a wallet provider to switch to a webpage if displaying a UI is necessary for the service it is performing. + +![HTTP/POST Diagram](https://raw.githubusercontent.com/onflow/fcl-js/master/packages/fcl-core/assets/service-method-diagrams/http-post.png) + +## EXT/RPC (Front Channel) + +`EXT/RPC` is used to enable and communicate between FCL and an installed web browser extension. (Though this specification is geared towards Chromium based browsers, it should be implementable in any browser with similar extension APIs available. From now on we will be using the word _Chrome_ to refer to Chromium based browsers.) + +An implementation of `EXT/RPC` needs to somehow enable communication between the application and the extension context. Implementing this is a bit more complex and usually relies on 3 key scripts to allow message passing between an installed extension and FCL. The separation of contexts enforced by Chrome and the availability of different Chrome APIs within those contexts require these scripts to be set up in a particular sequence so that the communication channels needed by FCL's `EXT/RPC` service method will work. + +The following is an overview of these scripts and the functionality they need to support FCL: + +- `background.js`: Used to launch the extension popup with `chrome.windows.create` if selected by the user from Discovery or set directly via `fcl.config.discovery.wallet` +- `content.js`: Used to proxy messages between the application to the extension via `chrome.runtime.sendMessage`. +- `script.js`: Injected by `content.js` into the application's HTML page. It appends the extension authn service to the `window.fcl_extensions` array on page load. This allows FCL to confirm installation and send extension details to Discovery or launch your wallet as the default wallet. + +An example and guide showing how to build an FCL compatible wallet extension on Flow can be found [here](https://github.com/onflow/wallet-extension-example). + +Once the extension is enabled (for example when the user selects it through the discovery service), the following communication protocol applies. (The term _send_ should specifically refer to using `window.postMessage` in the application context, as this is the only interface between the application and the extension. Note that since `window.postMessage` broadcasts messages to all message event handlers, care should be taken by each party to filter only the messages targeted at them.) + +- An `ExtensionServiceInitiationMessage` object is sent by FCL. It is the extension's responsibility to inspect the `endpoint` field of the service, and only activate itself (e.g. by opening a popup) if it is the provider of this service. +- The extension should respond by sending a `Message` with type `FCL:VIEW:READY`. (Usually this message will originate from the extension popup, and be relayed to the application context.) +- FCL will send a `Message` with type `FCL:VIEW:READY:RESPONSE`. Additional fields specific to the service (such as `body`, `params` or `data`) are usually present. See the section on the specific service for a description of these fields. +- The wallet sends back a `Message & PollingResponse` with type `FCL:VIEW:RESPONSE` with either an `APPROVED` or `DECLINED` status. + - If it's approved, the polling response's data field will need to be what FCL is expecting. + - If it's declined, the polling response's reason field should say why it was declined. + +The extension can send a `Message` with type `FCL:VIEW:CLOSE` at any point during this protocol to indicate an interruption. This will halt FCL's current routine. On the other hand, once a `PollingResponse` with either an `APPROVED` or `DECLINED` status was sent, the protocol is considered finished, and the extension should not send any further messages as part of this exchange. + +Conversely, when FCL sends a new `ExtensionServiceInitiationMessage`, the previous routine is interrupted. (This is the case even when the new service invocation is targeted at a different extension.) + +Note that as a consequence of the above restrictions, only single service invocation can be in progress at a time. + +Here is a code example for how an extension popup might send its response: + +```javascript +chrome.tabs.sendMessage(tabs[0].id, { + f_type: 'PollingResponse', + f_vsn: '1.0.0', + status: 'APPROVED', + reason: null, + data: { + f_type: 'AuthnResponse', + f_vsn: '1.0.0', + addr: address, + services: services, + }, +}); +``` + +![EXT/RPC Diagram](https://raw.githubusercontent.com/onflow/fcl-js/master/packages/fcl-core/assets/service-method-diagrams/ext-rpc.png) + +## `data` and `params` + +`data` and `params` are information that the wallet can provide in the service config that FCL will pass back to the service. + +- `params` will be added onto the `endpoint` as query params. +- `data` will be included in the body of the `HTTP/POST` request or in the `FCL:VIEW:READY:RESPONSE` for a `IFRAME/RPC`, `POP/RPC`, `TAB/RPC` or `EXT/RPC`. + +# Authentication Service + +In the following examples, we'll walk you through the process of building an authentication service. + +In FCL, wallets are configured by passing in a wallet provider's authentication URL or extension endpoint as the `discovery.wallet` config variable. + +You will need to make and expose a webpage or API hosted at an authentication endpoint that FCL will use. + +```javascript +// IN APPLICATION +// configuring fcl to point at a wallet looks like this +import { config } from '@onflow/fcl'; + +config({ + 'discovery.wallet': 'url-or-endpoint-fcl-will-use-for-authentication', // FCL Discovery endpoint, wallet provider's authentication URL or extension endpoint + 'discovery.wallet.method': 'IFRAME/RPC', // Optional. Available methods are "IFRAME/RPC", "POP/RPC", "TAB/RPC", "EXT/RPC" or "HTTP/POST", defaults to "IFRAME/RPC". +}); +``` + +If the method specified is `IFRAME/RPC`, `POP/RPC` or `TAB/RPC`, then the URL specified as `discovery.wallet` will be rendered as a webpage. If the configured method is `EXT/RPC`, `discovery.wallet` should be set to the extension's `authn` `endpoint`. Otherwise, if the method specified is `HTTP/POST`, then the authentication process will happen over HTTP requests. (While authentication can be accomplished using any of those service methods, this example will use the `IFRAME/RPC` service method.) + +Once the Authentication webpage is rendered, the extension popup is enabled, or the API is ready, you then need to tell FCL that it is ready. You will do this by sending a message to FCL, and FCL will send back a message with some additional information that you can use about the application requesting authentication on behalf of the user. + +The following example is using the `IFRAME/RPC` method. Your authentication webpage will likely resemble the following code: + +```javascript +// IN WALLET AUTHENTICATION FRAME +import {WalletUtils} from "@onflow/fcl" + +function callback(data) { + if (typeof data != "object") return + if (data.type !== "FCL:VIEW:READY:RESPONSE") return + + ... // Do authentication things ... + + // Send back AuthnResponse + WalletUtils.sendMsgToFCL("FCL:VIEW:RESPONSE", { + f_type: "PollingResponse", + f_vsn: "1.0.0", + status: "APPROVED", + data: { + f_type: "AuthnResponse", + f_vsn: "1.0.0" + ... + } + }) + + // Alternatively be sent using WalletUtils.approve (or WalletUtils.decline) + // which will wrap AuthnResponse in a PollingResponse + WalletUtils.approve({ + f_type: "AuthnResponse", + f_vsn: "1.0.0" + ... + }) +} +// add event listener first +WalletUtils.onMsgFromFCL("FCL:VIEW:READY:RESPONSE", callback) + +// tell fcl the wallet is ready +WalletUtils.sendMsgToFCL("FCL:VIEW:READY") + +// alternatively adds "FCL:VIEW:READY:RESPONSE" listener and sends "FCL:VIEW:READY" +WalletUtils.ready(callback) +``` + +During authentication, the application has a chance to request to you what they would like you to send back to them. These requests are included in the `FCL:VIEW:READY:RESPONSE` message sent to the wallet from FCL. + +An example of such a request is the OpenID service. The application can request for example that you to send them the email address of the current user. The application requesting this information does not mean you need to send it. It's entirely optional for you to do so. However, some applications may depend on you sending the requested information back, and should you decline to do so it may cause the application to not work. + +In the config they can also tell you a variety of things about them, such as the name of their application or a url for an icon of their application. You can use these pieces of information to customize your wallet's user experience should you desire to do so. + +Your wallet having a visual distinction from the application, but still a seamless and connected experience is our goal here. + +Whether your authentication process happens using a webpage with the `IFRAME/RPC`, `POP/RPC` or `TAB/RPC` methods, via an enabled extension using the `EXT/RPC` method, or using a backchannel to an API with the `HTTP/POST` method, the handshake is the same. The same messages are sent in all methods, however the transport mechanism changes. For `IFRAME/RPC`, `POP/RPC`, `TAB/RPC` or `EXT/RPC` methods, the transport is `window.postMessage()`, with the `HTTP/POST` method, the transport is HTTP post messages. + +As always, you must never trust anything you receive from an application. Always do your due-diligence and be alert as you are the user's first line of defense against potentially malicious applications. + +### Authenticate your User + +It's important that you are confident that the user is who the user claims to be. + +Have them provide enough proof to you that you are okay with passing their details back to FCL. +Using Blocto as an example, an authentication code is sent to the email a user enters at login. +This code can be used as validation and is everything Blocto needs to be confident in the user's identity. + +### Once you know who your User is + +Once you're confident in the user's identity, we can complete the authentication process. + +The authentication process is complete once FCL receives back a response that configures FCL with FCL Services for the current user. This response is extremely important to FCL. At its core it tells FCL who the user is, and then via the included services it tells FCL how the user authenticated, how to request transaction signatures, how to get a personal message signed and the user's email and other details if requested. In the future it may also include many more things! + +You can kind of think of FCL as a plugin system. But since those plugins exist elsewhere outside of FCL, FCL needs to be configured with information on how to communicate with them. + +What you are sending back to FCL is everything that it needs to communicate with the plugins that you are supplying. +Your wallet is like a plugin to FCL, and these details tell FCL how to use you as a plugin. + +Here is an example of an authentication response: + +```javascript +// IN WALLET AUTHENTICATION FRAME +import {WalletUtils} from "@onflow/fcl" + +WalletUtils.approve({ + f_type: "AuthnResponse", + f_vsn: "1.0.0", + addr: "0xUSER", // The user's flow address + + services: [ // All the stuff that configures FCL + + // Authentication Service - REQUIRED + { + f_type: "Service", // It's a service! + f_vsn: "1.0.0", // Follows the v1.0.0 spec for the service + type: "authn", // the type of service it is + method: "DATA", // It's data! + uid: "amazing-wallet#authn", // A unique identifier for the service + endpoint: "your-url-that-fcl-will-use-for-authentication", // should be the same as was passed into the config + id: "0xUSER", // the wallet's internal id for the user, use flow address if you don't have one + // The User's Info + identity: { + f_type: "Identity", // It's an Identity! + f_vsn: "1.0.0", // Follows the v1.0.0 spec for an identity + address: "0xUSER", // The user's address + keyId: 0, // OPTIONAL - The User's KeyId they will use + }, + // The Wallet's Info + provider: { + f_type: "ServiceProvider", // It's a Service Provider + f_vsn: "1.0.0", // Follows the v1.0.0 spec for service providers + address: "0xWallet", // A flow address owned by the wallet + name: "Amazing Wallet", // OPTIONAL - The name of your wallet. ie: "Dapper Wallet" or "Blocto Wallet" + description: "The best wallet", // OPTIONAL - A short description for your wallet + icon: "https://___", // OPTIONAL - Image url for your wallet's icon + website: "https://___", // OPTIONAL - Your wallet's website + supportUrl: "https://___", // OPTIONAL - An url the user can use to get support from you + supportEmail: "help@aw.com", // OPTIONAL - An email the user can use to get support from you + }, + }, + + // Authorization Service + { + f_type: "Service", + f_vsn: "1.0.0", + type: "authz", + uid: "amazing-wallet#authz", + ... + // We will cover this at length in the authorization section of this guide + }, + + // User Signature Service + { + f_type: "Service", + f_vsn: "1.0.0", + type: "user-signature", + uid: "amazing-wallet#user-signature", + ... + // We will cover this at length in the user signature section of this guide + }, + + // OpenID Service + { + f_type: "Service", + f_vsn: "1.0.0", + type: "open-id", + uid: "amazing-wallet#open-id", + method: "DATA", + data: { // only include data that was request, ideally only if the user approves the sharing of data, everything is optional + f_type: "OpenID", + f_vsn: "1.0.0", + profile: { + name: "Jeff", + family_name: "D", // icky underscored names because of OpenID Connect spec + given_name: "Jeffrey", + middle_name: "FakeMiddleName", + nickname: "JeffJeff", + preferred_username: "Jeff", + profile: "https://www.jeff.jeff/", + picture: "https://avatars.onflow.org/avatar/jeff", + website: "https://www.jeff.jeff/", + gender: "male", + birthday: "1900-01-01", // can use 0000 for year if year is not known + zoneinfo: "America/Vancouver", + locale: "en", + updated_at: "1625588304427" + }, + email: { + email: "jeff@jeff.jeff", + email_verified: false, + } + }, + } + ] +}) +``` + +### Stopping an Authentication Process + +From any frame, you can send a `FCL:VIEW:CLOSE` post message to FCL, which will halt FCL's current routine and close the frame. + +```javascript +import { WalletUtils } from '@onflow/fcl'; + +WalletUtils.sendMsgToFCL('FCL:VIEW:CLOSE'); +``` + +# Authorization Service + +Authorization services are depicted with with a `type: "authz"`, and a `method` of either `HTTP/POST`, `IFRAME/RPC`, `POP/RPC`, `TAB/RPC` or `EXT/RPC`. +They are expected to eventually return a `f_type: "CompositeSignature"`. + +An authorization service is expected to know the Account and the Key that will be used to sign the transaction at the time the service is sent to FCL (during authentication). + +```javascript +{ + f_type: "Service", + f_vsn: "1.0.0", + type: "authz", // say it's an authorization service + uid: "amazing-wallet#authz", // standard service uid + method: "HTTP/POST", // can also be `IFRAME/RPC` or `POP/RPC` + endpoint: "https://____", // where to talk to the service + identity: { + f_type: "Identity", + f_vsn: "1.0.0", + address: "0xUser", // the address that the signature will be for + keyId: 0, // the key for the address that the signature will be for + }, + data: {}, + params: {}, +} +``` + +FCL will use the `method` provided to request an array of composite signature from authorization service (Wrapped in a `PollingResponse`). +The authorization service will be sent a `Signable`. +The service is expected to construct an encoded message to sign from `Signable.voucher`. +It then needs to hash the encoded message, and prepend a required [transaction domain tag](https://github.com/onflow/fcl-js/blob/master/packages/sdk/src/encode/encode.ts#L18-L21). +Finally it signs the payload with the user/s keys, producing a signature. +This signature, as a HEX string, is sent back to FCL as part of the `CompositeSignature` which includes the user address and keyID in the data property of a `PollingResponse`. + +```elixir +signature = + signable.voucher + |> encode + |> hash + |> tag + |> sign + |> convert_to_hex +``` + +The eventual response back from the authorization service should resolve to something like this: + +```javascript +{ + f_type: "PollingResponse", + f_vsn: "1.0.0", + status: "APPROVED", + data: { + f_type: "CompositeSignature", + f_vsn: "1.0.0", + addr: "0xUSER", + keyId: 0, + signature: "signature as hex value" + } +} +``` + +A `CompositeSignature` can alternatively be constructed using `WalletUtils` + +```javascript +import {WalletUtils} from "@onflow/fcl" + +WalletUtils.CompositeSignature(addr: String, keyId: Number, signature: Hex) + +``` + +# User Signature Service + +User Signature services are depicted with a `type: "user-signature"` and a `method` of either `HTTP/POST`, `IFRAME/RPC`, `POP/RPC`, `TAB/RPC` or `EXT/RPC`. +They are expected to eventually return an array of `f_type: "CompositeSignature"`. + +The User Signature service is a stock/standard service. + +```javascript +{ + f_type: "Service", + f_vsn: "1.0.0", + type: "user-signature", // say it's an user-signature service + uid: "amazing-wallet#user-signature", // standard service uid + method: "HTTP/POST", // can also be `IFRAME/RPC` + endpoint: "https://___", // where to talk to the service + data: {}, + params: {}, +} +``` + +FCL will use the `method` provided to request an array of composite signatures from the user signature service (Wrapped in a `PollingResponse`). +The user signature service will be sent a `Signable`. +The service is expected to tag the `Signable.message` and then sign it with enough keys to produce a full weight. +The signatures need to be sent back to FCL as HEX strings in an array of `CompositeSignatures`. + +```javascript +// Pseudocode: +// For every required signature +import { WalletUtils } from '@onflow/fcl'; + +const encoded = WalletUtils.encodeMessageFromSignable(signable, signerAddress); +const taggedMessage = tagMessage(encoded); // Tag the message to sign +const signature = signMessage(taggedMessage); // Sign the message +const hexSignature = signatureToHex(signature); // Convert the signature to hex, if required. + +return hexSignature; +``` + +The eventual response back from the user signature service should resolve to something like this: + +```javascript +{ + f_type: "PollingResponse", + f_vsn: "1.0.0", + status: "APPROVED", + data: [ + { + f_type: "CompositeSignature", + f_vsn: "1.0.0", + addr: "0xUSER", + keyId: 0, + signature: "signature as hex value" + }, + { + f_type: "CompositeSignature", + f_vsn: "1.0.0", + addr: "0xUSER", + keyId: 1, + signature: "signature as hex value" + } + ] +} +``` + +# Pre Authz Service + +This is a strange one, but extremely powerful. This service should be used when a wallet is responsible for an account that's signing as multiple roles of a transaction, and wants the ability to change the accounts on a per role basis. + +Pre Authz Services are depicted with a `type: "pre-authz"` and a `method` of either `HTTP/POST`, `IFRAME/RPC`, `POP/RPC`, `TAB/RPC` or `EXT/RPC`. +They are expected to eventually return a `f_type: "PreAuthzResponse"`. + +The Pre Authz Service is a stock/standard service. + +```javascript +{ + f_type: "Service", + f_vsn: "1.0.0", + type: "pre-authz", // say it's a pre-authz service + uid: "amazing-wallet#pre-authz", // standard service uid + method: "HTTP/POST", // can also be IFRAME/RPC, POP/RPC, TAB/RPC + endpoint: "https://___", // where to talk to the service + data: {}, + params: {}, +} +``` + +FCL will use the `method` provided to request a `PreAuthzReponse` (Wrapped in a `PollingResponse`). +The Authorizations service will be sent a `PreSignable`. +The pre-authz service is expected to look at the `PreSignable` and determine the breakdown of accounts to be used. +The pre-authz service is expected to return `Authz` services for each role it is responsible for. +A pre-authz service can only supply roles it is responsible for. +If a pre-authz service is responsible for multiple roles, but it wants the same account to be responsible for all the roles, it will need to supply an Authz service per role. + +The eventual response back from the pre-authz service should resolve to something like this: + +```javascript +{ + f_type: "PollingResponse", + f_vsn: "1.0.0", + status: "APPROVED", + data: { + f_type: "PreAuthzResponse", + f_vsn: "1.0.0", + proposer: { // A single Authz Service + f_type: "Service", + f_vsn: "1.0.0", + type: "authz", + ... + }, + payer: [ // An array of Authz Services + { + f_type: "Service", + f_vsn: "1.0.0", + type: "authz", + ... + } + ], + authorization: [ // An array of Authz Services (it's singular because it only represents a singular authorization) + { + f_type: "Service", + f_vsn: "1.0.0", + type: "authz", + ... + } + ], + } +} +``` + +# Authentication Refresh Service + +Since synchronization of a user's session is important to provide a seamless user experience when using an app and transacting with the Flow Blockchain, a way to confirm, extend, and refresh a user session can be provided by the wallet. + +Authentication Refresh Services should include a `type: "authn-refresh"`, `endpoint`, and supported `method` (`HTTP/POST`, `IFRAME/RPC`, `POP/RPC`, or `EXT/RPC`). + +FCL will use the `endpoint` and service `method` provided to request updated authentication data. +The `authn-refresh` service should refresh the user's session if necessary and return updated authentication configuration and user session data. + +The service is expected to return a `PollingResponse` with a new `AuthnResponse` as data. If user input is required, a `PENDING` `PollingResponse` can be returned with a `local` view for approval/re-submission of user details. + +The Authentication Refresh Service is a stock/standard service. + +```javascript + { + "f_type": "Service", + "f_vsn": "1.0.0", + "type": "authn-refresh", + "uid": "uniqueDedupeKey", + "endpoint": "https://rawr", + "method": "HTTP/POST", // "HTTP/POST", // HTTP/POST | IFRAME/RPC | HTTP/RPC + "id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", // wallet's internal id for the user + "data": {}, // included in body of request + "params": {}, // included as query params on endpoint url + } +``` + +The provided `data` and `params` should include all the wallet needs to identify and re-authenticate the user if necessary. + +The eventual response back from the `authn-refresh` service should resolve to an `AuthnResponse` and look something like this: + +```javascript +{ + f_type: "PollingResponse", + f_vsn: "1.0.0", + status: "APPROVED", + data: { + f_type: "AuthnResponse", + f_vsn: "1.0.0", + addr: "0xUSER", + services: [ + // Authentication Service - REQUIRED + { + f_type: "Service", + f_vsn: "1.0.0", + type: "authn", + ... + }, + // Authorization Service + { + f_type: "Service", + f_vsn: "1.0.0", + type: "authz", + ... + }, + // Authentication Refresh Service + { + f_type: "Service", + f_vsn: "1.0.0", + type: "authn-refresh", + ... + } + // Additional Services + ], + } +} +``` + + +=== tools/wallet-provider-spec/custodial.md === +# Introduction + +A Wallet Provider handles Authentications and Authorizations. They play a very important role of being the place the users control their information and approve transactions. + +One of FCLs core ideals is for the user to be in control of their data, a wallet provider is where many users will do just that. + +FCL has been built in a way that it doesn't need to know any intimate details about a wallet provider up front, they can be discovered when the users wishes to let the dapp know about them. This gives us a concept we have been calling Bring Your Own Identity. + +# Identity + +Conceptually, FCL thinks of identity in two ways: Public and Private. + +Public identity will be stored on chain as a resource, it will be publicly available to anyone that knows the Flow Address for the account. + +In FCL getting a users public identity will be as easy as: + +```javascript +import {user} from "@onflow/fcl" + +const identity = await user(flowAddress).snapshot() +// ^ +// `------ The public identity for `flowAddress` + +const unsub = user(flowAddress).subscribe(identity => console.log(identity)) +// ^ +// `------- The public identity for `flowAddress` +``` + +Private identity will be stored by the Wallet Provider, it will only be available to the currentUser. + +In FCL getting the currentUsers identity will fetch both the public and the private identities, merging the private into the public. + +Private info needs to be requested via scopes before the challenge step, more on that later. +We highly recommend Wallet Providers let the user see what scopes are being requested, and decide what scopes to share with the dapp. + +Consumers of identities in FCL should always assume all data is optional, and should store as little as possible, FCL will make sure the users always see the latest. + +```javascript +import {config, currentUser, authenticate} from "@onflow/fcl" + +config.put("challenge.scope", "email") // request the email scope + +const unsub = currentUser().subscribe(identity => console.log(identity)) +// ^ +// `------- The private identity for the currentUser + +authenticate() // trigger the challenge step (authenticate the user via a wallet provider) +``` + +# Identity Data + +- All information in Identities are optional and may not be there. +- All values can be stored on chain, but most probably shouldn't be. + +We would love to see Wallet Providers enable the user to control the following info publicly, sort of a public profile starter kit if you will. + +FCL will always publicly try to fetch these fields when asked for a users information and it will be up to the Wallet provider to make sure they are there and keep them up to date if the user wants to change them. + +- **`name`** -- A human readable name/alias/nym for a dapp users display name +- **`avatar`** -- A fully qualified url to a smaller image used to visually represent the dapp user +- **`cover`** -- A fully qualified url to a bigger image, could be used by the dapp for personalization +- **`color`** -- A 6 character hex color, could be used by the dapp for personalization +- **`bio`** -- A small amount of text that a user can use to express themselves + +If we can give dapp developers a solid foundation of usable information that is in the direct control of the users from the very start, which we belive the above fields would do, our hopes are they can rely more on the chain and will need to store less in their own database. + +Private data on the other hand has more use cases than general data. It is pretty easy to imagine ordering something and needing information like contact details and where to ship something. + +Eventually we would love to see that sort of thing handled completely on-chain, securely, privately and safely, but in the interm it probably means storing a copy of data in a database when its needed, and allowed by a user. + +The process of a dapp receiving private data is as follows: + +1. The dapp requests the scopes they want up front `fcl.config().put("challenge.scope", "email+shippingAddress")`. +2. The User authenticates `fcl.authenticate()` and inside the Wallet Providers authentication process decides its okay for the dapp to know both the `email` and the `shippingAddress`. The User should be able to decide which information to share, if any at all. +3. When the dapp needs the information they can request it from FCLs current cache of data, if it isnt there the dapp needs to be okay with that and adjust accodingly. + +Below are the scopes we are thinking of supporting privately: +FCL will only publicly and privately try to fetch these when specified up front by a dapp. + +- **`email`** +- **`fullName`** +- **`phone`** +- **`textMessage`** +- **`address`** +- **`shippingAddress`** +- **`location`** +- **`publicKey`** + +All of the above are still subject to change as it is still early days, we would like to work closely with Wallet Providers to produce a robust, detailed and consitent spec regarding scopes. Feedback and thoughts are always welcome. + +# Authentication Challenge + +Authentication can happen one of two ways: + +- Iframe Flow +- Redirection Flow + +As a Wallet Provider you will be expected to register a URL endpoint (and some other information) with a handshake service (FCL will be launching with one in which registration happens on chain and is completely open source (Apache-2.0 lincense)). +This registered URL will be what is shown inside the iFrame or where the dapp users will be redirected. +For the remainder of this documentation we will refere to it as the _Authentication Endpoint_ and pair it with the `GET https://provider.com/flow/authentication` route. + +The Authentication Endpoint will receive the following data as query params: + +- `l6n` _(required)_ -- location (origin) of dapp +- `nonce` _(required)_ -- a random string supplied by the FCL +- `scope` _(optional)_ -- the scopes requested by the dapp +- `redirect` _(optional)_ -- where to redirect once the authentication challenge is complete + +``` +GET https://provider.com/flow/authenticate + ?l6n=https%3A%2F%2Fdapp.com + &nonce=asdfasdfasdf + &scope=email+shippingAddress + &redirect=https%3A%2F%2Fdapp.com%2Fflow%2Fcallback + +The values will use javascripts `encodeURIComponent` function and scopes will be `+` deliminated. +``` + +We can tell that this challenge is using the Redirect Flow because of the inclusion of the redirect query param. +The Iframe Flow will still need to be supported as it will be the default flow for dapps. + +At this point its on the Wallet Provider to do their magic and be confident enough that the user is who they say they are. +The user should then be shown in some form what the dapp is requesting via the scopes and allow them to opt in or out of anything they want. +Once the Wallet Provider is ready to hand back control to the dapp and FCL it needs to complete the challenge by redirecting or emiting a javascript `postMessage` event. + +Redirecting will look like this: + +``` +GET https://dapp.com/flow/callback # supplied by the redirect query param above + ?l6n=https%3A%2F%2Fdapp.com # the l6n supplied by FCL above + &nonce=asdfasdfasdf # the nonce supplied by FCL above + &addr=0xab4U9KMf # address for the users flow account (if available) -- will be used to fetch public identity information and hooks + &padder=0xhMgqTff86 # address for the Wallet Providers account -- will be used to fetch provider information + &code=afseasdfsadf # a token supplied to FCL from the Wallet Provider, FCL will use this token when requesting private information and hooks, can be any url safe value + &exp=1650400809517 # when the code expires, a value of `0` will be considered as never expires + &hks==https%3A%2F%2Fprovider.com%2Fhooks # a URL where FCL can request the private information and hooks +``` + +Iframe will look like this: + +```javascript +parent.postMessage( + { + type: "FCL::CHALLENGE::RESPONSE", // used by FCL to know what kind of message this is + addr: "0xab4U9KMf", + paddr: "0xhMgqTff86", + code: "afseasdfsadf", + exp: 1650400809517, + hks: "https://provider.com/hooks", + nonce: "asdfasdfasdf", + l6n: decodeURIComponent(l6n), + }, + decodeURIComponent(l6n) +) +``` + +FCL should now have everything it needs to collect the Public, Private and Wallet Provider Info. +The Wallet Provider info will be on chain so its not something that needs to be worried about here by the Wallet Provider. +What does need to be worried about handling the hooks request which was supplied to FCL via the `hks` value in the challenge response `https://provider.hooks`. + +The hooks request will be to the `hks` value supplied in the challenge response. The request will also include the code as a query param + +``` +GET https://povider.com/hooks + ?code=afseasdfsadf +``` + +This request needs to happen for a number of reasons. + +- If it fails FCL knows something is wrong and will attempt to re-authenticate. +- If is succeeds FCL knows that the code it has is valid. +- It creates a direct way for FCL to "verify" the user against the Wallet Provider. +- It gives FCL a direct way to get Private Identity Information and Hooks. +- The code can be passed to the backend to create a back-channel between the backend and the Wallet Provider. + +When users return to a dapp, if the code FCL stored hasnt expired, FCL will make this request again in order to stay up to date with the latest informtaion. FCL may also intermitently request this information before some critial actions. + +The hooks request should respond with the following JSON + +```javascript +const privateHooks = { + addr: "0xab4U9KMf", // the flow address this user is using for the dapp + keyId: 3, // the keyId the user wants to use when authorizing transaction + identity: { // the identity information fcl always wants if its there, will be deep merged into public info + name: "Bob the Builder", + avatar: "https://avatars.onflow.org/avatar/0xab4U9KMf.svg" + cover: "https://placekittens.com/g/900/300", + color: "cccc00", + bio: "", + }, + scoped: { // the private info request in the original challenge + email: "bob@bob.bob", // the user said it was okay for the dapp to know the email + shippingAddress: null, // the user said it was NOT okay for the dapp to know the shippingAddress + }, + provider: { + addr: "0xhMgqTff86", // the flow address for the wallet provider (used in the identity composite id) + pid: 2345432, // the wallet providers internal id for the user (used in the identity composite id) + name: "Super Wallet", + icon: "https://provider.com/assets/icon.svg", + authn: "https://provider.com/flow/authenticate", + } +} +``` + +When FCL requested the Public info from the chain it is expecting something like this. +It will be on the Wallet Provider to keep this information up to date. + +```javascript +const publicHooks = { + addr: "0xab4U9KMf", + keyId: 2, + identity: { + name: "Bob the Builder", + avatar: "https://avatars.onflow.org/avatar/0xab4U9KMf.svg" + cover: "https://placekittens.com/g/900/300", + color: "cccc00", + bio: "", + }, + authorizations: [ + { + id: 345324539, + addr: "0xhMgqTff86", + method: "HTTP/POST", + endpoint: "https://provider.com/flow/authorize", + data: { + id: 2345432 + } + } + ] +} +``` + +At this point FCL can be fairly confident who the currentUser is and is ready to initiate transactions the user can authorize. + +# Authorization + +FCL will broadcast authorization requests to the Public and Private authorization hooks it knows for a User, in a process we call Asynchronous Remote Signing. + +The core concepts to this idea are: + +- Hooks tell FCL where to send authorization requests (Wallet Provider) +- Wallet Provider responds imediately with: + - a back-channel where FCL can request the results of the authorization + - some optional local hooks ways the currentUser can authorize +- FCL will trigger the local hooks if they are for the currentUser +- FCL will poll the back-channel requesting updates until an approval or denial is given + +Below is the public authorization hook we received during the challenge above. + +```javascript + { + id: 345324539, + addr: "0xhMgqTff86", + method: "HTTP/POST", + endpoint: "https://provider.com/flow/authorize", + data: { + id: 2345432 + } + } +``` + +FCL will take that hook and do the following post requeset: + +``` +POST https://provider.com/flow/authorize + ?id=2345432 +--- +{ + message: "...", // what needs to be signed (needs to be convered from hex to binary before signing) + addr: "0xab4U9KMf", // the flow address that needs to sign + keyId: 3, // the flow account keyId for the private key that needs to sign + roles: { + proposer: true, // this accounts sequence number will be used in the transaction + authorizer: true, // this transaction can "move" and "modify" the accounts resources directly + payer: true, // this transaction will be paid for by this account (also signifies that they are signing an envelopeMessage instead of a payloadMessage) + }, + interaction: {...} // needed to recreate the message if the Wallet Provider wants to verify the message. +} +``` + +FCL ise expecting something like this in response: + +```javascript +{ + status: "PENDING", + reason: null, + compositeSignature: null, + authorizationUpdates: { + method: "HTTP/POST", + endpoint: "https://provider.com/flow/authorizations/4323", + }, + local: [ + { + method: "BROWSER/IFRAME", + endpoint: "https://provider.com/authorizations/4324", + width: "300", + height: "600", + background: "#ff0066" + } + ] +} +``` + +That local hook will be consumed by FCL, rendering an iframe with the endpoint as the src. If the user is already authenticated this screen could show them the Wallet Providers transaction approval process directly. +Because FCL isnt relying on any communication to or from the Iframe it can lock it down as much as possible, and remove it once the authorization is complete. +While displaying the local hook, it will request the status of the authorization from the `authorizationUpdates` hook. + +``` +POST https://provider.com/flow/authorizations/4323 +``` + +Expecting a response that has the same structure as the origin but without the local hooks: + +```javascript +{ + status: "PENDING", + reason: "", + compositeSignature: null, + authorizationUpdates: { + method: "HTTP/POST", + endpoint: "https://provider.com/flow/authorizations/4323", + }, +} +``` + +FCL will then follow the new `authorizationUpdates` hooks until the status changes to `"APPROVED"` or `"DECLINED"`. +If the authorization is declined it should include a reason if possible. + +```javascript +{ + status: "DECLINED", + reason: "They said no", +} +``` + +If the authorization is approved it should include a composite signature: + +```javascript +{ + status: "APPROVED", + compositeSignature: { + addr: "0xab4U9KMf", // the flow address that needs to sign + keyId: 3, // the flow account keyId for the private key that needs to sign + signature: "..." // binary signature of message encoded as hex + } +} +``` + +FCl can now submit the transaction to the Flow blockchain. + +# TL;DR Wallet Provider + +Register Provider with FCL Handshake and implement 5 Endpoints. + +- `GET flow/authenticate` -> `parent.postMessage(..., l6n)` +- `GET flow/hooks?code=___` -> `{ ...identityAndHooks }` +- `POST flow/authorize` -> `{ status, reason, compositeSignature, authorizationUpdates, local }` +- `POST authorizations/:authorization_id` +- `GET authorizations/:authorization_id` + +![diagram showing current fcl authn and authz flow](./assets/fcl-ars-auth-v3.2.png) + + +=== tools/wallet-provider-spec/authorization-function.md === +# Authorization Function + +## Overview + +An Authorization Function is a function which enables the JS-SDK and FCL to know which Flow account fulfills which signatory role in a transaction and how to recieve a signature on behalf of the supplied account. + +## How to Use an Authorization Function + +An authorization function is a function that you may use in place of an authorization in the Flow JS-SDK and FCL. An authorization is a concept that is used when denoting a proposer, payer or authorizer for a transaction. An authorization can either be a data structure represenating an authorization, or a function which when called returns an authorization called an Authorization Function. In this document we discuss the latter. + +To use an Authorization Function, you specify that Authorization Function as the authorization for a proposer, payer or authorizer for a transaction. + +> `fcl.currentUser().authorization` which is aliased to `fcl.authz` is itself an authorization function. It tells the underlying js-sdk the current users flow account will be used for the signatory role and supplies a signing function that enables the application to request a signature from the users wallet. + +Example 1: +```javascript +import * as fcl from "@onflow/fcl" + +const myAuthorizationFunction = ... // An Authorization Function + +const response = fcl.send([ + fcl.transaction`transaction() { prepare(acct: &Account) {} execute { log("Hello, Flow!") } }`, + fcl.proposer(myAuthorizationFunction), + fcl.payer(myAuthorizationFunction), + fcl.authorizers([ myAuthorizationFunction ]) +]) +``` + +The builder functions, `fcl.proposer`, `fcl.payer` and `fcl.authorizations` each consume the Authorization Function and set it as the resolve field on the internal Account object it creates. + +During the resolve phase of the Flow JS-SDK and FCL, when [`resolveAccounts`](https://github.com/onflow/fcl-js/blob/master/packages/sdk/src/resolve/resolve.js#L58) is called, the resolve field on each internal Account object is called, which means each Authorization Function is called appropriately and the account is _resolved_ into the data structure the authorizationFunction returns. These accounts are then deduped based on the a mix of the `addr`, `keyId` and `tempId` so that only a single signature request happens per `address` `keyId` pair. When [`resolveSignatures`](https://github.com/onflow/fcl-js/blob/master/packages/sdk/src/resolve/resolve.js#L62) is called the signing function for each `address` `keyId` pair is called returning a composite signature for each signatory role. + +## How to Create An Authorization Function + +Fortunately, creating an Authorization Function is relatively straight forward. + +An Authorization Function needs to be able to do at minimum two things. +- Who will sign -- Know which account is going to sign and the keyId of the key it will use to sign +- How they sign -- Know how to get a signature for the supplied account and key from the first piece. + +The Authorization Function has a concept of an account. An account represent a possible signatory for the transaction, it includes the who is signing as well as the how it will be signed. The Authorization Function is passed an empty Account and needs to return an Account, your job when making an Authorization Function is mostly to fill in this Account with the information so that the account you want to sign things can. + +Lets say we knew up front the account, keyId and had a function that could sign things. + +```javascript +const ADDRESS = "0xba1132bc08f82fe2" +const KEY_ID = 1 // this account on testnet has three keys, we want the one with an index of 1 (has a weight of 1000) +const sign = msg => { /* ... returns signature (for the key above) for supplied message ... */ } +``` + +Our Authorization Function becomes about filling things in: + +Example 2: +```javascript +const authorizationFunction = async (account) => { + // authorization function need to return an account + return { + ...account, // bunch of defaults in here, we want to overload some of them though + tempId: `${ADDRESS}-${KEY_ID}`, // tempIds are more of an advanced topic, for 99% of the times where you know the address and keyId you will want it to be a unique string per that address and keyId + addr: ADDRESS, // the address of the signatory + keyId: Number(KEY_ID), // this is the keyId for the accounts registered key that will be used to sign, make extra sure this is a number and not a string + signingFunction: async signable => { + // Singing functions are passed a signable and need to return a composite signature + // signable.message is a hex string of what needs to be signed. + return { + addr: ADDRESS, // needs to be the same as the account.addr + keyId: Number(KEY_ID), // needs to be the same as account.keyId, once again make sure its a number and not a string + signature: sign(signable.message), // this needs to be a hex string of the signature, where signable.message is the hex value that needs to be signed + } + } + } +} +``` + +## Async stuff + +Both the Authorization Function, and the accounts Signing Function can be asynchronous. This means both of these functions can go and get the information needed elsewhere. Say each of your users had a `userId`. From this `userId` say you had an api call that could return the corresponding address and key that is needed for the Authorization Functions account. You could also have another endpoint that when posted the signable (includes what needs to be signed) and the `userId` it can return with the composite signature if your api decides its okay to sign (the signable has all sorts of info to help you decide). An authorization function that can do that could look something like this. + +Example 3: +```javascript +const getAccount = (userId) => fetch(`/api/user/${userId}/account`).then(d => d.json()) +const getSignature = (userId, signable) = fetch(`/api/user/${userId}/sign`, { + method: "POST", + headers: { "Content-Type": "application/json"}, + body: JSON.stringify(signable), +}) + +function authz (userId) { + return async function authorizationFunction (account) { + const {addr, keyId} = await getAccount(userId) + + return { + ...account, + tempId: `${addr}-${keyId}`, + addr: addr, + keyId: Number(keyId), + signingFunction: signable => { + return getSignature(userId, signable) + } + } + } +} +``` +The above **Example 3** is the same as **Example 2**, but the information is gathered during the execution of the authorization function based on the supplied user id. + +## How to create a Signing Function + +Creating a signing function is also relatively simple! + +To create a signing function you specify a function which consumes a payload and returns a signature data structure. + +Example 3: +```javascript +const signingFunction = ({ + message, // The encoded string which needs to be used to produce the signature. + addr, // The address of the Flow Account this signature is to be produced for. + keyId, // The keyId of the key which is to be used to produce the signature. + roles: { + proposer, // A Boolean representing if this signature to be produced for a proposer. + authorizer, // A Boolean representing if this signature to be produced for a authorizer. + payer, // A Boolean representing if this signature to be produced for a payer. + }, + voucher, // The raw transactions information, can be used to create the message for additional safety and lack of trust in the supplied message. +}) => { + return { + addr, // The address of the Flow Account this signature was produced for. + keyId, // The keyId for which key was used to produce the signature. + signature: produceSignature(message) // The hex encoded string representing the signature of the message. + } +} +``` + + +=== tools/vscode-extension/index.md === +--- +title: Cadence VS Code Extension +sidebar_position: 4 +--- + +This extension integrates [Cadence](https://cadence-lang.org/docs), the resource-oriented smart contract programming language of [Flow](https://www.onflow.org/), into [Visual Studio Code](https://code.visualstudio.com/). +It provides features like syntax highlighting, type checking, code completion, etc. + +Note that most editing features (type checking, code completion, etc.) are implemented in the [Cadence Language Server](https://github.com/onflow/cadence-tools/tree/master/languageserver). + +## Features + +- Syntax highlighting (including in Markdown code fences) +- Run the emulator, submit transactions, scripts from the editor + +## Installation + +To install the extension, ensure you have the [VS Code IDE installed](https://code.visualstudio.com/docs/setup/mac). +Then, you can install the Cadence extension from the [VS Code Marketplace](https://marketplace.visualstudio.com/items?itemName=onflow.cadence). + +## Developing the Extension + +### Prerequisites + +- Must have Typescript installed globally: `npm i -g typescript` + +### Getting Started + +- Run the Typescript watcher: `tsc -watch -p ./` +- Launch the extension by pressing `F5` in VSCode +- Manually reload the extension host when you make changes to TypeScript code + +### Configuration for Extension Host if Missing (`launch.json`): + +``` +{ + "version": "0.2.0", + "configurations": [ + { + "type": "extensionHost", + "request": "launch", + "name": "Launch Extension", + "runtimeExecutable": "${execPath}", + "args": ["--extensionDevelopmentPath=${workspaceFolder}"], + "outFiles": ["${workspaceFolder}/out/**/*.js"] + } + ] +} + +``` + +### Building + +If you are building the extension from source, you need to build both the +extension itself and the Flow CLI (if you don't already have a version installed). +Unless you're developing the extension or need access to unreleased features, +you should use the Flow CLI install option (above). It's much easier! + +If you haven't already, install dependencies. + +```shell script +npm install +``` + +Next, build and package the extension. + +```shell script +npm run package +``` + +This will result in a `.vsix` file containing the packaged extension. + +Install the packaged extension. + +```shell script +code --install-extension cadence-*.vsix +``` + +Restart VS Code and the extension should be installed! + + +=== tools/kit/index.md === +--- +title: '@onflow/kit' +description: React hooks for interacting with the Flow blockchain. +sidebar_position: 1 +--- + +# @onflow/kit + +:::warning + +🚧 This library is currently in alpha and is subject to change. + +::: + +`@onflow/kit` is a lightweight React utility library that simplifies interacting with the Flow blockchain. It provides a collection of hooks, similar to those in other popular web3 libraries, that make it easier to build frontends that understand blockchain interactions. **In the future**, it will also provided components designed to make authentication, script execution, transactions, event subscriptions, and network configuration seamless in React apps. + +## 🔌 Included React Hooks + +- [`useCurrentFlowUser`](#usecurrentflowuser) - Authenticate and manage the current Flow user +- [`useFlowAccount`](#useflowaccount) - Fetch Flow account details by address +- [`useFlowBlock`](#useflowblock) - Query latest or specific Flow blocks +- [`useFlowConfig`](#useflowconfig) - Access the current Flow configuration +- [`useFlowEvents`](#useflowevents) - Subscribe to Flow events in real-time +- [`useFlowQuery`](#useflowquery) - Execute Cadence scripts with optional arguments +- [`useFlowMutate`](#useflowmutate) - Send transactions to the Flow blockchain +- [`useFlowTransaction`](#useflowtransaction) - Track transaction status updates + +## Installation + +```bash +npm install @onflow/kit +``` + +## Usage + +### Wrapping Your App With `FlowProvider` + +Begin by wrapping your application with the `FlowProvider` to initialize FCL configuration. This sets up FCL and maps its configuration keys to a strictly typed format for your hooks. + +```tsx +import React from 'react'; +import App from './App'; +import { FlowProvider } from '@onflow/kit'; +import flowJSON from '../flow.json'; + +function Root() { + return ( + + + + ); +} + +export default Root; +``` + +If you're using [Next.js], put this in `layout.tsx`. Adapt as appropriate for other frontend frameworks. + +--- + +## Hooks + +:::info + +Many of these hooks are built using [`@tanstack/react-query`](https://tanstack.com/query/latest), which provides powerful caching, revalidation, and background refetching features. As a result, you’ll see return types like `UseQueryResult` and `UseMutationResult` throughout this section. Other types—such as `Account`, `Block`, and `CurrentUser`—are from the [Flow Client Library (FCL) TypeDefs](https://github.com/onflow/fcl-js/blob/master/packages/typedefs/src/index.ts). Refer to their respective documentation for full type definitions and usage patterns. + +::: + +### `useCurrentFlowUser` + +```tsx +import { useCurrentFlowUser } from '@onflow/kit'; +``` + +#### Returns: + +- `user: CurrentUser` - The current user object from FCL +- `authenticate: () => Promise` - Triggers wallet authentication +- `unauthenticate: () => void` - Logs the user out + +```tsx +function AuthComponent() { + const { user, authenticate, unauthenticate } = useCurrentFlowUser(); + + return ( +
    + {user.loggedIn ? ( + <> +

    Logged in as {user.addr}

    + + + ) : ( + + )} +
    + ); +} +``` + +--- + +### `useFlowAccount` + +```tsx +import { useFlowAccount } from '@onflow/kit'; +``` + +#### Parameters: + +- `address?: string` - Flow address (with or without `0x` prefix) + +#### Returns: `UseQueryResult` + +```tsx +function AccountDetails() { + const { + data: account, + isLoading, + error, + refetch, + } = useFlowAccount('0x1cf0e2f2f715450'); + + if (isLoading) return

    Loading account...

    ; + if (error) return

    Error fetching account: {error.message}

    ; + if (!account) return

    No account data

    ; + + return ( +
    +

    Account: {account.address}

    +

    Balance: {account.balance}

    +
    {account.code}
    + +
    + ); +} +``` + +--- + +### `useFlowBlock` + +```tsx +import { useFlowBlock } from '@onflow/kit'; +``` + +#### Parameters (mutually exclusive): + +- `{}` - Latest block (default) +- `{ sealed: true }` - Latest sealed block +- `{ id: string }` - Block by ID +- `{ height: number }` - Block by height + +#### Returns: `UseQueryResult` + +```tsx +function LatestBlock() { + const { data: block, isLoading, error } = useFlowBlock(); + if (isLoading) return

    Loading...

    ; + if (error) return

    Error: {error.message}

    ; + if (!block) return

    No block data.

    ; + + return ( +
    +

    Block {block.height}

    +

    ID: {block.id}

    +
    + ); +} +``` + +--- + +### `useFlowConfig` + +```tsx +import { useFlowConfig } from '@onflow/kit'; +``` + +#### Returns: `FlowConfig` + +```tsx +function MyComponent() { + const config = useFlowConfig(); + + return ( +
    +

    Current network: {config.flowNetwork}

    +

    Current access node: {config.accessNodeUrl}

    +
    + ); +} +``` + +--- + +### `useFlowEvents` + +```tsx +import { useFlowEvents } from '@onflow/kit'; +``` + +#### Parameters: + +- `eventNameOrFilter`: string | EventFilter +- `options: { onEvent: (event) => void, onError?: (error) => void }` + +#### Example: + +```tsx +function EventListener() { + useFlowEvents('A.0xDeaDBeef.SomeContract.SomeEvent', { + onEvent: (event) => console.log('New event:', event), + onError: (error) => console.error('Error:', error), + }); + + return
    Listening for events...
    ; +} +``` + +--- + +### `useFlowQuery` + +```tsx +import { useFlowQuery } from '@onflow/kit'; +``` + +#### Parameters: + +- `cadence: string` - Cadence script to run +- `args?: (arg, t) => unknown[]` - Function returning FCL arguments +- `enabled?: boolean` - Defaults to `true` + +#### Returns: `UseQueryResult` + +```tsx +function QueryExample() { + const { data, isLoading, error, refetch } = useFlowQuery({ + cadence: ` + pub fun main(a: Int, b: Int): Int { + return a + b + } + `, + args: (arg, t) => [arg(1, t.Int), arg(2, t.Int)], + }); + + if (isLoading) return

    Loading query...

    ; + if (error) return

    Error: {error.message}

    ; + + return ( +
    +

    Result: {data}

    + +
    + ); +} +``` + +--- + +### `useFlowMutate` + +```tsx +import { useFlowMutate } from '@onflow/kit'; +``` + +#### Returns: `UseMutationResult` + +- `mutate`: A function to send the transaction +- `data`: Transaction ID +- `error`: Any error +- `isPending`: Boolean status + +```tsx +function CreatePage() { + const { mutate, isPending, error, data: txId } = useFlowMutate(); + + const sendTransaction = () => { + mutate({ + cadence: `transaction() { + prepare(acct: &Account) { + log(acct.address) + } + }`, + args: (arg, t) => [], + proposer: fcl.currentUser, + payer: fcl.currentUser, + authorizations: [], + limit: 100, + }); + }; + + return ( +
    + + {isPending &&

    Sending transaction...

    } + {error &&

    Error: {error.message}

    } + {txId &&

    Transaction ID: {txId}

    } +
    + ); +} +``` + +--- + +### `useFlowTransaction` + +```tsx +import { useFlowTransaction } from '@onflow/kit'; +``` + +#### Parameters: + +- `txId: string` - Transaction ID to subscribe to + +#### Returns: + +- `transactionStatus: TransactionStatus | null` +- `error: Error | null` + +```tsx +function TransactionComponent() { + const txId = 'your-transaction-id-here'; + const { transactionStatus, error } = useFlowTransaction(txId); + + if (error) return
    Error: {error.message}
    ; + + return
    Status: {transactionStatus?.statusString}
    ; +} +``` + + +=== tools/flow-dev-wallet/index.md === +--- +title: Flow Dev Wallet +sidebar_label: Flow Dev Wallet +sidebar_position: 5 +--- + +The Flow Dev Wallet is a mock Flow wallet that simulates the protocols used by [FCL](../clients/fcl-js/index.md) to interact with the Flow blockchain on behalf of simulated user accounts. + +:::warning[IMPORTANT] + +This project implements an FCL compatible +interface, but should **not** be used as a reference for +building a production grade wallet. + +This project should only be used in aid of local +development against a locally run instance of the Flow +blockchain like the Flow emulator, and should never be used in +conjunction with Flow Mainnet, Testnet, or any +other instances of Flow. + +::: + +:::info + +To see a full list of Flow compatible wallets visit [Wallets page](../../ecosystem/wallets.md) + +::: + +## Getting Started + +Before using the dev wallet, you'll need to start the Flow emulator. + +### Install the `flow-cli` + +The Flow emulator is bundled with the Flow CLI. Instructions for installing the CLI can be found here: [flow-cli/install/](../flow-cli/install.md) + +### Create a `flow.json` file + +Run this command to create `flow.json` file (typically in your project's root directory): + +```sh +flow init --config-only +``` + +### Start the Emulator + +Start the Emulator and deploy the contracts by running the following command from the directory containing `flow.json` in your project: + +```sh +flow emulator start +flow project deploy --network emulator +``` + +## Configuring Your JavaScript Application + +The Flow Dev Wallet is designed to be used with [`@onflow/fcl`](https://github.com/onflow/fcl-js) version `1.0.0` or higher. The FCL package can be installed with: `npm install @onflow/fcl` or `yarn add @onflow/fcl`. + +To use the dev wallet, configure FCL to point to the address of a locally running [Flow emulator](#start-the-emulator) and the dev wallet endpoint. + +```javascript +import * as fcl from '@onflow/fcl'; + +fcl + .config() + // Point App at Emulator REST API + .put('accessNode.api', 'http://localhost:8888') + // Point FCL at dev-wallet (default port) + .put('discovery.wallet', 'http://localhost:8701/fcl/authn'); +``` + +:::info + +For a full example refer to [Authenticate using FCL snippet](https://academy.ecdao.org/en/snippets/fcl-authenticate) + +::: + +### Test harness + +It's easy to use this FCL harness app as a barebones +app to interact with the dev-wallet during development: + +Navigate to http://localhost:8701/harness + +### Wallet Discovery + +[Wallet Discovery](../clients/fcl-js/discovery.md) offers a convenient modal and mechanism to authenticate users and connects to all wallets available in the Flow ecosystem. + +The following code from [Emerald Academy](https://academy.ecdao.org/en/snippets/fcl-authenticate) can be added to your React app to enable Wallet Discovery: + +```javascript +import { config, authenticate, unauthenticate, currentUser } from '@onflow/fcl'; +import { useEffect, useState } from 'react'; + +const fclConfigInfo = { + emulator: { + accessNode: 'http://127.0.0.1:8888', + discoveryWallet: 'http://localhost:8701/fcl/authn', + discoveryAuthInclude: [], + }, + testnet: { + accessNode: 'https://rest-testnet.onflow.org', + discoveryWallet: 'https://fcl-discovery.onflow.org/testnet/authn', + discoveryAuthnEndpoint: + 'https://fcl-discovery.onflow.org/api/testnet/authn', + // Adds in Dapper + Ledger + discoveryAuthInclude: ['0x82ec283f88a62e65', '0x9d2e44203cb13051'], + }, + mainnet: { + accessNode: 'https://rest-mainnet.onflow.org', + discoveryWallet: 'https://fcl-discovery.onflow.org/authn', + discoveryAuthnEndpoint: 'https://fcl-discovery.onflow.org/api/authn', + // Adds in Dapper + Ledger + discoveryAuthInclude: ['0xead892083b3e2c6c', '0xe5cd26afebe62781'], + }, +}; + +const network = 'emulator'; + +config({ + 'walletconnect.projectId': 'YOUR_PROJECT_ID', // your WalletConnect project ID + 'app.detail.title': 'Emerald Academy', // the name of your DApp + 'app.detail.icon': 'https://academy.ecdao.org/favicon.png', // your DApps icon + 'app.detail.description': 'Emerald Academy is a DApp for learning Flow', // a description of your DApp + 'app.detail.url': 'https://academy.ecdao.org', // the URL of your DApp + 'flow.network': network, + 'accessNode.api': fclConfigInfo[network].accessNode, + 'discovery.wallet': fclConfigInfo[network].discoveryWallet, + 'discovery.authn.endpoint': fclConfigInfo[network].discoveryAuthnEndpoint, + // adds in opt-in wallets like Dapper and Ledger + 'discovery.authn.include': fclConfigInfo[network].discoveryAuthInclude, + 'discovery.authn.exclude': ['0x1234567890abcdef'], // excludes chosen wallets by address +}); + +export default function App() { + const [user, setUser] = useState({ loggedIn: false, addr: '' }); + + // So that the user stays logged in + // even if the page refreshes + useEffect(() => { + currentUser.subscribe(setUser); + }, []); + + return ( +
    + + +

    {user.loggedIn ? `Welcome, ${user.addr}!` : 'Please log in.'}

    +
    + ); +} +``` + +### Account/Address creation + +You can [create a new account](https://cadence-lang.org/docs/language/accounts#account-creation) by using the `&Account` constructor. When you do this, make sure to specify which account will pay for the creation fees by setting it as the payer. + +The account you choose to pay these fees must have enough money to cover the cost. If it doesn't, the process will stop and the account won't be created. + +```cadence +transaction(publicKey: String) { + prepare(signer: &Account) { + let key = PublicKey( + publicKey: publicKey.decodeHex(), + signatureAlgorithm: SignatureAlgorithm.ECDSA_P256 + ) + let account = Account(payer: signer) + account.keys.add( + publicKey: key, + hashAlgorithm: HashAlgorithm.SHA3_256, + weight: 1000.0 + ) + } +} +``` + +To create a new Flow account refer to these resources + +- [Create an Account with FCL snippet](https://academy.ecdao.org/en/snippets/fcl-create-account) +- [Create an Account in Cadence snippet](https://academy.ecdao.org/en/snippets/cadence-create-account) + +### Get Flow Balance + +Retrieving the token balance of a specific account involves writing a script to pull data from onchain. The user may have both locked tokens as well as unlocked so to retrieve the total balance we would aggregate them together. + +```javascript +import * as fcl from '@onflow/fcl'; +import * as t from '@onflow/types'; +const CODE = ` +import "FungibleToken" +import "FlowToken" +import "LockedTokens" + +access(all) fun main(address: Address): UFix64 { + let account = getAccount(address) + let unlockedVault = account + .capabilities.get<&FlowToken.Vault>(/public/flowTokenBalance) + .borrow() + ?? panic("Could not borrow Balance reference to the Vault" + .concat(" at path /public/flowTokenBalance!") + .concat(" Make sure that the account address is correct ") + .concat("and that it has properly set up its account with a FlowToken Vault.")) + + let unlockedBalance = unlockedVault.balance + let lockedAccountInfoCap = account + .capabilities.get + <&LockedTokens.TokenHolder> + (LockedTokens.LockedAccountInfoPublicPath) + if !(lockedAccountInfoCap!.check()) { + return unlockedBalance + } + let lockedAccountInfoRef = lockedAccountInfoCap!.borrow()! + let lockedBalance = lockedAccountInfoRef.getLockedAccountBalance() + return lockedBalance + unlockedBalance +}`; +export const getTotalFlowBalance = async (address) => { + return await fcl.decode( + await fcl.send([fcl.script(CODE), fcl.args([fcl.arg(address, t.Address)])]), + ); +}; +``` + +## Contributing + +Releasing a new version of Dev Wallet is as simple as tagging and creating a release, a Github Action will then build a bundle of the Dev Wallet that can be used in other tools (such as CLI). If the update of the Dev Wallet is required in the CLI, a seperate update PR on the CLI should be created. For more information, please visit the [fcl-dev-wallet GitHub repository](https://github.com/onflow/fcl-dev-wallet). + +## More + +Additionally, consider exploring these resources: + +- [Guide to Creating a Fungible Token on Flow](../../build/guides/fungible-token.md) +- [Tutorial on Fungible Tokens](https://cadence-lang.org/docs/tutorial/fungible-tokens) +- [Faucets](../../ecosystem/faucets.md) + + +=== tools/flow-cli/tests.md === +--- +title: Running Cadence Tests +sidebar_label: Running Cadence Tests +description: How to run Cadence tests from the CLI +sidebar_position: 11 +--- + +The Flow CLI provides a straightforward command to execute Cadence tests, enabling developers to validate their scripts and smart contracts effectively. + +To run all tests in your project, simply use: + +```shell +flow test +``` + +The `flow test` command automatically discovers and runs all test scripts in your project that end with `_test.cdc`. + +> **Note:** The `test` command requires a properly initialized configuration. If you haven’t set up your Flow project yet, refer to the [flow init](flow.json/initialize-configuration.md) guide for assistance. + +## Prerequisites + +Before running your tests, ensure that your contracts are properly configured in your `flow.json` file, including any necessary testing aliases. + +### Setting Up Testing Aliases in Contracts + +If your tests involve deploying or interacting with contracts, you need to add your contracts to the `contracts` section in the `flow.json` configuration file. Specifically, include the contract name, source location, and an address alias for the `testing` environment. + +Example `flow.json` configuration: + +```json +{ + "contracts": { + "Counter": { + "source": "cadence/contracts/Counter.cdc", + "aliases": { + "testing": "0x0000000000000007" + } + } + }, + "networks": { + // ... your network configurations + }, + "accounts": { + // ... your account configurations + }, + "deployments": { + // ... your deployment configurations + } +} +``` + +For the `testing` alias, you can use one of the following addresses: + +- `0x0000000000000005` +- `0x0000000000000006` +- `0x0000000000000007` +- `0x0000000000000008` +- `0x0000000000000009` +- `0x000000000000000A` +- `0x000000000000000B` +- `0x000000000000000C` +- `0x000000000000000D` +- `0x000000000000000E` + +> **Note**: For more information on setting up contracts and aliases, refer to the [Flow CLI Configuration](flow.json/initialize-configuration.md) documentation. + +## Example Usage + +Assuming you have a test script named `test_script_test.cdc` in your project directory, which verifies the functionality of a Cadence script executed in the testing environment: + +```cadence +// test_script_test.cdc +import Test + +access(all) let blockchain = Test.newEmulatorBlockchain() + +access(all) fun testSumOfTwo() { + let scriptResult = blockchain.executeScript( + "access(all) fun main(a: Int, b: Int): Int { return a + b }", + [2, 3] + ) + + Test.expect(scriptResult, Test.beSucceeded()) + + let sum = scriptResult.returnValue! as! Int + Test.assertEqual(5, sum) +} +``` + +This script defines a single test case, `testSumOfTwo`, which checks if a Cadence script that adds two integers `(a + b)` works as expected. The test passes if the result matches the expected value of `5`. + +You can run all tests in your project using the CLI: + +```shell +$ flow test +``` + +The Flow CLI will discover all test scripts ending with `_test.cdc` and execute them. The results will be displayed in the terminal: + +```shell +Test results: +- PASS: test_script_test.cdc > testSumOfTwo +``` + +To learn more about writing tests in Cadence, visit the [Cadence Testing Framework](../../build/smart-contracts/testing.md) documentation. + +--- + +### Running Specific Tests + +If you wish to run a specific test script rather than all tests, you can provide the path to the test file: + +```shell +flow test path/to/your/test_script_test.cdc +``` + +This will execute only the tests contained in the specified file. + +--- + +## Flags + +The `flow test` command supports several flags that provide additional functionality for managing test execution and coverage reporting. + +### **Coverage Report** + +- **Flag:** `--cover` +- **Default:** `false` + +The `--cover` flag calculates the coverage of the code being tested, helping you identify untested parts of your scripts and contracts. + +```shell +$ flow test --cover +``` + +Sample output: + +```shell +Test results: +- PASS: test_script_test.cdc > testSumOfTwo +Coverage: 96.5% of statements +``` + +--- + +### Coverage Report Output File + +- **Flag:** `--coverprofile` +- **Valid Inputs:** A valid filename with extension `.json` or `.lcov` +- **Default:** `"coverage.json"` + +Use the `--coverprofile` flag to specify the output file for the coverage report. + +Example: + +```shell +$ flow test --cover --coverprofile="coverage.lcov" +``` + +The generated coverage file can then be inspected: + +```shell +$ cat coverage.lcov +``` + +### Coverage Code Type + +- **Flag:** `--covercode` +- **Valid Inputs:** `"all"` (default) or `"contracts"` +- **Default:** `"all"` + +The `--covercode` flag lets you limit the coverage report to specific types of code. Setting the value to `"contracts"` excludes scripts and transactions from the coverage analysis. + +```shell +$ flow test --cover --covercode="contracts" +``` + +Sample output when no contracts are present: + +```shell +Test results: +- PASS: test_script_test.cdc > testSumOfTwo +There are no statements to cover +``` + +> **Note:** In this example, the coverage report is empty because the `--covercode` flag is set to `"contracts"`, and the test script only contains scripts, not contracts. + +### Random Execution of Test Cases + +- **Flag:** `--random` +- **Default:** `false` + +Use the `--random` flag to execute test cases in a random order. This can help identify issues that may arise due to test dependencies or the order in which tests are run. + +```shell +flow test --random +``` + +### Seed for Random Execution + +- **Flag:** `--seed` +- **Default:** `0` + +Use the `--seed` flag to specify a seed value for the random execution order of test cases. This allows you to reproduce a specific random order by using the same seed value, which is helpful for debugging flaky tests. + +```shell +flow test --seed=12345 +``` + +> **Note:** If both `--random` and `--seed` are provided, the `--random` flag will be ignored, and the seed value from `--seed` will be used for randomization. + +--- + +### Run Specific Test by Name + +- **Flag:** `--name` +- **Default:** `""` (empty string) + +Use the `--name` flag to run only tests that match the given name. This is useful when you want to execute a specific test function within your test scripts. + +```shell +flow test --name=testSumOfTwo +``` + +This command will run only the test function named `testSumOfTwo` across all test scripts that contain it. + +To dive deeper into testing the functionality of your Cadence scripts and contracts, explore the [Cadence Testing Framework](https://cadence-lang.org/docs/testing-framework) documentation. + +=== tools/flow-cli/super-commands.md === +--- +title: Super Commands +description: How Flow Super Commands Work +sidebar_position: 2 +--- + +Flow CLI Super commands are set of commands that can be used during development of your dApp to greatly simplify the workflow. The result is you can focus on writing the contracts and the commands will take care of the rest. + +## Init +The initial command to start your new Flow project is flow init. It will ask you a few questions about how you'd like to configure your project and then create the necessary files and folders, set up the configuration file, and install any core contract dependencies you might need. + +During the initialization process, `flow init` will prompt you if you want to install any core smart contracts (e.g. `NonFungibleToken`) and set them up in your project. If you choose to install core contracts, the CLI will use the [Dependency Manager](dependency-manager.md) under the hood to automatically install any required smart contract dependencies. + +> Note: If you just want the `flow.json` configured without creating any folders or files, you can run `flow init --config-only`. + +Running the command: +``` +> flow init $PROJECT_NAME +``` + +Will create the following folders and files: +- `/contracts` folder should contain all your Cadence contracts, +- `/scripts` folder should contain all your Cadence scripts, +- `/transactions` folder should contain all your Cadence transactions, +- `/tests` folder should contain all your Cadence tests, +- `flow.json` is a configuration file for your project, which will be automatically maintained. + +### Using Scaffolds +Based on the purpose of your project you can select from a list of available scaffolds. +You can access the scaffolds by simply using the `--scaffold` flag like so: +``` +> flow init $PROJECT_NAME --scaffold +``` + +If you'd like to skip the interactive mode of selecting a scaffold, use the `--scaffold-id` flag with a known ID: + +``` +> flow init $PROJECT_NAME --scaffold-id=1 +``` + +The list of scaffolds will continuously grow, and you are welcome to contribute to that. +You can contribute by creating your own scaffold repository which can then be added to the scaffold +list by [following instructions here](https://github.com/onflow/flow-cli/blob/master/CONTRIBUTING.md#adding-a-scaffold). + +## Testing +`flow init` will also have created an example test file in the `/tests` folder. You can run the tests by using the `flow test` command. + +## Import Schema +You can simply import your contracts by name. We have introducted a new way to import your contracts. This will simply your workflow. + +The new import schema format looks like: +``` +import "{name of the contract}" +``` +Example: +``` +import "HelloWorld" +``` +This will automatically import the contract you have created in your project with the same name and +save the configuration in flow.json. It doesn't matter if the contract has been deployed on a non-default account. + +## Learn More + +To learn more about next steps following the initial setup, check out the following links: + +- [Depedency Manager](./dependency-manager.md): Lets you install and manage your contract dependencies with CLI commands. +- [Manage Configuration](./flow.json/manage-configuration.md): Learn how to manage your project configuration file. + +=== tools/flow-cli/lint.md === +--- +title: Cadence Linter +description: A static-analysis tool for finding potential issues in Cadence code +sidebar_position: 14 +--- + +The Cadence Linter is a static-analysis tool for finding potential issues in Cadence code. It is available in the Flow CLI & is designed to help developers write better code by identifying common mistakes and potential issues before they become problems. + +The linter will also check your code for any syntax or semantic errors, and provide suggestions for how to fix them. + +```shell +flow cadence lint [files] +``` + +## Example Usage + +```shell +flow cadence lint **/*.cdc +``` + +## Example Output + +```shell +test.cdc:27:6: semantic-error: cannot find variable in this scope: `abc` + +test.cdc:35:6: removal-hint: unnecessary force operator + +2 problems (1 error, 1 warning) +``` + +:::info +The Cadence Linter is also available in the [Cadence VSCode extension](../vscode-extension/index.md), which provides real-time feedback as you write your code. +::: + +=== tools/flow-cli/install.md === +--- +title: Install Instructions +description: How to install the Flow command-line interface (CLI) +sidebar_position: 1 +--- + +The Flow CLI can be installed on macOS, Windows (7 or greater) and most Linux systems. + +> Note: If you need to install the pre-release version of the Flow CLI supporting Cadence 1.0, please refer to the [Cadence 1.0 migration guide instructions](https://cadence-lang.org/docs/cadence-migration-guide#install-cadence-10-cli). + +## macOS + +### Homebrew + +```sh +brew install flow-cli +``` + +### From a pre-built binary + +_This installation method only works on x86-64._ + +This script downloads and installs the appropriate binary for your system: + +```sh +sh -ci "$(curl -fsSL https://raw.githubusercontent.com/onflow/flow-cli/master/install.sh)" +``` + +To update, simply re-run the installation command above. + +It is currently not possible to install earlier versions of the Flow CLI with Homebrew. +## Linux + +### From a pre-built binary + +_This installation method only works on x86-64._ + +This script downloads and installs the appropriate binary for your system: + +```sh +sh -ci "$(curl -fsSL https://raw.githubusercontent.com/onflow/flow-cli/master/install.sh)" +``` + +To update, simply re-run the installation command above. + +### Install a specific version + +To install a specific version of Flow CLI newer than v0.42.0, append the version tag to the command (e.g. the command below installs CLI version v0.44.0). + +```sh +sh -ci "$(curl -fsSL https://raw.githubusercontent.com/onflow/flow-cli/master/install.sh)" -- v0.44.0 +``` + +To install a version older than v0.42.0, refer to [Installing versions before 0.42.0](#installing-versions-before-0420) below. + +## Windows + +### From a pre-built binary + +_This installation method only works on Windows 10, 8.1, or 7 (SP1, with [PowerShell 3.0](https://www.microsoft.com/en-ca/download/details.aspx?id=34595)), on x86-64._ + +1. Open PowerShell ([Instructions](https://docs.microsoft.com/en-us/powershell/scripting/install/installing-windows-powershell?view=powershell-7#finding-powershell-in-windows-10-81-80-and-7)) +2. In PowerShell, run: + + ```powershell + iex "& { $(irm 'https://raw.githubusercontent.com/onflow/flow-cli/master/install.ps1') }" + ``` + +To update, simply re-run the installation command above. + +# Upgrade the Flow CLI + +## macOS + +### Homebrew + +```sh +brew upgrade flow-cli +``` + +### From a pre-built binary + +_This update method only works on x86-64._ + +This script downloads and updates the appropriate binary for your system: + +```sh +sh -ci "$(curl -fsSL https://raw.githubusercontent.com/onflow/flow-cli/master/install.sh)" +``` + +## Linux + +### From a pre-built binary + +_This update method only works on x86-64._ + +This script downloads and updates the appropriate binary for your system: + +```sh +sh -ci "$(curl -fsSL https://raw.githubusercontent.com/onflow/flow-cli/master/install.sh)" +``` + +## Windows + +### From a pre-built binary + +_This update method only works on Windows 10, 8.1, or 7 (SP1, with [PowerShell 3.0](https://www.microsoft.com/en-ca/download/details.aspx?id=34595)), on x86-64._ + +1. Open PowerShell ([Instructions](https://docs.microsoft.com/en-us/powershell/scripting/install/installing-windows-powershell?view=powershell-7#finding-powershell-in-windows-10-81-80-and-7)) +2. In PowerShell, run: + + ```powershell + iex "& { $(irm 'https://raw.githubusercontent.com/onflow/flow-cli/master/install.ps1') }" + ``` + +# Uninstalling Flow CLI +To remove the flow CLI you can run the following command if it was previously installed using a pre-built binary. + +- macOS: `rm /usr/local/bin/flow` +- Linux: `rm ~/.local/bin/flow` +- Windows: `rm ~/Users/{user}/AppData/Flow/flow.exe` + +If you installed it using Hombrew you can remove it using: `brew uninstall flow-cli`. + +## Installing versions before 0.42.0 +If you want to install versions before v0.42.0 you have to use a different install command. + +**Linux/macOS** +``` +https://raw.githubusercontent.com/onflow/flow-cli/v0.41.3/install.ps1 + +sh -ci "$(curl -fsSL https://raw.githubusercontent.com/onflow/flow-cli/v0.41.3/install.sh)" -- v0.41.2 +``` + +**Windows** +``` +iex "& { $(irm 'https://raw.githubusercontent.com/onflow/flow-cli/master/install.ps1') }" +``` + + +=== tools/flow-cli/index.md === +--- +title: Flow CLI +sidebar_label: Flow CLI +sidebar_position: 3 +--- + +The **Flow Command Line Interface (CLI)** is a powerful tool that enables developers to seamlessly interact with the Flow blockchain across various environments, including testnet, mainnet, and local development using the Flow Emulator. Designed for ease of use, the Flow CLI simplifies common blockchain tasks such as managing accounts and contract dependencies, sending transactions, querying chain state, deploying smart contracts, and much more. + +With Flow CLI, developers can: + +- **Initialize Projects**: Quickly set up new Flow projects using the `flow init` command, which creates the necessary files and directories, sets up your project configuration, and installs any core contract dependencies. +- **Manage Contract Dependencies**: Use the [Dependency Manager](dependency-manager.md) to install and manage smart contract dependencies effortlessly, simplifying the integration of external contracts into your project. +- **Manage Accounts**: Create and manage Flow accounts, configure keys, and handle account-related operations. +- **Send Transactions**: Build, sign, and submit transactions to the Flow network, allowing for contract interaction and fund transfers. +- **Query Chain State**: Retrieve data from the Flow blockchain, including account balances, event logs, and the status of specific transactions. +- **Deploy Smart Contracts**: Easily deploy and update Cadence smart contracts on any Flow environment (emulator, testnet, or mainnet). +- **Use the Emulator:** Set up a local Flow blockchain instance with the Flow emulator to test and debug smart contracts in a development environment before deploying them on the network. +- **Interact with the [Flow Access API](/http-api)**: Automate complex workflows using configuration files and command-line scripting, which allows for greater flexibility in continuous integration (CI) or custom development tools. +- **Access Flow’s Tooling Ecosystem**: Integrate Flow CLI with other developer tools like the [Cadence Extension for VSCode](https://marketplace.visualstudio.com/items?itemName=onflow.cadence) to enhance your development experience. + +The Flow CLI is essential for developers looking to build, test, and maintain decentralized applications on the Flow blockchain efficiently, offering a feature-rich, user-friendly interface for both beginners and experienced blockchain developers. + +## Installation + +Follow [these steps](../flow-cli/install.md) to install the Flow CLI on +macOS, Linux, and Windows. + +## Create Your First Project + +To get started with creating your first Flow project and to learn more about how to use the Flow CLI super commands, please refer to the [Super Commands documentation](super-commands.md). These commands simplify the setup and development process, allowing you to focus on building your application without worrying about the underlying configurations. + + +=== tools/flow-cli/flix.md === +--- +title: Flow Interaction Templates (FLIX) +sidebar_label: Flow Interaction Templates (FLIX) +description: Flow Interaction Templates (FLIX) via the CLI +sidebar_position: 15 +--- + +FLIX helps developers reuse existing Cadence transactions and scripts to easily integrate with existing Cadence smart contracts. Get more information about [Flow Interaction Templates](../../build/advanced-concepts/flix.md) + +## Introduction + +The Flow CLI provides a `flix` command with a few sub commands `execute` and `package`. Get familiar with Flow Interaction Templates [(FLIX)](https://github.com/onflow/flips/blob/main/application/20220503-interaction-templates.md). FLIX are a standard for distributing Cadence scripts and transactions, and metadata in a way that is consumable by tooling and wallets. FLIX can be audited for correctness and safety by auditors in the ecosystem. + +```shell +>flow flix +execute, generate, package + +Usage: + flow flix [command] + +Available Commands: + execute execute FLIX template with a given id, name, local filename, or url + generate generate FLIX json template given local Cadence filename + package package file for FLIX template fcl-js is default + + +``` + +### Execute + +The Flow CLI provides a `flix` command to `execute` FLIX. The Cadence being execute in the FLIX can be a transaction or script. + +```shell +flow flix execute [ ...] [flags] +``` + +:::warning + +A FLIX template might only support testnet and/or mainnet. Generally, emulator is not supported. This can be the case if the FLIX template relies on contract dependencies. + +::: + + +Queries can be a FLIX `id`, `name`, `url` or `path` to a local FLIX file. + +### Execute Usage + +```shell +# Execute a FLIX transaction by name on Testnet +flow flix execute transfer-flow 5.0 "0x123" --network testnet --signer "testnet-account" +``` + +```shell +# Execute a FLIX script by id on Testnet +flow flix execute bd10ab0bf472e6b58ecc0398e9b3d1bd58a4205f14a7099c52c0640d9589295f --network testnet +``` + +```shell +# Execute a local FLIX script by path on Testnet +flow flix execute ./multiply.template.json 2 3 --network testnet +``` + +The Flow CLI provides a `flix` command to `package` up generated plain and simple JavaScript. This JavaScript uses FCL (Flow Client Library) to call the cadence the Flow Interaction Templates (FLIX) is based on. + +:::info + +Currently, `flix package` command only supports generating FCL (Flow Client Library) specific JavaScript and TypeScirpt, there are plans to support other languages like golang. + +::: + + +```shell +flow flix package [flags] +``` + +### Generate + +Generate FLIX json file. This command will take in a Cadence file and produce a FLIX json file. There are two ways to provide metadata to populate the FLIX json structure. + - Use `--pre-fill` flag to pass in a pre populated FLIX json structure + - Use `--exclude-networks` flag to specify excluded networks when generating a FLIX templates. Example, `--exclude-networks testnet,mainnet` + +:::warning + +When generating a FLIX template, make sure all contract dependencies have been deployed to the supported networks. Add any aliases to your flow.json that will be needed to populate dependencies. Verify all dependencies have been populated after generating. + +::: + + +### Generate Usage + +```shell +# Generate FLIX json file using cadence transaction or script, this example is not using a prefilled json file so will not have associated message metadata +flow flix generate cadence/transactions/update-helloworld.cdc --save cadence/templates/update-helloworld.template.json +``` + +Example of Cadence simple, no metadata associated +```cadence + +import "HelloWorld" +access(all) fun main(): String { + return HelloWorld.greeting +} +``` + + +### Cadence Doc Pragma: +It's recommended to use pragma to set the metadata for the script or transaction. More information on [Cadence Doc Pragma FLIP](https://github.com/onflow/flips/blob/main/application/20230406-interaction-template-cadence-doc.md) + +A pragma is short for "pragmatic information", it's special instructions to convey information to a processor in this case the utility that generates FLIX. +```cadence +import "HelloWorld" + +#interaction ( + version: "1.1.0", + title: "Update Greeting", + description: "Update the greeting on the HelloWorld contract", + language: "en-US", +) + +transaction(greeting: String) { + + prepare(acct: &Account) { + log(acct.address) + } + + execute { + HelloWorld.updateGreeting(newGreeting: greeting) + } +} + +``` + +:::info +Cadence v0.42.7 supports additional Cadence pragma functionality that FlIX utility can use to generate FLIX. It will support parameters "title" and "description". +::: + + +The resulting json metadata is extracted from Cadence Doc Pragma +```json +{ + "f_type": "InteractionTemplate", + "f_version": "1.1.0", + "id": "", + "data": { + "type": "transaction", + "interface": "", + "messages": [ + { + "key": "title", + "i18n": [ + { + "tag": "en-US", + "translation": "Update Greeting" + } + ] + }, + { + "key": "description", + "i18n": [ + { + "tag": "en-US", + "translation": "Update the greeting on the HelloWorld contract" + } + ] + } + ], + "cadence": {}, + "dependencies": [], + "parameters": [ + { + "label": "greeting", + "index": 0, + "type": "String", + "messages": [] + } + ] + } +} +``` + +Example of using a prefilled FLIX json file. No need to use Cadence pragma when using a prefilled FLIX json file. This method separates FLIX specific information from the transaction or script Cadence. Use the `flow flix generate` command: + +```shell +flow flix generate cadence/scripts/read-helloworld.cdc --pre-fill cadence/templates/read-helloworld.prefill.json --save cadence/templates/read-helloworld.template.json +``` + +Using a pre-filled FLIX template, the cadence can be simple but no metadata accompanies it. + +```cadence +import "HelloWorld" +access(all) fun main(): String { + return HelloWorld.greeting +} +``` + +Example of json prefill file with message metadata: +```json +{ + "f_type": "InteractionTemplate", + "f_version": "1.1.0", + "id": "", + "data": { + "type": "script", + "interface": "", + "messages": [ + { + "key": "title", + "i18n": [ + { + "tag": "en-US", + "translation": "Get Greeting" + } + ] + }, + { + "key": "description", + "i18n": [ + { + "tag": "en-US", + "translation": "Call HelloWorld contract to get greeting" + } + ] + } + ] + } +} + +``` + +The resulting FLIX json file after generation: + +```json +{ + "f_type": "InteractionTemplate", + "f_version": "1.1.0", + "id": "fd9abd34f51741401473eb1cf676b105fed28b50b86220a1619e50d4f80b0be1", + "data": { + "type": "script", + "interface": "", + "messages": [ + { + "key": "title", + "i18n": [ + { + "tag": "en-US", + "translation": "Get Greeting" + } + ] + }, + { + "key": "description", + "i18n": [ + { + "tag": "en-US", + "translation": "Call HelloWorld contract to get greeting" + } + ] + } + ], + "cadence": { + "body": "import \"HelloWorld\"\naccess(all) fun main(): String {\n return HelloWorld.greeting\n}\n", + "network_pins": [ + { + "network": "testnet", + "pin_self": "41c4c25562d467c534dc92baba92e0c9ab207628731ee4eb4e883425abda692c" + } + ] + }, + "dependencies": [ + { + "contracts": [ + { + "contract": "HelloWorld", + "networks": [ + { + "network": "testnet", + "address": "0xe15193734357cf5c", + "dependency_pin_block_height": 137864533, + "dependency_pin": { + "pin": "aad46badcab3caaeb4f0435625f43e15bb4c15b1d55c74a89e6f04850c745858", + "pin_self": "a06b3cd29330a3c22df3ac2383653e89c249c5e773fd4bbee73c45ea10294b97", + "pin_contract_name": "HelloWorld", + "pin_contract_address": "0xe15193734357cf5c", + "imports": [] + } + } + ] + } + ] + } + ], + "parameters": null + } +} + +``` + + +### Package + +Queries can be a FLIX `url` or `path` to a local FLIX file. This command leverages [FCL](../clients/fcl-js/) which will execute FLIX cadence code. Package files can be generated in JavaScript or TypeScript. + +:::warning + +Currently package doesn't support `id`, `name` flix query. + +::: + +### Package Usage + +```shell +# Generate packaged code that leverages FCL to call the Cadence transaction code, `--save` flag will save the output to a specific file +flow flix package transfer-flow --save ./package/transfer-flow.js +``` + +```shell +# Generate package code for a FLIX script using id, since there is no saving file, the result will display in terminal +flow flix package bd10ab0bf472e6b58ecc0398e9b3d1bd58a4205f14a7099c52c0640d9589295f +``` + +```shell +# Generate package code using local template file to save in a local file +flow flix package ./multiply.template.json --save ./multiply.js +``` + +```shell +# Generate package code using local template file to save in a local typescript file +flow flix package ./multiply.template.json --lang ts --save ./multiply.ts +``` + + +### Example Package Output +```shell +flow flix package https://flix.flow.com/v1/templates\?name\=transfer-flow +``` + +```javascript + +/** + This binding file was auto generated based on FLIX template v1.0.0. + Changes to this file might get overwritten. + Note fcl version 1.3.0 or higher is required to use templates. +**/ + +import * as fcl from "@onflow/fcl" +const flixTemplate = "https://flix.flow.com/v1/templates?name=transfer-flow" + +/** +* Transfer tokens from one account to another +* @param {Object} Parameters - parameters for the cadence +* @param {string} Parameters.amount - The amount of FLOW tokens to send: UFix64 +* @param {string} Parameters.to - The Flow account the tokens will go to: Address +* @returns {Promise} - returns a promise which resolves to the transaction id +*/ +export async function transferTokens({amount, to}) { + const transactionId = await fcl.mutate({ + template: flixTemplate, + args: (arg, t) => [arg(amount, t.UFix64), arg(to, t.Address)] + }); + + return transactionId +} + + +``` + +```shell +# Generate TypeScript version of package file +flow flix package https://flix.flow.com/v1/templates?name=transfer-flow --lang ts +``` + +```typescript + +/** + This binding file was auto generated based on FLIX template v1.1.0. + Changes to this file might get overwritten. + Note fcl version 1.9.0 or higher is required to use templates. +**/ + +import * as fcl from "@onflow/fcl" +const flixTemplate = "https://flix.flow.com/v1/templates?name=transfer-flow" + +interface TransferTokensParams { + amount: string; // The amount of FLOW tokens to send + to: string; // The Flow account the tokens will go to +} + +/** +* transferTokens: Transfer tokens from one account to another +* @param string amount - The amount of FLOW tokens to send +* @param string to - The Flow account the tokens will go to +* @returns {Promise} - Returns a promise that resolves to the transaction ID +*/ +export async function transferTokens({amount, to}: TransferTokensParams): Promise { + const transactionId = await fcl.mutate({ + template: flixTemplate, + args: (arg, t) => [arg(amount, t.UFix64), arg(to, t.Address)] + }); + + return transactionId +} + +``` +:::warning + +Notice that fcl v1.9.0 is needed to use FLIX v1.1 templates + +::: + +## Resources + +To find out more about FLIX, see the [read the FLIP](https://github.com/onflow/flips/blob/main/application/20220503-interaction-templates.md). + +For a list of all templates, check out the [FLIX template repository](https://github.com/onflow/flow-interaction-template-service/tree/master/templates). + +To generate a FLIX, see the [FLIX CLI readme](https://github.com/onflow/flow-interaction-template-tools/tree/master/cli). + +## Arguments +- Name: `argument` +- Valid input: valid [FLIX](https://github.com/onflow/flips/blob/main/application/20220503-interaction-templates.md) + +Input argument value matching corresponding types in the source code and passed in the same order. +You can pass a `nil` value to optional arguments by executing the flow FLIX execute script like this: `flow flix execute template.json nil`. + +## Flags + +### Arguments JSON + +- Flag: `--args-json` +- Valid inputs: arguments in JSON-Cadence form. +- Example: `flow flix execute template.script.json '[{"type": "String", "value": "Hello World"}]'` + +Arguments passed to the Cadence script in the Cadence JSON format. +Cadence JSON format contains `type` and `value` keys and is +[documented here](https://cadencelang.dev/docs/1.0/json-cadence-spec). + +## Pre Fill + +- Flag: `--pre-fill` +- Valid inputs: a json file in the FLIX json structure [FLIX json format](https://github.com/onflow/flips/blob/main/application/20220503-interaction-templates.md) + + +## Block Height + +- Flag: `--block-height` +- Valid inputs: a block height number + +## Block ID + +- Flag: `--block-id` +- Valid inputs: a block ID + +### Signer + +- Flag: `--signer` +- Valid inputs: the name of an account defined in the configuration (`flow.json`) + +Specify the name of the account that will be used to sign the transaction. + +### Proposer + +- Flag: `--proposer` +- Valid inputs: the name of an account defined in the configuration (`flow.json`) + +Specify the name of the account that will be used as proposer in the transaction. + +### Payer + +- Flag: `--payer` +- Valid inputs: the name of an account defined in the configuration (`flow.json`) + +Specify the name of the account that will be used as payer in the transaction. + +### Authorizer + +- Flag: `--authorizer` +- Valid inputs: the name of a single or multiple comma-separated accounts defined in the configuration (`flow.json`) + +Specify the name of the account(s) that will be used as authorizer(s) in the transaction. If you want to provide multiple authorizers separate them using commas (e.g. `alice,bob`) + +### Gas Limit + +- Flag: `--gas-limit` +- Valid inputs: an integer greater than zero. +- Default: `1000` + +Specify the gas limit for this transaction. + +### Host + +- Flag: `--host` +- Valid inputs: an IP address or hostname. +- Default: `127.0.0.1:3569` (Flow Emulator) + +Specify the hostname of the Access API that will be +used to execute the command. This flag overrides +any host defined by the `--network` flag. + +### Network Key + +- Flag: `--network-key` +- Valid inputs: A valid network public key of the host in hex string format + +Specify the network public key of the Access API that will be +used to create a secure GRPC client when executing the command. + +### Network + +- Flag: `--network` +- Short Flag: `-n` +- Valid inputs: the name of a network defined in the configuration (`flow.json`) +- Default: `emulator` + +Specify which network you want the command to use for execution. + +### Filter + +- Flag: `--filter` +- Short Flag: `-x` +- Valid inputs: a case-sensitive name of the result property. + +Specify any property name from the result you want to return as the only value. + +### Output + +- Flag: `--output` +- Short Flag: `-o` +- Valid inputs: `json`, `inline` + +Specify the format of the command results. + +### Save + +- Flag: `--save` +- Short Flag: `-s` +- Valid inputs: a path in the current filesystem. + +Specify the filename where you want the result to be saved + +### Log + +- Flag: `--log` +- Short Flag: `-l` +- Valid inputs: `none`, `error`, `debug` +- Default: `info` + +Specify the log level. Control how much output you want to see during command execution. + +### Configuration + +- Flag: `--config-path` +- Short Flag: `-f` +- Valid inputs: a path in the current filesystem. +- Default: `flow.json` + +Specify the path to the `flow.json` configuration file. +You can use the `-f` flag multiple times to merge +several configuration files. + +### Version Check + +- Flag: `--skip-version-check` +- Default: `false` + +Skip version check during start up to speed up process for slow connections. + + +=== tools/flow-cli/dependency-manager.md === +--- +title: Dependency Manager +sidebar_label: Dependency Manager +description: Dependency Manager for the Flow Blockchain. +sidebar_position: 11 +--- + +The Dependency Manager in the Flow CLI streamlines the development process when you use contracts from outside your project. It eliminates the manual tasks of copying, pasting, and updating contracts that you use or build upon, such as core contracts or any other ecosystem contracts. + +For example, if you wanted to build a new application using the `FlowToken` contract, you would traditionally need to locate the contract on the network, copy it into your local project, and add it to your `flow.json`. You would repeat this process for each import (dependency) it relies on, like the `NonFungibleToken` contract. The Dependency Manager simplifies this process with a few straightforward commands. + +## `install` + +The `install` command allows you to install dependencies and all their sub-dependencies with ease. You can use it to install specific dependencies or to install all dependencies listed in your `flow.json`. + +### Installing Specific Dependencies + +If you know the address and name of the contract you want to install (which can often be found via the [Contract Browser](https://contractbrowser.com/)), you can use the following syntax: + +```bash +flow dependencies install testnet://7e60df042a9c0868.FlowToken +``` + +In this command, the string `testnet://7e60df042a9c0868.FlowToken` used as the `source` in the `flow.json` is broken down as: + +- **Network:** `testnet` +- **Address:** `7e60df042a9c0868` +- **Contract Name:** `FlowToken` + +This specifies the remote source of the contract on the network that will be used as the source of truth. + +### Installing Core Contracts Using Simplified Syntax + +For core contracts, you can use a simplified syntax that defaults to the Flow Mainnet: + +```bash +flow dependencies install FlowToken +``` + +This command is functionally equivalent to: + +```bash +flow dependencies install mainnet://1654653399040a61.FlowToken +``` + +### Installing Multiple Dependencies + +You can also install multiple dependencies at once. For example: + +```bash +flow dependencies install testnet://7e60df042a9c0868.FlowToken NonFungibleToken +``` + +This command installs both the `FlowToken` contract from Testnet and the `NonFungibleToken` contract from Mainnet. + +### Installing All Dependencies From an Address + +Sometimes you may want to install all the contracts that exist at a particular address, rather than specifying each contract name individually. You can do this by omitting the contract name in the dependency source. For example: + +```bash +flow dependencies install testnet://7e60df042a9c0868 +``` + +This tells the Dependency Manager to fetch every contract deployed at the `7e60df042a9c0868` address on `testnet` and store them in your `imports` folder. You can later import these contracts in your code or use them in your deployments as needed. + +### Installing Dependencies from `flow.json` + +If you run the `install` command without specifying any dependencies, it will install all the dependencies listed in your `flow.json` file and ensure they are up to date: + +```bash +flow dependencies install +``` + +This command checks all the dependencies specified in your `flow.json`, installs them, and updates them if there have been changes on the network. + +### Example `flow.json` Entry + +After installing, your `flow.json` might include an entry like: + +```json +{ + "dependencies": { + "FlowToken": { + "source": "testnet://7e60df042a9c0868.FlowToken", + "aliases": { + "emulator": "0ae53cb6e3f42a79" + } + } + } +} +``` + +### Other Things to Note + +- After installation, a local folder named `imports` will be created. It's recommended to add this folder to your `.gitignore`, as it stores your dependencies locally. +- If the contracts change on the network, the Dependency Manager will prompt you to update the local dependencies in your `imports` folder. The hash saved in the dependency object is used for this check, so avoid removing it. +- Dependencies function just like local contracts. You can add them to [`deployments` in your `flow.json`](./deployment/deploy-project-contracts.md) and run `flow project deploy`. You can also import them in your scripts, transactions, and contracts (e.g., `import "FlowToken"`). +- Core contract aliases are automatically added for you across all networks. + +## `discover` + +The `discover` command helps you interactively find and install core contracts for your project. Core contracts are standard smart contracts maintained by the Flow Foundation and are commonly used across the Flow ecosystem (learn more about core contracts [here](../../build/core-contracts/index.md)). + +To use the `discover` command, run: + +```bash +flow dependencies discover +``` + +You'll be presented with a list of available core contracts to install: + +```shell +Select any core contracts you would like to install or skip to continue. +Use arrow keys to navigate, space to select, enter to confirm or skip, q to quit: + +> [ ] FlowEpoch + [ ] FlowIDTableStaking + [ ] FlowClusterQC + [ ] FlowDKG + [ ] FlowServiceAccount + [ ] NodeVersionBeacon + [ ] RandomBeaconHistory + [ ] FlowStorageFees + [ ] FlowFees + [ ] FungibleTokenSwitchboard + [ ] EVM + [ ] Crypto +``` + +After selecting the contracts, press `enter` to confirm. The selected contracts will be added to your `flow.json` file and will be accessible in your project. + +=== tools/flow-cli/data-collection.md === +--- +title: Data Collection +description: Data collected from Flow CLI usage +sidebar_position: 17 +--- + +Flow CLI tracks flow command usage count using Mixpanel. + +Data collection is enabled by default. Users can opt out of our data collection through running `flow settings metrics disable`. +To opt back in, users can run `flow settings metrics enable`. + +## Why do we collect data about flow cli usage? + +Collecting aggregate command count allow us to prioritise features and fixes based on how users use flow cli. + +## What data do we collect? + +We only collect the number of times a command is executed. + +We don't keep track of the values of arguments, flags used +and the values of the flags used. We also don't associate any commands to any particular user. + +The only property that we collect from our users are their preferences for opting in / out of data collection. +The analytics user ID is specific to Mixpanel and does not permit Flow CLI maintainers to e.g. track you across websites you visit. + +Further details regarding the data collected can be found under Mixpanel's data collection page in `Ingestion API` +section of https://help.mixpanel.com/hc/en-us/articles/115004613766-Default-Properties-Collected-by-Mixpanel. + +Please note that although Mixpanel's page above mentions that geolocation properties are recorded by default, +we have turned off geolocation data reporting to Mixpanel. + + +=== tools/flow-cli/boilerplate.md === +--- +title: Cadence Boilerplate Generation +sidebar_label: Cadence Boilerplate +description: Cadence Boilerplate Generation via the CLI +sidebar_position: 16 +--- + +## Introduction + +Flow CLI now includes a feature to automatically generate boilerplate code for contracts, transactions, and scripts. This feature enhances the development experience by simplifying the initial setup of various components in Flow. + +```shell +> flow generate +Usage: + flow generate [command] + +Aliases: + generate, g + +Available Commands: + contract Generate a new contract + script Generate a new script + transaction Generate a new transaction +``` + +## Generate Contract + +To create a new contract with basic structure, use the `contract` command. It creates a new Cadence file with a template contract definition. + +```shell +flow generate contract [ContractName] +``` + +### Usage Example + +```shell +> flow generate contract HelloWorld +``` + +This command creates a file `cadence/contracts/HelloWorld.cdc` with the following content: + +```cadence +access(all) contract HelloWorld { + init() {} +} +``` + +## Generate Transaction + +For initializing a transaction, use the `transaction` command. It sets up a new Cadence file with a template transaction structure. + +```shell +flow generate transaction [TransactionName] +``` + +### Usage Example + +```shell +> flow generate transaction SayHello +``` + +This command creates a file `cadence/transactions/SayHello.cdc` with the following content: + +```cadence +transaction() { + prepare() {} + + execute {} +} +``` + +## Generate Script + +Similarly, to start a new script, the `script` command generates a Cadence file with a basic script structure. + +```shell +flow generate script [ScriptName] +``` + +### Usage Example + +```shell +> flow generate script ReadHello +``` + +This command creates a file `cadence/scripts/ReadHello.cdc` with the following content: + +```cadence +access(all) fun main() {} +``` + +## Optional `--dir` Flag + +The `--dir` flag is an optional feature in the Flow CLI `generate` commands, allowing you to specify a custom directory for the generated contract, transaction, or script files. If this flag is not provided, the CLI adheres to the recommended project setup: + +- Contracts are generated in the `cadence/contracts` directory. +- Transactions are generated in the `cadence/transactions` directory. +- Scripts are generated in the `cadence/scripts` directory. + +- **Usage**: `--dir=` +- **Example**: `flow generate contract HelloWorld --dir=custom_contracts` + +Use the `--dir` flag only if your project requires a different organizational structure than the default. + + + +=== tools/flow-cli/_template.md === +--- +title: -title- +sidebar_label: +description: -description- +--- + +\{short description\} + +```shell +{command} +``` + +\{optional warning\} + +## Example Usage + +```shell +{usage example with response} +``` + +## Arguments + +### \{Argument 1\} + +- Name: `\{argument\}` +- Valid Input: `\{input\}` + +\{argument general description\} + +## Arguments + +### Address + +- Name: `address` +- Valid Input: Flow account address + +Flow [account address](../../../build/basics/accounts.md) (prefixed with `0x` or not). + +## Flags + +### \{Option 1\} + +- Flag: `\{flag value\}` +- Valid inputs: \{input description\} + +\{flag general description\} + +### Signer + +- Flag: `--signer` +- Valid inputs: the name of an account defined in the configuration (`flow.json`) + +Specify the name of the account that will be used to sign the transaction. + +### Host + +- Flag: `--host` +- Valid inputs: an IP address or hostname. +- Default: `127.0.0.1:3569` (Flow Emulator) + +Specify the hostname of the Access API that will be +used to execute the commands. + +### Network Key + +- Flag: `--network-key` +- Valid inputs: A valid network public key of the host in hex string format + +Specify the network public key of the Access API that will be +used to create a secure GRPC client when executing the command. + +### Network + +- Flag: `--network` +- Short Flag: `-n` +- Valid inputs: the name of a network defined in the configuration (`flow.json`) +- Default: `emulator` + +Specify which network you want the command to use for execution. + +### Filter + +- Flag: `--filter` +- Short Flag: `-x` +- Valid inputs: case-sensitive name of the result property. + +Specify any property name from the result you want to return as the only value. + +### Output + +- Flag: `--output` +- Short Flag: `-o` +- Valid inputs: `json`, `inline` + +Specify in which format you want to display the result. + +### Save + +- Flag: `--save` +- Short Flag: `-s` +- Valid inputs: valid filename + +Specify the filename where you want the result to be saved. + +### Log + +- Flag: `--log` +- Short Flag: `-l` +- Valid inputs: `none`, `error`, `debug` +- Default: `info` + +Specify the log level. Control how much output you want to see while command execution. + +### Configuration + +- Flag: `--config-path` +- Short Flag: `-f` +- Valid inputs: valid filename + +Specify a filename for the configuration files, you can provide multiple configuration +files by using `-f` flag multiple times. + +### Version Check + +- Flag: `--skip-version-check` +- Default: `false` + +Skip version check during start up to speed up process for slow connections. + + +=== tools/flow-cli/utils/tools.md === +--- +title: Development Tools +description: How to start development tools using the Flow CLI +--- + +The Flow CLI integrates different development tools, which can now be easily started +and managed from a single place. + +Currently the CLI supports starting: +- [Flow Development Wallet](https://github.com/onflow/fcl-dev-wallet) + + +## Flow Development Wallet + +The Flow Dev Wallet is a mock Flow wallet that simulates the protocols used by FCL to interact with the Flow blockchain on behalf of simulated user accounts. + +**Be sure you have the emulator running before starting this command** +_You can start it using the `flow emulator` command_. + +```shell +flow dev-wallet +``` +_⚠️ This project implements an FCL compatible +interface, but should **not** be used as a reference for +building a production grade wallet._ + +After starting dev-wallet, you can set your fcl config to use it like below: + +```javascript +import * as fcl from "@onflow/fcl" + +fcl.config() + // Point App at Emulator + .put("accessNode.api", "http://localhost:8080") + // Point FCL at dev-wallet (default port) + .put("discovery.wallet", "http://localhost:8701/fcl/authn") +``` +You can read more about setting up dev-wallet at [Flow Dev Wallet Project](https://github.com/onflow/fcl-dev-wallet) + + +## Flags + +### Port + +- Flag: `--port` +- Valid inputs: Number +- Default: `8701` + +Port on which the dev wallet server will listen on. + +### Emulator Host + +- Flag: `--emulator-host` +- Valid inputs: a hostname +- Default: `http://localhost:8080` + +Specifies the host configuration for dev wallet + +### Configuration + +- Flag: `--config-path` +- Short Flag: `-f` +- Valid inputs: valid filename + +Specify a filename for the configuration files, you can provide multiple configuration +files by using `-f` flag multiple times. + +Specify a filename for the configuration files, you can provide multiple configuration +files by using `-f` flag multiple times. + +### Version Check + +- Flag: `--skip-version-check` +- Default: `false` + +Skip version check during start up to speed up process for slow connections. + + + + +=== tools/flow-cli/utils/snapshot-save.md === +--- +title: Snapshot Save +description: How to save a protocol snapshot from the command line +--- + +The FLOW CLI provides a command to save the latest finalized protocol state snapshot + +```shell +flow snapshot save +``` + +## Example Usage + +```shell +flow snapshot save /tmp/snapshot.json --network testnet +``` + +### Example response +```shell +snapshot saved: /tmp/snapshot.json +``` + +## Arguments + +### Output Path +- Name: `output path` +- Valid Input: any valid string path + +Output path where the protocol snapshot JSON file will be saved. + +## Flags + + +### Host +- Flag: `--host` +- Valid inputs: an IP address or hostname. +- Default: `127.0.0.1:3569` (Flow Emulator) + +Specify the hostname of the Access API that will be +used to execute the commands. + +### Network Key + +- Flag: `--network-key` +- Valid inputs: A valid network public key of the host in hex string format + +Specify the network public key of the Access API that will be +used to create a secure GRPC client when executing the command. + +### Network + +- Flag: `--network` +- Short Flag: `-n` +- Valid inputs: the name of a network defined in the configuration (`flow.json`) +- Default: `emulator` + +Specify which network you want the command to use for execution. + +### Filter + +- Flag: `--filter` +- Short Flag: `-x` +- Valid inputs: case-sensitive name of the result property. + +Specify any property name from the result you want to return as the only value. + +### Output + +- Flag: `--output` +- Short Flag: `-o` +- Valid inputs: `json`, `inline` + +Specify in which format you want to display the result. + +### Version Check + +- Flag: `--skip-version-check` +- Default: `false` + +Skip version check during start up to speed up process for slow connections. + + + + + + +=== tools/flow-cli/utils/signature-verify.md === +--- +title: Verify Signature +description: How to verify a signature from the command line +--- + +Verify validity of a signature based on provided message and public key of the signature creator. + +```shell +flow signatures verify +``` + +## Example Usage + +```shell +> flow signatures verify + 'The quick brown fox jumps over the lazy dog' + b1c9eff5d829fdeaf2dad6308fc8033e3b8875bc185ef804ce5d0d980545ef5be0f98b47afc979d12272d257ce13c4b490e431bfcada485cb1d2e3f209be8d07 + 0xc92a7c72a78f8f046a79f8a5fe1ef72424258a55eb869f13e6133301d64ad025d3362d5df9e7c82289637af1431042c4025d241fd430242368ce662d39636987 + +Valid true +Message The quick brown fox jumps over the lazy dog +Signature b1c9eff5d829fdeaf2...7ce13c4b490eada485cb1d2e3f209be8d07 +Public Key c92a7c72a78...1431042c4025d241fd430242368ce662d39636987 +Hash Algorithm SHA3_256 +Signature Algorithm ECDSA_P256 +``` + +## Arguments + +### Message +- Name: `message` + +Message data used for creating the signature. + +### Signature +- Name: `signature` + +Message signature that will be verified. + +### Public Key +- Name: `public key` + +Public key of the private key used for creating the signature. + +## Flags + +### Public Key Signature Algorithm + +- Flag: `--sig-algo` +- Valid inputs: `"ECDSA_P256", "ECDSA_secp256k1"` + +Specify the ECDSA signature algorithm of the key pair used for signing. + +Flow supports the secp256k1 and P-256 curves. + +### Public Key Hash Algorithm + +- Flag: `--hash-algo` +- Valid inputs: `"SHA2_256", "SHA3_256"` +- Default: `"SHA3_256"` + +Specify the hash algorithm of the key pair used for signing. + +### Filter + +- Flag: `--filter` +- Short Flag: `-x` +- Valid inputs: case-sensitive name of the result property. + +Specify any property name from the result you want to return as the only value. + +### Output + +- Flag: `--output` +- Short Flag: `-o` +- Valid inputs: `json`, `inline` + +Specify in which format you want to display the result. + +### Save + +- Flag: `--save` +- Short Flag: `-s` +- Valid inputs: valid filename + +Specify the filename where you want the result to be saved. + +### Log + +- Flag: `--log` +- Short Flag: `-l` +- Valid inputs: `none`, `error`, `debug` +- Default: `info` + +Specify the log level. Control how much output you want to see while command execution. + +### Version Check + +- Flag: `--skip-version-check` +- Default: `false` + +Skip version check during start up to speed up process for slow connections. + + + + +=== tools/flow-cli/utils/signature-generate.md === +--- +title: Generate a Signature +description: How to generate a new signature from the command line +--- + +Generate a signature using the private key of the signer account. + +```shell +flow signatures generate +``` + +⚠️ _Make sure the account you want to use for signing is saved in the `flow.json` configuration. +The address of the account is not important, just the private key._ + +## Example Usage + +```shell +> flow signatures generate 'The quick brown fox jumps over the lazy dog' --signer alice + +Signature b33eabfb05d374b...f09929da96f5beec167fd1f123ec +Message The quick brown fox jumps over the lazy dog +Public Key 0xc92a7c...042c4025d241fd430242368ce662d39636987 +Hash Algorithm SHA3_256 +Signature Algorithm ECDSA_P256 +``` + +## Arguments + +### Message +- Name: `message` + +Message used for signing. + +## Flags + +### Signer + +- Flag: `--signer` +- Valid inputs: the name of an account defined in the configuration (`flow.json`) + +Specify the name of the account that will be used to sign the transaction. + +### Filter + +- Flag: `--filter` +- Short Flag: `-x` +- Valid inputs: case-sensitive name of the result property. + +Specify any property name from the result you want to return as the only value. + +### Output + +- Flag: `--output` +- Short Flag: `-o` +- Valid inputs: `json`, `inline` + +Specify in which format you want to display the result. + +### Save + +- Flag: `--save` +- Short Flag: `-s` +- Valid inputs: valid filename + +Specify the filename where you want the result to be saved. + +### Log + +- Flag: `--log` +- Short Flag: `-l` +- Valid inputs: `none`, `error`, `debug` +- Default: `info` + +Specify the log level. Control how much output you want to see while command execution. + +### Configuration + +- Flag: `--config-path` +- Short Flag: `-f` +- Valid inputs: valid filename + +Specify a filename for the configuration files, you can provide multiple configuration +files by using `-f` flag multiple times. + +### Version Check + +- Flag: `--skip-version-check` +- Default: `false` + +Skip version check during start up to speed up process for slow connections. + + + + + +=== tools/flow-cli/transactions/sign-transaction.md === +--- +title: Sign a Transaction +description: How to sign a Flow transaction from the command line +sidebar_position: 5 +--- + +The Flow CLI provides a command to sign transactions with options to specify +authorizer accounts, payer accounts and proposer accounts. + +Use this functionality in the following order: +1. Use the `build` command to build the transaction. +2. Use this command (`sign`) to sign with each account specified in the build process. +3. Use the `send-signed` command to submit the signed transaction to the Flow network. + +```shell +flow transactions sign +``` + +## Example Usage + +```shell +> flow transactions sign ./built.rlp --signer alice \ + --filter payload --save signed.rlp + +Hash b03b18a8d9d30ff7c9f0fdaa80fcaab242c2f36eedb687dd9b368326311fe376 +Payer f8d6e0586b0a20c7 +Authorizers [f8d6e0586b0a20c7] + +Proposal Key: + Address f8d6e0586b0a20c7 + Index 0 + Sequence 6 + +No Envelope Signatures + +Payload Signature 0: + Address f8d6e0586b0a20c7 + Signature b5b1dfed2a899037...164e1b224a7ac924018e7033b68b0df86769dd54 + Key Index 0 + + +Arguments (1): + - Argument 0: {"type":"String","value":"Meow"} + + +Code + +transaction(greeting: String) { + let guest: Address + + prepare(authorizer: &Account) { + self.guest = authorizer.address + } + + execute { + log(greeting.concat(",").concat(self.guest.toString())) + } +} + + +Payload: +f90184f...a199bfd9b837a11a0885f9104b54014750f5e3e5bfe4a5795968b0df86769dd54c0 +``` + +## Arguments + +### Built Transaction Filename or Remote Server URL +- Name: `built transaction filename | --from-remote-url ` +- Valid inputs: Any filename and path valid on the system or --from-remote-url flag and fully qualified remote server url. + +Specify the filename containing valid transaction payload that will be used for signing. +To be used with the `flow transaction build` command. + +When --from-remote-url flag is used the value needs to be a fully qualified url to transaction RLP +Example: `flow transaction sign --from-remote-url https://fully/qualified/url --signer alice` +## Flags + +### From Remote Url +- Flag: `--from-remote-url` +- Valid input: `http(s)://fully/qualified/server/url` + +Specify this flag with a fully qualified url to transaction RLP. The RLP will be fetched from server then signed. The resulting signed RLP is then posted to the remote url. This feature is to support protocol level multiple signature transaction coordination between multiple signers. +Note: --yes flag is not supported and will fail `sign` command when this flag is used. This forces the user to verify the cadence code. + +### Include Fields + +- Flag: `--include` +- Valid inputs: `code`, `payload`, `signatures` + +Specify fields to include in the result output. Applies only to the text output. + +### Signer + +- Flag: `--signer` +- Valid inputs: the name of an account defined in the configuration (`flow.json`) + +Specify the name of the account that will be used to sign the transaction. + +### Host +- Flag: `--host` +- Valid inputs: an IP address or hostname. +- Default: `127.0.0.1:3569` (Flow Emulator) + +Specify the hostname of the Access API that will be +used to execute the commands. + +### Network Key + +- Flag: `--network-key` +- Valid inputs: A valid network public key of the host in hex string format + +Specify the network public key of the Access API that will be +used to create a secure GRPC client when executing the command. + +### Network + +- Flag: `--network` +- Short Flag: `-n` +- Valid inputs: the name of a network defined in the configuration (`flow.json`) +- Default: `emulator` + +Specify which network you want the command to use for execution. + +### Filter + +- Flag: `--filter` +- Short Flag: `-x` +- Valid inputs: case-sensitive name of the result property. + +Specify any property name from the result you want to return as the only value. + +### Output + +- Flag: `--output` +- Short Flag: `-o` +- Valid inputs: `json`, `inline` + +Specify in which format you want to display the result. + +### Save + +- Flag: `--save` +- Short Flag: `-s` +- Valid inputs: valid filename + +Specify the filename where you want the result to be saved. + +### Log + +- Flag: `--log` +- Short Flag: `-l` +- Valid inputs: `none`, `error`, `debug` +- Default: `info` + +Specify the log level. Control how much output you want to see while command execution. + +### Configuration + +- Flag: `--conf` +- Short Flag: `-f` +- Valid inputs: valid filename + +Specify a filename for the configuration files, you can provide multiple configuration +files by using `-f` flag multiple times. + +### Version Check + +- Flag: `--skip-version-check` +- Default: `false` + +Skip version check during start up to speed up process for slow connections. + +=== tools/flow-cli/transactions/send-transactions.md === +--- +title: Send a Transaction +description: How to send a Flow transaction from the command line +sidebar_position: 1 +--- + +The Flow CLI provides a command to sign and send transactions to +any Flow Access API. + +```shell +flow transactions send [ ...] [flags] +``` + +## Example Usage + +```shell +> flow transactions send ./tx.cdc "Hello" + +Status ✅ SEALED +ID b04b6bcc3164f5ee6b77fa502c3a682e0db57fc47e5b8a8ef3b56aae50ad49c8 +Payer f8d6e0586b0a20c7 +Authorizers [f8d6e0586b0a20c7] + +Proposal Key: + Address f8d6e0586b0a20c7 + Index 0 + Sequence 0 + +No Payload Signatures + +Envelope Signature 0: f8d6e0586b0a20c7 +Signatures (minimized, use --include signatures) + +Events: None + +Code (hidden, use --include code) + +Payload (hidden, use --include payload) + +``` + +Multiple arguments example: +```shell +> flow transactions send tx1.cdc Foo 1 2 10.9 0x1 '[123,222]' '["a","b"]' +``` +Transaction code: +``` +transaction(a: String, b: Int, c: UInt16, d: UFix64, e: Address, f: [Int], g: [String]) { + prepare(authorizer: &Account) {} +} +``` + +In the above example, the `flow.json` file would look something like this: + +```json +{ + "accounts": { + "my-testnet-account": { + "address": "a2c4941b5f3c7151", + "key": "12c5dfde...bb2e542f1af710bd1d40b2" + } + } +} +``` + +JSON arguments from a file example: +```shell +> flow transactions send tx1.cdc --args-json "$(cat args.json)" +``` + +## Arguments + +### Code Filename +- Name: `code filename` +- Valid inputs: Any filename and path valid on the system. + +The first argument is a path to a Cadence file containing the +transaction to be executed. + +### Arguments +- Name: `argument` +- Valid inputs: valid [cadence values](https://cadencelang.dev/docs/1.0/json-cadence-spec) + matching argument type in transaction code. + +Input arguments values matching corresponding types in the source code and passed in the same order. +You can pass a `nil` value to optional arguments by sending the transaction like this: `flow transactions send tx.cdc nil`. + +## Flags + +### Include Fields + +- Flag: `--include` +- Valid inputs: `code`, `payload` + +Specify fields to include in the result output. Applies only to the text output. + +### Code + +- Flag: `--code` + +⚠️ No longer supported: use filename argument. + +### Results + +- Flag: `--results` + +⚠️ No longer supported: all transactions will provide result. + +### Exclude Fields + +- Flag: `--exclude` +- Valid inputs: `events` + +Specify fields to exclude from the result output. Applies only to the text output. + +### Signer + +- Flag: `--signer` +- Valid inputs: the name of an account defined in the configuration (`flow.json`) + +Specify the name of the account that will be used to sign the transaction. + +### Proposer + +- Flag: `--proposer` +- Valid inputs: the name of an account defined in the configuration (`flow.json`) + +Specify the name of the account that will be used as proposer in the transaction. + +### Payer + +- Flag: `--payer` +- Valid inputs: the name of an account defined in the configuration (`flow.json`) + +Specify the name of the account that will be used as payer in the transaction. + +### Authorizer + +- Flag: `--authorizer` +- Valid inputs: the name of a single or multiple comma-separated accounts defined in the configuration (`flow.json`) + +Specify the name of the account(s) that will be used as authorizer(s) in the transaction. If you want to provide multiple authorizers separate them using commas (e.g. `alice,bob`) + +### Arguments JSON + +- Flag: `--args-json` +- Valid inputs: arguments in JSON-Cadence form. +- Example: `flow transactions send ./tx.cdc '[{"type": "String", "value": "Hello World"}]'` + +Arguments passed to the Cadence transaction in Cadence JSON format. +Cadence JSON format contains `type` and `value` keys and is +[documented here](https://cadencelang.dev/docs/1.0/json-cadence-spec). + +### Gas Limit + +- Flag: `--gas-limit` +- Valid inputs: an integer greater than zero. +- Default: `1000` + +Specify the gas limit for this transaction. + +### Host + +- Flag: `--host` +- Valid inputs: an IP address or hostname. +- Default: `127.0.0.1:3569` (Flow Emulator) + +Specify the hostname of the Access API that will be +used to execute the command. This flag overrides +any host defined by the `--network` flag. + +### Network Key + +- Flag: `--network-key` +- Valid inputs: A valid network public key of the host in hex string format + +Specify the network public key of the Access API that will be +used to create a secure GRPC client when executing the command. + +### Network + +- Flag: `--network` +- Short Flag: `-n` +- Valid inputs: the name of a network defined in the configuration (`flow.json`) +- Default: `emulator` + +Specify which network you want the command to use for execution. + +### Filter + +- Flag: `--filter` +- Short Flag: `-x` +- Valid inputs: a case-sensitive name of the result property. + +Specify any property name from the result you want to return as the only value. + +### Output + +- Flag: `--output` +- Short Flag: `-o` +- Valid inputs: `json`, `inline` + +Specify the format of the command results. + +### Save + +- Flag: `--save` +- Short Flag: `-s` +- Valid inputs: a path in the current filesystem. + +Specify the filename where you want the result to be saved + +### Log + +- Flag: `--log` +- Short Flag: `-l` +- Valid inputs: `none`, `error`, `debug` +- Default: `info` + +Specify the log level. Control how much output you want to see during command execution. + +### Configuration + +- Flag: `--config-path` +- Short Flag: `-f` +- Valid inputs: a path in the current filesystem. +- Default: `flow.json` + +Specify the path to the `flow.json` configuration file. +You can use the `-f` flag multiple times to merge +several configuration files. + +### Version Check + +- Flag: `--skip-version-check` +- Default: `false` + +Skip version check during start up to speed up process for slow connections. + + +=== tools/flow-cli/transactions/send-signed-transactions.md === +--- +title: Send Signed Transaction +description: How to send a signed Flow transaction from the command line +sidebar_position: 6 +--- + +The Flow CLI provides a command to send signed transactions to +any Flow Access API. + +Use this functionality in the following order: +1. Use the `build` command to build the transaction. +2. Use the `sign` command to sign with each account specified in the build process. +3. Use this command (`send-signed`) to submit the signed transaction to the Flow network. + +```shell +flow transactions send-signed +``` + +## Example Usage + +```shell +> flow transactions send-signed ./signed.rlp + +Status ✅ SEALED +ID 528332aceb288cdfe4d11d6522aa27bed94fb3266b812cb350eb3526ed489d99 +Payer f8d6e0586b0a20c7 +Authorizers [f8d6e0586b0a20c7] + +Proposal Key: + Address f8d6e0586b0a20c7 + Index 0 + Sequence 0 + +No Payload Signatures + +Envelope Signature 0: f8d6e0586b0a20c7 +Signatures (minimized, use --include signatures) + +Events: None + +Code (hidden, use --include code) + +Payload (hidden, use --include payload) + +``` + + +## Arguments + +### Signed Code Filename +- Name: `signed transaction filename` +- Valid inputs: Any filename and path valid on the system. + +The first argument is a path to a Cadence file containing the +transaction to be executed. + +## Flags + +### Include Fields + +- Flag: `--include` +- Valid inputs: `code`, `payload` + +Specify fields to include in the result output. Applies only to the text output. + +### Exclude Fields + +- Flag: `--exclude` +- Valid inputs: `events` + +Specify fields to exclude from the result output. Applies only to the text output. + +### Filter + +- Flag: `--filter` +- Short Flag: `-x` +- Valid inputs: a case-sensitive name of the result property. + +Specify any property name from the result you want to return as the only value. + +### Host + +- Flag: `--host` +- Valid inputs: an IP address or hostname. +- Default: `127.0.0.1:3569` (Flow Emulator) + +Specify the hostname of the Access API that will be +used to execute the command. This flag overrides +any host defined by the `--network` flag. + +### Network Key + +- Flag: `--network-key` +- Valid inputs: A valid network public key of the host in hex string format + +Specify the network public key of the Access API that will be +used to create a secure GRPC client when executing the command. + +### Network + +- Flag: `--network` +- Short Flag: `-n` +- Valid inputs: the name of a network defined in the configuration (`flow.json`) +- Default: `emulator` + +Specify which network you want the command to use for execution. + +### Output + +- Flag: `--output` +- Short Flag: `-o` +- Valid inputs: `json`, `inline` + +Specify the format of the command results. + +### Save + +- Flag: `--save` +- Short Flag: `-s` +- Valid inputs: a path in the current filesystem. + +Specify the filename where you want the result to be saved + +### Log + +- Flag: `--log` +- Short Flag: `-l` +- Valid inputs: `none`, `error`, `debug` +- Default: `info` + +Specify the log level. Control how much output you want to see during command execution. + +### Configuration + +- Flag: `--config-path` +- Short Flag: `-f` +- Valid inputs: a path in the current filesystem. +- Default: `flow.json` + +Specify the path to the `flow.json` configuration file. +You can use the `-f` flag multiple times to merge +several configuration files. + +### Version Check + +- Flag: `--skip-version-check` +- Default: `false` + +Skip version check during start up to speed up process for slow connections. + +=== tools/flow-cli/transactions/get-transactions.md === +--- +title: Get a Transaction +description: How to get a Flow transaction from the command line +sidebar_position: 2 +--- + +The Flow CLI provides a command to fetch a transaction +that was previously submitted to an Access API. + +```shell +flow transactions get +``` + +## Example Usage + +```shell +> flow transactions get 40bc4b100c1930c61381c22e0f4c10a7f5827975ee25715527c1061b8d71e5aa --network mainnet + +Status ✅ SEALED +ID 40bc4b100c1930c61381c22e0f4c10a7f5827975ee25715527c1061b8d71e5aa +Payer 18eb4ee6b3c026d2 +Authorizers [18eb4ee6b3c026d2] + +Proposal Key: + Address 18eb4ee6b3c026d2 + Index 11 + Sequence 17930 + +Payload Signature 0: 18eb4ee6b3c026d2 +Payload Signature 1: 18eb4ee6b3c026d2 +Envelope Signature 0: 18eb4ee6b3c026d2 +Signatures (minimized, use --include signatures) + +Events: + Index 0 + Type A.1654653399040a61.FlowToken.TokensWithdrawn + Tx ID 40bc4b100c1930c61381c22e0f4c10a7f5827975ee25715527c1061b8d71e5aa + Values + - amount (UFix64): 0.00100000 + - from ({}?): 18eb4ee6b3c026d2 + + Index 1 + Type A.1654653399040a61.FlowToken.TokensDeposited + Tx ID 40bc4b100c1930c61381c22e0f4c10a7f5827975ee25715527c1061b8d71e5aa + Values + - amount (UFix64): 0.00100000 + - to ({}?): 5068e27f275c546c + + Index 2 + Type A.18eb4ee6b3c026d2.PrivateReceiverForwarder.PrivateDeposit + Tx ID 40bc4b100c1930c61381c22e0f4c10a7f5827975ee25715527c1061b8d71e5aa + Values + - amount (UFix64): 0.00100000 + - to ({}?): 5068e27f275c546c + + + +Code (hidden, use --include code) + +Payload (hidden, use --include payload) +``` + +## Arguments + +### Transaction ID + +- Name: `` +- Valid Input: transaction ID. + +The first argument is the ID (hash) of the transaction. + +## Flags + +### Include Fields + +- Flag: `--include` +- Valid inputs: `code`, `payload`, `signatures` + +Specify fields to include in the result output. Applies only to the text output. + +### Wait for Seal + +- Flag: `--sealed` +- Default: `false` + +Indicate whether to wait for the transaction to be sealed +before displaying the result. + +### Exclude Fields + +- Flag: `--exclude` +- Valid inputs: `events` + +Specify fields to exclude from the result output. Applies only to the text output. + +### Host + +- Flag: `--host` +- Valid inputs: an IP address or hostname. +- Default: `127.0.0.1:3569` (Flow Emulator) + +Specify the hostname of the Access API that will be +used to execute the command. This flag overrides +any host defined by the `--network` flag. + +### Network Key + +- Flag: `--network-key` +- Valid inputs: A valid network public key of the host in hex string format + +Specify the network public key of the Access API that will be +used to create a secure GRPC client when executing the command. + +### Network + +- Flag: `--network` +- Short Flag: `-n` +- Valid inputs: the name of a network defined in the configuration (`flow.json`) +- Default: `emulator` + +Specify which network you want the command to use for execution. + +### Filter + +- Flag: `--filter` +- Short Flag: `-x` +- Valid inputs: a case-sensitive name of the result property. + +Specify any property name from the result you want to return as the only value. + +### Output + +- Flag: `--output` +- Short Flag: `-o` +- Valid inputs: `json`, `inline` + +Specify the format of the command results. + +### Save + +- Flag: `--save` +- Short Flag: `-s` +- Valid inputs: a path in the current filesystem. + +Specify the filename where you want the result to be saved + +### Log + +- Flag: `--log` +- Short Flag: `-l` +- Valid inputs: `none`, `error`, `debug` +- Default: `info` + +Specify the log level. Control how much output you want to see during command execution. + +### Configuration + +- Flag: `--config-path` +- Short Flag: `-f` +- Valid inputs: a path in the current filesystem. +- Default: `flow.json` + +Specify the path to the `flow.json` configuration file. +You can use the `-f` flag multiple times to merge +several configuration files. + +### Version Check + +- Flag: `--skip-version-check` +- Default: `false` + +Skip version check during start up to speed up process for slow connections. + +=== tools/flow-cli/transactions/decode-transactions.md === +--- +title: Build a Complex Transaction +description: How to decode a Flow transaction from the command line +sidebar_position: 7 +--- + +The Flow CLI provides a command to decode a transaction +from RLP in a file. It uses same transaction format as get command + +```shell +flow transactions decode +``` + +## Example Usage + +```shell +> flow transactions decode ./rlp-file.rlp + +ID c1a52308fb906358d4a33c1f1d5fc458d3cfea0d570a51a9dea915b90d678346 +Payer 83de1a7075f190a1 +Authorizers [83de1a7075f190a1] + +Proposal Key: + Address 83de1a7075f190a1 + Index 1 + Sequence 1 + +No Payload Signatures + +Envelope Signature 0: 83de1a7075f190a1 +Signatures (minimized, use --include signatures) + +Code (hidden, use --include code) + +Payload (hidden, use --include payload) +``` + +## Arguments + +### Filename + +- Name: `` +- Valid Input: file name. + +The first argument is the filename containing the transaction RLP. + +## Flags + +### Include Fields + +- Flag: `--include` +- Valid inputs: `code`, `payload`, `signatures` + +Specify fields to include in the result output. Applies only to the text output. + +### Output + +- Flag: `--output` +- Short Flag: `-o` +- Valid inputs: `json`, `inline` + +Specify the format of the command results. + +### Save + +- Flag: `--save` +- Short Flag: `-s` +- Valid inputs: a path in the current filesystem. + +Specify the filename where you want the result to be saved + +### Version Check + +- Flag: `--skip-version-check` +- Default: `false` + +Skip version check during start up to speed up process for slow connections. + +=== tools/flow-cli/transactions/complex-transactions.md === +--- +title: Build a Complex Transaction +description: How to build and send a complex Flow transaction from the command line +sidebar_position: 4 +--- + +**Simple Transactions** + +Sending a transaction using the Flow CLI can simply be +achieved by using the [send command documented here](./send-transactions.md). + +**Complex Transactions** + +If you would like to build more complex transactions the Flow CLI provides +commands to build, sign and send transactions allowing you to specify different +authorizers, signers and proposers. + +The process of sending a complex transactions includes three steps: +1. [build a transaction](./build-transactions.md) +2. [sign the built transaction](./sign-transaction.md) +3. [send signed transaction](./send-signed-transactions.md) + +Read more about each command flags and arguments in the above links. + +## Examples +We will describe common examples for complex transactions. All examples are using an [example configuration](./complex-transactions.md#configuration). + +### Single payer, proposer and authorizer +The simplest Flow transaction declares a single account as the proposer, payer and authorizer. + +Build the transaction: +```shell +> flow transactions build tx.cdc + --proposer alice + --payer alice + --authorizer alice + --filter payload --save tx1 +``` +Sign the transaction: +```shell +> flow transactions sign tx1 --signer alice + --filter payload --save tx2 +``` +Submit the signed transaction: +```shell +> flow transactions send-signed tx2 +``` +Transaction content (`tx.cdc`): +``` +transaction { + prepare(signer: &Account) {} + execute { ... } +} +``` + +### Single payer and proposer, multiple authorizers +A transaction that declares same payer and proposer but multiple authorizers each required to sign the transaction. Please note that the order of signing is important, and [the payer must sign last](../../../build/basics/transactions.md#payer-signs-last). + +Build the transaction: +```shell +> flow transactions build tx.cdc + --proposer alice + --payer alice + --authorizer bob + --authorizer charlie + --filter payload --save tx1 +``` +Sign the transaction with authorizers: +```shell +> flow transactions sign tx1 --signer bob + --filter payload --save tx2 +``` +```shell +> flow transactions sign tx2 --signer charlie + --filter payload --save tx3 +``` +Sign the transaction with payer: +```shell +> flow transactions sign tx3 --signer alice + --filter payload --save tx4 +``` +Submit the signed transaction: +```shell +> flow transactions send-signed tx4 +``` +Transaction content (`tx.cdc`): +``` +transaction { + prepare(bob: &Account, charlie: &Account) {} + execute { ... } +} +``` + +### Different payer, proposer and authorizer +A transaction that declares different payer, proposer and authorizer each signing separately. +Please note that the order of signing is important, and [the payer must sign last](../../../build/basics/transactions.md#payer-signs-last). + +Build the transaction: +```shell +> flow transactions build tx.cdc + --proposer alice + --payer bob + --authorizer charlie + --filter payload --save tx1 +``` +Sign the transaction with proposer: +```shell +> flow transactions sign tx1 --signer alice + --filter payload --save tx2 +``` +Sign the transaction with authorizer: +```shell +> flow transactions sign tx2 --signer charlie + --filter payload --save tx3 +``` +Sign the transaction with payer: +```shell +> flow transactions sign tx3 --signer bob + --filter payload --save tx4 +``` +Submit the signed transaction: +```shell +> flow transactions send-signed tx4 +``` +Transaction content (`tx.cdc`): +``` +transaction { + prepare(charlie: &Account) {} + execute { ... } +} +``` + +### Single payer, proposer and authorizer but multiple keys +A transaction that declares same payer, proposer and authorizer but the signer account has two keys with half weight, required to sign with both. + + +Build the transaction: +```shell +> flow transactions build tx.cdc + --proposer dylan1 + --payer dylan1 + --authorizer dylan1 + --filter payload --save tx1 +``` +Sign the transaction with the first key: +```shell +> flow transactions sign tx1 --signer dylan1 + --filter payload --save tx2 +``` +Sign the transaction with the second key: +```shell +> flow transactions sign tx2 --signer dylan2 + --filter payload --save tx3 +``` +Submit the signed transaction: +```shell +> flow transactions send-signed tx3 +``` +Transaction content (`tx.cdc`): +``` +transaction { + prepare(signer: &Account) {} + execute { ... } +} +``` + +### Configuration +This is an example configuration using mock values: +```json +{ + ... + "accounts": { + "alice": { + "address": "0x1", + "key": "111...111" + }, + "bob": { + "address": "0x2", + "key": "222...222" + }, + "charlie": { + "address": "0x3", + "key": "333...333" + }, + "dylan1": { + "address": "0x4", + "key": "444...444" + }, + "dylan2": { + "address": "0x4", + "key": "555...555" + } + } + ... +} +``` + + +=== tools/flow-cli/transactions/build-transactions.md === +--- +title: Build a Transaction +description: How to build a Flow transaction from the command line +sidebar_position: 3 +--- + +The Flow CLI provides a command to build a transactions with options to specify +authorizer accounts, payer account and proposer account. + +The `build` command doesn't produce any signatures and instead +is designed to be used with the `sign` and `send-signed` commands. + +Use this functionality in the following order: +1. Use this command (`build`) to build the transaction. +2. Use the `sign` command to sign with each account specified in the build process. +3. Use the `send-signed` command to submit the signed transaction to the Flow network. + +```shell +flow transactions build [ ...] [flags] +``` + +## Example Usage + +```shell +> flow transactions build ./transaction.cdc "Meow" \ + --authorizer alice \ + --proposer bob \ + --payer charlie \ + --filter payload --save built.rlp + +ID e8c0a69952fbe50a66703985e220307c8d44b8fa36c76cbca03f8c43d0167847 +Payer e03daebed8ca0615 +Authorizers [f3fcd2c1a78f5eee] + +Proposal Key: + Address 179b6b1cb6755e31 + Index 0 + Sequence 1 + +No Payload Signatures + +No Envelope Signatures + + +Arguments (1): + - Argument 0: {"type":"String","value":"Meow"} + + +Code + +transaction(greeting: String) { + let guest: Address + + prepare(authorizer: &Account) { + self.guest = authorizer.address + } + + execute { + log(greeting.concat(",").concat(self.guest.toString())) + } +} + + +Payload: +f9013df90138b8d17472616e...73616374696f6e286eeec0c0 +``` + +JSON arguments from a file example: +```shell +> flow transactions build tx1.cdc --args-json "$(cat args.json)" +``` + +## Arguments + +### Code Filename + +- Name: `filename` +- Valid inputs: Any filename and path valid on the system. + +The first argument is a path to a Cadence file containing the +transaction to be executed. + +### Arguments +- Name: `argument` +- Valid inputs: valid [cadence values](https://cadencelang.dev/docs/1.0/json-cadence-spec) + matching argument type in transaction code. + +Input arguments values matching corresponding types in the source code and passed in the same order. +For passing complex argument values see [send transaction](./send-transactions.md#example-usage) document. + +## Flags + +### Payer + +- Flag: `--payer` +- Valid Inputs: Flow address or account name from configuration. +- Default: service account + +Specify account address that will be paying for the transaction. +Read more about payers [here](../../../build/basics/transactions.md). + +### Proposer + +- Flag: `--proposer` +- Valid inputs: Flow address or account name from configuration. +- Default: service account + +Specify a name of the account that is proposing the transaction. +Account must be defined in flow configuration. + +### Proposer Key Index + +- Flag: `--proposer-key-index` +- Valid inputs: number of existing key index +- Default: 0 + +Specify key index for the proposer account. + +### Authorizer + +- Flag: `--authorizer` +- Valid Inputs: Flow address or account name from configuration. +- Default: service account + +Additional authorizer addresses to add to the transaction. +Read more about authorizers [here](../../../build/basics/transactions.md). + +### Arguments JSON + +- Flag: `--args-json` +- Valid inputs: arguments in JSON-Cadence form. +- Example: `flow transactions build ./tx.cdc '[{"type": "String", "value": "Hello World"}]'` + +Arguments passed to the Cadence transaction in Cadence JSON format. +Cadence JSON format contains `type` and `value` keys and is +[documented here](https://cadencelang.dev/docs/1.0/json-cadence-spec). + +### Gas Limit + +- Flag: `--gas-limit` +- Valid inputs: an integer greater than zero. +- Default: `1000` + +Specify the gas limit for this transaction. + +### Host + +- Flag: `--host` +- Valid inputs: an IP address or hostname. +- Default: `127.0.0.1:3569` (Flow Emulator) + +Specify the hostname of the Access API that will be +used to execute the commands. + +### Network Key + +- Flag: `--network-key` +- Valid inputs: A valid network public key of the host in hex string format + +Specify the network public key of the Access API that will be +used to create a secure GRPC client when executing the command. + +### Network + +- Flag: `--network` +- Short Flag: `-n` +- Valid inputs: the name of a network defined in the configuration (`flow.json`) +- Default: `emulator` + +Specify which network you want the command to use for execution. + +### Include Fields + +- Flag: `--include` +- Valid inputs: `code`, `payload`, `signatures` + +Specify fields to include in the result output. Applies only to the text output. + +### Filter + +- Flag: `--filter` +- Short Flag: `-x` +- Valid inputs: case-sensitive name of the result property. + +Specify any property name from the result you want to return as the only value. + +### Output + +- Flag: `--output` +- Short Flag: `-o` +- Valid inputs: `json`, `inline` + +Specify in which format you want to display the result. + +### Save + +- Flag: `--save` +- Short Flag: `-s` +- Valid inputs: valid filename + +Specify the filename where you want the result to be saved. + +### Log + +- Flag: `--log` +- Short Flag: `-l` +- Valid inputs: `none`, `error`, `debug` +- Default: `info` + +Specify the log level. Control how much output you want to see while command execution. + +### Configuration + +- Flag: `--config-path` +- Short Flag: `-f` +- Valid inputs: valid filename + +Specify a filename for the configuration files, you can provide multiple configuration +files by using `-f` flag multiple times. + +### Version Check + +- Flag: `--skip-version-check` +- Default: `false` + +Skip version check during start up to speed up process for slow connections. + + + +=== tools/flow-cli/scripts/execute-scripts.md === +--- +title: Execute a Script +description: How to execute a Cadence script on Flow from the command line +sidebar_position: 6 +--- + +The Flow CLI provides a command to execute a Cadence script on +the Flow execution state with any Flow Access API. + +```shell +flow scripts execute [ ...] [flags] +``` + +## Example Usage + +```shell +# Execute a script on Flow Testnet +> flow scripts execute script.cdc "Hello" "World" + +"Hello World" +``` + +Script source code: +``` +access(all) fun main(greeting: String, who: String): String { + return greeting.concat(" ").concat(who) +} +``` + +## Arguments + +### Filename + +- Name: `filename` +- Valid inputs: a path in the current filesystem. + +The first argument is a path to a Cadence file containing the +script to be executed. + +### Arguments +- Name: `argument` +- Valid inputs: valid [cadence values](https://cadencelang.dev/docs/1.0/json-cadence-spec) + matching argument type in script code. + +Input arguments values matching corresponding types in the source code and passed in the same order. +You can pass a `nil` value to optional arguments by executing the flow script like this: `flow scripts execute script.cdc nil`. + + +## Flags + +### Arguments JSON + +- Flag: `--args-json` +- Valid inputs: arguments in JSON-Cadence form. +- Example: `flow scripts execute script.cdc '[{"type": "String", "value": "Hello World"}]'` + +Arguments passed to the Cadence script in the Cadence JSON format. +Cadence JSON format contains `type` and `value` keys and is +[documented here](https://cadencelang.dev/docs/1.0/json-cadence-spec). + +### Host + +- Flag: `--host` +- Valid inputs: an IP address or hostname. +- Default: `127.0.0.1:3569` (Flow Emulator) + +Specify the hostname of the Access API that will be +used to execute the command. This flag overrides +any host defined by the `--network` flag. + +### Network Key + +- Flag: `--network-key` +- Valid inputs: A valid network public key of the host in hex string format + +Specify the network public key of the Access API that will be +used to create a secure GRPC client when executing the command. + +### Network + +- Flag: `--network` +- Short Flag: `-n` +- Valid inputs: the name of a network defined in the configuration (`flow.json`) +- Default: `emulator` + +Specify which network you want the command to use for execution. + +### Filter + +- Flag: `--filter` +- Short Flag: `-x` +- Valid inputs: a case-sensitive name of the result property. + +Specify any property name from the result you want to return as the only value. + +### Output + +- Flag: `--output` +- Short Flag: `-o` +- Valid inputs: `json`, `inline` + +Specify the format of the command results. + +### Save + +- Flag: `--save` +- Short Flag: `-s` +- Valid inputs: a path in the current filesystem. + +Specify the filename where you want the result to be saved + +### Log + +- Flag: `--log` +- Short Flag: `-l` +- Valid inputs: `none`, `error`, `debug` +- Default: `info` + +Specify the log level. Control how much output you want to see during command execution. + +### Configuration + +- Flag: `--config-path` +- Short Flag: `-f` +- Valid inputs: a path in the current filesystem. +- Default: `flow.json` + +Specify the path to the `flow.json` configuration file. +You can use the `-f` flag multiple times to merge +several configuration files. + +### Version Check + +- Flag: `--skip-version-check` +- Default: `false` + +Skip version check during start up to speed up process for slow connections. + + +=== tools/flow-cli/keys/generate-keys.md === +--- +title: Generate Keys +description: How to generate key pair from the command line +sidebar_position: 1 +--- + +The Flow CLI provides a command to generate ECDSA key pairs +that can be [attached to new or existing Flow accounts](../../../build/basics/accounts.md). + +```shell +flow keys generate +``` + +⚠️ Store private key safely and don't share with anyone! + +## Example Usage + +```shell +flow keys generate +``` + +### Example response + +```shell +> flow keys generate + +🔴️ Store Private Key safely and don't share with anyone! +Private Key c778170793026a9a7a3815dabed68ded445bde7f40a8c66889908197412be89f +Public Key 584245c57e5316d6606c53b1ce46dae29f5c9bd26e9e8...aaa5091b2eebcb2ac71c75cf70842878878a2d650f7 +``` + +## Flags + +### Seed + +- Flag: `--seed` +- Valid inputs: any string with length >= 32 + +Specify a UTF-8 seed string that will be used to generate the key pair. +Key generation is deterministic, so the same seed will always +result in the same key. + +If no seed is specified, the key pair will be generated using +a random 32 byte seed. + +⚠️ Using seed with production keys can be dangerous if seed was not generated +by using safe random generators. + +### Signature Algorithm + +- Flag: `--sig-algo` +- Valid inputs: `"ECDSA_P256", "ECDSA_secp256k1"` + +Specify the ECDSA signature algorithm for the key pair. + +Flow supports the secp256k1 and P-256 curves. + +### Filter + +- Flag: `--filter` +- Short Flag: `-x` +- Valid inputs: a case-sensitive name of the result property. + +Specify any property name from the result you want to return as the only value. + +### Output + +- Flag: `--output` +- Short Flag: `-o` +- Valid inputs: `json`, `inline` + +Specify the format of the command results. + +### Save + +- Flag: `--save` +- Short Flag: `-s` +- Valid inputs: a path in the current filesystem. + +Specify the filename where you want the result to be saved + +### Log + +- Flag: `--log` +- Short Flag: `-l` +- Valid inputs: `none`, `error`, `debug` +- Default: `info` + +Specify the log level. Control how much output you want to see during command execution. + +### Configuration + +- Flag: `--config-path` +- Short Flag: `-f` +- Valid inputs: a path in the current filesystem. +- Default: `flow.json` + +Specify the path to the `flow.json` configuration file. +You can use the `-f` flag multiple times to merge +several configuration files. + +### Version Check + +- Flag: `--skip-version-check` +- Default: `false` + +Skip version check during start up to speed up process for slow connections. + + +=== tools/flow-cli/keys/derive-keys.md === +--- +title: Derive Public Key +description: How to derive Flow public key from a private key from the command line +sidebar_position: 3 +--- + +The Flow CLI provides a command to derive Public Key from a Private Key. + +```shell +flow keys derive +``` + +## Example Usage + +### Derive Public Key from a Private Key +```shell +> flow keys derive c778170793026a9a7a3815dabed68ded445bde7f40a8c66889908197412be89f +``` + +### Example response + +```shell +> flow keys generate + +🔴️ Store Private Key safely and don't share with anyone! +Private Key c778170793026a9a7a3815dabed68ded445bde7f40a8c66889908197412be89f +Public Key 584245c57e5316d6606c53b1ce46dae29f5c9bd26e9e8...aaa5091b2eebcb2ac71c75cf70842878878a2d650f7 +``` + +## Arguments + +### Private Key +- Name: `private key` +- Valid inputs: valid private key content + +## Flags + +### Signature Algorithm + +- Flag: `--sig-algo` +- Valid inputs: `"ECDSA_P256", "ECDSA_secp256k1"` + +Specify the ECDSA signature algorithm for the key pair. + +Flow supports the secp256k1 and P-256 curves. + + +### Filter + +- Flag: `--filter` +- Short Flag: `-x` +- Valid inputs: a case-sensitive name of the result property. + +Specify any property name from the result you want to return as the only value. + +### Output + +- Flag: `--output` +- Short Flag: `-o` +- Valid inputs: `json`, `inline` + +Specify the format of the command results. + +### Save + +- Flag: `--save` +- Short Flag: `-s` +- Valid inputs: a path in the current filesystem. + +Specify the filename where you want the result to be saved + + +=== tools/flow-cli/keys/decode-keys.md === +--- +title: Decode Public Keys +description: How to decode Flow public keys from the command line +sidebar_position: 2 +--- + +The Flow CLI provides a command to decode encoded public account keys. + +```shell +flow keys decode +``` + +## Example Usage + +### Decode RLP Encoded Public Key +```shell +> flow keys decode rlp f847b84084d716c14b051ad6b001624f738f5d302636e6b07cc75e4530af7776a4368a2b586dbefc0564ee28384c2696f178cbed52e62811bcc9ecb59568c996d342db2402038203e8 + +Public Key 84d716c1...bcc9ecb59568c996d342db24 +Signature algorithm ECDSA_P256 +Hash algorithm SHA3_256 +Weight 1000 +Revoked false +``` + +### Decode PEM Encoded Public Key From File +```shell +> flow keys decode pem --from-file key.pem + +Public Key d479b3c...c4615360039a6660a366a95f +Signature algorithm ECDSA_P256 +Hash algorithm UNKNOWN +Revoked false + +``` + +## Arguments + +### Encoding +- Valid inputs: `rlp`, `pem` + +First argument specifies a valid encoding of the public key provided. + +### Optional: Public Key +- Name: `encoded public key` +- Valid inputs: valid encoded key content + +Optional second argument provides content of the encoded public key. +If this argument is omitted the `--from-file` must be used instead. + +## Flags + +### From File + +- Flag: `--from-file` +- Valid inputs: valid filepath + +Provide file with the encoded public key. + +### Filter + +- Flag: `--filter` +- Short Flag: `-x` +- Valid inputs: a case-sensitive name of the result property. + +Specify any property name from the result you want to return as the only value. + +### Output + +- Flag: `--output` +- Short Flag: `-o` +- Valid inputs: `json`, `inline` + +Specify the format of the command results. + +### Save + +- Flag: `--save` +- Short Flag: `-s` +- Valid inputs: a path in the current filesystem. + +Specify the filename where you want the result to be saved + +### Version Check + +- Flag: `--skip-version-check` +- Default: `false` + +Skip version check during start up to speed up process for slow connections. + +=== tools/flow-cli/get-flow-data/get-status.md === +--- +title: Network Status +description: How to get access node status from the command line +sidebar_position: 4 +--- + +The Flow CLI provides a command to get network status of specified Flow Access Node + +`flow status` + +## Example Usage + +```shell +> flow status --network testnet + +Status: 🟢 ONLINE +Network: testnet +Access Node: access.devnet.nodes.onflow.org:9000 +``` + +## Flags + +### Network + +- Flag: `--network` +- Short Flag: `-n` +- Valid inputs: the name of a network defined in the configuration (`flow.json`). + +Specify which network you want the command to use for execution. + +### Host + +- Flag: `--host` +- Valid inputs: an IP address or hostname. +- Default: `127.0.0.1:3569` (Flow Emulator) + +Specify the hostname of the Access API that will be +used to execute the command. This flag overrides +any host defined by the `--network` flag. + +### Network Key + +- Flag: `--network-key` +- Valid inputs: A valid network public key of the host in hex string format + +Specify the network public key of the Access API that will be +used to create a secure GRPC client when executing the command. + +### Filter + +- Flag: `--filter` +- Short Flag: `-x` +- Valid inputs: a case-sensitive name of the result property. + +Specify any property name from the result you want to return as the only value. + +### Output + +- Flag: `--output` +- Short Flag: `-o` +- Valid inputs: `json`, `inline` + +Specify the format of the command results. + +### Save + +- Flag: `--save` +- Short Flag: `-s` +- Valid inputs: a path in the current filesystem. + +Specify the filename where you want the result to be saved + +### Log + +- Flag: `--log` +- Short Flag: `-l` +- Valid inputs: `none`, `error`, `debug` +- Default: `info` + +Specify the log level. Control how much output you want to see during command execution. + +### Configuration + +- Flag: `--conf` +- Short Flag: `-f` +- Valid inputs: a path in the current filesystem. +- Default: `flow.json` + +Specify the path to the `flow.json` configuration file. +You can use the `-f` flag multiple times to merge +several configuration files. + +### Version Check + +- Flag: `--skip-version-check` +- Default: `false` + +Skip version check during start up to speed up process for slow connections. + +=== tools/flow-cli/get-flow-data/get-events.md === +--- +title: Get Events +description: How to get an event from the command line +sidebar_position: 2 +--- + +Use the event command to fetch a single or multiple events in a specific range of blocks. +You can provide start and end block height range, but also specify number of the latest blocks to +be used to search for specified event. Events are fetched concurrently by using multiple workers which +optionally you can also control by specifying the flags. + +```shell +flow events get +``` + +## Example Usage + +Get the event by name `A.0b2a3299cc857e29.TopShot.Deposit` from the last 20 blocks on mainnet. +```shell +> flow events get A.0b2a3299cc857e29.TopShot.Deposit --last 20 --network mainnet + + Events Block #12913388: + Index 2 + Type A.0b2a3299cc857e29.TopShot.Deposit + Tx ID 0a1e6cdc4eeda0e23402193d7ad5ba01a175df4c08f48fa7ac8d53e811c5357c + Values + id (UInt64) 3102159 + to ({}?) 24214cf0faa7844d + + Index 2 + Type A.0b2a3299cc857e29.TopShot.Deposit + Tx ID 1fa5e64dcdc8ed5dad87ba58207ee4c058feb38fa271fff659ab992dc2ec2645 + Values + id (UInt64) 5178448 + to ({}?) 26c96b6c2c31e419 + + Index 9 + Type A.0b2a3299cc857e29.TopShot.Deposit + Tx ID 262ab3996bdf98f5f15804c12b4e5d4e89c0fa9b71d57be4d7c6e8288c507c4a + Values + id (UInt64) 1530408 + to ({}?) 2da5c6d1a541971b + +... +``` + +Get two events `A.1654653399040a61.FlowToken.TokensDeposited` +and `A.1654653399040a61.FlowToken.TokensWithdrawn` in the block height range on mainnet. +```shell +> flow events get \ + A.1654653399040a61.FlowToken.TokensDeposited \ + A.1654653399040a61.FlowToken.TokensWithdrawn \ + --start 11559500 --end 11559600 --network mainnet + + Events Block #17015045: + Index 0 + Type A.1654653399040a61.FlowToken.TokensWithdrawn + Tx ID 6dcf60d54036acb52b2e01e69890ce34c3146849998d64364200e4b21e9ac7f1 + Values + - amount (UFix64): 0.00100000 + - from (Address?): 0x9e06eebf494e2d78 + + Index 1 + Type A.1654653399040a61.FlowToken.TokensWithdrawn + Tx ID 6dcf60d54036acb52b2e01e69890ce34c3146849998d64364200e4b21e9ac7f1 + Values + - amount (UFix64): 0.00100000 + - from (Never?): nil + + Events Block #17015047: + Index 0 + Type A.1654653399040a61.FlowToken.TokensWithdrawn + Tx ID 24979a3c0203f514f7f5822cc8ae7046e24f25d4a775bef697a654898fb7673e + Values + - amount (UFix64): 0.00100000 + - from (Address?): 0x18eb4ee6b3c026d2 + + Index 1 + Type A.1654653399040a61.FlowToken.TokensWithdrawn + Tx ID 24979a3c0203f514f7f5822cc8ae7046e24f25d4a775bef697a654898fb7673e + Values + - amount (UFix64): 0.00100000 + - from (Never?): nil +``` + +## Arguments + +### Event Name + +- Name: `event_name` +- Valid Input: String + +Fully-qualified identifier for the events. +You can provide multiple event names separated by a space. + +## Flags + +### Start + +- Flag: `--start` +- Valid inputs: valid block height + +Specify the start block height used alongside the end flag. +This will define the lower boundary of the block range. + +### End + +- Flag: `--end` +- Valid inputs: valid block height + +Specify the end block height used alongside the start flag. +This will define the upper boundary of the block range. + +### Last + +- Flag: `--last` +- Valid inputs: number +- Default: `10` + +Specify the number of blocks relative to the last block. Ignored if the +start flag is set. Used as a default if no flags are provided. + +### Batch + +- Flag: `--batch` +- Valid inputs: number +- Default: `25` + +Number of blocks each worker will fetch. + +### Workers + +- Flag: `--workers` +- Valid inputs: number +- Default: `10` + +Number of workers to use when fetching events concurrently. + + +### Host + +- Flag: `--host` +- Valid inputs: an IP address or hostname. +- Default: `127.0.0.1:3569` (Flow Emulator) + +Specify the hostname of the Access API that will be +used to execute the command. This flag overrides +any host defined by the `--network` flag. + +### Network Key + +- Flag: `--network-key` +- Valid inputs: A valid network public key of the host in hex string format + +Specify the network public key of the Access API that will be +used to create a secure GRPC client when executing the command. + +### Network + +- Flag: `--network` +- Short Flag: `-n` +- Valid inputs: the name of a network defined in the configuration (`flow.json`) +- Default: `emulator` + +Specify which network you want the command to use for execution. + +### Filter + +- Flag: `--filter` +- Short Flag: `-x` +- Valid inputs: a case-sensitive name of the result property. + +Specify any property name from the result you want to return as the only value. + +### Output + +- Flag: `--output` +- Short Flag: `-o` +- Valid inputs: `json`, `inline` + +Specify the format of the command results. + +### Save + +- Flag: `--save` +- Short Flag: `-s` +- Valid inputs: a path in the current filesystem. + +Specify the filename where you want the result to be saved + +### Log + +- Flag: `--log` +- Short Flag: `-l` +- Valid inputs: `none`, `error`, `debug` +- Default: `info` + +Specify the log level. Control how much output you want to see during command execution. + +### Configuration + +- Flag: `--config-path` +- Short Flag: `-f` +- Valid inputs: a path in the current filesystem. +- Default: `flow.json` + +Specify the path to the `flow.json` configuration file. +You can use the `-f` flag multiple times to merge +several configuration files. + +### Version Check + +- Flag: `--skip-version-check` +- Default: `false` + +Skip version check during start up to speed up process for slow connections. + +=== tools/flow-cli/get-flow-data/get-collections.md === +--- +title: Get Collection +description: How to get a collection from the command line +sidebar_position: 3 +--- + +The Flow CLI provides a command to fetch any collection from the Flow network. + +```shell +flow collections get +``` + +## Example Usage + +```shell +flow collections get 3e694588e789a72489667a36dd73104dea4579bcd400959d47aedccd7f930eeb \ +--host access.mainnet.nodes.onflow.org:9000 +``` + +### Example response + +```shell +Collection ID 3e694588e789a72489667a36dd73104dea4579bcd400959d47aedccd7f930eeb: +acc2ae1ff6deb2f4d7663d24af6ab1baf797ec264fd76a745a30792f6882093b +ae8bfbc85ce994899a3f942072bfd3455823b1f7652106ac102d161c17fcb55c +70c4d39d34e654173c5c2746e7bb3a6cdf1f5e6963538d62bad2156fc02ea1b2 +2466237b5eafb469c01e2e5f929a05866de459df3bd768cde748e068c81c57bf + +``` + +## Arguments + +### Collection ID +- Name: `collection_id` +- Valid Input: SHA3-256 hash of the collection contents + +## Arguments + +## Flags + +### Host + +- Flag: `--host` +- Valid inputs: an IP address or hostname. +- Default: `127.0.0.1:3569` (Flow Emulator) + +Specify the hostname of the Access API that will be +used to execute the command. This flag overrides +any host defined by the `--network` flag. + +### Network Key + +- Flag: `--network-key` +- Valid inputs: A valid network public key of the host in hex string format + +Specify the network public key of the Access API that will be +used to create a secure GRPC client when executing the command. + +### Network + +- Flag: `--network` +- Short Flag: `-n` +- Valid inputs: the name of a network defined in the configuration (`flow.json`) +- Default: `emulator` + +Specify which network you want the command to use for execution. + +### Filter + +- Flag: `--filter` +- Short Flag: `-x` +- Valid inputs: a case-sensitive name of the result property. + +Specify any property name from the result you want to return as the only value. + +### Output + +- Flag: `--output` +- Short Flag: `-o` +- Valid inputs: `json`, `inline` + +Specify the format of the command results. + +### Save + +- Flag: `--save` +- Short Flag: `-s` +- Valid inputs: a path in the current filesystem. + +Specify the filename where you want the result to be saved + +### Log + +- Flag: `--log` +- Short Flag: `-l` +- Valid inputs: `none`, `error`, `debug` +- Default: `info` + +Specify the log level. Control how much output you want to see during command execution. + +### Configuration + +- Flag: `--config-path` +- Short Flag: `-f` +- Valid inputs: a path in the current filesystem. +- Default: `flow.json` + +Specify the path to the `flow.json` configuration file. +You can use the `-f` flag multiple times to merge +several configuration files. + +### Version Check + +- Flag: `--skip-version-check` +- Default: `false` + +Skip version check during start up to speed up process for slow connections. + +=== tools/flow-cli/get-flow-data/get-blocks.md === +--- +title: Get Block +description: How to get a block from the command line +sidebar_position: 1 +--- + +The Flow CLI provides a command to fetch any block from the Flow network. + +```shell +flow blocks get +``` + +## Example Usage + +```shell +flow blocks get 12884163 --host access.mainnet.nodes.onflow.org:9000 --include transactions +``` + +### Example response + +```shell +Block ID 2fb7571a6ccf02f3ac42f27c14ce0a4cb119060e4fbd7af36fd51894465e7002 +Prent ID 1c5a6267ba9512e141e4e90630cb326cecfbf6113818487449efeb37fc98ca18 +Timestamp 2021-03-19 17:46:15.973305066 +0000 UTC +Height 12884163 +Status Sealed +Total Seals 2 +Total Collections 8 + Collection 0: 3e694588e789a72489667a36dd73104dea4579bcd400959d47aedccd7f930eeb + Transaction 0: acc2ae1ff6deb2f4d7663d24af6ab1baf797ec264fd76a745a30792f6882093b + Transaction 1: ae8bfbc85ce994899a3f942072bfd3455823b1f7652106ac102d161c17fcb55c + Transaction 2: 70c4d39d34e654173c5c2746e7bb3a6cdf1f5e6963538d62bad2156fc02ea1b2 + Transaction 3: 2466237b5eafb469c01e2e5f929a05866de459df3bd768cde748e068c81c57bf + Collection 1: e93f2bd988d66288c7e1ad991dec227c6c74b8039a430e43896ad94cf8feccce + Transaction 0: 4d790300722b646e7ed3e2c52675430d7ccf2efd1d93f106b53bc348df601af6 + Collection 2: c7d93b80ae55809b1328c686f6a8332e8e15083ab32f8b3105c4d910646f54bf + Transaction 0: 95c4efbb30f86029574d6acd7df04afe6108f6fd610d823dfd398c80cfa5e842 + Collection 3: 1a4f563b48aaa38f3a7e867c89422e0bd84887de125e8f48ba147f4ee58ddf0d + Transaction 0: fbcc99326336d4dbb4cbc01a3b9b85cfcdcdc071b3d0e01ee88ecd144444600b + Collection 4: 01000c7773cc3c22cba6d8917a2486dc7a1a1842dd7fb7c0e87e63c22bb14abe + Transaction 0: a75097639b434044de0122d3a28620e093f277fa715001e80a035568e118c59f + Collection 5: 6f2b08f9673545a2e61e954feb8d55d2a3ef2b3cef7a8d2f8de527bc42d92c28 + Transaction 0: 8ea63d397bd07a25db3f06fb9785dbf09bc652159f68a84c55ea2be606ada1e9 + Collection 6: 13b5c48252930824a8c6e846470763582cacdacb772c1e9c584adefced6724b2 + Transaction 0: 8ba57a92311367189a89a59bcb3c32192387fefca9bde493e087bc0d479186a8 + Transaction 1: 8ab1d99702ccf31b6f4b3acd2580dddd440f08bc07acab4884337c0c593a8f69 + Collection 7: bf90fdd2761b8f37565af60fc38165dd09edf0671fdd35b37f718a7eb45e804f + Transaction 0: b92a14c0802183719efed00363d31076d7e50f41a6207781cf34d39c822bbacb + + +``` + +## Arguments + +### Query +- Name: `` +- Valid Input: Block ID, `latest` or block height + +Specify the block to retrieve by block ID or block height. + +## Arguments + +### Address +- Name: `address` +- Valid Input: Flow account address + +Flow [account address](../../../build/basics/accounts.md) (prefixed with `0x` or not). + + +## Flags + +### Events + +- Flag: `--events` +- Valid inputs: Valid event name + +List events of this type for the block. + +### Include + +- Flag: `--include` +- Valid inputs: `transactions` + +Include additional values in the response. + +### Signer + +- Flag: `--signer` +- Valid inputs: the name of an account defined in the configuration (`flow.json`) + +Specify the name of the account that will be used to sign the transaction. + +### Host + +- Flag: `--host` +- Valid inputs: an IP address or hostname. +- Default: `127.0.0.1:3569` (Flow Emulator) + +Specify the hostname of the Access API that will be +used to execute the command. This flag overrides +any host defined by the `--network` flag. + +### Network Key + +- Flag: `--network-key` +- Valid inputs: A valid network public key of the host in hex string format + +Specify the network public key of the Access API that will be +used to create a secure GRPC client when executing the command. + +### Network + +- Flag: `--network` +- Short Flag: `-n` +- Valid inputs: the name of a network defined in the configuration (`flow.json`) +- Default: `emulator` + +Specify which network you want the command to use for execution. + +### Filter + +- Flag: `--filter` +- Short Flag: `-x` +- Valid inputs: a case-sensitive name of the result property. + +Specify any property name from the result you want to return as the only value. + +### Output + +- Flag: `--output` +- Short Flag: `-o` +- Valid inputs: `json`, `inline` + +Specify the format of the command results. + +### Save + +- Flag: `--save` +- Short Flag: `-s` +- Valid inputs: a path in the current filesystem. + +Specify the filename where you want the result to be saved + +### Log + +- Flag: `--log` +- Short Flag: `-l` +- Valid inputs: `none`, `error`, `debug` +- Default: `info` + +Specify the log level. Control how much output you want to see during command execution. + +### Configuration + +- Flag: `--config-path` +- Short Flag: `-f` +- Valid inputs: a path in the current filesystem. +- Default: `flow.json` + +Specify the path to the `flow.json` configuration file. +You can use the `-f` flag multiple times to merge +several configuration files. + +### Version Check + +- Flag: `--skip-version-check` +- Default: `false` + +Skip version check during start up to speed up process for slow connections. + +=== tools/flow-cli/flow.json/security.md === +--- +title: Security +description: How to securely use CLI +sidebar_position: 4 +--- + +The managing of accounts and private keys is intrinsically dangerous. +We must take extra precautions to not expose private key data when using +the CLI. + +The Flow CLI provides several options to secure private account data. + +⚠️ Warning: please be careful when using private keys in configuration files. +Never commit private key data to source control. +If private key data must be kept in text, we suggest using a separate file +that is not checked into source control (e.g. excluded with `.gitignore`). + +### Private Account Configuration File +Storing an account key to a separate file which is not checked into source control (e.g. excluded with `.gitignore`) +can be the first step towards better security. + +#### Main configuration file +```json +... +"accounts": { + "my-testnet-account": { + "address": "3ae53cb6e3f42a79", + "key": { + "type": "file", + "location": "./my-testnet-account.key" + } + } +} +... +``` + +#### Separate account key file +⚠️ Put this file in `.gitignore` + +The `my-testnet-account.key` file only contains the hex-encoded private key. +``` +334232967f52bd75234ae9037dd4694c1f00baad63a10c35172bf65fbb8ad1111 +``` +--- + +#### Private configuration file + +⚠️ Put this file in `.gitignore`: + +```json +// flow.testnet.json +{ + "accounts": { + "my-testnet-account": { + "address": "3ae53cb6e3f42a79", + "key": "334232967f52bd75234ae9037dd4694c1f00baad63a10c35172bf65fbb8ad1111" + } + } +} +``` + +### Store Configuration in Environment Variables + +You can use environment variables for values that should be kept private (e.g. private keys, addresses). + +See example below: + +```shell +PRIVATE_KEY=key flow project deploy +``` + +```json +// flow.json +{ + ... + "accounts": { + "my-testnet-account": { + "address": "3ae53cb6e3f42a79", + "key": "$PRIVATE_KEY" + } + } + ... +} +``` + +### Private Dotenv File + +The CLI will load environment variables defined in the `.env` file in the active directory, if one exists. +These variables can be substituted inside the `flow.json`, +just like any other environment variable. + +⚠️ You should never commit `.env` to source control, +especially if it contains sensitive information +like a private key. + +Example `.env` file: +```bash +PRIVATE_KEY=123 +``` + +### Composing Multiple Configuration Files + +You can merge multiple configuration files like so: + +```shell +flow project deploy -f main.json -f private.json +``` + + +=== tools/flow-cli/flow.json/manage-configuration.md === +--- +title: Manage Configuration +description: How to configure the Flow CLI +sidebar_position: 3 +--- + +Configuration should be managed by using `config add` +and `config remove` commands. Using add command will also +validate values that will be added to the configuration. + +```shell +flow config add +flow config remove +``` + +## Example Usage + +```shell +flow config add account + +Name: Admin +Address: f8d6e0586b0a20c7 +✔ ECDSA_P256 +✔ SHA3_256 +Private key: e382a0e494...9285809356 +Key index (Default: 0): 0 +``` + +### Configuration + +- Flag: `--config-path` +- Short Flag: `-f` +- Valid inputs: valid filename + +Specify a filename for the configuration files, you can provide multiple configuration +files by using `-f` flag multiple times. + + + + + + + + +=== tools/flow-cli/flow.json/initialize-configuration.md === +--- +title: Initialize Configuration +description: How to initialize Flow configuration using CLI +sidebar_position: 1 +--- + +Flow CLI uses a state to operate which is called configuration (usually `flow.json` file). +Before using commands that require this configuration we must initialize the project by +using the init command. Read more about [state configuration here](./configuration.md). + +```shell +flow init +``` + +## Example Usage + +```shell +> flow init + +Configuration initialized +Service account: 0xf8d6e0586b0a20c7 + +Start emulator by running: 'flow emulator' +Reset configuration using: 'flow init --reset' + +``` + +### Error Handling + +Existing configuration will cause the error below. +You should initialize in an empty folder or reset configuration using `--reset` flag +or by removing the configuration file first. +```shell +❌ Command Error: configuration already exists at: flow.json, if you want to reset configuration use the reset flag +``` + +## Global Configuration + +Flow supports global configuration which is a `flow.json` file saved in your home +directory and loaded as the first configuration file wherever you execute the CLI command. + +Please be aware that global configuration has the lowest priority and is overwritten +by any other configuration file if they exist (if `flow.json` exist in your current +directory it will overwrite properties in global configuration, but only those which overlap). + +You can generate a global configuration using `--global` flag. + +Command example: `flow init --global`. + +Global flow configuration is saved as: +- MacOs: `~/flow.json` +- Linux: `~/flow.json` +- Windows: `C:\Users\$USER\flow.json` + + +## Flags + +### Reset + +- Flag: `--reset` + +Using this flag will reset the existing configuration and create a new one. + +### Global + +- Flag: `--global` + +Using this flag will create a global Flow configuration. + +### Service Private Key + +- Flag: `--service-private-key` +- Valid inputs: a hex-encoded private key in raw form. + +Private key used on the default service account. + + +### Service Key Signature Algorithm + +- Flag: `--service-sig-algo` +- Valid inputs: `"ECDSA_P256", "ECDSA_secp256k1"` +- Default: `"ECDSA_P256"` + +Specify the ECDSA signature algorithm for the provided public key. + +Flow supports the secp256k1 and P-256 curves. + +### Service Key Hash Algorithm + +- Flag: `--service-hash-algo` +- Valid inputs: `"SHA2_256", "SHA3_256"` +- Default: `"SHA3_256"` + +Specify the hashing algorithm that will be paired with the public key +upon account creation. + +### Log + +- Flag: `--log` +- Short Flag: `-l` +- Valid inputs: `none`, `error`, `debug` +- Default: `info` + +Specify the log level. Control how much output you want to see while command execution. + + + + + + + + +=== tools/flow-cli/flow.json/configuration.md === +--- +title: Configuration +description: What is Flow CLI Configuration +sidebar_position: 2 +--- + +Flow CLI uses a state called configuration which is stored in a file (usually `flow.json`). + +Flow configuration (`flow.json`) file will contain the following properties: + +- A `networks` list pre-populated with the Flow emulator, testnet and mainnet connection configuration. +- An `accounts` list pre-populated with the Flow Emulator service account. +- A `deployments` empty object where all [deployment targets](../deployment/project-contracts.md#define-contract-deployment-targets) can be defined. +- A `contracts` empty object where you [define contracts](../deployment/project-contracts.md#add-a-contract) you wish to deploy. + +## Example Project Configuration + +```json +{ + "networks": { + "emulator": "127.0.0.1:3569", + "mainnet": "access.mainnet.nodes.onflow.org:9000", + "testnet": "access.devnet.nodes.onflow.org:9000" + }, + "accounts": { + "emulator-account": { + "address": "f8d6e0586b0a20c7", + "key": "ae1b44c0f5e8f6992ef2348898a35e50a8b0b9684000da8b1dade1b3bcd6ebee", + } + }, + "deployments": {}, + "contracts": {} +} +``` + +## Configuration + +Below is an example of a configuration file for a complete Flow project. +We'll walk through each property one by one. + +```json +{ + "contracts": { + "NonFungibleToken": "./cadence/contracts/NonFungibleToken.cdc", + "Kibble": "./cadence/contracts/Kibble.cdc", + "KittyItems": "./cadence/contracts/KittyItems.cdc", + "KittyItemsMarket": "./cadence/contracts/KittyItemsMarket.cdc", + "FungibleToken": { + "source": "./cadence/contracts/FungibleToken.cdc", + "aliases": { + "testnet": "9a0766d93b6608b7", + "emulator": "ee82856bf20e2aa6" + } + } + }, + + "deployments": { + "testnet": { + "admin-account": ["NonFungibleToken"], + "user-account": ["Kibble", "KittyItems", "KittyItemsMarket"] + }, + "emulator": { + "emulator-account": [ + "NonFungibleToken", + "Kibble", + "KittyItems", + "KittyItemsMarket" + ] + } + }, + + "accounts": { + "admin-account": { + "address": "3ae53cb6e3f42a79", + "key": "12332967fd2bd75234ae9037dd4694c1f00baad63a10c35172bf65fbb8ad1111" + }, + "user-account": { + "address": "e2a8b7f23e8b548f", + "key": "22232967fd2bd75234ae9037dd4694c1f00baad63a10c35172bf65fbb8ad1111" + }, + "emulator-account": { + "address": "f8d6e0586b0a20c7", + "key": "2eae2f31cb5b756151fa11d82949c634b8f28796a711d7eb1e52cc301ed11111", + } + }, + + "networks": { + "emulator": "127.0.0.1:3569", + "mainnet": "access.mainnet.nodes.onflow.org:9000", + "testnet": "access.devnet.nodes.onflow.org:9000", + "testnetSecure": { + "Host": "access-001.devnet30.nodes.onflow.org:9001", + "NetworkKey": "ba69f7d2e82b9edf25b103c195cd371cf0cc047ef8884a9bbe331e62982d46daeebf836f7445a2ac16741013b192959d8ad26998aff12f2adc67a99e1eb2988d" + } + } +} +``` + +### Contracts + +Contracts are specified as key-value pairs, where the key is the contract name, +and the value is the location of the Cadence source code. + +The advanced format allows us to specify aliases for each network. + +#### Simple Format + +```json +... + +"contracts": { + "NonFungibleToken": "./cadence/contracts/NonFungibleToken.cdc" +} + +... +``` + +#### Advanced Format + +Using advanced format we can define `aliases`. Aliases define an address where the contract is already deployed for that specific network. +In the example scenario below the contract `FungibleToken` would be imported from the address `9a0766d93b6608b7` when deploying to testnet network +and address `ee82856bf20e2aa6` when deploying to the Flow emulator. +We can specify aliases for each network we have defined. When deploying to testnet it is always a good idea to specify aliases for all the [common contracts](../../../build//core-contracts/index.md) that have already been deployed to the testnet. + +⚠️ If we use an alias for the contract we should not specify it in the `deployment` section for that network. + + +```json +... +"FungibleToken": { + "source": "./cadence/contracts/FungibleToken.cdc", + "aliases": { + "testnet": "9a0766d93b6608b7", + "emulator": "ee82856bf20e2aa6" + } +} +... +``` + +Format used to specify advanced contracts is: +```json +"CONTRACT NAME": { + "source": "CONTRACT SOURCE FILE LOCATION", + "aliases": { + "NETWORK NAME": "ADDRESS ON SPECIFIED NETWORK WITH DEPLOYED CONTRACT" + ... + } +} +``` + +### Accounts + +The accounts section is used to define account properties such as keys and addresses. +Each account must include a name, which is then referenced throughout the configuration file. + +#### Simple Format + +When using the simple format, simply specify the address for the account, and a single hex-encoded +private key. + +```json +... + +"accounts": { + "admin-account": { + "address": "3ae53cb6e3f42a79", + "key": "12332967fd2bd75234ae9037dd4694c1f00baad63a10c35172bf65fbb8ad1111" + } +} + +... +``` + +#### Advanced format + +The advanced format allows us to define more properties for the account. +We can define the signature algorithm and hashing algorithm, as well as custom key formats. + +Please note that we can use `service` for address in case the account is used on `emulator` network as this is a special +value that is defined on the run time to the default service address on the emulator network. + +**Example for advanced hex format:** +```json +... + +"accounts": { + "admin-account": { + "address": "service", + "key":{ + "type": "hex", + "index": 0, + "signatureAlgorithm": "ECDSA_P256", + "hashAlgorithm": "SHA3_256", + "privateKey": "12332967fd2bd75234ae9037dd4694c1f00baad63a10c35172bf65fbb8ad1111" + } + } +} + +... +``` + +You can also use BIP44 to derive keys from a mnemonic. For more details please see the [FLIP](https://github.com/onflow/flips/blob/main/application/20201125-bip-44-multi-account.md) + +**Example for BIP44 format:** +```json +... + +"accounts": { + "admin-account": { + "address": "service", + "key":{ + "type": "bip44", + "index": 0, + "signatureAlgorithm": "ECDSA_P256", + "hashAlgorithm": "SHA3_256", + "mnemonic": "skull design wagon top faith actor valley crystal subject volcano access join", + "derivationPath": "m/44'/539'/0'/0/0" + } + } +} + +... +``` + +Note: Default value for `derivationPath` is `m/44'/539'/0'/0/0` if omitted. + + + +You can also use a key management system (KMS) to sign the transactions. Currently, we only support Google KMS. + +**Example for Google KMS format:** +```json +... +"accounts": { + "admin-account": { + "address": "service", + "key": { + "type": "google-kms", + "index": 0, + "signatureAlgorithm": "ECDSA_P256", + "hashAlgorithm": "SHA3_256", + "resourceID": "projects/flow/locations/us/keyRings/foo/bar/cryptoKeyVersions/1" + } + } +} +... +``` + +You can store the account key to a separate file and provide the file location as part of the key configuration. + +**Example for separate key file:** +```json +... +"accounts": { + "admin-account": { + "address": "service", + "key": { + "type": "file", + "location": "./test.key" + } + } +} +... +``` +Inside the `test.key` file you should only put the hex key content (e.g. `12332967fd2bd75234ae9037dd4694c1f00baad63a10c35172bf65fbb8ad1111`) + +### Deployments + +The deployments section defines where the `project deploy` command will deploy specified contracts. +This configuration property acts as the glue that ties together accounts, +contracts and networks, all of which are referenced by name. + +In the deployments section we specify the network, account name and list of contracts to be deployed to that account. + +Format specifying the deployment is: +```json +... +"deployments": { + "NETWORK": { + "ACCOUNT NAME": ["CONTRACT NAME"] + } +} + +... +``` + + +```json +... + +"deployments": { + "emulator": { + "emulator-account": [ + "NonFungibleToken", + "Kibble", + "KittyItems", + "KittyItemsMarket" + ] + }, + "testnet": { + "admin-account": ["NonFungibleToken"], + "user-account": [ + "Kibble", + "KittyItems", + "KittyItemsMarket" + ] + } +} + +... +``` + +### Networks + +Use this section to define networks and connection parameters for that specific network. + +Format for networks is: + +```json +... +"networks": { + "NETWORK NAME": "ADDRESS" +} +... +``` + +```json +... +"networks": { + "NETWORK NAME": { + "host": "ADDRESS", + "key": "ACCESS NODE NETWORK KEY" + } +} +... +``` + +```json +... + +"networks": { + "emulator": "127.0.0.1:3569", + "mainnet": "access.mainnet.nodes.onflow.org:9000", + "testnet": "access.devnet.nodes.onflow.org:9000", + "testnetSecure": { + "host": "access-001.devnet30.nodes.onflow.org:9001", + "key": "ba69f7d2e82b9edf25b103c195cd371cf0cc047ef8884a9bbe331e62982d46daeebf836f7445a2ac16741013b192959d8ad26998aff12f2adc67a99e1eb2988d" + }, +} + +... +``` +### Emulators + +The default emulator CLI is automatically configured with name being `"default"` and values of +`serviceAccount`: `"emulator-account"` and `port`: `"3569"`. The default emulator configuration will not show up on +flow.json. + +To customize emulator values, add emulator section like the example below: + +```json +... + +"emulators": { + "custom-emulator": { + "port": 3600, + "serviceAccount": "emulator-account" + } +} + +... +``` + + +=== tools/flow-cli/deployment/start-emulator.md === +--- +title: Start Emulator +description: How to start the Flow Emulator from the command line +sidebar_position: 1 +--- + +The Flow Emulator is a lightweight development tool that mimics the behavior of the real Flow network. It is bundled with the [Flow CLI](https://docs.onflow.org/flow-cli/), which makes starting and configuring the emulator straightforward. + +## Initial Configuration + +The emulator requires a configuration file (`flow.json`). If you don’t already have one, create it using the `flow init` command: + +```bash +flow init +``` + +This initializes a default configuration file that the emulator will use. + +## Starting the Emulator + +To start the emulator with default settings, use the following command: + +```bash +flow emulator +``` + +This will start the emulator with the configuration defined in `flow.json`. + +### Example Output + +When you run the `flow emulator` command, you will see output similar to the following: + +```bash +INFO[0000] ⚙️ Using service account 0xf8d6e0586b0a20c7 serviceAddress=f8d6e0586b0a20c7 ... +INFO[0000] 🌱 Starting Flow Emulator +INFO[0000] 🛠 GRPC server started on 127.0.0.1:3569 +INFO[0000] 📡 HTTP server started on 127.0.0.1:8080 +``` + +## Customizing the Emulator + +You can customize the emulator behavior by using flags. Here are some examples: + +Change the gRPC and REST API ports: + +```bash +flow emulator --port 9000 --rest-port 9001 +``` + +Enable persistence of state across restarts: + +```bash +flow emulator --persist +``` + +Enable detailed logs for debugging: + +```bash +flow emulator --verbose +``` + +For a complete list of available flags, run: + +```bash +flow emulator --help +``` + +## Learn More + +To explore advanced features like snapshots, rollbacks, and debugging, visit the [Flow Emulator README](https://github.com/onflow/flow-emulator). + +=== tools/flow-cli/deployment/project-contracts.md === +--- +title: Add Project Contracts +description: How to define the Cadence contracts for Flow project +sidebar_position: 2 +--- + +## Add a Contract + +To add a contract to your project, update the `"contracts"` section of your `flow.json` file. + +Contracts are specified as key-value pairs, where the key is the contract name, +and the value is the location of the Cadence source code. + +For example, the configuration below will register the +contract `Foo` from the `FooContract.cdc` file. + +```json +{ + "contracts": { + "Foo": "./cadence/contracts/FooContract.cdc" + } +} +``` + +## Define Contract Deployment Targets + +Once a contract is added, it can then be assigned to one or more deployment targets. + +A deployment target is an account to which the contract will be deployed. +In a typical project, a contract has one deployment target per network (e.g. Emulator, Testnet, Mainnet). + +Deployment targets are defined in the `"deployments"` section of your `flow.json` file. + +Targets are grouped by their network, where each network is a mapping from target account to contract list. +Multiple contracts can be deployed to the same target account. + +For example, here's how we'd deploy contracts `Foo` and `Bar` to the account `my-testnet-account`: + +```json +{ + "contracts": { + "Foo": "./cadence/contracts/FooContract.cdc", + "Bar": "./cadence/contracts/BarContract.cdc" + }, + "deployments": { + "testnet": { + "my-testnet-account": ["Foo", "Bar"] + } + } +} +``` + + +=== tools/flow-cli/deployment/emulator-snapshot.md === +--- +title: Create Emulator Snapshot +description: How to start create emulator snapshot from the command line +sidebar_position: 4 +--- + +The Flow CLI provides a command to create emulator snapshots, which are points in blockchain +history you can later jump to and reset the state to that moment. This can be useful for testing where you +establish a begining state, run tests and after revert back to the initial state. + +The command syntax is: +```shell +flow emulator snapshot create|load|list {name} +``` + +## Example Usage + +### Create a new snapshot +Create a new emulator snapshot at the current block with a name of `myInitialState`. +```shell +> flow emulator snapshot create myInitialState +``` + +### Load an existing snapshot +To jump to a previously created snapshot we use the load command in combination with the name. +```shell +> flow emulator snapshot load myInitialState +``` + +### List all existing snapshots +To list all the existing snapshots we previously created and can load to we run the following command: +```shell +> flow emulator list +``` + + +To learn more about using the Emulator, have a look at the [README of the repository](https://github.com/onflow/flow-emulator). + +## Flags + +### Emulator Flags +You can specify any [emulator flags found here](https://github.com/onflow/flow-emulator#configuration) and they will be applied to the emulator service. + +### Configuration + +- Flag: `--config-path` +- Short Flag: `-f` +- Valid inputs: valid filename + +Specify a filename for the configuration files, you can provide multiple configuration +files by using `-f` flag multiple times. + +### Version Check + +- Flag: `--skip-version-check` +- Default: `false` + +Skip version check during start up to speed up process for slow connections. + + +=== tools/flow-cli/deployment/deploy-project-contracts.md === +--- +title: Deploy a Project +description: How to deploy Flow project contracts with the CLI +sidebar_position: 3 +--- + +```shell +flow project deploy +``` + +This command automatically deploys your project's contracts based on the +configuration defined in your `flow.json` file. + +Before using this command, read about how to +[configure project contracts and deployment targets](./project-contracts.md). + +## Example Usage + +```shell +> flow project deploy --network=testnet + +Deploying 2 contracts for accounts: my-testnet-account + +NonFungibleToken -> 0x8910590293346ec4 +KittyItems -> 0x8910590293346ec4 + +✨ All contracts deployed successfully +``` + +In the example above, your `flow.json` file might look something like this: + +```json +{ + ... + "contracts": { + "NonFungibleToken": "./cadence/contracts/NonFungibleToken.cdc", + "KittyItems": "./cadence/contracts/KittyItems.cdc" + }, + "deployments": { + "testnet": { + "my-testnet-account": ["KittyItems", "NonFungibleToken"] + } + }, + ... +} +``` + +Here's a sketch of the contract source files: + +```cadence NonFungibleToken.cdc +access(all) contract NonFungibleToken { + // ... +} +``` + +```cadence KittyItems.cdc +import NonFungibleToken from "./NonFungibleToken.cdc" + +access(all) contract KittyItems { + // ... +} +``` + +## Initialization Arguments +Deploying contracts that take initialization arguments +can be achieved with adding those arguments to the configuration. + +Each deployment can be specified as an object containing +`name` and `args` key specifying arguments to be +used during the deployment. Example: + +``` +... + "deployments": { + "testnet": { + "my-testnet-account": [ + "NonFungibleToken", { + "name": "Foo", + "args": [ + { "type": "String", "value": "Hello World" }, + { "type": "UInt32", "value": "10" } + ] + }] + } + } +... +``` + + +⚠️ Warning: before proceeding, +we recommend reading the [Flow CLI security guidelines](../flow.json/security.md) +to learn about the best practices for private key storage. + +## Dependency Resolution + +The `deploy` command attempts to resolve the import statements in all contracts being deployed. + +After the dependencies are found, the CLI will deploy the contracts in a deterministic order +such that no contract is deployed until all of its dependencies are deployed. +The command will return an error if no such ordering exists due to one or more cyclic dependencies. + +In the example above, `Foo` will always be deployed before `Bar`. + +## Address Replacement + +After resolving all dependencies, the `deploy` command rewrites each contract so +that its dependencies are imported from their _target addresses_ rather than their +source file location. + +The rewritten versions are then deployed to their respective targets, +leaving the original contract files unchanged. + +In the example above, the `KittyItems` contract would be rewritten like this: + +```cadence KittyItems.cdc +import NonFungibleToken from 0xf8d6e0586b0a20c7 + +access(all) contract KittyItems { + // ... +} +``` +## Merging Multiple Configuration Files + +You can use the `-f` flag multiple times to merge several configuration files. + +If there is an overlap in any of the fields in the configuration between two or more configuration files, the value of +the overlapped field in the resulting configuration will come from the configuration file that is on the further right +order in the list of configuration files specified in the -f flag + +Let's look at an example of `deploy` commands with multiple configuration files below + +```cadence flow.json +{ + "accounts": { + "admin-account": { + "address": "f8d6e0586b0a20c7", + "key": "21c5dfdeb0ff03a7a73ef39788563b62c89adea67bbb21ab95e5f710bd1d40b7" + }, + "test-account": { + "address": "f8d6e0586b0a20c8", + "key": "52d5dfdeb0ff03a7a73ef39788563b62c89adea67bbb21ab95e5f710bd1d51c9" + } + } +} +``` +```cadence private.json +{ + "accounts":{ + "admin-account":{ + "address":"f1d6e0586b0a20c7", + "key":"3335dfdeb0ff03a7a73ef39788563b62c89adea67bbb21ab95e5f710bd1d40b7" + } + } +} +``` +In the example above, when we try to use the `deploy` command with multiple configuration files and there is an overlap +in the `admin-account` account in `accounts` field of the configuration, the resulting configuration will be like this + +> flow project deploy -f flow.json -f private.json +``` +{ + "accounts":{ + "admin-account":{ + "address":"f1d6e0586b0a20c7", + "key":"3335dfdeb0ff03a7a73ef39788563b62c89adea67bbb21ab95e5f710bd1d40b7" + }, + "test-account":{ + "address":"f8d6e0586b0a20c8", + "key":"52d5dfdeb0ff03a7a73ef39788563b62c89adea67bbb21ab95e5f710bd1d51c9" + } + } +} +``` + +## Flags + +### Allow Updates + +- Flag: `--update` +- Valid inputs: `true`, `false` +- Default: `false` + +Indicate whether to overwrite and upgrade existing contracts. Only contracts with difference with existing contracts +will be overwritten. + +### Show Update Diff + +- Flag: `--show-diff` +- Valid inputs: `true`, `false` +- Default: `false` + +Shows a diff to approve before updating between deployed contract and new contract updates. + +### Host + +- Flag: `--host` +- Valid inputs: an IP address or hostname. +- Default: `127.0.0.1:3569` (Flow Emulator) + +Specify the hostname of the Access API that will be +used to execute the command. This flag overrides +any host defined by the `--network` flag. + +### Network Key + +- Flag: `--network-key` +- Valid inputs: A valid network public key of the host in hex string format + +Specify the network public key of the Access API that will be +used to create a secure GRPC client when executing the command. + +### Network + +- Flag: `--network` +- Short Flag: `-n` +- Valid inputs: the name of a network defined in the configuration (`flow.json`) +- Default: `emulator` + +Specify which network you want the command to use for execution. + +### Filter + +- Flag: `--filter` +- Short Flag: `-x` +- Valid inputs: a case-sensitive name of the result property. + +Specify any property name from the result you want to return as the only value. + +### Output + +- Flag: `--output` +- Short Flag: `-o` +- Valid inputs: `json`, `inline` + +Specify the format of the command results. + +### Save + +- Flag: `--save` +- Short Flag: `-s` +- Valid inputs: a path in the current filesystem. + +Specify the filename where you want the result to be saved + +### Log + +- Flag: `--log` +- Short Flag: `-l` +- Valid inputs: `none`, `error`, `debug` +- Default: `info` + +Specify the log level. Control how much output you want to see during command execution. + +### Configuration + +- Flag: `--config-path` +- Short Flag: `-f` +- Valid inputs: a path in the current filesystem. +- Default: `flow.json` + +Specify the path to the `flow.json` configuration file. +You can use the `-f` flag multiple times to merge +several configuration files. + +### Version Check + +- Flag: `--skip-version-check` +- Default: `false` + +Skip version check during start up to speed up process for slow connections. + +=== tools/flow-cli/accounts/get-accounts.md === +--- +title: Get an Account +description: How to get a Flow account from the command line +sidebar_position: 1 +--- + +The Flow CLI provides a command to fetch any account by its address from the Flow network. + +```shell +flow accounts get
    +``` + +## Example Usage + +```shell +flow accounts get 0xf8d6e0586b0a20c7 +``` + +### Example response +```shell +Address 0xf8d6e0586b0a20c7 +Balance 99999999999.70000000 +Keys 1 + +Key 0 Public Key 640a5a359bf3536d15192f18d872d57c98a96cb871b92b70cecb0739c2d5c37b4be12548d3526933c2cda9b0b9c69412f45ffb6b85b6840d8569d969fe84e5b7 + Weight 1000 + Signature Algorithm ECDSA_P256 + Hash Algorithm SHA3_256 + Revoked false + Sequence Number 6 + Index 0 + +Contracts Deployed: 2 +Contract: 'FlowServiceAccount' +Contract: 'FlowStorageFees' + + +``` + +## Arguments + +### Address + +- Name: `address` +- Valid Input: Flow account address + +Flow [account address](../../../build/basics/accounts.md) (prefixed with `0x` or not). + + +## Flags + +### Include Fields + +- Flag: `--include` +- Valid inputs: `contracts` + +Specify fields to include in the result output. Applies only to the text output. + +### Host + +- Flag: `--host` +- Valid inputs: an IP address or hostname. +- Default: `127.0.0.1:3569` (Flow Emulator) + +Specify the hostname of the Access API that will be +used to execute the command. This flag overrides +any host defined by the `--network` flag. + +### Network Key + +- Flag: `--network-key` +- Valid inputs: A valid network public key of the host in hex string format + +Specify the network public key of the Access API that will be +used to create a secure GRPC client when executing the command. + +### Network + +- Flag: `--network` +- Short Flag: `-n` +- Valid inputs: the name of a network defined in the configuration (`flow.json`) +- Default: `emulator` + +Specify which network you want the command to use for execution. + +### Filter + +- Flag: `--filter` +- Short Flag: `-x` +- Valid inputs: a case-sensitive name of the result property. + +Specify any property name from the result you want to return as the only value. + +### Output + +- Flag: `--output` +- Short Flag: `-o` +- Valid inputs: `json`, `inline` + +Specify the format of the command results. + +### Save + +- Flag: `--save` +- Short Flag: `-s` +- Valid inputs: a path in the current filesystem. + +Specify the filename where you want the result to be saved + +### Log + +- Flag: `--log` +- Short Flag: `-l` +- Valid inputs: `none`, `error`, `debug` +- Default: `info` + +Specify the log level. Control how much output you want to see during command execution. + +### Configuration + +- Flag: `--config-path` +- Short Flag: `-f` +- Valid inputs: a path in the current filesystem. +- Default: `flow.json` + +Specify the path to the `flow.json` configuration file. +You can use the `-f` flag multiple times to merge +several configuration files. + +### Version Check + +- Flag: `--skip-version-check` +- Default: `false` + +Skip version check during start up to speed up process for slow connections. + +=== tools/flow-cli/accounts/create-accounts.md === +--- +title: Create an Account +description: How to create a Flow account from the command line +sidebar_position: 2 +--- + +The Flow CLI provides a command to submit an account creation +transaction to any Flow Access API. There are two options how to create an account, you can use the +interactive mode which guides you through the process and creates the account for you or by using +the manual process which requires a pre-existing account on the network you chose. + +## Interactive Mode +Creating the account in interactive mode prompts you for an account name and network selection. +After you enter the required information the account will be created for you and saved to `flow.json`. +If account creation is done on testnet or mainnet the account key will be saved to a separate key file, +which will also be put in `.gitignore`. You can [read more about key security here](../flow.json/security.md). + +💡 _Please note that the account creation process can take up to a minute so please be patient._ + +```shell +flow accounts create + +Enter an account name: mike +✔ Testnet + +🎉 New account created with address 0x77e6ae4c8c2f1dd6 and name mike on Testnet network. + +Here’s a summary of all the actions that were taken: + - Added the new account to flow.json. + - Saved the private key to mike.pkey. + - Added mike.pkey to .gitignore. +``` + +## Manual Mode +Manual mode requires you to have a pre-existing account on the network which you will have to provide as a signer. +That account must be added to `flow.json` for the command to work. You also have to generate a key pair, we +suggest using the `flow keys generate` command, [which you can read more about here](../keys/generate-keys.md). + +```shell +# Create an account on Flow Testnet +> flow accounts create \ + --key a69c6986e846ba6d0....1397f5904cd319c3e01e96375d5777f1a47010 \ + --signer my-testnet-account + +Address 0x01cf0e2f2f715450 +Balance 10000000 +Keys 1 + +Key 0 Public Key a69c6986e846ba6d0....1397f5904cd319c3e01e96375d5777f1a47010 + Weight 1000 + Signature Algorithm ECDSA_P256 + Hash Algorithm SHA3_256 + +Contracts Deployed: 0 +``` + +In the above example, the `flow.json` file would look something like this: + +```json +{ + "accounts": { + "my-testnet-account": { + "address": "a2c4941b5f3c7151", + "key": "12c5dfde...bb2e542f1af710bd1d40b2" + } + } +} +``` + +## Flags + +### Public Key + +- Flag: `--key` +- Valid inputs: a hex-encoded public key in raw form. + +Specify the public key that will be added to the new account +upon creation. + +### Key Weight + +- Flag: `--key-weight` +- Valid inputs: number between 0 and 1000 +- Default: 1000 + +Specify the weight of the public key being added to the new account. + +When opting to use this flag, you must specify a `--key-weight` flag for each public `--key` flag provided. + +### Public Key Signature Algorithm + +- Flag: `--sig-algo` +- Valid inputs: `"ECDSA_P256", "ECDSA_secp256k1"` +- Default: `"ECDSA_P256"` + +Specify the ECDSA signature algorithm for the provided public key. +This option can only be used together with the `--key` flag. + +Flow supports the secp256k1 and P-256 curves. + +### Public Key Hash Algorithm + +- Flag: `--hash-algo` +- Valid inputs: `"SHA2_256", "SHA3_256"` +- Default: `"SHA3_256"` + +Specify the hash algorithm that will be paired with the public key +upon account creation. + +### Signer + +- Flag: `--signer` +- Valid inputs: the name of an account defined in `flow.json`. + +Specify the name of the account that will be used to sign the transaction +and pay the account creation fee. + +### Contract + +- Flag: `--contract` +- Valid inputs: String with format `name:filename`, where `name` is + name of the contract as it is defined in the contract source code + and `filename` is the filename of the contract source code. + +Specify one or more contracts to be deployed during account creation. + +### Include Fields + +- Flag: `--include` +- Valid inputs: `contracts` + +Specify fields to include in the result output. Applies only to the text output. + +### Host + +- Flag: `--host` +- Valid inputs: an IP address or hostname. +- Default: `127.0.0.1:3569` (Flow Emulator) + +Specify the hostname of the Access API that will be +used to execute the command. This flag overrides +any host defined by the `--network` flag. + +### Network Key + +- Flag: `--network-key` +- Valid inputs: A valid network public key of the host in hex string format + +Specify the network public key of the Access API that will be +used to create a secure GRPC client when executing the command. + +### Network + +- Flag: `--network` +- Short Flag: `-n` +- Valid inputs: the name of a network defined in the configuration (`flow.json`) +- Default: `emulator` + +Specify which network you want the command to use for execution. + +### Filter + +- Flag: `--filter` +- Short Flag: `-x` +- Valid inputs: a case-sensitive name of the result property. + +Specify any property name from the result you want to return as the only value. + +### Output + +- Flag: `--output` +- Short Flag: `-o` +- Valid inputs: `json`, `inline` + +Specify the format of the command results. + +### Save + +- Flag: `--save` +- Short Flag: `-s` +- Valid inputs: a path in the current filesystem. + +Specify the filename where you want the result to be saved + +### Log + +- Flag: `--log` +- Short Flag: `-l` +- Valid inputs: `none`, `error`, `debug` +- Default: `info` + +Specify the log level. Control how much output you want to see during command execution. + +### Configuration + +- Flag: `--config-path` +- Short Flag: `-f` +- Valid inputs: a path in the current filesystem. +- Default: `flow.json` + +Specify the path to the `flow.json` configuration file. +You can use the `-f` flag multiple times to merge +several configuration files. + +### Version Check + +- Flag: `--skip-version-check` +- Default: `false` + +Skip version check during start up to speed up process for slow connections. + +=== tools/flow-cli/accounts/account-update-contract.md === +--- +title: Update a Contract +sidebar_position: 4 +--- + +Update an existing contract deployed to a Flow account using the Flow CLI. + +```shell +flow accounts update-contract [ ...] [flags] +``` + +⚠️ Deprecation notice: using name argument in update contract command will be deprecated soon. +```shell +flow accounts update-contract [ ...] [flags] +``` + +## Example Usage + +```shell +> flow accounts update-contract ./FungibleToken.cdc + +Contract 'FungibleToken' updated on account '0xf8d6e0586b0a20c7' + +Address 0xf8d6e0586b0a20c7 +Balance 99999999999.70000000 +Keys 1 + +Key 0 Public Key 640a5a359bf3536d15192f18d872d57c98a96cb871b92b70cecb0739c2d5c37b4be12548d3526933c2cda9b0b9c69412f45ffb6b85b6840d8569d969fe84e5b7 + Weight 1000 + Signature Algorithm ECDSA_P256 + Hash Algorithm SHA3_256 + Revoked false + Sequence Number 6 + Index 0 + +Contracts Deployed: 1 +Contract: 'FungibleToken' +``` +**Testnet Example** +``` +> flow accounts update-contract ./FungibleToken.cdc --signer alice --network testnet + +Contract 'FungibleToken' updated on account '0xf8d6e0586b0a20c7' + +Address 0xf8d6e0586b0a20c7 +Balance 99999999999.70000000 +Keys 1 + +Key 0 Public Key 640a5a359bf3536d15192f18d872d57c98a96cb871b92b70cecb0739c2d5c37b4be12548d3526933c2cda9b0b9c69412f45ffb6b85b6840d8569d969fe84e5b7 + Weight 1000 + Signature Algorithm ECDSA_P256 + Hash Algorithm SHA3_256 + Revoked false + Sequence Number 6 + Index 0 + +Contracts Deployed: 1 +Contract: 'FungibleToken' +``` +*Make sure alice account is defined in flow.json* + +## Arguments + +### Name +- Name: `name` +- Valid inputs: Any string value + +Name of the contract as it is defined in the contract source code. + +⚠️ Deprecation notice: use filename argument only, no need to use name argument. + +### Filename +- Name: `filename` +- Valid inputs: Any filename and path valid on the system. + +Filename of the file containing contract source code. + +### Arguments +- Name: `argument` +- Valid inputs: valid [cadence values](https://cadencelang.dev/docs/1.0/json-cadence-spec) + matching argument type in transaction code. + +Input arguments values matching corresponding types in the source code and passed in the same order. + +Example: +```shell +> flow accounts update-contract ./contract.cdc Hello 2 +``` +Transaction code: +``` +access(all) contract HelloWorld { + init(a:String, b:Int) { + } +} +``` + +## Flags + +### Signer + +- Flag: `--signer` +- Valid inputs: the name of an account defined in the configuration (`flow.json`) + +Specify the name of the account that will be used to sign the transaction. + +### Show Diff + +- Flag: `--show-diff` +- Valid inputs: `true`, `false` + +Shows a diff to approve before updating between deployed contract and new contract updates. + +### Arguments JSON + +- Flag: `--args-json` +- Valid inputs: arguments in JSON-Cadence form. +- Example: `flow accounts update-contract ./tx.cdc '[{"type": "String", "value": "Hello"}]'` + +Arguments passed to the Cadence transaction in Cadence JSON format. +Cadence JSON format contains `type` and `value` keys and is +[documented here](https://cadencelang.dev/docs/1.0/json-cadence-spec). + +### Include Fields + +- Flag: `--include` +- Valid inputs: `contracts` + +Specify fields to include in the result output. Applies only to the text output. + +### Host + +- Flag: `--host` +- Valid inputs: an IP address or hostname. +- Default: `127.0.0.1:3569` (Flow Emulator) + +Specify the hostname of the Access API that will be +used to execute the command. This flag overrides +any host defined by the `--network` flag. + +### Network Key + +- Flag: `--network-key` +- Valid inputs: A valid network public key of the host in hex string format + +Specify the network public key of the Access API that will be +used to create a secure GRPC client when executing the command. + +### Network + +- Flag: `--network` +- Short Flag: `-n` +- Valid inputs: the name of a network defined in the configuration (`flow.json`) +- Default: `emulator` + +Specify which network you want the command to use for execution. + +### Filter + +- Flag: `--filter` +- Short Flag: `-x` +- Valid inputs: a case-sensitive name of the result property + +Specify any property name from the result you want to return as the only value. + +### Output + +- Flag: `--output` +- Short Flag: `-o` +- Valid inputs: `json`, `inline` + +Specify the format of the command results. + +### Save + +- Flag: `--save` +- Short Flag: `-s` +- Valid inputs: a path in the current filesystem + +Specify the filename where you want the result to be saved + +### Log + +- Flag: `--log` +- Short Flag: `-l` +- Valid inputs: `none`, `error`, `debug` +- Default: `info` + +Specify the log level. Control how much output you want to see during command execution. + +### Configuration + +- Flag: `--config-path` +- Short Flag: `-f` +- Valid inputs: a path in the current filesystem +- Default: `flow.json` + +Specify the path to the `flow.json` configuration file. +You can use the `-f` flag multiple times to merge +several configuration files. + +### Version Check + +- Flag: `--skip-version-check` +- Default: `false` + +Skip version check during start up to speed up process for slow connections. + +=== tools/flow-cli/accounts/account-staking-info.md === +--- +title: Account Staking Info +description: How to get staking info +sidebar_position: 6 +--- + +Retrieve staking information for the account on the Flow network using Flow CLI. + +```shell +flow accounts staking-info
    +``` + +## Example Usage + +```shell +> accounts staking-info 535b975637fb6bee --host access.testnet.nodes.onflow.org:9000 + +Account Staking Info: + ID: "ca00101101010100001011010101010101010101010101011010101010101010" + Initial Weight: 100 + Networking Address: "ca00101101010100001011010101010101010101010101011010101010101010" + Networking Key: "ca00101101010100001011010101010101010101010101011010101010101010ca00101101010100001011010101010101010101010101011010101010101010" + Role: 1 + Staking Key: "ca00101101010100001011010101010101010101010101011010101010101010ca00101101010100001011010101010101010101010101011010101010101010ca00101101010100001011010101010101010101010101011010101010101010" + Tokens Committed: 0.00000000 + Tokens To Unstake: 0.00000000 + Tokens Rewarded: 82627.77000000 + Tokens Staked: 250000.00000000 + Tokens Unstaked: 0.00000000 + Tokens Unstaking: 0.00000000 + Node Total Stake (including delegators): 250000.00000000 + + +Account Delegation Info: + ID: 7 + Tokens Committed: 0.00000000 + Tokens To Unstake: 0.00000000 + Tokens Rewarded: 30397.81936000 + Tokens Staked: 100000.00000000 + Tokens Unstaked: 0.00000000 + Tokens Unstaking: 0.00000000 + +``` + +## Arguments + +### Address + +- Name: `address` +- Valid Input: Flow account address. + +Flow [account address](../../../build/basics/accounts.md) (prefixed with `0x` or not). + +## Flags + +### Include Fields + +- Flag: `--include` +- Valid inputs: `contracts` + +Specify fields to include in the result output. Applies only to the text output. + + +### Host + +- Flag: `--host` +- Valid inputs: an IP address or hostname. +- Default: `127.0.0.1:3569` (Flow Emulator) + +Specify the hostname of the Access API that will be +used to execute the command. This flag overrides +any host defined by the `--network` flag. + +### Network Key + +- Flag: `--network-key` +- Valid inputs: A valid network public key of the host in hex string format + +Specify the network public key of the Access API that will be +used to create a secure GRPC client when executing the command. + +### Network + +- Flag: `--network` +- Short Flag: `-n` +- Valid inputs: the name of a network defined in the configuration (`flow.json`) +- Default: `emulator` + +Specify which network you want the command to use for execution. + +### Filter + +- Flag: `--filter` +- Short Flag: `-x` +- Valid inputs: a case-sensitive name of the result property + +Specify any property name from the result you want to return as the only value. + +### Output + +- Flag: `--output` +- Short Flag: `-o` +- Valid inputs: `json`, `inline` + +Specify the format of the command results. + +### Save + +- Flag: `--save` +- Short Flag: `-s` +- Valid inputs: a path in the current filesystem + +Specify the filename where you want the result to be saved + +### Log + +- Flag: `--log` +- Short Flag: `-l` +- Valid inputs: `none`, `error`, `debug` +- Default: `info` + +Specify the log level. Control how much output you want to see during command execution. + +### Configuration + +- Flag: `--config-path` +- Short Flag: `-f` +- Valid inputs: a path in the current filesystem +- Default: `flow.json` + +Specify the path to the `flow.json` configuration file. +You can use the `-f` flag multiple times to merge +several configuration files. + +### Version Check + +- Flag: `--skip-version-check` +- Default: `false` + +Skip version check during start up to speed up process for slow connections. + + +=== tools/flow-cli/accounts/account-remove-contract.md === +--- +title: Remove a Contract +sidebar_position: 5 +--- +_This feature is only found in the Emulator. You **cannot** remove a contract on Testnet or Mainnet._ + +Remove an existing contract deployed to a Flow account using the Flow CLI. + +```shell +flow accounts remove-contract +``` + +## Example Usage + +```shell +> flow accounts remove-contract FungibleToken + +Contract 'FungibleToken' removed from account '0xf8d6e0586b0a20c7' + +Address 0xf8d6e0586b0a20c7 +Balance 99999999999.70000000 +Keys 1 + +Key 0 Public Key 640a5a359bf3536d15192f18d872d57c98a96cb871b92b70cecb0739c2d5c37b4be12548d3526933c2cda9b0b9c69412f45ffb6b85b6840d8569d969fe84e5b7 + Weight 1000 + Signature Algorithm ECDSA_P256 + Hash Algorithm SHA3_256 + Revoked false + Sequence Number 6 + Index 0 + +Contracts Deployed: 0 +``` +**Testnet Example** +``` +> flow accounts remove-contract FungibleToken --signer alice --network testnet + +Contract 'FungibleToken' removed from account '0xf8d6e0586b0a20c7' + +Address 0xf8d6e0586b0a20c7 +Balance 99999999999.70000000 +Keys 1 + +Key 0 Public Key 640a5a359bf3536d15192f18d872d57c98a96cb871b92b70cecb0739c2d5c37b4be12548d3526933c2cda9b0b9c69412f45ffb6b85b6840d8569d969fe84e5b7 + Weight 1000 + Signature Algorithm ECDSA_P256 + Hash Algorithm SHA3_256 + Revoked false + Sequence Number 6 + Index 0 + +Contracts Deployed: 0 + +``` +*Make sure alice account is defined in flow.json* + +## Arguments + +### Name + +- Name: `name` +- Valid inputs: any string value. + +Name of the contract as it is defined in the contract source code. + +## Flags + +### Signer + +- Flag: `--signer` +- Valid inputs: the name of an account defined in the configuration (`flow.json`). + +Specify the name of the account that will be used to sign the transaction. + +### Include Fields + +- Flag: `--include` +- Valid inputs: `contracts` + +Specify fields to include in the result output. Applies only to the text output. + + +### Host + +- Flag: `--host` +- Valid inputs: an IP address or hostname. +- Default: `127.0.0.1:3569` (Flow Emulator) + +Specify the hostname of the Access API that will be +used to execute the command. This flag overrides +any host defined by the `--network` flag. + +### Network Key + +- Flag: `--network-key` +- Valid inputs: A valid network public key of the host in hex string format + +Specify the network public key of the Access API that will be +used to create a secure GRPC client when executing the command. + +### Network + +- Flag: `--network` +- Short Flag: `-n` +- Valid inputs: the name of a network defined in the configuration (`flow.json`) +- Default: `emulator` + +Specify which network you want the command to use for execution. + +### Filter + +- Flag: `--filter` +- Short Flag: `-x` +- Valid inputs: a case-sensitive name of the result property + +Specify any property name from the result you want to return as the only value. + +### Output + +- Flag: `--output` +- Short Flag: `-o` +- Valid inputs: `json`, `inline` + +Specify the format of the command results. + +### Save + +- Flag: `--save` +- Short Flag: `-s` +- Valid inputs: a path in the current filesystem + +Specify the filename where you want the result to be saved + +### Log + +- Flag: `--log` +- Short Flag: `-l` +- Valid inputs: `none`, `error`, `debug` +- Default: `info` + +Specify the log level. Control how much output you want to see during command execution. + +### Configuration + +- Flag: `--config-path` +- Short Flag: `-f` +- Valid inputs: a path in the current filesystem +- Default: `flow.json` + +Specify the path to the `flow.json` configuration file. +You can use the `-f` flag multiple times to merge +several configuration files. + +### Version Check + +- Flag: `--skip-version-check` +- Default: `false` + +Skip version check during start up to speed up process for slow connections. + + +=== tools/flow-cli/accounts/account-fund.md === +--- +title: Funding a Testnet Account +description: How to fund a Testnet Flow account from the command line +sidebar_position: 7 +--- + +:::info + +The [Flow Testnet Faucet](https://testnet-faucet.onflow.org/) allows users to create accounts and receive 1,000 Testnet FLOW tokens for testing and development purposes. You can also fund an existing Testnet accounts without needing to create one through the site, or through the CLI. + +::: + +Fund a valid Testnet Flow Account using the Flow CLI. + +```shell +flow accounts fund
    +``` + +## Example Usage + +``` +> flow accounts fund 8e94eaa81771313a + +Opening the faucet to fund 0x8e94eaa81771313a on your native browser. + +If there is an issue, please use this link instead: https://testnet-faucet.onflow.org/fund-account?address=8e94eaa81771313a + +``` + +## Arguments + +### Address + +- Name: `address` +- Valid Input: Flow Testnet account address. + +Flow [account address](../../../build/basics/accounts.md) (prefixed with `0x` or not). + + +=== tools/flow-cli/accounts/account-add-contract.md === +--- +title: Deploy a Contract +sidebar_position: 3 +--- + +Deploy a new contract to a Flow account using the Flow CLI. + +```shell +flow accounts add-contract [ ...] [flags] +``` + +⚠️ Deprecation notice: using name argument in adding contract command will be deprecated soon. +```shell +flow accounts add-contract [ ...] [flags] +``` + +## Example Usage + +```shell +> flow accounts add-contract ./FungibleToken.cdc + +Contract 'FungibleToken' deployed to the account 0xf8d6e0586b0a20c7 + +Address 0xf8d6e0586b0a20c7 +Balance 99999999999.70000000 +Keys 1 + +Key 0 Public Key 640a5a359bf3536d15192f18d872d57c98a96cb871b92b70cecb0739c2d5c37b4be12548d3526933c2cda9b0b9c69412f45ffb6b85b6840d8569d969fe84e5b7 + Weight 1000 + Signature Algorithm ECDSA_P256 + Hash Algorithm SHA3_256 + Revoked false + Sequence Number 6 + Index 0 + +Contracts Deployed: 1 +Contract: 'FungibleToken' +``` +**Testnet Example** +``` +> flow accounts add-contract ./FungibleToken.cdc --signer alice --network testnet + +Contract 'FungibleToken' deployed to the account 0xf8d6e0586b0a20c7 + +Address 0xf8d6e0586b0a20c7 +Balance 99999999999.70000000 +Keys 1 + +Key 0 Public Key 640a5a359bf3536d15192f18d872d57c98a96cb871b92b70cecb0739c2d5c37b4be12548d3526933c2cda9b0b9c69412f45ffb6b85b6840d8569d969fe84e5b7 + Weight 1000 + Signature Algorithm ECDSA_P256 + Hash Algorithm SHA3_256 + Revoked false + Sequence Number 6 + Index 0 + +Contracts Deployed: 1 +Contract: 'FungibleToken' +``` +*Make sure alice account is defined in flow.json* + +## Arguments + +### Name + +- Name: `name` +- Valid inputs: any string value. + +Name of the contract as it is defined in the contract source code. + +⚠️ Deprecation notice: use filename argument only, no need to use name argument. + +### Filename + +- Name: `filename` +- Valid inputs: a path in the current filesystem. + +Path to the file containing the contract source code. + +### Arguments +- Name: `argument` +- Valid inputs: valid [cadence values](https://cadencelang.dev/docs/1.0/json-cadence-spec) + matching argument type in transaction code. + +Input arguments values matching corresponding types in the source code and passed in the same order. + +Example: +```shell +> flow accounts add-contract ./contract.cdc Hello 2 +``` +Transaction code: +``` +access(all) contract HelloWorld { + init(a:String, b:Int) { + } +} +``` + +## Flags + +### Signer + +- Flag: `--signer` +- Valid inputs: the name of an account defined in the configuration (`flow.json`) + +Specify the name of the account that will be used to sign the transaction. + +### Arguments JSON + +- Flag: `--args-json` +- Valid inputs: arguments in JSON-Cadence form. +- Example: `flow accounts add-contract ./tx.cdc '[{"type": "String", "value": "Hello"}]'` + +Arguments passed to the Cadence transaction in Cadence JSON format. +Cadence JSON format contains `type` and `value` keys and is +[documented here](https://cadencelang.dev/docs/1.0/json-cadence-spec). + +### Include Fields + +- Flag: `--include` +- Valid inputs: `contracts` + +Specify fields to include in the result output. Applies only to the text output. + + +### Host + +- Flag: `--host` +- Valid inputs: an IP address or hostname. +- Default: `127.0.0.1:3569` (Flow Emulator) + +Specify the hostname of the Access API that will be +used to execute the command. This flag overrides +any host defined by the `--network` flag. + +### Network Key + +- Flag: `--network-key` +- Valid inputs: A valid network public key of the host in hex string format + +Specify the network public key of the Access API that will be +used to create a secure GRPC client when executing the command. + +### Network + +- Flag: `--network` +- Short Flag: `-n` +- Valid inputs: the name of a network defined in the configuration (`flow.json`). +- Default: `emulator` + +Specify which network you want the command to use for execution. + +### Filter + +- Flag: `--filter` +- Short Flag: `-x` +- Valid inputs: a case-sensitive name of the result property. + +Specify any property name from the result you want to return as the only value. + +### Output + +- Flag: `--output` +- Short Flag: `-o` +- Valid inputs: `json`, `inline` + +Specify the format of the command results. + +### Save + +- Flag: `--save` +- Short Flag: `-s` +- Valid inputs: a path in the current filesystem. + +Specify the filename where you want the result to be saved + +### Log + +- Flag: `--log` +- Short Flag: `-l` +- Valid inputs: `none`, `error`, `debug` +- Default: `info` + +Specify the log level. Control how much output you want to see during command execution. + +### Configuration + +- Flag: `--config-path` +- Short Flag: `-f` +- Valid inputs: a path in the current filesystem. +- Default: `flow.json` + +Specify the path to the `flow.json` configuration file. +You can use the `-f` flag multiple times to merge +several configuration files. + +### Version Check + +- Flag: `--skip-version-check` +- Default: `false` + +Skip version check during start up to speed up process for slow connections. + + +=== tools/emulator/index.md === +--- +title: Flow Emulator +description: A development tool that looks, acts and talks like Flow +sidebar_position: 3 +--- + +The Flow Emulator is a lightweight tool that emulates the behaviour of the real Flow network. + +The emulator exposes a gRPC server that implements the Flow Access API, +which is designed to have near feature parity with the real network API. + +## Running the emulator with the Flow CLI + +The emulator is bundled with the [Flow CLI](../../tools/flow-cli/index.md), a command-line interface for working with Flow. + +### Installation + +Follow [these steps](../../tools/flow-cli/install.md) to install the Flow CLI on macOS, Linux, and Windows. + +## Usage + +To learn more about using the Emulator, +have a look at [the README of the repository](https://github.com/onflow/flow-emulator/#starting-the-server). + + +=== tools/clients/index.md === +--- +title: Client Tools +description: Comprehensive guide to Flow's client tools and SDKs, including FCL-JS, Go SDK, and various language-specific implementations for interacting with the Flow blockchain. +sidebar_position: 6 +keywords: + - FCL + - Flow Client Library + - SDKs + - client tools + - JavaScript + - Go + - Python + - Ruby + - JVM + - Swift + - .NET + - Rust + - PHP + - Elixir + - HTTP API + - blockchain + - development + - integration + - wallets + - authentication + - transactions + - cross-vm + - EVM + - Cadence +--- + +# Client Tools + +Flow provides a comprehensive suite of client tools and SDKs designed to help developers build applications that interact with the Flow blockchain. These tools support various programming languages and platforms, offering different levels of abstraction and functionality. + +## JavaScript (FCL) + +[Flow Client Library (FCL)] is the primary JavaScript/TypeScript client for Flow. It provides: + +- Wallet integration and authentication +- Transaction and script execution +- Cross-VM functionality for EVM integration +- TypeScript support +- Built-in security features + +## Go SDK + +[Flow Go SDK] offers a robust set of packages for Go developers, including: + +- High-performance blockchain interaction +- Transaction building and signing +- Account management +- Event subscription +- Comprehensive testing utilities + +## Python SDK + +[Flow Python SDK] provides Python developers with: + +- Simple blockchain interaction +- Transaction management +- Account handling +- Event monitoring +- Easy integration with Python applications + +## Ruby + +[FlowClient] is a Ruby gRPC client that enables: + +- Direct blockchain communication +- Transaction processing +- Account management +- Event handling +- Ruby-native blockchain integration + +## JVM + +[Flow JVM SDK] supports JVM-compatible languages (Java, Kotlin, Scala) with: + +- Kotlin-first implementation +- Transaction management +- Account handling +- Event subscription +- Cross-platform compatibility + +## Swift + +[flow-swift] is designed for iOS development, offering: + +- Native iOS integration +- Wallet connectivity +- Transaction management +- Account handling +- SwiftUI support + +## .NET + +[flow.net] provides .NET developers with: + +- C# and .NET Core support +- Transaction management +- Account handling +- Event monitoring +- Cross-platform compatibility + +## Rust + +[Rust SDK] offers Rust developers: + +- High-performance blockchain interaction +- Type-safe transaction handling +- Account management +- Event subscription +- Memory safety guarantees + +## PHP + +[PHP SDK] enables PHP developers to: + +- Integrate blockchain functionality +- Handle transactions +- Manage accounts +- Monitor events +- Build web applications + +## Elixir + +[OnFlow] provides Elixir developers with: + +- Functional blockchain interaction +- Transaction management +- Account handling +- Event subscription +- Comprehensive documentation + +## HTTP API + +[Flow OpenAPI] specification provides: + +- RESTful API endpoints +- Standardized API documentation +- Language-agnostic integration +- Easy API testing +- Swagger/OpenAPI support + +Each client tool is designed with specific use cases and developer needs in mind. Choose the one that best fits your development environment and requirements. + +[Flow Client Library (FCL)]: ./fcl-js/index.md +[Flow Go SDK]: ./flow-go-sdk/index.md +[Flow Python SDK]: https://github.com/janezpodhostnik/flow-py-sdk +[FlowClient]: https://github.com/glucode/flow_client +[Flow JVM SDK]: https://github.com/onflow/flow-jvm-sdk +[flow-swift]: https://github.com/Outblock/flow-swift +[flow.net]: https://github.com/tyronbrand/flow.net +[Rust SDK]: https://github.com/fee1-dead/flow.rs +[PHP SDK]: https://github.com/mayvenstudios/flow-php-sdk +[OnFlow]: https://github.com/nkezhaya/on_flow +[Flow OpenAPI]: /http-api + + +=== tools/clients/flow-go-sdk/migration-v0.25.0.md === +# Migration Guide v0.25.0 + +The Go SDK version 0.25.0 introduced breaking changes in the API and package naming. +Changes were required to make the implementation of the new HTTP access node API available. + +We will list all the changes and provide examples on how to migrate. + +- **Renamed package: client -> access:** the `client` package was renamed to `access` +which now includes both `grpc` package containing previously only gRPC implementation and +also `http` package containing the new HTTP API implementation. +- **Removed package: convert:** the `convert` package was removed and all its functions were moved +to each of the corresponding `grpc` or `http` packages. The methods were also changed to not be exported, +so you can no longer use them outside the `convert` package. +- **New clients:** new clients were added each implementing the functions from the client interface +and exposing a factory for creating them. +- **New Client Interface**: new client interface was created which is now network agnostic, meaning it +doesn't any more expose additional options in the API that were used to pass gRPC specific options. You can +still pass those options but you must use the network specific client as shown in the example bellow. +The interface also changed some functions: + - `GetCollectionByID` renamed to `GetCollection` + - `Close() error` was added + + +### Migration + +#### Creating a Client +Creating a client for communicating with the access node has changed since it's now possible +to pick and choose between HTTP and gRPC communication protocols. + +*Previous versions:* +```go +// initialize a gRPC emulator client +flowClient, err := client.New("127.0.0.1:3569", grpc.WithInsecure()) +``` + +*Version 0.25.0*: +```go +// common client interface +var flowClient access.Client + +// initialize an http emulator client +flowClient, err := http.NewClient(http.EmulatorHost) + +// initialize a gPRC emulator client +flowClient, err = grpc.NewClient(grpc.EmulatorHost) +``` + +#### Using the gRPC Client with Options +Using the client is in most cases the same except for the advance case of passing additional +options to the gRPC client which is no longer possible in the base client, you must use a +network specific client as shown in the advanced example: + +*Previous versions:* +```go +// initialize a gRPC emulator client +flowClient, err := client.New("127.0.0.1:3569", grpc.WithInsecure()) +latestBlock, err := flowClient.GetLatestBlock(ctx, true, MaxCallSendMsgSize(100)) +``` + +*Version 0.25.0:* +```go +// initialize a grpc network specific client +flowClient, err := NewBaseClient( + grpc.EmulatorHost, + grpc.WithTransportCredentials(insecure.NewCredentials()), +) +latestBlock, err := flowClient.GetLatestBlock(ctx, true, MaxCallSendMsgSize(100)) +``` + + +=== tools/clients/flow-go-sdk/index.md === +--- +title: Flow Go SDK +--- + + +
    + +## Overview + +This reference documents all the methods available in the SDK, and explains in detail how these methods work. +SDKs are open source, and you can use them according to the licence. + +The library client specifications can be found here: + +[](https://pkg.go.dev/github.com/onflow/flow-go-sdk/client) + +## Getting Started + +### Installing + +The recommended way to install Go Flow SDK is by using Go modules. + +If you already initialized your Go project, you can run the following command in your terminal: + +```sh +go get github.com/onflow/flow-go-sdk +``` + +It's usually good practice to pin your dependencies to a specific version. +Refer to the [SDK releases](https://github.com/onflow/flow-go-sdk/tags) page to identify the latest version. + +### Importing the Library + +After the library has been installed you can import it. + +```go +import "github.com/onflow/flow-go-sdk" +``` + +## Connect + +[](https://pkg.go.dev/github.com/onflow/flow-go-sdk/client#New) + +The Go SDK library uses HTTP or gRPC APIs to communicate with the access nodes and it must be configured with correct access node API URL. +The library provides default factories for connecting to Flow AN APIs and you can easily switch between HTTP or gRPC if you use the provided client interface. + +You can check more examples for creating clients in the examples: +**[](https://github.com/onflow/flow-go-sdk/blob/master/examples/http_grpc_clients/main.go)** + +Basic Example: + +```go +// common client interface +var flowClient client.Client + +// initialize an http emulator client +flowClient, err := http.NewClient(http.EmulatorHost) + +// initialize a gPRC emulator client +flowClient, err = grpc.NewClient(grpc.EmulatorHost) +``` + +You can also initialize an HTTP client or gRPC client directly which will offer you access to network specific options, +but be aware you won't be able to easily switch between those since they don't implement a common interface. This is only +advisable if the implementation needs the access to those advanced options. +Advanced Example: + +```go +// initialize http specific client +httpClient, err := http.NewHTTPClient(http.EMULATOR_URL) + +// initialize grpc specific client +grpcClient, err := grpc.NewGRPCClient( + grpc.EMULATOR_URL, + grpcOpts.WithTransportCredentials(insecure.NewCredentials()), +) +``` + +## Querying the Flow Network + +After you have established a connection with an access node, you can query the +Flow network to retrieve data about blocks, accounts, events and transactions. We will explore +how to retrieve each of these entities in the sections below. + +### Get Blocks + +[](https://pkg.go.dev/github.com/onflow/flow-go-sdk/client#Client.GetBlockByHeight) + +Query the network for block by id, height or get the latest block. + +📖 **Block ID** is SHA3-256 hash of the entire block payload. This hash is stored as an ID field on any block response object (ie. response from `GetLatestBlock`). + +📖 **Block height** expresses the height of the block on the chain. The latest block height increases by one for every valid block produced. + +#### Examples + +This example depicts ways to get the latest block as well as any other block by height or ID: + +**[](https://github.com/onflow/flow-go-sdk/blob/master/examples/get_blocks/main.go)** + +```go +func demo() { + ctx := context.Background() + flowClient := examples.NewFlowClient() + + // get the latest sealed block + isSealed := true + latestBlock, err := flowClient.GetLatestBlock(ctx, isSealed) + printBlock(latestBlock, err) + + // get the block by ID + blockID := latestBlock.ID.String() + blockByID, err := flowClient.GetBlockByID(ctx, flow.HexToID(blockID)) + printBlock(blockByID, err) + + // get block by height + blockByHeight, err := flowClient.GetBlockByHeight(ctx, 0) + printBlock(blockByHeight, err) +} + +func printBlock(block *flow.Block, err error) { + examples.Handle(err) + + fmt.Printf("\nID: %s\n", block.ID) + fmt.Printf("height: %d\n", block.Height) + fmt.Printf("timestamp: %s\n\n", block.Timestamp) +} +``` + +Result output: + +```bash +ID: 835dc83939141097aa4297aa6cf69fc600863e3b5f9241a0d7feac1868adfa4f +height: 10 +timestamp: 2021-10-06 15:06:07.105382 +0000 UTC + + +ID: 835dc83939141097aa4297aa6cf69fc600863e3b5f9241a0d7feac1868adfa4f +height: 10 +timestamp: 2021-10-06 15:06:07.105382 +0000 UTC + + +ID: 7bc42fe85d32ca513769a74f97f7e1a7bad6c9407f0d934c2aa645ef9cf613c7 +height: 0 +timestamp: 2018-12-19 22:32:30.000000042 +0000 UTC +``` + +### Get Account + +[](https://pkg.go.dev/github.com/onflow/flow-go-sdk/client#Client.GetAccount) + +Retrieve any account from Flow network's latest block or from a specified block height. +The `GetAccount` method is actually an alias for the get account at latest block method. + +📖 **Account address** is a unique account identifier. Be mindful about the `0x` prefix, you should use the prefix as a default representation but be careful and safely handle user inputs without the prefix. + +An account includes the following data: + +- Address: the account address. +- Balance: balance of the account. +- Contracts: list of contracts deployed to the account. +- Keys: list of keys associated with the account. + +#### Examples + +Example depicts ways to get an account at the latest block and at a specific block height: + +**[](https://github.com/onflow/flow-go-sdk/blob/master/examples/get_accounts/main.go)** + +```go +func demo() { + ctx := context.Background() + flowClient := examples.NewFlowClient() + + // get account from the latest block + address := flow.HexToAddress("f8d6e0586b0a20c7") + account, err := flowClient.GetAccount(ctx, address) + printAccount(account, err) + + // get account from the block by height 0 + account, err = flowClient.GetAccountAtBlockHeight(ctx, address, 0) + printAccount(account, err) +} + +func printAccount(account *flow.Account, err error) { + examples.Handle(err) + + fmt.Printf("\nAddress: %s", account.Address.String()) + fmt.Printf("\nBalance: %d", account.Balance) + fmt.Printf("\nContracts: %d", len(account.Contracts)) + fmt.Printf("\nKeys: %d\n", len(account.Keys)) +} +``` + +Result output: + +```bash +Address: f8d6e0586b0a20c7 +Balance: 999999999999600000 +Contracts: 2 +Keys: 1 + +Address: f8d6e0586b0a20c7 +Balance: 999999999999600000 +Contracts: 2 +Keys: 1 +``` + +### Get Transactions + +[](https://pkg.go.dev/github.com/onflow/flow-go-sdk/client#Client.GetTransaction) + +Retrieve transactions from the network by providing a transaction ID. After a transaction has been submitted, you can also get the transaction result to check the status. + +📖 **Transaction ID** is a hash of the encoded transaction payload and can be calculated before submitting the transaction to the network. + +⚠️ The transaction ID provided must be from the current spork. + +📖 **Transaction status** represents the state of transaction in the blockchain. Status can change until it is sealed. + +| Status | Final | Description | +| --------- | ----- | ------------------------------------------------------------------------ | +| UNKNOWN | ❌ | The transaction has not yet been seen by the network | +| PENDING | ❌ | The transaction has not yet been included in a block | +| FINALIZED | ❌ | The transaction has been included in a block | +| EXECUTED | ❌ | The transaction has been executed but the result has not yet been sealed | +| SEALED | ✅ | The transaction has been executed and the result is sealed in a block | +| EXPIRED | ✅ | The transaction reference block is outdated before being executed | + +**[](https://github.com/onflow/flow-go-sdk/blob/master/examples/get_transactions/main.go)** + +```go +func demo(txID flow.Identifier) { + ctx := context.Background() + flowClient := examples.NewFlowClient() + + tx, err := flowClient.GetTransaction(ctx, txID) + printTransaction(tx, err) + + txr, err := flowClient.GetTransactionResult(ctx, txID) + printTransactionResult(txr, err) +} + +func printTransaction(tx *flow.Transaction, err error) { + examples.Handle(err) + + fmt.Printf("\nID: %s", tx.ID().String()) + fmt.Printf("\nPayer: %s", tx.Payer.String()) + fmt.Printf("\nProposer: %s", tx.ProposalKey.Address.String()) + fmt.Printf("\nAuthorizers: %s", tx.Authorizers) +} + +func printTransactionResult(txr *flow.TransactionResult, err error) { + examples.Handle(err) + + fmt.Printf("\nStatus: %s", txr.Status.String()) + fmt.Printf("\nError: %v", txr.Error) +} +``` + +Example output: + +```bash +ID: fb1272c57cdad79acf2fcf37576d82bf760e3008de66aa32a900c8cd16174e1c +Payer: f8d6e0586b0a20c7 +Proposer: f8d6e0586b0a20c7 +Authorizers: [] +Status: SEALED +Error: +``` + +### Get Events + +[](https://pkg.go.dev/github.com/onflow/flow-go-sdk/client#Client.GetEventsForBlockIDs) + +Retrieve events by a given type in a specified block height range or through a list of block IDs. + +📖 **Event type** is a string that follow a standard format: + +``` +A.{contract address}.{contract name}.{event name} +``` + +Please read more about [events in the documentation](../../../build/core-contracts/03-flow-token.md). The exception to this standard are +core events, and you should read more about them in [this document](https://cadence-lang.org/docs/language/core-events). + +📖 **Block height range** expresses the height of the start and end block in the chain. + +#### Examples + +Example depicts ways to get events within block range or by block IDs: + +**[](https://github.com/onflow/flow-go-sdk/blob/master/examples/get_events/main.go)** + +```go +func demo(deployedContract *flow.Account, runScriptTx *flow.Transaction) { + ctx := context.Background() + flowClient := examples.NewFlowClient() + + // Query for account creation events by type + result, err := flowClient.GetEventsForHeightRange(ctx, "flow.AccountCreated", 0, 30) + printEvents(result, err) + + // Query for our custom event by type + customType := fmt.Sprintf("AC.%s.EventDemo.EventDemo.Add", deployedContract.Address.Hex()) + result, err = flowClient.GetEventsForHeightRange(ctx, customType, 0, 10) + printEvents(result, err) + + // Get events directly from transaction result + txResult, err := flowClient.GetTransactionResult(ctx, runScriptTx.ID()) + examples.Handle(err) + printEvent(txResult.Events) +} + +func printEvents(result []client.BlockEvents, err error) { + examples.Handle(err) + + for _, block := range result { + printEvent(block.Events) + } +} + +func printEvent(events []flow.Event) { + for _, event := range events { + fmt.Printf("\n\nType: %s", event.Type) + fmt.Printf("\nValues: %v", event.Value) + fmt.Printf("\nTransaction ID: %s", event.TransactionID) + } +} +``` + +Example output: + +```bash +Type: flow.AccountCreated +Values: flow.AccountCreated(address: 0xfd43f9148d4b725d) +Transaction ID: ba9d53c8dcb0f9c2f854f93da8467a22d053eab0c540bde0b9ca2f7ad95eb78e + +Type: flow.AccountCreated +Values: flow.AccountCreated(address: 0xeb179c27144f783c) +Transaction ID: 8ab7bfef3de1cf8b2ffb36559446100bf4129a9aa88d6bc59f72a467acf0c801 + +... + +Type: A.eb179c27144f783c.EventDemo.Add +Values: A.eb179c27144f783c.EventDemo.Add(x: 2, y: 3, sum: 5) +Transaction ID: f3a2e33687ad23b0e02644ebbdcd74a7cd8ea7214065410a8007811d0bcbd353 +``` + +### Get Collections + +[](https://pkg.go.dev/github.com/onflow/flow-go-sdk/client#Client.GetCollection) + +Retrieve a batch of transactions that have been included in the same block, known as **_collections_**. +Collections are used to improve consensus throughput by increasing the number of transactions per block and they act as a link between a block and a transaction. + +📖 **Collection ID** is SHA3-256 hash of the collection payload. + +Example retrieving a collection: + +```go +func demo(exampleCollectionID flow.Identifier) { + ctx := context.Background() + flowClient := examples.NewFlowClient() + + // get collection by ID + collection, err := flowClient.GetCollection(ctx, exampleCollectionID) + printCollection(collection, err) +} + +func printCollection(collection *flow.Collection, err error) { + examples.Handle(err) + + fmt.Printf("\nID: %s", collection.ID().String()) + fmt.Printf("\nTransactions: %s", collection.TransactionIDs) +} +``` + +Example output: + +```bash +ID: 3d7b8037381f2497d83f2f9e09422c036aae2a59d01a7693fb6003b4d0bc3595 +Transactions: [cf1184e3de4bd9a7232ca3d0b9dd2cfbf96c97888298b81a05c086451fa52ec1] +``` + +### Execute Scripts + +[](https://pkg.go.dev/github.com/onflow/flow-go-sdk/client#Client.ExecuteScriptAtLatestBlock) + +Scripts allow you to write arbitrary non-mutating Cadence code on the Flow blockchain and return data. You can learn more about [Cadence and scripts here](https://cadence-lang.org/docs/language), but we are now only interested in executing the script code and getting back the data. + +We can execute a script using the latest state of the Flow blockchain or we can choose to execute the script at a specific time in history defined by a block height or block ID. + +📖 **Block ID** is SHA3-256 hash of the entire block payload, but you can get that value from the block response properties. + +📖 **Block height** expresses the height of the block in the chain. + +**[](https://github.com/onflow/flow-go-sdk/blob/master/examples/execute_script/main.go)** + +```go +func demo() { + ctx := context.Background() + flowClient := examples.NewFlowClient() + + script := []byte(` + access(all) fun main(a: Int): Int { + return a + 10 + } + `) + args := []cadence.Value{ cadence.NewInt(5) } + value, err := flowClient.ExecuteScriptAtLatestBlock(ctx, script, args) + + examples.Handle(err) + fmt.Printf("\nValue: %s", value.String()) + + complexScript := []byte(` + access(all) struct User { + access(all) var balance: UFix64 + access(all) var address: Address + access(all) var name: String + + init(name: String, address: Address, balance: UFix64) { + self.name = name + self.address = address + self.balance = balance + } + } + + access(all) fun main(name: String): User { + return User( + name: name, + address: 0x1, + balance: 10.0 + ) + } + `) + args = []cadence.Value{ cadence.NewString("Dete") } + value, err = flowClient.ExecuteScriptAtLatestBlock(ctx, complexScript, args) + printComplexScript(value, err) +} + +type User struct { + balance uint64 + address flow.Address + name string +} + +func printComplexScript(value cadence.Value, err error) { + examples.Handle(err) + fmt.Printf("\nString value: %s", value.String()) + + s := value.(cadence.Struct) + u := User{ + balance: s.Fields[0].ToGoValue().(uint64), + address: s.Fields[1].ToGoValue().([flow.AddressLength]byte), + name: s.Fields[2].ToGoValue().(string), + } + + fmt.Printf("\nName: %s", u.name) + fmt.Printf("\nAddress: %s", u.address.String()) + fmt.Printf("\nBalance: %d", u.balance) +} +``` + +Example output: + +```bash +Value: 15 +String value: s.34a17571e1505cf6770e6ef16ca387e345e9d54d71909f23a7ec0d671cd2faf5.User(balance: 10.00000000, address: 0x1, name: "Dete") +Name: Dete +Address: 0000000000000001 +Balance: 1000000000 +``` + +## Mutate Flow Network + +Flow, like most blockchains, allows anybody to submit a transaction that mutates the shared global chain state. A transaction is an object that holds a payload, which describes the state mutation, and one or more authorizations that permit the transaction to mutate the state owned by specific accounts. + +Transaction data is composed and signed with help of the SDK. The signed payload of transaction then gets submitted to the access node API. If a transaction is invalid or the correct number of authorizing signatures are not provided, it gets rejected. + +Executing a transaction requires couple of steps: + +- [Building transaction](#build-the-transaction). +- [Signing transaction](#sign-transactions). +- [Sending transaction](#send-transactions). + +## Transactions + +A transaction is nothing more than a signed set of data that includes script code which are instructions on how to mutate the network state and properties that define and limit it's execution. All these properties are explained bellow. + +📖 **Script** field is the portion of the transaction that describes the state mutation logic. On Flow, transaction logic is written in [Cadence](https://cadence-lang.org/docs). Here is an example transaction script: + +``` +transaction(greeting: String) { + execute { + log(greeting.concat(", World!")) + } +} +``` + +📖 **Arguments**. A transaction can accept zero or more arguments that are passed into the Cadence script. The arguments on the transaction must match the number and order declared in the Cadence script. Sample script from above accepts a single `String` argument. + +📖 **[Proposal key](../../../build/basics/transactions.md#proposal-key)** must be provided to act as a sequence number and prevent reply and other potential attacks. + +Each account key maintains a separate transaction sequence counter; the key that lends its sequence number to a transaction is called the proposal key. + +A proposal key contains three fields: + +- Account address +- Key index +- Sequence number + +A transaction is only valid if its declared sequence number matches the current on-chain sequence number for that key. The sequence number increments by one after the transaction is executed. + +📖 **[Payer](../../../build/basics/transactions.md#signer-roles)** is the account that pays the fees for the transaction. A transaction must specify exactly one payer. The payer is only responsible for paying the network and gas fees; the transaction is not authorized to access resources or code stored in the payer account. + +📖 **[Authorizers](../../../build/basics/transactions.md#signer-roles)** are accounts that authorize a transaction to read and mutate their resources. A transaction can specify zero or more authorizers, depending on how many accounts the transaction needs to access. + +The number of authorizers on the transaction must match the number of &Account parameters declared in the prepare statement of the Cadence script. + +Example transaction with multiple authorizers: + +``` +transaction { + prepare(authorizer1: &Account, authorizer2: &Account) { } +} +``` + +#### Gas Limit + +📖 **Gas limit** is the limit on the amount of computation a transaction requires, and it will abort if it exceeds its gas limit. +Cadence uses metering to measure the number of operations per transaction. You can read more about it in the [Cadence documentation](https://cadence-lang.org/docs). + +The gas limit depends on the complexity of the transaction script. Until dedicated gas estimation tooling exists, it's best to use the emulator to test complex transactions and determine a safe limit. + +#### Reference Block + +📖 **Reference block** specifies an expiration window (measured in blocks) during which a transaction is considered valid by the network. +A transaction will be rejected if it is submitted past its expiry block. Flow calculates transaction expiry using the _reference block_ field on a transaction. +A transaction expires after `600` blocks are committed on top of the reference block, which takes about 10 minutes at average Mainnet block rates. + +### Build Transactions + +[](https://pkg.go.dev/github.com/onflow/flow-go-sdk#Transaction) + +Building a transaction involves setting the required properties explained above and producing a transaction object. + +Here we define a simple transaction script that will be used to execute on the network and serve as a good learning example. + +``` +transaction(greeting: String) { + + let guest: Address + + prepare(authorizer: &Account) { + self.guest = authorizer.address + } + + execute { + log(greeting.concat(",").concat(self.guest.toString())) + } +} +``` + +**[](https://github.com/onflow/flow-go-sdk/blob/master/examples/transaction_signing/single_party/main.go)** + +```go +import ( + "context" + "os" + "github.com/onflow/flow-go-sdk" + "github.com/onflow/flow-go-sdk/client" +) + +func main() { + + greeting, err := os.ReadFile("Greeting2.cdc") + if err != nil { + panic("failed to load Cadence script") + } + + proposerAddress := flow.HexToAddress("9a0766d93b6608b7") + proposerKeyIndex := 3 + + payerAddress := flow.HexToAddress("631e88ae7f1d7c20") + authorizerAddress := flow.HexToAddress("7aad92e5a0715d21") + + var accessAPIHost string + + // Establish a connection with an access node + flowClient := examples.NewFlowClient() + + // Get the latest sealed block to use as a reference block + latestBlock, err := flowClient.GetLatestBlockHeader(context.Background(), true) + if err != nil { + panic("failed to fetch latest block") + } + + // Get the latest account info for this address + proposerAccount, err := flowClient.GetAccountAtLatestBlock(context.Background(), proposerAddress) + if err != nil { + panic("failed to fetch proposer account") + } + + // Get the latest sequence number for this key + sequenceNumber := proposerAccount.Keys[proposerKeyIndex].SequenceNumber + + tx := flow.NewTransaction(). + SetScript(greeting). + SetComputeLimit(100). + SetReferenceBlockID(latestBlock.ID). + SetProposalKey(proposerAddress, proposerKeyIndex, sequenceNumber). + SetPayer(payerAddress). + AddAuthorizer(authorizerAddress) + + // Add arguments last + + hello := cadence.NewString("Hello") + + err = tx.AddArgument(hello) + if err != nil { + panic("invalid argument") + } +} +``` + +After you have successfully [built a transaction](#build-the-transaction) the next step in the process is to sign it. + +### Sign Transactions + +[](https://pkg.go.dev/github.com/onflow/flow-go-sdk#Transaction.SignEnvelope) + +Flow introduces new concepts that allow for more flexibility when creating and signing transactions. +Before trying the examples below, we recommend that you read through the [transaction signature documentation](../../../build/basics/transactions.md. + +After you have successfully [built a transaction](#build-the-transaction) the next step in the process is to sign it. Flow transactions have envelope and payload signatures, and you should learn about each in the [signature documentation](../../../build/basics/transactions.md). + +Quick example of building a transaction: + +```go +import ( + "github.com/onflow/flow-go-sdk" + "github.com/onflow/flow-go-sdk/crypto" +) + +var ( + myAddress flow.Address + myAccountKey flow.AccountKey + myPrivateKey crypto.PrivateKey +) + +tx := flow.NewTransaction(). + SetScript([]byte("transaction { execute { log(\"Hello, World!\") } }")). + SetComputeLimit(100). + SetProposalKey(myAddress, myAccountKey.Index, myAccountKey.SequenceNumber). + SetPayer(myAddress) +``` + +Transaction signing is done through the `crypto.Signer` interface. The simplest (and least secure) implementation of `crypto.Signer` is `crypto.InMemorySigner`. + +Signatures can be generated more securely using keys stored in a hardware device such as an [HSM](https://en.wikipedia.org/wiki/Hardware_security_module). The `crypto.Signer` interface is intended to be flexible enough to support a variety of signer implementations and is not limited to in-memory implementations. + +Simple signature example: + +```go +// construct a signer from your private key and configured hash algorithm +mySigner, err := crypto.NewInMemorySigner(myPrivateKey, myAccountKey.HashAlgo) +if err != nil { + panic("failed to create a signer") +} + +err = tx.SignEnvelope(myAddress, myAccountKey.Index, mySigner) +if err != nil { + panic("failed to sign transaction") +} +``` + +Flow supports great flexibility when it comes to transaction signing, we can define multiple authorizers (multi-sig transactions) and have different payer account than proposer. We will explore advanced signing scenarios bellow. + +### [Single party, single signature](../../../build/basics/transactions.md#single-party-single-signature) + +- Proposer, payer and authorizer are the same account (`0x01`). +- Only the envelope must be signed. +- Proposal key must have full signing weight. + +| Account | Key ID | Weight | +| ------- | ------ | ------ | +| `0x01` | 1 | 1000 | + +**[](https://github.com/onflow/flow-go-sdk/tree/master/examples#single-party-single-signature)** + +```go +account1, _ := c.GetAccount(ctx, flow.HexToAddress("01")) + +key1 := account1.Keys[0] + +// create signer from securely-stored private key +key1Signer := getSignerForKey1() + +referenceBlock, _ := flow.GetLatestBlock(ctx, true) +tx := flow.NewTransaction(). + SetScript([]byte(` + transaction { + prepare(signer: &Account) { log(signer.address) } + } + `)). + SetComputeLimit(100). + SetProposalKey(account1.Address, key1.Index, key1.SequenceNumber). + SetReferenceBlockID(referenceBlock.ID). + SetPayer(account1.Address). + AddAuthorizer(account1.Address) + +// account 1 signs the envelope with key 1 +err := tx.SignEnvelope(account1.Address, key1.Index, key1Signer) +``` + +### [Single party, multiple signatures](../../../build/basics/transactions.md#single-party-multiple-signatures) + +- Proposer, payer and authorizer are the same account (`0x01`). +- Only the envelope must be signed. +- Each key has weight 500, so two signatures are required. + +| Account | Key ID | Weight | +| ------- | ------ | ------ | +| `0x01` | 1 | 500 | +| `0x01` | 2 | 500 | + +**[](https://github.com/onflow/flow-go-sdk/tree/master/examples#single-party-multiple-signatures)** + +```go +account1, _ := c.GetAccount(ctx, flow.HexToAddress("01")) + +key1 := account1.Keys[0] +key2 := account1.Keys[1] + +// create signers from securely-stored private keys +key1Signer := getSignerForKey1() +key2Signer := getSignerForKey2() + +referenceBlock, _ := flow.GetLatestBlock(ctx, true) +tx := flow.NewTransaction(). + SetScript([]byte(` + transaction { + prepare(signer: &Account) { log(signer.address) } + } + `)). + SetComputeLimit(100). + SetProposalKey(account1.Address, key1.Index, key1.SequenceNumber). + SetReferenceBlockID(referenceBlock.ID). + SetPayer(account1.Address). + AddAuthorizer(account1.Address) + +// account 1 signs the envelope with key 1 +err := tx.SignEnvelope(account1.Address, key1.Index, key1Signer) + +// account 1 signs the envelope with key 2 +err = tx.SignEnvelope(account1.Address, key2.Index, key2Signer) +``` + +### [Multiple parties](../../../build/basics/transactions.md#multiple-parties) + +- Proposer and authorizer are the same account (`0x01`). +- Payer is a separate account (`0x02`). +- Account `0x01` signs the payload. +- Account `0x02` signs the envelope. + - Account `0x02` must sign last since it is the payer. + +| Account | Key ID | Weight | +| ------- | ------ | ------ | +| `0x01` | 1 | 1000 | +| `0x02` | 3 | 1000 | + +**[](https://github.com/onflow/flow-go-sdk/tree/master/examples#multiple-parties)** + +```go +account1, _ := c.GetAccount(ctx, flow.HexToAddress("01")) +account2, _ := c.GetAccount(ctx, flow.HexToAddress("02")) + +key1 := account1.Keys[0] +key3 := account2.Keys[0] + +// create signers from securely-stored private keys +key1Signer := getSignerForKey1() +key3Signer := getSignerForKey3() + +referenceBlock, _ := flow.GetLatestBlock(ctx, true) +tx := flow.NewTransaction(). + SetScript([]byte(` + transaction { + prepare(signer: &Account) { log(signer.address) } + } + `)). + SetComputeLimit(100). + SetProposalKey(account1.Address, key1.Index, key1.SequenceNumber). + SetReferenceBlockID(referenceBlock.ID). + SetPayer(account2.Address). + AddAuthorizer(account1.Address) + +// account 1 signs the payload with key 1 +err := tx.SignPayload(account1.Address, key1.Index, key1Signer) + +// account 2 signs the envelope with key 3 +// note: payer always signs last +err = tx.SignEnvelope(account2.Address, key3.Index, key3Signer) +``` + +### [Multiple parties, two authorizers](../../../build/basics/transactions.md#multiple-parties) + +- Proposer and authorizer are the same account (`0x01`). +- Payer is a separate account (`0x02`). +- Account `0x01` signs the payload. +- Account `0x02` signs the envelope. + - Account `0x02` must sign last since it is the payer. +- Account `0x02` is also an authorizer to show how to include two `&Account` objects into an transaction + +| Account | Key ID | Weight | +| ------- | ------ | ------ | +| `0x01` | 1 | 1000 | +| `0x02` | 3 | 1000 | + +**[](https://github.com/onflow/flow-go-sdk/tree/master/examples#multiple-parties-two-authorizers)** + +```go +account1, _ := c.GetAccount(ctx, flow.HexToAddress("01")) +account2, _ := c.GetAccount(ctx, flow.HexToAddress("02")) + +key1 := account1.Keys[0] +key3 := account2.Keys[0] + +// create signers from securely-stored private keys +key1Signer := getSignerForKey1() +key3Signer := getSignerForKey3() + +referenceBlock, _ := flow.GetLatestBlock(ctx, true) +tx := flow.NewTransaction(). + SetScript([]byte(` + transaction { + prepare(signer1: &Account, signer2: &Account) { + log(signer.address) + log(signer2.address) + } + } + `)). + SetComputeLimit(100). + SetProposalKey(account1.Address, key1.Index, key1.SequenceNumber). + SetReferenceBlockID(referenceBlock.ID). + SetPayer(account2.Address). + AddAuthorizer(account1.Address). + AddAuthorizer(account2.Address) + +// account 1 signs the payload with key 1 +err := tx.SignPayload(account1.Address, key1.Index, key1Signer) + +// account 2 signs the envelope with key 3 +// note: payer always signs last +err = tx.SignEnvelope(account2.Address, key3.Index, key3Signer) +``` + +### [Multiple parties, multiple signatures](../../../build/basics/transactions.md#multiple-parties) + +- Proposer and authorizer are the same account (`0x01`). +- Payer is a separate account (`0x02`). +- Account `0x01` signs the payload. +- Account `0x02` signs the envelope. + - Account `0x02` must sign last since it is the payer. +- Both accounts must sign twice (once with each of their keys). + +| Account | Key ID | Weight | +| ------- | ------ | ------ | +| `0x01` | 1 | 500 | +| `0x01` | 2 | 500 | +| `0x02` | 3 | 500 | +| `0x02` | 4 | 500 | + +**[](https://github.com/onflow/flow-go-sdk/tree/master/examples#multiple-parties-multiple-signatures)** + +```go +account1, _ := c.GetAccount(ctx, flow.HexToAddress("01")) +account2, _ := c.GetAccount(ctx, flow.HexToAddress("02")) + +key1 := account1.Keys[0] +key2 := account1.Keys[1] +key3 := account2.Keys[0] +key4 := account2.Keys[1] + +// create signers from securely-stored private keys +key1Signer := getSignerForKey1() +key2Signer := getSignerForKey1() +key3Signer := getSignerForKey3() +key4Signer := getSignerForKey4() + +referenceBlock, _ := flow.GetLatestBlock(ctx, true) +tx := flow.NewTransaction(). + SetScript([]byte(` + transaction { + prepare(signer: &Account) { log(signer.address) } + } + `)). + SetComputeLimit(100). + SetProposalKey(account1.Address, key1.Index, key1.SequenceNumber). + SetReferenceBlockID(referenceBlock.ID). + SetPayer(account2.Address). + AddAuthorizer(account1.Address) + +// account 1 signs the payload with key 1 +err := tx.SignPayload(account1.Address, key1.Index, key1Signer) + +// account 1 signs the payload with key 2 +err = tx.SignPayload(account1.Address, key2.Index, key2Signer) + +// account 2 signs the envelope with key 3 +// note: payer always signs last +err = tx.SignEnvelope(account2.Address, key3.Index, key3Signer) + +// account 2 signs the envelope with key 4 +// note: payer always signs last +err = tx.SignEnvelope(account2.Address, key4.Index, key4Signer) +``` + +### Send Transactions + +[](https://pkg.go.dev/github.com/onflow/flow-go-sdk/client#Client.SendTransaction) + +After a transaction has been [built](#build-the-transaction) and [signed](#sign-transactions), it can be sent to the Flow blockchain where it will be executed. If sending was successful you can then [retrieve the transaction result](#get-transactions). + +**[](https://github.com/onflow/flow-go-sdk/blob/master/examples/send_transactions/main.go)** + +```go +func demo(tx *flow.Transaction) { + ctx := context.Background() + flowClient := examples.NewFlowClient() + + err := flowClient.SendTransaction(ctx, *tx) + if err != nil { + fmt.Println("error sending transaction", err) + } +} +``` + +### Create Accounts + +[](https://pkg.go.dev/github.com/onflow/flow-go-sdk/templates#CreateAccount) + +On Flow, account creation happens inside a transaction. Because the network allows for a many-to-many relationship between public keys and accounts, it's not possible to derive a new account address from a public key offline. + +The Flow VM uses a deterministic address generation algorithm to assign account addresses on chain. You can find more details about address generation in the [accounts & keys documentation](../../../build/basics/accounts.md). + +#### Public Key + +Flow uses ECDSA key pairs to control access to user accounts. Each key pair can be used in combination with the SHA2-256 or SHA3-256 hashing algorithms. + +⚠️ You'll need to authorize at least one public key to control your new account. + +Flow represents ECDSA public keys in raw form without additional metadata. Each key is a single byte slice containing a concatenation of its X and Y components in big-endian byte form. + +A Flow account can contain zero (not possible to control) or more public keys, referred to as account keys. Read more about [accounts in the documentation](../../../build/basics/accounts.md). + +An account key contains the following data: + +- Raw public key (described above) +- Signature algorithm +- Hash algorithm +- Weight (integer between 0-1000) + +Account creation happens inside a transaction, which means that somebody must pay to submit that transaction to the network. We'll call this person the account creator. Make sure you have read [sending a transaction section](#send-transactions) first. + +```go +var ( + creatorAddress flow.Address + creatorAccountKey *flow.AccountKey + creatorSigner crypto.Signer +) + +var accessAPIHost string + +// Establish a connection with an access node +flowClient := examples.NewFlowClient() + +// Use the templates package to create a new account creation transaction +tx := templates.CreateAccount([]*flow.AccountKey{accountKey}, nil, creatorAddress) + +// Set the transaction payer and proposal key +tx.SetPayer(creatorAddress) +tx.SetProposalKey( + creatorAddress, + creatorAccountKey.Index, + creatorAccountKey.SequenceNumber, +) + +// Get the latest sealed block to use as a reference block +latestBlock, err := flowClient.GetLatestBlockHeader(context.Background(), true) +if err != nil { + panic("failed to fetch latest block") +} + +tx.SetReferenceBlockID(latestBlock.ID) + +// Sign and submit the transaction +err = tx.SignEnvelope(creatorAddress, creatorAccountKey.Index, creatorSigner) +if err != nil { + panic("failed to sign transaction envelope") +} + +err = flowClient.SendTransaction(context.Background(), *tx) +if err != nil { + panic("failed to send transaction to network") +} +``` + +After the account creation transaction has been submitted you can retrieve the new account address by [getting the transaction result](#get-transactions). + +The new account address will be emitted in a system-level `flow.AccountCreated` event. + +```go +result, err := flowClient.GetTransactionResult(ctx, tx.ID()) +if err != nil { + panic("failed to get transaction result") +} + +var newAddress flow.Address + +if result.Status != flow.TransactionStatusSealed { + panic("address not known until transaction is sealed") +} + +for _, event := range result.Events { + if event.Type == flow.EventAccountCreated { + newAddress = flow.AccountCreatedEvent(event).Address() + break + } +} +``` + +### Generate Keys + +[](../../../build/basics/accounts.md#signature-and-hash-algorithms) + +Flow uses [ECDSA](https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm) signatures to control access to user accounts. Each key pair can be used in combination with the `SHA2-256` or `SHA3-256` hashing algorithms. + +Here's how to generate an ECDSA private key for the P-256 (secp256r1) curve. + +```go +import "github.com/onflow/flow-go-sdk/crypto" + +// deterministic seed phrase +// note: this is only an example, please use a secure random generator for the key seed +seed := []byte("elephant ears space cowboy octopus rodeo potato cannon pineapple") + +privateKey, err := crypto.GeneratePrivateKey(crypto.ECDSA_P256, seed) + +// the private key can then be encoded as bytes (i.e. for storage) +encPrivateKey := privateKey.Encode() +// the private key has an accompanying public key +publicKey := privateKey.PublicKey() +``` + +The example above uses an ECDSA key pair on the P-256 (secp256r1) elliptic curve. Flow also supports the secp256k1 curve used by Bitcoin and Ethereum. Read more about [supported algorithms here](../../../build/basics/accounts.md#signature-and-hash-algorithms). + +### Transfering Flow + +This is an example of how to construct a FLOW token transfer transaction +with the Flow Go SDK. + +## Cadence Script + +The following Cadence script will transfer FLOW tokens from a sender +to a recipient. + +_Note: this transaction is only compatible with Flow Mainnet._ + +```cadence +// This transaction is a template for a transaction that +// could be used by anyone to send tokens to another account +// that has been set up to receive tokens. +// +// The withdraw amount and the account from getAccount +// would be the parameters to the transaction + +import "FungibleToken" +import "FlowToken" + +transaction(amount: UFix64, to: Address) { + + // The Vault resource that holds the tokens that are being transferred + let sentVault: @{FungibleToken.Vault} + + prepare(signer: auth(BorrowValue) &Account) { + + // Get a reference to the signer's stored vault + let vaultRef = signer.storage.borrow(from: /storage/flowTokenVault) + ?? panic("Could not borrow reference to the owner's Vault!") + + // Withdraw tokens from the signer's stored vault + self.sentVault <- vaultRef.withdraw(amount: amount) + } + + execute { + + // Get a reference to the recipient's Receiver + let receiverRef = getAccount(to) + .capabilities.borrow<&{FungibleToken.Receiver}>(/public/flowTokenReceiver) + ?? panic("Could not borrow receiver reference to the recipient's Vault") + + // Deposit the withdrawn tokens in the recipient's receiver + receiverRef.deposit(from: <-self.sentVault) + } +} +``` + +## Build the Transaction + +```go +import ( + "github.com/onflow/cadence" + "github.com/onflow/flow-go-sdk" +) + +// Replace with script above +const transferScript string = TOKEN_TRANSFER_CADENCE_SCRIPT + +var ( + senderAddress flow.Address + senderAccountKey flow.AccountKey + senderPrivateKey crypto.PrivateKey +) + +func main() { + tx := flow.NewTransaction(). + SetScript([]byte(transferScript)). + SetComputeLimit(100). + SetPayer(senderAddress). + SetAuthorizer(senderAddress). + SetProposalKey(senderAddress, senderAccountKey.Index, senderAccountKey.SequenceNumber) + + amount, err := cadence.NewUFix64("123.4") + if err != nil { + panic(err) + } + + recipient := cadence.NewAddress(flow.HexToAddress("0xabc...")) + + err = tx.AddArgument(amount) + if err != nil { + panic(err) + } + + err = tx.AddArgument(recipient) + if err != nil { + panic(err) + } +} +``` + + +=== tools/clients/fcl-js/wallet-connect.md === +--- +title: WalletConnect 2.0 Manual Configuration +--- + +:::warning +This guide is for advanced users who want to manually configure WalletConnect 2.0 with FCL-JS. Since `@onflow/fcl@1.11.0`, FCL-JS has supported WalletConnect 2.0 out of the box. For most users, we recommend using this built-in WalletConnect 2.0 support ([see how to configure FCL-JS here](./configure-fcl.md)). +::: + +To improve developer experience and streamline **Flow** dApp integration with **WalletConnect 2.0** wallets, **FCL `^1.3.0`** introduces support for **`discovery-service`** plugins. These **`ServicePlugins`** allow for injection of client configured **services**, service **methods**, and the execution **strategies** required to interact with them. +FCL dApps can opt-in through use of the [**fcl-wc**](https://www.npmjs.com/package/@onflow/fcl-wc) package and **FCL Plugin Registry**. + +When using FCL Discovery for authentication, dApps are able to support most FCL-compatible wallets and their users on Flow without any custom integrations or changes needed to the dApp code. + +These instructions explain how dApps can also add support for FCL compatible wallets that use the WalletConnect 2.0 protocol. + +## How does it work? + +- The **`fcl-wc`** package is used to initialize a **WalletConnect 2.0** [**`SignClient`**](https://docs.walletconnect.com/2.0/introduction/sign) instance, and build a **`discovery-service`** **`ServicePlugin`** based on dApp specified options. +- **`discovery-service`** plugins are used to add opt-in wallets and other services to **FCL Wallet Discovery** (UI/API). +- The **FCL Plugin Registry** offers dApps the ability to add new services, methods, and the execution strategies needed to interact with them. + +### Requirements + +- `fcl` version >= `1.3.0` +- `fcl-wc` version >= `1.0.0` + +### Implementation path + +| | | | +| :--------------------------------------------------------------------: | :------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------ | +| [**1**](#1-add-required-packages) | Add required packages | Install and import minimum `fcl` and `fcl-wc` [versions](#requirements) | +| [**2**](#2-obtain-a-walletconnect-projectid) | Obtain a WalletConnect `projectID` | Visit [WalletConnect Cloud Registry](https://cloud.walletconnect.com/) and register for public relay server access and an application `projectId` | +| [**3**](#3-initialize-walletconnect-signclient-and-fclwcserviceplugin) | Initialize WalletConnect `SignClient` and `FclWcServicePlugin` | Initialize WalletConnect `SignClient` and `FclWcServicePlugin` with [configuration options](#configuration-options) | +| [**4**](#4-add-fclwcserviceplugin-to-fcl-plugin-registry) | Add `FclWcServicePlugin` to FCL Plugin Registry | Inject `FclWcServicePlugin` via `fcl.pluginRegistry.add(FclWcServicePlugin)` | + +### 1. Add required packages + +Install the `fcl` and `fcl-wc` packages: + +```bash +npm install @onflow/fcl @onflow/fcl-wc +``` + +### 2. Obtain a WalletConnect projectID + +Visit [WalletConnect Cloud Registry](https://cloud.walletconnect.com/) and register for public relay server access and an application **`projectId`**. + +### 3. Initialize WalletConnect `SignClient` and `FclWcServicePlugin` + +In addition to the WalletConnect `SignClient`, the `init` method of `fcl-wc` returns a [`ServicePlugin`](#serviceplugin-spec) object. This object can be injected using the [FCL Plugin Registry](#pluginregistry) to add support for new service methods and their corresponding execution strategies (like `WC/RPC` for WalletConnect ). +A `discovery-service` `ServicePlugin` may also include additional opt-in wallets to offer your users through FCL Wallet Discovery. + +#### Configuration options + +Initialize WalletConnect `SignClient` and `FclWcServicePlugin` with the following configuration options: + +| Name | Type | Default | Description | +| ---------------------- | ---------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `projectId` | boolean **(required)** | null | A WalletConnect projectId for public relay server access. Your Project ID can be obtained from [WalletConnect Cloud Dashboard](https://cloud.walletconnect.com/app) | +| `metadata` | object | `{ }` | Optional dApp metadata to describe your application and define its appearance in a web browser. More details can be found [here](https://docs.walletconnect.com/2.0/swift/sign/dapp-usage) | +| `includeBaseWC` | boolean | false | Optional configuration to include a generic WalletConnect service in FCL Discovery (UI/API).
    :exclamation: BaseWC Service offers no deeplink support for mobile. | +| `wcRequestHook` | function | null | Optional function is called on all desktop WalletConnect client session proposals and signing requests. Use this to handle alerting user to check wallet for approval. | +| `pairingModalOverride` | function | null | Optional function called to allow override of included QRCodeModal. Function receives two arguments:
    1. Connection `uri` to display QR code or send to wallet to create pairing.
    2. Callback function to manually cancel the request. | +| `wallets` | array | `[ ]` | Optional list of WalletConnect `authn` services to include in FCL Wallet Discovery (UI/API).
    :exclamation: Only available for use on **`testnet`**. These services will be combined with wallets returned from [WalletConnect cloud registry API](https://cloud.walletconnect.com/) and sent to Discovery for display in UI and inclusion in API response. | +| `disableNotifications` | boolean | false | Optional flag to disable pending WalletConnect request notifications within the application's UI. | + +#### Returns + +| Name | Type | Description | +| ----------------------------------------- | --------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | +| [FclWcServicePlugin](#fclwcserviceplugin) | `ServicePlugin` | A `ServicePlugin` of type `discovery-service`. May also include optional `authn` services to offer through FCL Wallet Discovery (UI/API). | +| [client](#) | `SignClient` | An initialized WalletConnect [`SignClient`](https://docs.walletconnect.com/2.0/introduction/sign). | + +```js +const FclWcServicePlugin = { + name: "fcl-plugin-service-walletconnect", + f_type: "ServicePlugin", // the type of FCL plugin + type: "discovery-service", // the is a service sent to Discovery + services: [Service], // (optional) Generic, Cloud Registry and client injected WalletConnect services + serviceStrategy: {method: "WC/RPC", exec: execStrategy, // the method name and execution strategy for WalletConnect services +} +``` + +:exclamation: Setting FCL config `flow.network` to **`testnet`** or **`mainnet`** is required to use `fcl-wc` as it enables `"WC/RPC"` service strategy to request correct chain permissions. + +``` +import {config} from '@onflow/config' + +config({ + "flow.network": "mainnet" +}) +``` + +See [FCL Configuration](./configure-fcl.md) for more information. + +### 4. Add FclWcServicePlugin to FCL Plugin Registry + +In addition to the WalletConnect `SignClient`, the `init` method of `fcl-wc` returns a [`ServicePlugin`](#serviceplugin-spec) object. This object can be injected into the FCL Plugin Registry to add FCL support for new service methods, (like WC/RPC for WalletConnect) and their corresponding execution strategies. + +#### Usage + +```js +import * as fcl from '@onflow/fcl'; +import { init } from 'fcl-wc'; + +const { FclWcServicePlugin, client } = await init({ + projectId: WC_PROJECT_ID, // required + metadata: WC_APP_METADATA, // optional + includeBaseWC: false, // optional, default: false + wallets: [], // optional, default: [] + wcRequestHook: (wcRequestData) => { + // optional,default: null + handlePendingRequest(data); + }, + pairingModalOverride: (uri, rejectPairingRequest) => { + // optional,default: null + handlePendingPairingRequest(data); + }, +}); + +fcl.pluginRegistry.add(FclWcServicePlugin); +``` + +--- + +### ServicePlugin Spec + +| Key | Value Type | Description | +| ----------------- | ------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `name` | string | The name of the plugin. | +| `f_type` | string | The type of plugin (currently only supports `ServicePlugin` type). | +| `type` | string | The plugin subtype (currently only supports `discovery-service` type). | +| `services` | array | A list of services to add to FCL. | +| `serviceStrategy` | `{ method: string, exec: function }` | The method and corresponding strategy FCL uses to interact with the service. A service with the `service.method` property set to `"WC/RPC"` tells FCL to use the corresponding service strategy if it is supported by the dApp. | + +--- + +## Integrating With Wallet Discovery + +Knowing all the wallets available to users on a blockchain can be challenging. FCL's Discovery mechanism relieves much of the burden of integrating with Flow compatible wallets and let's developers focus on building their dApp and providing as many options as possible to their users. + +There are two ways an app can use [Wallet Discovery](./discovery.md): + +1. The UI version which can be configured for display via iFrame, Popup, or Tab. + +2. The API version which allows you to access authentication services directly in your code via `fcl.discovery.authn` method which we'll describe below. + +When using FCL Wallet Discovery for authentication, dApps are able to support FCL-compatible wallets on Flow without any custom integrations or changes needed to the dApp code. + +#### `discovery-service` ServicePlugin + +`FclWcServicePlugin` is a `ServicePlugin` of type `discovery-service`. `discovery-service` plugins may include additional authentication services to offer through FCL Wallet Discovery. + +Once a valid `discovery-service` plugin is registered, FCL shares client supported services with Discovery to add registered and injected wallets to the UI and API. + +To connect a Flow supported wallet using WalletConnect 2.0, users of your dApp will go through the authentication process and have the option to select their preferred wallet. + +:exclamation: Once a WalletConnect session is established and a `currentUser` is authenticated, FCL will handle client pairings and sessions during FCL `authn`, and initiate signing requests as part of `authz` using `fcl.mutate` and [`user-sign`](https://github.com/onflow/fcl-js/blob/master/docs/networks/user-signatures.mdx) using `fcl.signUserMessage`. + +### How to add your FCL compatible WalletConnect wallet to Discovery (UI/API) + +1. [Submit a PR](https://github.com/onflow/fcl-discovery/blob/master/data/services.json) to add your wallet to FCL Wallet Discovery `services.json` +2. Submit your FCL compatible wallet to [WalletConnect Cloud Registry](https://cloud.walletconnect.com/) +3. Add Wallet Service to `fcl-wc` init options. :exclamation: testnet only. + +FCL tells Wallet Discovery which services are supported by the client (installed extensions and `discovery-service` `ServicePlugins`) so only those supported will be shown in Discovery UI or returned via Discovery API. + +![Wallet Discovery UI](./images/wc-discovery.png) + +## Wallet Provider Spec + +### Implementation path + +| | | | +| :---: | :------------------------------------------------------------------------------------------------------------------------------------ | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **1** | Obtain a WalletConnect `projectId` | Register to receive a `projectId` from the [WalletConnect Cloud Registry](https://cloud.walletconnect.com/). | +| **2** | Conform to [FCL Wallet Provider Spec](https://github.com/onflow/fcl-js/blob/master/packages/fcl/src/wallet-provider-spec/draft-v4.md) | Compatible wallets must support `flow_authn`, `flow_authz`, and `flow_user_sign` methods and wrap data in the appropriate FCL Response type. Services returned with the `AuthnResponse` of `flow_authn` should set `service.endpoint` to corresponding methods.
    **ServiceType** `authz` : `flow_authz`
    **ServiceType** `user-signature` : `flow_user_sign` | +| **3** | Add wallet to WalletConnect Cloud Registry API **(optional)** | Submit your wallet to be included in the [WalletConnect Cloud Registry API and Explorer](https://explorer.walletconnect.com/) | +| **4** | Responses | All responses need to be wrapped in a [`PollingResponse`](https://github.com/onflow/fcl-js/blob/master/packages/fcl/src/wallet-provider-spec/draft-v4.md#pollingresponse) | + +#### Metadata requirements + +:exclamation: In order to correctly identify, improve pairing, and include deep link support for mobile, services using the `WC/RPC` method need to use the same universal link as their `uid` and `url` in Wallet metadata. +Wallets sourced from WalletConnect Cloud Registry automatically build the service from data and will set the `service.uid` to the universal link. + +```javascript +import SignClient from '@walletconnect/sign-client'; + +export let signClient: SignClient; + +export async function createSignClient() { + signClient = await SignClient.init({ + projectId: PROJECT_ID, + relayUrl: 'wss://relay.walletconnect.com', + metadata: { + name: 'Awesome Wallet', + description: 'Awesome Wallet with FCL Support for WalletConnect', + url: 'https://deeplink.awesome-wallet.com/', + icons: ['https://avatars.githubusercontent.com/u/37784886'], + }, + }); +} +``` + +## Next steps + +1. Read the [FCL Wallet Provider Spec](https://github.com/onflow/fcl-js/blob/master/packages/fcl/src/wallet-provider-spec/draft-v4.md). +2. Check out the a WalletConnect 2.0 [React POC Wallet](https://github.com/gregsantos/flow-walletconnect-v2-react-wallet) and [FCL Flow dApp](https://github.com/gregsantos/flow-walletconnect-v2-react-dapp) with support for WalletConnect v2.0. +3. Read and review the [WalletConnect 2.0 Docs](https://docs.walletconnect.com/2.0/), [examples and resources](https://docs.walletconnect.com/2.0/introduction/examples-and-resources). + + +=== tools/clients/fcl-js/user-signatures.md === +--- +title: Signing and Verifying Arbitrary Data +--- + +## Signing Arbitrary Data + +Cryptographic signatures are a key part of the blockchain. They are used to prove ownership of an address without exposing its private key. While primarily used for signing transactions, cryptographic signatures can also be used to sign arbitrary messages. + +FCL has a feature that lets you send arbitrary data to a configured wallet/service where the user may approve signing it with their private key/s. + +## Verifying User Signatures + +What makes message signatures more interesting is that we can use Flow blockchain to verify the signatures. Cadence has a built-in function `publicKey.verify` that will verify a signature against a Flow account given the account address. + +FCL includes a utility function, `AppUtils.verifyUserSignatures`, for verifying one or more signatures against an account's public key on the Flow blockchain. + +You can use both in tandem to prove a user is in control of a private key or keys. + +This enables cryptographically-secure login flow using a message-signing-based authentication mechanism with a user’s public address as their identifier. + +--- + +## `currentUser.signUserMessage()` + +A method to use allowing the user to personally sign data via FCL Compatible Wallets/Services. + +> :Note: **Requires authentication/configuration with an authorized signing service.** + +### Arguments + +| Name | Type | Description | +| --------- | ------ | --------------------------------- | +| `message` | string | A hexadecimal string to be signed | + +#### Returns + +| Type | Description | +| ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `Array` | An Array of [CompositeSignatures](https://github.com/onflow/fcl-js/blob/master/packages/fcl-core/src/wallet-provider-spec/draft-v2.md#compositesignature): {`addr`, `keyId`, `signature`} | + +#### Usage + +```javascript +import * as fcl from "@onflow/fcl" + +const signMessage = async () => { + const MSG = Buffer.from("FOO").toString("hex") + try { + return await fcl.currentUser.signUserMessage(MSG) + } catch (error) { + console.log(error) + } +} +``` + +--- + +## `AppUtils.verifyUserSignatures` + +#### Note + +⚠️ `fcl.config.flow.network` or options override is required to use this API. See [FCL Configuration](./configure-fcl.md). + +A method allowing applications to cryptographically verify the ownership of a Flow account by verifying a message was signed by a user's private key/s. This is typically used with the response from `currentUser.signUserMessage`. + +### Arguments + +| Name | Type | Description | +| --------------------- | --------------------- | --------------------------------- | +| `message` | string **(required)** | A hexadecimal string | +| `compositeSignatures` | Array **(required)** | An Array of `CompositeSignatures` | +| `opts` | Object **(optional)** | `opts.fclCryptoContract` can be provided to override FCLCryptoContract address for local development | + +#### Returns + +| Type | Description | +| ------- | ---------------------------- | +| Boolean | `true` if verified or `false` | + +#### Usage + +```javascript +/** + * Verify a valid signature/s for an account on Flow. + * + * @param {string} msg - A message string in hexadecimal format + * @param {Array} compSigs - An array of Composite Signatures + * @param {string} compSigs[].addr - The account address + * @param {number} compSigs[].keyId - The account keyId + * @param {string} compSigs[].signature - The signature to verify + * @param {Object} [opts={}] - Options object + * @param {string} opts.fclCryptoContract - An optional override of Flow account address where the FCLCrypto contract is deployed + * @return {bool} + * + * @example + * + * const isValid = await fcl.AppUtils.verifyUserSignatures( + * Buffer.from('FOO').toString("hex"), + * [{f_type: "CompositeSignature", f_vsn: "1.0.0", addr: "0x123", keyId: 0, signature: "abc123"}], + * {fclCryptoContract} + * ) + */ +``` + +#### Examples + +Use cases include cryptographic login, message validation, verifiable credentials, and others. + +--- + + +=== tools/clients/fcl-js/transactions.md === +# Transactions + +Transactions let you send Cadence code to the Flow blockchain that permanently alters its state. + +We are assuming you have read the [Scripts Documentation](./scripts.md) before this, as transactions are sort of scripts with more required things. + +While `query` is used for sending scripts to the chain, `mutate` is used for building and sending transactions. Just like [scripts](./scripts.md), `fcl.mutate` is a [JavaScript Tagged Template Literal](https://styled-components.com/docs/advanced#tagged-template-literals) that we can pass Cadence code into. + +Unlike scripts, they require a little more information, things like a proposer, authorizations and a payer, which may be a little confusing and overwhelming. + +## Sending Your First Transaction + +There is a lot to unpack in the following code snippet. +It sends a transaction to the Flow blockchain. For the transaction, the current user is authorizing it as both the `proposer` and the `payer`. +Something that is unique to Flow is the one paying for the transaction doesn't always need to be the one performing the transaction. +Proposers and Payers are special kinds of authorizations that are always required for a transaction. +The `proposer` acts similar to the `nonce` in Ethereum transactions, and helps prevent repeat attacks. +The `payer` is who will be paying for the transaction. +If these are not set, FCL defaults to using the current user for all roles. + +`fcl.mutate` will return a `transactionId`. We can pass the response directly to `fcl.tx` and then use the `onceExecuted` method which resolves a promise when a transaction result is available. + +```javascript +import * as fcl from "@onflow/fcl" + +const transactionId = await fcl.mutate({ + cadence: ` + transaction { + execute { + log("Hello from execute") + } + } + `, + proposer: fcl.currentUser, + payer: fcl.currentUser, + limit: 50 +}) + +const transaction = await fcl.tx(transactionId).onceExecuted() +console.log(transaction) // The transactions status and events after being executed +``` + +## Authorizing a Transaction + +The below code snippet is the same as the above one, except for one extremely important difference. +Our Cadence code this time has a prepare statement, and we are using the `fcl.currentUser` when constructing our transaction. + +The `prepare` statement's arguments directly map to the order of the authorizations in the `authorizations` array. +Four authorizations means four `&Account`s as arguments passed to `prepare`. In this case though there is only one, and it is the `currentUser`. + +These authorizations are important as you can only access/modify an accounts storage if you have the said accounts authorization. + +```javascript +import * as fcl from "@onflow/fcl" + +const transactionId = await fcl.mutate({ + cadence: ` + transaction { + prepare(acct: &Account) { + log("Hello from prepare") + } + execute { + log("Hello from execute") + } + } + `, + proposer: fcl.currentUser, + payer: fcl.currentUser, + authorizations: [fcl.currentUser], + limit: 50 +}) + +const transaction = await fcl.tx(transactionId).onceExecuted() +console.log(transaction) // The transactions status and events after being executed +``` + +To learn more about `mutate`, check out the [API documentation](./api.md#mutate). + +## Transaction Finality + +As of **FCL v1.15.0**, it is now recommended to use use `onceExecuted` in most cases, leading to a 2.5x reduction in latency when waiting for a transaction result. For example, the following code snippet should be updated from: + +```ts +import * as fcl from "@onflow/fcl" +const result = await fcl.tx(txId).onceSealed() +``` + +to: + +```ts +import * as fcl from "@onflow/fcl" +const result = await fcl.tx(txId).onceExecuted() +``` + +Developers manually subscribing to transaction statuses should update their listeners to treat "executed" as the final status (see the release notes [here](https://github.com/onflow/fcl-js/releases/tag/%40onflow%2Ffcl%401.15.0)). For example, the following code snippet should be updated from: + +```ts +import * as fcl from "@onflow/fcl" +import { TransactionExecutionStatus } from "@onflow/typedefs" + +fcl.tx(txId).subscribe((txStatus) => { + if ( + txStatus.status === TransactionExecutionStatus.SEALED + ) { + console.log("Transaction executed!") + } +}) +``` + +```ts +import * as fcl from "@onflow/fcl" +import { TransactionExecutionStatus } from "@onflow/typedefs" + +fcl.tx(txId).subscribe((txStatus) => { + if ( + // SEALED status is no longer necessary + txStatus.status === TransactionExecutionStatus.EXECUTED + ) { + console.log("Transaction executed!") + } +}) +``` + +The "executed" status corresponds to soft finality, indicating that the transaction has been included in a block and a transaction status is available, backed by a cryptographic proof. Only in rare cases should a developer need to wait for "sealed" status in their applications and you can learn more about the different transaction statuses on Flow [here](../../../build/basics/transactions.md#transaction-status). + +See the following video for demonstration of how to update your code to wait for "executed" status: + + + +=== tools/clients/fcl-js/sdk-guidelines.md === +--- +title: SDK Reference +sidebar_label: SDK Reference +sidebar_position: 2 +--- + +## Overview + +This reference documents methods available in the SDK that can be accessed via FCL, and explains in detail how these methods work. +FCL/SDKs are open source, and you can use them according to the licence. + +The library client specifications can be found here: + +[](./api.md) + + +## Getting Started + +### Installing +NPM: +``` +npm install --save @onflow/fcl @onflow/types +``` + +Yarn: +``` +yarn add @onflow/fcl @onflow/types +``` + +### Importing the Library +```javascript +import * as fcl from "@onflow/fcl" +import * as types from "@onflow/types" +``` + +## Connect +[](./configure-fcl.md) + +By default, the library uses HTTP to communicate with the access nodes and it must be configured with the correct access node API URL. An error will be returned if the host is unreachable. + +📖**The HTTP/REST API information** can be found [here](/http-api/). The public Flow HTTP/REST access nodes are accessible at: +- Testnet `https://rest-testnet.onflow.org` +- Mainnet `https://rest-mainnet.onflow.org` +- Local Emulator `127.0.0.1:8888` + +Example: +```javascript +import { config } from "@onflow/fcl" + +config({ + "accessNode.api": "https://rest-testnet.onflow.org" +}) +``` + +## Querying the Flow Network +After you have established a connection with an access node, you can query the Flow network to retrieve data about blocks, accounts, events and transactions. We will explore how to retrieve each of these entities in the sections below. + +### Get Blocks +[](./api.md#getblock) + +Query the network for block by id, height or get the latest block. + +📖 **Block ID** is SHA3-256 hash of the entire block payload. This hash is stored as an ID field on any block response object (ie. response from `GetLatestBlock`). + +📖 **Block height** expresses the height of the block on the chain. The latest block height increases by one for every valid block produced. + +#### Examples + +This example depicts ways to get the latest block as well as any other block by height or ID: + +``` +import * as fcl from "@onflow/fcl"; + +// Get latest block +const latestBlock = await fcl.latestBlock(true); // If true, get the latest sealed block + +// Get block by ID (uses builder function) +await fcl.send([fcl.getBlock(), fcl.atBlockId("23232323232")]).then(fcl.decode); + +// Get block at height (uses builder function) +await fcl.send([fcl.getBlock(), fcl.atBlockHeight(123)]).then(fcl.decode) +``` +Result output: [BlockObject](./api.md#blockobject) + +### Get Account +[](./api.md#account) + +Retrieve any account from Flow network's latest block or from a specified block height. + +📖 **Account address** is a unique account identifier. Be mindful about the `0x` prefix, you should use the prefix as a default representation but be careful and safely handle user inputs without the prefix. + +An account includes the following data: +- Address: the account address. +- Balance: balance of the account. +- Contracts: list of contracts deployed to the account. +- Keys: list of keys associated with the account. + +#### Examples +Example depicts ways to get an account at the latest block and at a specific block height: + +```javascript +import * as fcl from "@onflow/fcl"; + +// Get account from latest block height +const account = await fcl.account("0x1d007d755706c469"); + +// Get account at a specific block height +fcl.send([ + fcl.getAccount("0x1d007d755706c469"), + fcl.atBlockHeight(123) +]); +``` +Result output: [AccountObject](./api.md#accountobject) + + +### Get Transactions +[](./api.md#gettransaction) + +Retrieve transactions from the network by providing a transaction ID. After a transaction has been submitted, you can also get the transaction result to check the status. + +📖 **Transaction ID** is a hash of the encoded transaction payload and can be calculated before submitting the transaction to the network. + +⚠️ The transaction ID provided must be from the current spork. + +📖 **Transaction status** represents the state of a transaction in the blockchain. Status can change until it is finalized. + +| Status | Final | Description | +| ------------ | ------- | ----------- | +| UNKNOWN | ❌ | The transaction has not yet been seen by the network | +| PENDING | ❌ | The transaction has not yet been included in a block | +| FINALIZED | ❌ | The transaction has been included in a block | +| EXECUTED | ❌ | The transaction has been executed but the result has not yet been sealed | +| SEALED | ✅ | The transaction has been executed and the result is sealed in a block | +| EXPIRED | ✅ | The transaction reference block is outdated before being executed | + +```javascript +import * as fcl from "@onflow/fcl"; + +// Snapshot the transaction at a point in time +fcl.tx(transactionId).snapshot(); + +// Subscribe to a transaction's updates +fcl.tx(transactionId).subscribe(callback); + +// Provides the transaction once the status is finalized +fcl.tx(transactionId).onceFinalized(); + +// Provides the transaction once the status is executed +fcl.tx(transactionId).onceExecuted(); + +// Provides the transaction once the status is sealed +fcl.tx(transactionId).onceSealed(); +``` +Result output: [TransactionStatusObject](./api.md#gettransactionstatus) + + +### Get Events +[](./api.md#geteventsatblockheightrange) + +Retrieve events by a given type in a specified block height range or through a list of block IDs. + +📖 **Event type** is a string that follow a standard format: +``` +A.{contract address}.{contract name}.{event name} +``` + +Please read more about [events in the documentation](https://cadence-lang.org/docs/language/core-events). The exception to this standard are +core events, and you should read more about them in [this document](https://cadence-lang.org/docs/language/core-events). + +📖 **Block height range** expresses the height of the start and end block in the chain. + +#### Examples +Example depicts ways to get events within block range or by block IDs: + +```javascript +import * as fcl from "@onflow/fcl"; + +// Get events at block height range +await fcl + .send([ + fcl.getEventsAtBlockHeightRange( + "A.7e60df042a9c0868.FlowToken.TokensWithdrawn", // event name + 35580624, // block to start looking for events at + 35580624 // block to stop looking for events at + ), + ]) + .then(fcl.decode); + +// Get events from list of block ids +await fcl + .send([ + fcl.getEventsAtBlockIds("A.7e60df042a9c0868.FlowToken.TokensWithdrawn", [ + "c4f239d49e96d1e5fbcf1f31027a6e582e8c03fcd9954177b7723fdb03d938c7", + "5dbaa85922eb194a3dc463c946cc01c866f2ff2b88f3e59e21c0d8d00113273f", + ]), + ]) + .then(fcl.decode); +``` +Result output: [EventObject](./api.md#event-object) + +### Get Collections +[](./api.md#getcollection) + +Retrieve a batch of transactions that have been included in the same block, known as ***collections***. +Collections are used to improve consensus throughput by increasing the number of transactions per block and they act as a link between a block and a transaction. + +📖 **Collection ID** is SHA3-256 hash of the collection payload. + +Example retrieving a collection: +```javascript +import * as fcl from "@onflow/fcl"; + +const collection = await fcl + .send([ + fcl.getCollection( + "cccdb0c67d015dc7f6444e8f62a3244ed650215ed66b90603006c70c5ef1f6e5" + ), + ]) + .then(fcl.decode); +``` +Result output: [CollectionObject](./api.md#collectionobject) + +### Execute Scripts +[](./api.md#query) + +Scripts allow you to write arbitrary non-mutating Cadence code on the Flow blockchain and return data. You can learn more about [Cadence here](https://cadence-lang.org/docs/language) and [scripts here](./scripts.md), but we are now only interested in executing the script code and getting back the data. + +We can execute a script using the latest state of the Flow blockchain or we can choose to execute the script at a specific time in history defined by a block height or block ID. + +📖 **Block ID** is SHA3-256 hash of the entire block payload, but you can get that value from the block response properties. + +📖 **Block height** expresses the height of the block in the chain. + +```javascript +import * as fcl from "@onflow/fcl"; + +const result = await fcl.query({ + cadence: ` + access(all) fun main(a: Int, b: Int, addr: Address): Int { + log(addr) + return a + b + } + `, + args: (arg, t) => [ + arg(7, t.Int), // a: Int + arg(6, t.Int), // b: Int + arg("0xba1132bc08f82fe2", t.Address), // addr: Address + ], +}); +``` +Example output: +```bash +console.log(result); // 13 +``` + +## Mutate Flow Network +Flow, like most blockchains, allows anybody to submit a transaction that mutates the shared global chain state. A transaction is an object that holds a payload, which describes the state mutation, and one or more authorizations that permit the transaction to mutate the state owned by specific accounts. + +Transaction data is composed and signed with help of the SDK. The signed payload of transaction then gets submitted to the access node API. If a transaction is invalid or the correct number of authorizing signatures are not provided, it gets rejected. + +## Transactions +A transaction is nothing more than a signed set of data that includes script code which are instructions on how to mutate the network state and properties that define and limit it's execution. All these properties are explained bellow. + +📖 **Script** field is the portion of the transaction that describes the state mutation logic. On Flow, transaction logic is written in [Cadence](https://cadence-lang.org/docs). Here is an example transaction script: +``` +transaction(greeting: String) { + execute { + log(greeting.concat(", World!")) + } +} +``` + +📖 **Arguments**. A transaction can accept zero or more arguments that are passed into the Cadence script. The arguments on the transaction must match the number and order declared in the Cadence script. Sample script from above accepts a single `String` argument. + +📖 **[Proposal key](../../../build/basics/transactions.md#proposal-key)** must be provided to act as a sequence number and prevent replay and other potential attacks. + +Each account key maintains a separate transaction sequence counter; the key that lends its sequence number to a transaction is called the proposal key. + +A proposal key contains three fields: +- Account address +- Key index +- Sequence number + +A transaction is only valid if its declared sequence number matches the current on-chain sequence number for that key. The sequence number increments by one after the transaction is executed. + +📖 **[Payer](../../../build/basics/transactions.md#signer-roles)** is the account that pays the fees for the transaction. A transaction must specify exactly one payer. The payer is only responsible for paying the network and gas fees; the transaction is not authorized to access resources or code stored in the payer account. + +📖 **[Authorizers](../../../build/basics/transactions.md#signer-roles)** are accounts that authorize a transaction to read and mutate their resources. A transaction can specify zero or more authorizers, depending on how many accounts the transaction needs to access. + +The number of authorizers on the transaction must match the number of `&Account` parameters declared in the prepare statement of the Cadence script. + +Example transaction with multiple authorizers: +``` +transaction { + prepare(authorizer1: &Account, authorizer2: &Account) { } +} +``` + +📖 **Gas limit** is the limit on the amount of computation a transaction requires, and it will abort if it exceeds its gas limit. +Cadence uses metering to measure the number of operations per transaction. You can read more about it in the [Cadence documentation](https://cadence-lang.org/docs). + +The gas limit depends on the complexity of the transaction script. Until dedicated gas estimation tooling exists, it's best to use the emulator to test complex transactions and determine a safe limit. + +📖 **Reference block** specifies an expiration window (measured in blocks) during which a transaction is considered valid by the network. +A transaction will be rejected if it is submitted past its expiry block. Flow calculates transaction expiry using the _reference block_ field on a transaction. +A transaction expires after `600` blocks are committed on top of the reference block, which takes about 10 minutes at average Mainnet block rates. + +### Mutate +[](./api.md#mutate) + +FCL "mutate" does the work of building, signing, and sending a transaction behind the scenes. In order to mutate the blockchain state using FCL, you need to do the following: + +```javascript +import * as fcl from "@onflow/fcl" + +await fcl.mutate({ + cadence: ` + transaction(a: Int) { + prepare(acct: &Account) { + log(acct) + log(a) + } + } + `, + args: (arg, t) => [ + arg(6, t.Int) + ], + limit: 50 +}) +``` + +Flow supports great flexibility when it comes to transaction signing, we can define multiple authorizers (multi-sig transactions) and have different payer account than proposer. We will explore advanced signing scenarios bellow. + +### [Single party, single signature](../../../build/basics/transactions.md#single-party-single-signature) + +- Proposer, payer and authorizer are the same account (`0x01`). +- Only the envelope must be signed. +- Proposal key must have full signing weight. + +| Account | Key ID | Weight | +| ------- | ------ | ------ | +| `0x01` | 1 | 1000 | + +```javascript +// There are multiple ways to acheive this +import * as fcl from "@onflow/fcl" + +// FCL provides currentUser as an authorization function +await fcl.mutate({ + cadence: ` + transaction { + prepare(acct: &Account) {} + } + `, + proposer: currentUser, + payer: currentUser, + authorizations: [currentUser], + limit: 50, +}) + +// Or, simplified + +mutate({ + cadence: ` + transaction { + prepare(acct: &Account) {} + } + `, + authz: currentUser, // Optional. Will default to currentUser if not provided. + limit: 50, +}) + + +// Or, create a custom authorization function +const authzFn = async (txAccount) => { + return { + ...txAccount, + addr: "0x01", + keyId: 0, + signingFunction: async(signable) => { + return { + addr: "0x01", + keyId: 0, + signature + } + } + } +} + +mutate({ + cadence: ` + transaction { + prepare(acct: &Account) {} + } + `, + proposer: authzFn, + payer: authzFn, + authorizations: [authzFn], + limit: 50, +}) +``` + +### [Single party, multiple signatures](../../../build/basics/transactions.md#single-party-multiple-signatures) + +- Proposer, payer and authorizer are the same account (`0x01`). +- Only the envelope must be signed. +- Each key has weight 500, so two signatures are required. + +| Account | Key ID | Weight | +| ------- | ------ | ------ | +| `0x01` | 1 | 500 | +| `0x01` | 2 | 500 | + +**[](https://github.com/onflow/flow-go-sdk/tree/master/examples#single-party-multiple-signatures)** +```javascript +import * as fcl from "@onflow/fcl" + +const authzFn = async (txAccount) => { + return [ + { + ...txAccount, + addr: "0x01", + keyId: 0, + signingFunction: async(signable) => { + return { + addr: "0x01", + keyId: 0, + signature + } + } + }, + { + ...txAccount, + addr: "0x01", + keyId: 1, + signingFunction: async(signable) => { + return { + addr: "0x01", + keyId: 1, + signature + } + } + } + ] +} + +mutate({ + cadence: ` + transaction { + prepare(acct: &Account) {} + } + `, + proposer: authzFn, + payer: authzFn, + authorizations: [authzFn], + limit: 50, +}) +``` + +### [Multiple parties](../../../build/basics/transactions.md#multiple-parties) + +- Proposer and authorizer are the same account (`0x01`). +- Payer is a separate account (`0x02`). +- Account `0x01` signs the payload. +- Account `0x02` signs the envelope. + - Account `0x02` must sign last since it is the payer. + +| Account | Key ID | Weight | +| ------- | ------ | ------ | +| `0x01` | 1 | 1000 | +| `0x02` | 3 | 1000 | + +**[](https://github.com/onflow/flow-go-sdk/tree/master/examples#multiple-parties)** +```javascript +import * as fcl from "@onflow/fcl" + +const authzFn = async (txAccount) => { + return { + ...txAccount, + addr: "0x01", + keyId: 0, + signingFunction: async(signable) => { + return { + addr: "0x01", + keyId: 0, + signature + } + } + } +} + +const authzTwoFn = async (txAccount) => { + return { + ...txAccount, + addr: "0x02", + keyId: 0, + signingFunction: async(signable) => { + return { + addr: "0x02", + keyId: 0, + signature + } + } + } +} + +mutate({ + cadence: ` + transaction { + prepare(acct: &Account) {} + } + `, + proposer: authzFn, + payer: authzTwoFn, + authorizations: [authzFn], + limit: 50, +}) +``` + +### [Multiple parties, two authorizers](../../../build/basics/transactions.md#multiple-parties) + +- Proposer and authorizer are the same account (`0x01`). +- Payer is a separate account (`0x02`). +- Account `0x01` signs the payload. +- Account `0x02` signs the envelope. + - Account `0x02` must sign last since it is the payer. +- Account `0x02` is also an authorizer to show how to include two `&Account` objects into an transaction + +| Account | Key ID | Weight | +| ------- | ------ | ------ | +| `0x01` | 1 | 1000 | +| `0x02` | 3 | 1000 | + +**[](https://github.com/onflow/flow-go-sdk/tree/master/examples#multiple-parties-two-authorizers)** +```javascript +import * as fcl from "@onflow/fcl" + +const authzFn = async (txAccount) => { + return { + ...txAccount, + addr: "0x01", + keyId: 0, + signingFunction: async(signable) => { + return { + addr: "0x01", + keyId: 0, + signature + } + } + } +} + +const authzTwoFn = async (txAccount) => { + return { + ...txAccount, + addr: "0x02", + keyId: 0, + signingFunction: async(signable) => { + return { + addr: "0x02", + keyId: 0, + signature + } + } + } +} + +mutate({ + cadence: ` + transaction { + prepare(acct: &Account, acct2: &Account) {} + } + `, + proposer: authzFn, + payer: authzTwoFn, + authorizations: [authzFn, authzTwoFn], + limit: 50, +}) +``` + +### [Multiple parties, multiple signatures](../../../build/basics/transactions.md#multiple-parties) + +- Proposer and authorizer are the same account (`0x01`). +- Payer is a separate account (`0x02`). +- Account `0x01` signs the payload. +- Account `0x02` signs the envelope. + - Account `0x02` must sign last since it is the payer. +- Both accounts must sign twice (once with each of their keys). + +| Account | Key ID | Weight | +| ------- | ------ | ------ | +| `0x01` | 1 | 500 | +| `0x01` | 2 | 500 | +| `0x02` | 3 | 500 | +| `0x02` | 4 | 500 | + +```javascript +import * as fcl from "@onflow/fcl" + +const authzFn = async (txAccount) => { + return [ + { + ...txAccount, + addr: "0x01", + keyId: 0, + signingFunction: async(signable) => { + return { + addr: "0x01", + keyId: 0, + signature + } + } + }, + { + ...txAccount, + addr: "0x01", + keyId: 1, + signingFunction: async(signable) => { + return { + addr: "0x01", + keyId: 1, + signature + } + } + } + ] +} + +const authzTwoFn = async (txAccount) => { + return [ + { + ...txAccount, + addr: "0x02", + keyId: 0, + signingFunction: async(signable) => { + return { + addr: "0x02", + keyId: 0, + signature + } + } + }, + { + ...txAccount, + addr: "0x02", + keyId: 1, + signingFunction: async(signable) => { + return { + addr: "0x02", + keyId: 1, + signature + } + } + } + ] +} + +mutate({ + cadence: ` + transaction { + prepare(acct: &Account) {} + } + `, + proposer: authzFn, + payer: authzTwoFn, + authorizations: [authzFn], + limit: 50, +}) +``` + +After a transaction has been **built** and **signed**, it can be sent to the Flow blockchain where it will be executed. If sending was successful you can then [retrieve the transaction result](#get-transactions). + + +=== tools/clients/fcl-js/scripts.md === +# Scripts + +Scripts let you run non-permanent Cadence scripts on the Flow blockchain. They can return data. + +They always need to contain a `access(all) fun main()` function as an entry point to the script. + +`fcl.query` is a function that sends Cadence scripts to the chain and receives back decoded responses. + +The `cadence` key inside the object sent to the `query` function is a [JavaScript Tagged Template Literal](https://styled-components.com/docs/advanced#tagged-template-literals) that we can pass Cadence code into. + +### Sending Your First Script + +The following example demonstrates how to send a script to the Flow blockchain. This script adds two numbers and returns the result. + +```javascript +import * as fcl from "@onflow/fcl" + +const response = await fcl.query({ + cadence: ` + access(all) fun main(): Int { + return 1 + 2 + } + ` +}) + +console.log(response) // 3 +``` + +### A More Complex Script + +[Resources](https://cadence-lang.org/docs/language/resources) and [Structs](https://cadence-lang.org/docs/language/composite-types#structures) are complex data types that are fairly common place in Cadence. + +In the following code snippet, our script defines a struct called `Point`, it then returns a list of them. + +The closest thing to a Structure in JavaScript is an object. In this case when we decode this response, we would be expecting to get back an array of objects, where the objects have an `x` and `y` value. + +```javascript +import * as fcl from "@onflow/fcl" + +const response = await fcl.query({ + cadence: ` + access(all) struct Point { + access(all) var x: Int + access(all) var y: Int + + init(x: Int, y: Int) { + self.x = x + self.y = y + } + } + + access(all) fun main(): [Point] { + return [Point(x: 1, y: 1), Point(x: 2, y: 2)] + } + ` +}) + +console.log(response) // [{x:1, y:1}, {x:2, y:2}] +``` + +### Transforming Data with Custom Decoders + +In our app, we probably have a way of representing these Cadence values internally. In the above example it might be a `Point` class. + +FCL enables us to provide custom decoders that we can use to transform the data we receive from the Flow blockchain at the edge, before anything else in our dapp gets a chance to look at it. + +We add these custom decoders by [Configuring FCL](./configure-fcl.md). +This lets us set it once when our dapp starts up and use our normalized data through out the rest of our dapp. + +In the below example we will use the concept of a `Point` again, but this time, we will add a custom decoder, that enables `fcl.decode` to transform it into a custom JavaScript `Point` class. + +```javascript +import * as fcl from "@onflow/fcl" + +class Point { + constructor({ x, y }) { + this.x = x + this.y = y + } +} + +fcl.config() + .put("decoder.Point", point => new Point(point)) + +const response = await fcl.query({ + cadence: ` + access(all) struct Point { + access(all) var x: Int + access(all) var y: Int + + init(x: Int, y: Int) { + self.x = x + self.y = y + } + } + + access(all) fun main(): [Point] { + return [Point(x: 1, y: 1), Point(x: 2, y: 2)] + } + ` +}) + +console.log(response) // [Point{x:1, y:1}, Point{x:2, y:2}] +``` + +To learn more about `query`, check out the [API documentation](./api.md#query). + + +=== tools/clients/fcl-js/proving-authentication.mdx === +--- +title: Proving Ownership of a Flow Account +--- + +## Proving Ownership of a Flow Account + +A common desire that application developers have is to be able to prove that a +user controls an on-chain account. Proving ownership of an on-chain account is a +way to authenticate a user with an application backend. Fortunately, +FCL provides a way to achieve this. + +During user authentication, some FCL compatible wallets will choose to support +the FCL `account-proof` service. If a wallet chooses to support this service, and +the user approves the signing of message data, they will return `account-proof` data +and a signature(s) that can be used to prove a user controls an on-chain account. + +We'll walk through how you, an application developer, can use the `account-proof` service to +authenticate a user. + +> Are you an FCL Wallet Developer? Check out the wallet provider specific docs +> [here](https://github.com/onflow/fcl-js/tree/master/packages/fcl/src/wallet-provider-spec/provable-authn.md) + +### Authenticating a user using `account-proof` + +In order to authenticate your users via a wallet provider's account-proof service, your application needs to +configure FCL by setting `fcl.accountProof.resolver` and providing two pieces of information. + +The `fcl.accountProof.resolver` is an async resolver function used by FCL to retrieve account proof data +from your application server. It can be set in your application configuration under the `fcl.accountProof.resolver` +key. The resolved data should include a specific application identifier (`appIdentifier`) and a random `nonce`. +This data will be sent to the wallet for signing by the user. If the user approves and authentication is successfull, +a signature is returned to the client in the data field of an `account-proof` service. + +**Application Identifier** + +An application identifier is a human-readable string that uniquely identifies your application name. +The identifier is displayed by wallets when users are asked to approve a signing request. +It helps users compare against the request origin and detect some malicious phishing attempts, +improving trust of the application and signing process. + +**Random Nonce** + +In addition to the `appIdentifier` your application must provide a **minimum 32-byte random nonce** as a hex string. + +If for any reason your application backend does not want to request an `account-proof` during authentication, +it should send a response of `null`. If FCL receives a `null` response from the `accountProof.resolver` it will +continue the authentication process with the wallet but will not request an account-proof and no signature will be returned. + +> In the case of a network or server error FCL will cancel the authentication process and return a rejected promise. + +```js +import {config} from "@onflow/fcl" + +type AccountProofData { + // e.g. "Awesome App (v0.0)" - A human readable string to identify your application during signing + appIdentifier: string; + + // e.g. "75f8587e5bd5f9dcc9909d0dae1f0ac5814458b2ae129620502cb936fde7120a" - minimum 32-byte random nonce as hex string + nonce: string; +} + +type AccountProofDataResolver = () => Promise; + +config({ + "fcl.accountProof.resolver": accountProofDataResolver +}) +``` + +Here is the suggested order of operations of how your application might use the +`account-proof` service: + +- A user would like to authenticate via your application client using FCL. The process is triggered + by a call to `fcl.authenticate()`. If `fcl.accountProof.resolver` is configured, FCL will attempt + to retrieve the account proof data (`appIdentifier` and `nonce`) and trigger your server to start a new + account proof authentication process. +- Your application server generates a **minimum 32-byte random nonce** using a local source of entropy and + sends it to the client. The server saves the challenge for future look-ups. +- If FCL successfully retrieves the `account-proof` data, it continues the authentication process over a secure channel with the wallet. + FCL includes the `appIdentifier` and `nonce` as part of the `FCL:VIEW:READY:RESPONSE` or HTTP POST request body. + If the resolver function call fails to retrieve the nonce, FCL will cancel the authentication process. +- If the wallet supports account proofs and the user approves authentication with the wallet, the wallet will return the `account-proof` + service with its response. + +The data within the `account-proof` service will look like this: + +```js +{ + f_type: "Service", // Its a service! + f_vsn: "1.0.0", // Follows the v1.0.0 spec for the service + type: "account-proof", // The type of service it is + method: "DATA", // Its data! + uid: "awesome-wallet#account-proof", // A unique identifier for the service + data: { + f_type: "account-proof", + f_vsn: "2.0.0" + + // The user's address (8 bytes, i.e 16 hex characters) + address: "0xf8d6e0586b0a20c7", + + // Nonce signed by the current account-proof (minimum 32 bytes in total, i.e 64 hex characters) + nonce: "75f8587e5bd5f9dcc9909d0dae1f0ac5814458b2ae129620502cb936fde7120a", + + signatures: [CompositeSignature], + } +} +``` + +- Your application client initiates a secure channel with your application server + to relay the `account-proof` data and authenticate the user with your server. + Subsequent exchanges between the client and server will happen over this channel. + +- Your application server receives the `account-proof` data structure, and can then + begin the verification process. + + - The server checks if the Flow address corresponds to an existing application + account and determines whether it needs to sign in a returning user or create + a new account. It is up to your application to decide how to manage + the two cases. + - The server looks the challenge up. If the nonce is not found or the nonce + has expired, reject the authentication request, otherwise continue. + - The server determines whether the `CompositeSignature` in the + `account-proof` data structure contains valid signatures for the nonce + and on-chain accounts (more details in the section below on how this is done). + - If the verification is successful, delete the `nonce` or mark it as expired, + the application account defined by the on-chain address is successfully + logged in. Otherwise the authentication fails and the `nonce` is not deleted. + +**Verification** + +Your application can verify the signature against the data from `account-proof` +data using FCL's provided utility: + +```js + +import { AppUtils } from "@onflow/fcl" + + const accountProofData = { + accountProof.address, // address of the user authenticating + accountProof.nonce, // nonce + accountProof.signatures // signatures + } + + const isValid = await AppUtils.verifyAccountProof( + appIdentifier, + accountProofData + ) +``` + +## Implementation considerations: + +- The authentication assumes the Flow address is the identifier of the user's application account. + If an existing user doesn't have a Flow address in their profile, or if they decide to authenticate using + a Flow address different than the one saved in their profile, the user's account won't be found and the + process would consider a new user creating an account. It is useful for your application to consider + other authentication methods that allow an existing user to update the Flow address in their profile so + they are able to use FCL authentication. +- In the `account-proof` flow as described in this document, + the backend doesn't know the user's account address at the moment of generating a nonce. + This results in the nonces not being tied to particular Flow addresses. The backend should + enforce an expiry window for each nonce to avoid the pool of valid nonces from growing indefinitely. + Your application is encouraged to implement further mitigations against malicious attempts and + maintain a scalable authentication process. +- FCL `account-proof` provides functionality to prove a user is in control of + a Flow address. All other aspects of authentication, authorization and session management + are up to the application. There are many resources available for setting up secure user + authentication systems. Application developers should carefully consider what's best for their use + case and follow industry best practices. +- It is important to use a secure source of entropy to generate the random nonces. The source should insure + nonces are not predictable by looking at previously generated nonces. Moreover, backend should use its own + local source and not rely on a publicly available source. Using a nonce of at least 32-bytes insures + it is extremely unlikely to have a nonce collision. +- Your application identifier `appIdentifier` is a constant defined by your backend. It is + important that the backend uses the `appIdentifier` it expects when verifying the signatures, + and not rely on an identifier passed along with the `account-proof`. For this reason, + `appIdentifier` is not included in the `account-proof` data. +- A successful FCL authentication proves the user fully controls a Flow account. This means the user + controls one or many account keys with weights that add up to the full account weight. The authentication + would fail if the user doesn't control keys that add up to a full weight. + + +=== tools/clients/fcl-js/interaction-templates.mdx === +--- +title: Interaction Templates +--- + +# Interaction Templates + +> Interaction Templates are a concept established in FLIP-934. Read the FLIP [here](https://github.com/onflow/flips/blob/main/application/20220503-interaction-templates.md) + +> "Interaction" in this context refers to the higher order term establised in FLIP-934 that encompases a transaction and script, things that _interact_ with the blockchain. + +## Overview + +Interaction Templates establish a format for metadata that exists about an interaction. Interaction Templates can include: + +- Human readable, internationalized messages about the interaction +- The Cadence code to carry out the interaction +- Information about arguments such as internationalized human readable messages and what the arguments act upon +- Contract dependencies the Interaction engages with, pinned to a version of them and their dependency tree + +Applications and Wallets can use Interaction Templates and it's interaction metadata. + +For example Applications and Wallets can extract the internationalized human readable messaging from an Interaction Template to display to their users prior to execution of the interaction. + +## For Applications + +FCL `mutate` and `query` can accept an Interaction Template. FCL `mutate` and `query` will use the Interaction Template to: + +- Extract the Cadence code to carry out the interaction +- Extract dependency configuration for the interaction (eg: Information about contract import addresses) + +Here is an example of using `mutate` with an Interaction Template: +```javascript +import * as fcl from "@onflow/fcl" +import myTransactionTemplate from "./my-transaction-template.template.json" + +const txId = await fcl.mutate({ + template: myTransactionTemplate +}) +``` + +An Interaction Template can also be used with `query`: +```javascript +import * as fcl from "@onflow/fcl" +import myScriptTemplate from "./my-script-template.template.json" + +const info = await fcl.query({ + template: myScriptTemplate +}) +``` + +Interaction Templates can be resolved from remote locations: + +```javascript +import * as fcl from "@onflow/fcl" + +const txId = await fcl.mutate({ + template: "http://interactions.awesome-crypto-project.com/buy-nft" +}) + +const nftInfo = await fcl.query({ + template: "http://interactions.awesome-crypto-project.com/read-nft", + args: (arg, t) => [arg("nft-id", t.String)] +}) +``` + +FCL will resolve the template from the remote location before using it to execute its underlying transaction or script. + +> 💡 By requesting an Interaction Template from an external location, applications have a mechanism to always retrieve the most up to date way of accomplishing an interaction. + +By default FCL supports resolving Interaction Templates over http/https, but FCL can also be configured with various other ways to resolve Interaction Templates: + +```javascript +import * as fcl from "@onflow/fcl" + +await fcl.config().put("document.resolver.ipfs", async ({ url }) => { + const jsonTemplate = getDocumentFromIPFS(url) // resolve interaction template from ipfs + return jsonTemplate +}) + +const txId = await fcl.mutate({ + template: "ipfs://IPFSHASHGOESHERE" +}) +``` + +## For Wallets + +Wallets can use Interaction Templates to: +- Display internationalized human readable information about a transaction to their users during signing +- Verify the dependencies of an Interaction Template have not changed since when the Interaction Template was created +- Using Interaction Template Audits, gain confidence in the correctness and safety of an Interaction Template and it's underlying transaction + +When recieving a transaction to sign, wallets can query for an Interaction Template that corresponds to it. + +Flow operates an "Interaction Template Discovery Service" which wallets can use to query for Interaction Templates. Anyone can run an "Interaction Template Discovery Service" and wallets can choose to query from any of them. + +```javascript +const cadence = cadenceFromTransactionToSign +const network = "mainnet" // "mainnet" | "testnet" + +const cadence_base64 = btoa(cadence) + +const interactionTemplate = await fetch( + "https://flix.flow.com/v1/templates/search", + { + method: "POST", + headers: { + "Content-Type": "application/json" + } + body: JSON.stringify({ + cadence_base64, + network + }) + } +) +``` + +> 📖 For more on the "Interaction Template Discovery Service" that Flow operates, see [here](https://github.com/onflow/flow-interaction-template-service) + +> ❗️ Not all transactions will have a corresponding Interaction Template. Wallets are encouraged to always support signing transactions that do not have a corresponding Interaction Template, or if they fail to discover one. + +Once a wallet has a corresponding Interaction Template for a given transaction, they may also may wish to verify that the transaction it represents is safe to sign, and that the Interaction Template is accurate for that transaction. + +To do so, wallets can rely on themselves, along with external Interaction Template Auditors to gain confidence in the Interaction Template and it's underlying transaction. Interaction Template Auditors are entities that audit Interaction Templates for correctness and safety. + +> 💡 Anyone can be an Interaction Template Auditor. Wallets can choose auditors they trust, if any. + +Wallets can specify auditors it trusts to FCL by configuring FCL with the address of each auditor: + +```javascript +import * as fcl from "@onflow/fcl" + +await fcl.config().put("flow.network", "mainnet") + +const auditorA_FlowAddress = "0xABC123DEF456" +const auditorB_FlowAddress = "0xFFAA1212DEFF" + +await fcl.config().put("flow.auditors", [ + auditorA_FlowAddress, + auditorB_FlowAddress +]) +``` + +Wallets can check if the auditors they configured FCL with have audited a given Interaction Template: + +```javascript +import * as fcl from "@onflow/fcl" +import myTransactionTemplate from "./my-transaction-template.template.json" + +const audits = await fcl.InteractionTemplateUtils + .getInteractionTemplateAudits({ + template: myTransactionTemplate + }) + +/** + * audits = { + * "0xABC123DEF456": true, + * "0xFFAA1212DEFF": false + * } + ** / +``` + +The Flow team operates these auditor accounts: + +| Flow Team Auditor Accounts | Address | +|----------------------------|:-------------------| +| TestNet | 0xf78bfc12d0a786dc | +| MainNet | 0xfd100e39d50a13e6 | + +Since not all auditors that a wallet trusts may have audited a given Interaction Template, trusting multiple auditors can increase the chance that at least one of the trusted auditors has audited the Interaction Template. + +> ❗️ Auditors can revoke audits at any time, so be sure to always check an Interaction Template's audit status. + +Since contracts on Flow are mutable, wallets may additionally wish to verify that none of the dependency tree for the transaction an Interaction Template represents has changed since when it was created and of what it was audited against. + +```javascript +import * as fcl from "@onflow/fcl" +import myTransactionTemplate from "./my-transaction-template.template.json" + +const hasDependencyTreeChanged = await fcl.InteractionTemplateUtils + .verifyDependencyPinsSameAtLatestSealedBlock({ + template: myTransactionTemplate + }) +``` + +If the dependency tree has changed, wallets may choose to disregard the Interaction Template (and it's audits). + +Once the Interaction Template has been sufficiently audited by auditors the wallet trusts, and it's dependency tree determined unchanged since the interaction was created and audited against, then the wallet can use the Interaction Template with greater confidence in it's correctness and safety. + +The wallet may then decide to render human readable information about the transaction such as: +- Internationalized 'title' and 'description' of the transaction +- Internationalized 'title' for each of the transactions arguments alongside the arguments value + +The wallet may then also make the status of it's audits known to the user in their UI. This allows the user to have greater confidence in the safety of the transaction. + +## Data Structure + +The following is an example Interaction Template that corresponds to a "Transfer FLOW" transaction: + +```json +{ + "f_type": "InteractionTemplate", + "f_version": "1.0.0", + "id": "290b6b6222b2a77b16db896a80ddf29ebd1fa3038c9e6625a933fa213fce51fa", + "data": { + "type": "transaction", + "interface": "", + "messages": { + "title": { + "i18n": { + "en-US": "Transfer Tokens" + } + }, + "description": { + "i18n": { + "en-US": "Transfer tokens from one account to another" + } + } + }, + "cadence": "import FungibleToken from 0xFUNGIBLETOKENADDRESS\ntransaction(amount: UFix64, to: Address) {\nlet vault: @FungibleToken.Vault\nprepare(signer: &Account) {\nself.vault <- signer\n.borrow<&{FungibleToken.Provider}>(from: /storage/flowTokenVault)!\n.withdraw(amount: amount)\n}\nexecute {\ngetAccount(to)\n.capabilities.get(/public/flowTokenReceiver)!\n.borrow<&{FungibleToken.Receiver}>()!\n.deposit(from: <-self.vault)\n}\n}", + "dependencies": { + "0xFUNGIBLETOKENADDRESS": { + "FungibleToken": { + "mainnet": { + "address": "0xf233dcee88fe0abe", + "fq_address": "A.0xf233dcee88fe0abe.FungibleToken", + "contract": "FungibleToken", + "pin": "83c9e3d61d3b5ebf24356a9f17b5b57b12d6d56547abc73e05f820a0ae7d9cf5", + "pin_block_height": 34166296 + }, + "testnet": { + "address": "0x9a0766d93b6608b7", + "fq_address": "A.0x9a0766d93b6608b7.FungibleToken", + "contract": "FungibleToken", + "pin": "83c9e3d61d3b5ebf24356a9f17b5b57b12d6d56547abc73e05f820a0ae7d9cf5", + "pin_block_height": 74776482 + } + } + } + }, + "arguments": { + "amount": { + "index": 0, + "type": "UFix64", + "messages": { + "title": { + "i18n": { + "en-US": "The amount of FLOW tokens to send" + } + } + } + }, + "to": { + "index": 1, + "type": "Address", + "messages": { + "title": { + "i18n": { + "en-US": "The Flow account the tokens will go to" + } + } + } + } + } + } +} +``` + + +=== tools/clients/fcl-js/installation.mdx === +# Installation + +This chapter explains the installation of the FCL JS library in your system. However, before moving to the installation, let us verify the prerequisite first. + +## Prerequisite +- Node.js version v12.0.0 or higher. + +FCL JS depends on Node.js version v12.0.0 or higher. You can check your currently installed version using the below command: + +```javascript +node --version +``` + +If Node.js is not installed on your system, you can download and install it by visiting [Node.js Download](https://nodejs.org/en/download/). + + +Install FCL JS using **npm** or **yarn** + +```shell +npm i -S @onflow/fcl +``` + +```shell +yarn add @onflow/fcl +``` +#### Importing + +**ES6** +```js +import * as fcl from "@onflow/fcl"; +``` +**Node.js** +```js +const fcl = require("@onflow/fcl"); +``` + + +=== tools/clients/fcl-js/index.md === +--- +sidebar_position: 3 +--- + +# Flow Client Library (FCL) + +## 🌟 What is FCL? + +The **Flow Client Library (FCL) JS** is a package designed to facilitate interactions between dapps, wallets, and the Flow blockchain. It provides a standardized way for applications to connect with users and their wallets, **eliminating the need for custom integrations**. + +### 🔑 Key Features: +- 🔌 **Universal Wallet Support** – Works seamlessly with all FCL-compatible wallets, making authentication simple. +- 🔐 **Secure Authentication** – Standardized authentication flow ensures a smooth user experience. +- ⚡ **Blockchain Interactions** – Enables querying, mutating, and interacting with smart contracts on Flow. +- 🛠️ **Full-Featured Utilities** – Offers built-in functions to streamline blockchain development. +- 🌍 **Flexible Environment** – Can run in both browser and server environments, though wallet interactions are browser-only. + +FCL was created to make building Flow-connected applications **easy, secure, and scalable** by defining **standardized communication patterns** between wallets, applications, and users. + +For iOS, we also offer [FCL Swift](https://github.com/Outblock/fcl-swift). + +--- +## Getting Started + +### Requirements +- Node version `v12.0.0 or higher`. + +### Installation + +To use the FCL JS in your application, install using **yarn** or **npm** + +```shell +npm i -S @onflow/fcl +``` + +```shell +yarn add @onflow/fcl +``` +#### Importing + +**ES6** +```js +import * as fcl from "@onflow/fcl"; +``` +**Node.js** +```js +const fcl = require("@onflow/fcl"); +``` +--- +## FCL for Dapps +#### Wallet Interactions + +- *Wallet Discovery* and *Sign-up/Login*: Onboard users with ease. Never worry about supporting multiple wallets. + Authenticate users with any [FCL compatible wallet](#current-wallet-providers). +```js +// in the browser +import * as fcl from "@onflow/fcl" + +fcl.config({ + "discovery.wallet": "https://fcl-discovery.onflow.org/testnet/authn", // Endpoint set to Testnet +}) + +fcl.authenticate() +``` +![FCL Default Discovery UI](images/discovery.png) + +> **Note**: A [Dapper Wallet](https://meetdapper.com/developers) developer account is required. To enable Dapper Wallet inside FCL, you need to [follow this guide](https://docs.meetdapper.com/get-started). + +- *Interact with smart contracts*: Authorize transactions via the user's chosen wallet +- *Prove ownership of a wallet address*: Signing and verifying user signed data + +[Learn more about wallet interactions >](api.md#wallet-interactions) + +#### Blockchain Interactions +- *Query the chain*: Send arbitrary Cadence scripts to the chain and receive back decoded values +```js +import * as fcl from "@onflow/fcl"; + +const result = await fcl.query({ + cadence: ` + pub fun main(a: Int, b: Int, addr: Address): Int { + log(addr) + return a + b + } + `, + args: (arg, t) => [ + arg(7, t.Int), // a: Int + arg(6, t.Int), // b: Int + arg("0xba1132bc08f82fe2", t.Address), // addr: Address + ], +}); +console.log(result); // 13 +``` +- *Mutate the chain*: Send arbitrary transactions with your own signatures or via a user's wallet to perform state changes on chain. +```js +import * as fcl from "@onflow/fcl"; +// in the browser, FCL will automatically connect to the user's wallet to request signatures to run the transaction +const txId = await fcl.mutate({ + cadence: ` + import Profile from 0xba1132bc08f82fe2 + + transaction(name: String) { + prepare(account: AuthAccount) { + account.borrow<&{Profile.Owner}>(from: Profile.privatePath)!.setName(name) + } + } + `, + args: (arg, t) => [arg("myName", t.String)], +}); +``` + +[Learn more about on-chain interactions >](api.md#on-chain-interactions) + +#### Utilities +- Get account details from any Flow address +- Get the latest block +- Transaction status polling +- Event polling +- Custom authorization functions + +[Learn more about utilities >](api.md#pre-built-interactions) + +## Typescript Support + +FCL JS supports TypeScript. If you need to import specific types, you can do so via the [@onflow/typedefs](https://github.com/onflow/fcl-js/tree/master/packages/typedefs) package. + +```typescript +import {CurrentUser} from "@onflow/typedefs" + +const newUser: CurrentUser = { + addr: null, + cid: null, + expiresAt: null, + f_type: 'User', + f_vsn: '1.0.0', + loggedIn: null, + services: [] +} +``` + +For all type definitions available, see [this file](https://github.com/onflow/fcl-js/blob/master/packages/typedefs/src/index.ts) + +## Next Steps + +- See the [Flow App Quick Start](../../../build/getting-started/fcl-quickstart.md). +- See the full [API Reference](api.md) for all FCL functionality. +- Learn Flow's smart contract language to build any script or transactions: [Cadence](https://cadence-lang.org). +- Explore all of Flow [docs and tools](https://developers.flow.com). + +--- +## FCL for Wallet Providers +Wallet providers on Flow have the flexibility to build their user interactions and UI through a variety of ways: +- Front channel communication via Iframe, pop-up, tab, or extension +- Back channel communication via HTTP + +FCL is agnostic to the communication channel and be configured to create both custodial and non-custodial wallets. This enables users to interact with wallet providers without needing to download an app or extension. + +The communication channels involve responding to a set of pre-defined FCL messages to deliver the requested information to the dapp. Implementing a FCL compatible wallet on Flow is as simple as filling in the responses with the appropriate data when FCL requests them. If using any of the front-channel communication methods, FCL also provides a set of [wallet utilities](https://github.com/onflow/fcl-js/blob/master/packages/fcl-core/src/wallet-utils/index.js) to simplify this process. + +### Current Wallet Providers +- [Flow Wallet](https://wallet.flow.com/) +- [NuFi Wallet](https://nu.fi/) +- [Blocto](https://blocto.portto.io/en/) +- [Ledger](https://ledger.com) (limited transaction support) +- [Dapper Wallet](https://www.meetdapper.com/) (beta access - general availability coming soon) + +### Wallet Discovery +It can be difficult to get users to discover new wallets on a chain. To solve this, we created a [wallet discovery service](https://github.com/onflow/fcl-discovery) that can be configured and accessed through FCL to display all available Flow wallet providers to the user. This means: +- Dapps can display and support all FCL compatible wallets that launch on Flow without needing to change any code +- Users don't need to sign up for new wallets - they can carry over their existing one to any dapp that uses FCL for authentication and authorization. + +The discovery feature can be used via API allowing you to customize your own UI or you can use the default UI without any additional configuration. + +> Note: To get your wallet added to the discovery service, make a PR in [fcl-discovery](https://github.com/onflow/fcl-discovery). + +### Building a FCL compatible wallet + +- Read the [wallet guide](https://github.com/onflow/fcl-js/blob/master/packages/fcl-core/src/wallet-provider-spec/draft-v4.md) to understand the implementation details. +- Review the architecture of the [FCL dev wallet](https://github.com/onflow/fcl-dev-wallet) for an overview. +- If building a non-custodial wallet, see the [Account API](https://github.com/onflow/flow-account-api) and the [FLIP](https://github.com/onflow/flow/pull/727) on derivation paths and key generation. + +--- + +## 🛠 Want to Use the Flow SDK Directly? + +If you prefer to interact with Flow at a **lower level** without using FCL, you can use the [Flow JavaScript SDK](sdk-guidelines.md) directly. The SDK provides raw access to Flow's API for sending transactions, executing scripts, and managing accounts. + +FCL is built **on top of the Flow SDK**, making it easier to handle authentication, wallet interactions, and dapp connectivity. Choose the approach that best fits your use case. + +## Support + +- Notice a problem or want to request a feature? [Add an issue](https://github.com/onflow/fcl-js/issues). +- Join the Flow community on [Discord](https://discord.gg/flow) to keep up to date and to talk to the team. +- Read the [Contributing Guide](https://github.com/onflow/fcl-js/blob/master/CONTRIBUTING.md) to learn how to contribute to the project. + + +=== tools/clients/fcl-js/discovery.md === +--- +title: Wallet Discovery +--- + +## Wallet Discovery + +Knowing all the wallets available to users on a blockchain can be challenging. FCL's Discovery mechanism relieves much of the burden of integrating with Flow compatible wallets and let's developers focus on building their dapp and providing as many options as possible to their users. + +There are two ways an app can use Discovery: + +1. The **UI version** which can be configured for display via iFrame, Popup, or Tab. +2. The **API version** which allows you to access authentication services directly in your code via `fcl.discovery.authn` method which we'll describe below. + +## UI Version + +When authenticating via FCL using Discovery UI, a user is shown a list of services they can use to login. + +![FCL Default Discovery UI](./images/discovery.png) + +This method is the simplest way to integrate Discovery and its wallets and services into your app. All you have to do is configure `discovery.wallet` with the host endpoint for testnet or mainnet. + +> **Note**: Opt-in wallets, like Ledger and Dapper Wallet, require you to explicitly state you'd like to use them. For more information on including opt-in wallets, [see these docs](./api.md#more-configuration). +> +> A [Dapper Wallet](https://meetdapper.com/developers) developer account is required. To enable Dapper Wallet inside FCL, you need to [follow this guide](https://docs.meetdapper.com/quickstart). + +```javascript +import { config } from '@onflow/fcl'; + +config({ + 'accessNode.api': 'https://rest-testnet.onflow.org', + 'discovery.wallet': 'https://fcl-discovery.onflow.org/testnet/authn', +}); +``` + +Any time you call `fcl.authenticate` the user will be presented with that screen. + +To change the default view from iFrame to popup or tab set `discovery.wallet.method` to `POP/RPC` (opens as a popup) or `TAB/RPC` (opens in a new tab). More info about service methods can be [found here](https://github.com/onflow/fcl-js/blob/9bce741d3b32fde18b07084b62ea15f9bbdb85bc/packages/fcl/src/wallet-provider-spec/draft-v3.md). + +### Branding Discovery UI + +Starting in version 0.0.79-alpha.4, dapps now have the ability to display app a title and app icon in the Discovery UI by setting a few values in their FCL app config. This branding provides users with messaging that has clear intent before authenticating to add a layer of trust. + +All you have to do is set `app.detail.icon` and `app.detail.title` like this: + +```javascript +import { config } from '@onflow/fcl'; + +config({ + 'app.detail.icon': 'https://placekitten.com/g/200/200', + 'app.detail.title': 'Kitten Dapp', +}); +``` + +**Note:** If these configuration options aren't set, Dapps using the Discovery API will still display a default icon and "Unknown App" as the title when attempting to authorize a user who is not logged in. It is highly recommended to set these values accurately before going live. + +## API Version + +If you want more control over your authentication UI, the Discovery API is also simple to use as it exposes Discovery directly in your code via `fcl`. + +Setup still requires configuration of the Discovery endpoint, but when using the API it is set via `discovery.authn.endpoint` as shown below. + +```javascript +import { config } from '@onflow/fcl'; + +config({ + 'accessNode.api': 'https://rest-testnet.onflow.org', + 'discovery.authn.endpoint': + 'https://fcl-discovery.onflow.org/api/testnet/authn', +}); +``` + +You can access services in your Dapp from `fcl.discovery`: + +```javascript +import * as fcl from '@onflow/fcl'; + +fcl.discovery.authn.subscribe(callback); + +// OR + +fcl.discovery.authn.snapshot(); +``` + +In order to authenticate with a service (for example, when a user click's "login"), pass the selected service to the `fcl.authenticate` method described here [in the API reference](./api.md#authenticate): + +```jsx +fcl.authenticate({ service }); +``` + +A simple React component may end up looking like this: + +```jsx +import './config'; +import { useState, useEffect } from 'react'; +import * as fcl from '@onflow/fcl'; + +function Component() { + const [services, setServices] = useState([]); + useEffect( + () => fcl.discovery.authn.subscribe((res) => setServices(res.results)), + [], + ); + + return ( +
    + {services.map((service) => ( + + ))} +
    + ); +} +``` + +Helpful fields for your UI can be found in the `provider` object inside of the service. Fields include the following: + +```json +{ + ..., + "provider": { + "address": "0xf086a545ce3c552d", + "name": "Blocto", + "icon": "/images/blocto.png", + "description": "Your entrance to the blockchain world.", + "color": "#afd8f7", + "supportEmail": "support@blocto.app", + "authn_endpoint": "https://flow-wallet-testnet.blocto.app/authn", + "website": "https://blocto.portto.io" + } +} +``` + +## Network Configuration + +### Discovery UI URLs + +| Environment | Example | +| ----------- | ------------------------------------------------ | +| Mainnet | `https://fcl-discovery.onflow.org/authn` | +| Testnet | `https://fcl-discovery.onflow.org/testnet/authn` | +| Local | `https://fcl-discovery.onflow.org/local/authn` | + +### Discovery API Endpoints + +| Environment | Example | +| ----------- | ---------------------------------------------------- | +| Mainnet | `https://fcl-discovery.onflow.org/api/authn` | +| Testnet | `https://fcl-discovery.onflow.org/api/testnet/authn` | +| Local | `https://fcl-discovery.onflow.org/api/local/authn` | + +> Note: Local will return [Dev Wallet](https://github.com/onflow/fcl-dev-wallet) on emulator for developing locally with the default port of 8701. If you'd like to override the default port add ?port=0000 with the port being whatever you'd like to override it to. + +## Other Configuration + +> Note: Configuration works across both UI and API versions of Discovery. + +### Include Opt-In Wallets + +**Starting in FCL v0.0.78-alpha.10** + +Opt-in wallets are those that don't have support for authentication, authorization, and user signature services. Or, support only a limited set of transactions. + +To include opt-in wallets from FCL: + +``` +import * as fcl from "@onflow/fcl" + +fcl.config({ + "discovery.wallet": "https://fcl-discovery.onflow.org/testnet/authn", + "discovery.authn.endpoint": "https://fcl-discovery.onflow.org/api/testnet/authn", + "discovery.authn.include": ["0x123"] // Service account address +}) +``` + +**Opt-In Wallet Addresses on Testnet and Mainnet** + +| Service | Testnet | Mainnet | +| --------------- | ------------------ | ------------------ | +| `Dapper Wallet` | 0x82ec283f88a62e65 | 0xead892083b3e2c6c | +| `Ledger` | 0x9d2e44203cb13051 | 0xe5cd26afebe62781 | + +To learn more about other possible configurations, check out the following links: + +- [Discovery API Docs](./api.md#discovery-1) +- [Discovery Github Repo](https://github.com/onflow/fcl-discovery) + +### Exclude Wallets + +To exclude wallets from FCL Discovery, you can use the `discovery.authn.exclude` configuration option. This allows you to specify a list of service account addresses that you want to hide from the Discovery UI or API. + +```javascript +import * as fcl from '@onflow/fcl'; +fcl.config({ + 'discovery.wallet': 'https://fcl-discovery.onflow.org/testnet/authn', + 'discovery.authn.endpoint': + 'https://fcl-discovery.onflow.org/api/testnet/authn', + 'discovery.authn.exclude': ['0x123', '0x456'], // Service account addresses to exclude +}); +``` + + +=== tools/clients/fcl-js/configure-fcl.md === +--- +title: How to Configure FCL +--- + +## Configuration + +FCL provides a mechanism to configure various aspects of its behavior. The key principle is that when switching between different Flow Blockchain environments (e.g., Local Emulator → Testnet → Mainnet), the only required change should be your FCL configuration. + +## Setting Configuration Values + +Values only need to be set once. We recommend doing this once and as early in the life cycle as possible. +To set a configuration value, the `put` method on the `config` instance needs to be called, the `put` method returns the `config` instance so they can be chained. + +```javascript +import * as fcl from '@onflow/fcl'; + +fcl + .config() // returns the config instance + .put('foo', 'bar') // configures "foo" to be "bar" + .put('baz', 'buz'); // configures "baz" to be "buz" +``` + +## Getting Configuration Values + +The `config` instance has an asynchronous `get` method. You can also pass it a fallback value incase the configuration state does not include what you are wanting. + +```javascript +import * as fcl from '@onflow/fcl'; + +fcl.config().put('foo', 'bar').put('woot', 5).put('rawr', 7); + +const FALLBACK = 1; + +async function addStuff() { + var woot = await fcl.config().get('woot', FALLBACK); // will be 5 -- set in the config before + var rawr = await fcl.config().get('rawr', FALLBACK); // will be 7 -- set in the config before + var hmmm = await fcl.config().get('hmmm', FALLBACK); // will be 1 -- uses fallback because this isnt in the config + + return woot + rawr + hmmm; +} + +addStuff().then((d) => console.log(d)); // 13 (5 + 7 + 1) +``` + +## Common Configuration Keys + +- `accessNode.api` -- Api URL for the Flow Blockchain Access Node you want to be communicating with. +- `app.detail.title` - **(INTRODUCED `@onflow/fcl@0.0.68`)** Your applications title, can be requested by wallets and other services. Used by WalletConnect plugin & Wallet Discovery service. +- `app.detail.icon` - **(INTRODUCED `@onflow/fcl@0.0.68`)** Url for your applications icon, can be requested by wallets and other services. Used by WalletConnect plugin & Wallet Discovery service. +- `app.detail.description` - **(INTRODUCED `@onflow/fcl@1.11.0`)** Your applications description, can be requested by wallets and other services. Used by WalletConnect plugin & Wallet Discovery service. +- `app.detail.url` - **(INTRODUCED `@onflow/fcl@1.11.0`)** Your applications url, can be requested by wallets and other services. Used by WalletConnect plugin & Wallet Discovery service. +- `challenge.handshake` -- **(DEPRECATED `@onflow/fcl@0.0.68`)** Points FCL at the Wallet or Wallet Discovery mechanism. +- `discovery.wallet` -- **(INTRODUCED `@onflow/fcl@0.0.68`)** Points FCL at the Wallet or Wallet Discovery mechanism. +- `discovery.wallet.method` -- Describes which service strategy a wallet should use: `IFRAME/RPC`, `POP/RPC`, `TAB/RPC`, `HTTP/POST`, `EXT/RPC` +- `env` -- **(DEPRECATED `@onflow/fcl@1.0.0`)** Used in conjunction with stored interactions. Possible values: `local`, `testnet`, `mainnet` +- `fcl.limit` -- Specifies fallback compute limit if not provided in transaction. Provided as integer. +- `flow.network` (recommended) -- **(INTRODUCED `@onflow/fcl@1.0.0`)** Used in conjunction with stored interactions and provides FCLCryptoContract address for `testnet` and `mainnet`. Possible values: `local`, `testnet`, `mainnet`. +- `service.OpenID.scopes` - **(INTRODUCED `@onflow/fcl@0.0.68`)** Open ID Connect claims for Wallets and OpenID services. +- `walletconnect.projectId` -- **(INTRODUCED `@onflow/fcl@1.11.0`)** Your app's WalletConnect project ID. See [WalletConnect Cloud](https://cloud.walletconnect.com/sign-in) to obtain a project ID for your application. +- `walletconnect.disableNotifications` -- **(INTRODUCED `@onflow/fcl@1.13.0`)** Flag to disable pending WalletConnect request notifications within the application's UI. Default is `false`. + +## Using Contracts in Scripts and Transactions + +### Address Replacement + +Configuration keys that start with `0x` will be replaced in FCL scripts and transactions, this allows you to write your script or transaction Cadence code once and not have to change it when you point your application at a difference instance of the Flow Blockchain. + +```javascript +import * as fcl from '@onflow/fcl'; + +fcl.config().put('0xFungibleToken', '0xf233dcee88fe0abe'); + +async function myScript() { + return fcl + .send([ + fcl.script` + import FungibleToken from 0xFungibleToken // will be replaced with 0xf233dcee88fe0abe because of the configuration + + access(all) fun main() { /* Rest of the script goes here */ } + `, + ]) + .then(fcl.decode); +} + +async function myTransaction() { + return fcl + .send([ + fcl.transaction` + import FungibleToken from 0xFungibleToken // will be replaced with 0xf233dcee88fe0abe because of the configuration + + transaction { /* Rest of the transaction goes here */ } + `, + ]) + .then(fcl.decode); +} +``` + +#### Example + +```javascript +import * as fcl from '@onflow/fcl'; + +fcl + .config() + .put('flow.network', 'testnet') + .put('accessNode.api', 'https://rest-testnet.onflow.org') + .put('discovery.wallet', 'https://fcl-discovery.onflow.org/testnet/authn') + .put('walletconnect.projectId', 'YOUR_PROJECT_ID') + .put('app.detail.title', 'Test Harness') + .put('app.detail.icon', 'https://i.imgur.com/r23Zhvu.png') + .put('app.detail.description', 'A test harness for FCL') + .put('app.detail.url', 'https://myapp.com') + .put('0xFlowToken', '0x7e60df042a9c0868'); +``` + +### Using `flow.json` + +A simpler way to import contracts in scripts and transactions is to use the `config.load` method to ingest your contracts from your `flow.json` file. This keeps the import syntax unified across tools and lets FCL figure out which address to use for what network based on the network provided in config. To use `config.load` you must first import your `flow.json` file and then pass it to `config.load` as a parameter. + +```javascript +import { config } from '@onflow/fcl'; +import flowJSON from '../flow.json'; + +config({ + 'flow.network': 'testnet', + 'accessNode.api': 'https://rest-testnet.onflow.org', + 'discovery.wallet': `https://fcl-discovery.onflow.org/testnet/authn`, +}).load({ flowJSON }); +``` + +Let's say your `flow.json` file looks like this: + +``` +{ + "contracts": { + "HelloWorld": "cadence/contracts/HelloWorld.cdc" + } +} +``` + +Then in your scripts and transactions, all you have to do is: + +``` +import "HelloWorld" +``` + +FCL will automatically replace the contract name with the address for the network you are using. + +> Note: never put private keys in your `flow.json`. You should use the [key/location syntax](../../flow-cli/flow.json/security.md) to separate your keys into a separate git ignored file. + + +=== tools/clients/fcl-js/authentication.md === +# Authentication + +Authentication in FCL is closely tied to the concept of `currentUser`. In fact, `fcl.authenticate` and `fcl.unauthenticate` are simply aliases for `fcl.currentUser.authenticate()` and `fcl.currentUser.unauthenticate()`, respectively. So, let’s take a closer look at `currentUser`. + +As an onchain app developer using FCL, the primary authentication functionalities revolve around: + +- Determining the `currentUser` and whether they are logged in. +- Logging a user in. +- Logging a user out. + +Due to the way FCL works, logging in and signing up are essentially the same process. + +# Retrieving Information About the Current User + +FCL provides two ways to get information about the current user: + +1. **A promise-based method** that returns a snapshot of the user’s data. +2. **A subscription-based method** that triggers a callback function with the latest user information whenever it changes. + +### Snapshot of the Current User + +```javascript +import * as fcl from "@onflow/fcl" + +const currentUser = await fcl.currentUser.snapshot() +console.log("The Current User:", currentUser) +``` + +### Subscribe to the Current User + +```javascript +import * as fcl from "@onflow/fcl" + +// Returns an unsubscribe function +const unsubscribe = fcl.currentUser.subscribe(currentUser => { + console.log("The Current User:", currentUser) +}) +``` + +# Authenticating and Unauthenticating + +The TL;DR: Call `fcl.authenticate()` to log in and `fcl.unauthenticate()` to log out. + +On Flow mainnet, no additional configuration is needed—your app’s users will go through the authentication process and be able to use any FCL-compatible wallet provider. + +During development, you’ll likely want to configure your app to use [`@onflow/dev-wallet`](https://github.com/onflow/fcl-dev-wallet). The [Quick Start](../../../build/getting-started/fcl-quickstart.md) guide will walk you through setting it up. + +We also recommend using the [FCL Discovery Service](discovery.md) to help users discover and connect to FCL-compatible wallets. + +Whether you're new to building onchain, or an established veteran, we’re here to help. If you run into any issues, reach out to us on [Discord](https://discord.gg/flow) — we’re happy to assist! + +=== tools/clients/fcl-js/api.md === +--- +sidebar_label: FCL Reference +sidebar_position: 2 +--- + +# Flow Client Library (FCL) API Reference + +> For release updates, [see the repo](https://github.com/onflow/fcl-js/releases) + +## Configuration + +FCL has a mechanism that lets you configure various aspects of FCL. When you move from one instance of the Flow Blockchain to another (Local Emulator to Testnet to Mainnet) the only thing you should need to change for your FCL implementation is your configuration. + +--- + +### Setting Configuration Values + +Values only need to be set once. We recommend doing this once and as early in the life cycle as possible. To set a configuration value, the `put` method on the `config` instance needs to be called, the `put` method returns the `config` instance so they can be chained. + +Alternatively, you can set the config by passing a JSON object directly. + +```javascript +import * as fcl from '@onflow/fcl'; + +fcl + .config() // returns the config instance + .put('foo', 'bar') // configures "foo" to be "bar" + .put('baz', 'buz'); // configures "baz" to be "buz" + +// OR + +fcl.config({ + foo: 'bar', + baz: 'buz', +}); +``` + +### Getting Configuration Values + +The `config` instance has an **asynchronous** `get` method. You can also pass it a fallback value. + +```javascript +import * as fcl from '@onflow/fcl'; + +fcl.config().put('foo', 'bar').put('woot', 5).put('rawr', 7); + +const FALLBACK = 1; + +async function addStuff() { + var woot = await fcl.config().get('woot', FALLBACK); // will be 5 -- set in the config before + var rawr = await fcl.config().get('rawr', FALLBACK); // will be 7 -- set in the config before + var hmmm = await fcl.config().get('hmmm', FALLBACK); // will be 1 -- uses fallback because this isnt in the config + + return woot + rawr + hmmm; +} + +addStuff().then((d) => console.log(d)); // 13 (5 + 7 + 1) +``` + +### Common Configuration Keys + +| Name | Example | Description | +| ------------------------------------ | ------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `accessNode.api` **(required)** | `https://rest-testnet.onflow.org` | API URL for the Flow Blockchain Access Node you want to be communicating with. See all available access node endpoints [here](https://developers.onflow.org/http-api/). | +| `app.detail.title` | `Cryptokitties` | Your applications title, can be requested by wallets and other services. Used by WalletConnect plugin & Wallet Discovery service. | +| `app.detail.icon` | `https://fcl-discovery.onflow.org/images/blocto.png` | Url for your applications icon, can be requested by wallets and other services. Used by WalletConnect plugin & Wallet Discovery service. | +| `app.detail.description` | `Cryptokitties is a blockchain game` | Your applications description, can be requested by wallets and other services. Used by WalletConnect plugin & Wallet Discovery service. | +| `app.detail.url` | `https://cryptokitties.co` | Your applications url, can be requested by wallets and other services. Used by WalletConnect plugin & Wallet Discovery service. | +| `challenge.handshake` | **DEPRECATED** | Use `discovery.wallet` instead. | +| `discovery.authn.endpoint` | `https://fcl-discovery.onflow.org/api/testnet/authn` | Endpoint for alternative configurable Wallet Discovery mechanism. Read more on [discovery](#discovery) | +| `discovery.wallet` **(required)** | `https://fcl-discovery.onflow.org/testnet/authn` | Points FCL at the Wallet or Wallet Discovery mechanism. | +| `discovery.wallet.method` | `IFRAME/RPC`, `POP/RPC`, `TAB/RPC`, `HTTP/POST`, or `EXT/RPC` | Describes which service strategy a wallet should use. | +| `fcl.limit` | `100` | Specifies fallback compute limit if not provided in transaction. Provided as integer. | +| `flow.network` **(recommended)** | `testnet` | Used in conjunction with stored interactions and provides FCLCryptoContract address for `testnet` and `mainnet`. Possible values: `local`, `testnet`, `mainnet`. | +| `walletconnect.projectId` | `YOUR_PROJECT_ID` | Your app's WalletConnect project ID. See [WalletConnect Cloud](https://cloud.walletconnect.com/sign-in) to obtain a project ID for your application. | +| `walletconnect.disableNotifications` | `false` | Optional flag to disable pending WalletConnect request notifications within the application's UI. | + +## Using Contracts in Scripts and Transactions + +### Address Replacement + +Configuration keys that start with `0x` will be replaced in FCL scripts and transactions, this allows you to write your script or transaction Cadence code once and not have to change it when you point your application at a difference instance of the Flow Blockchain. + +```javascript +import * as fcl from '@onflow/fcl'; + +fcl.config().put('0xFungibleToken', '0xf233dcee88fe0abe'); + +async function myScript() { + return fcl + .send([ + fcl.script` + import FungibleToken from 0xFungibleToken // will be replaced with 0xf233dcee88fe0abe because of the configuration + + access(all) fun main() { /* Rest of the script goes here */ } + `, + ]) + .then(fcl.decode); +} + +async function myTransaction() { + return fcl + .send([ + fcl.transaction` + import FungibleToken from 0xFungibleToken // will be replaced with 0xf233dcee88fe0abe because of the configuration + + transaction { /* Rest of the transaction goes here */ } + `, + ]) + .then(fcl.decode); +} +``` + +#### Example + +```javascript +import * as fcl from '@onflow/fcl'; + +fcl + .config() + .put('flow.network', 'testnet') + .put('walletconnect.projectId', 'YOUR_PROJECT_ID') + .put('accessNode.api', 'https://rest-testnet.onflow.org') + .put('discovery.wallet', 'https://fcl-discovery.onflow.org/testnet/authn') + .put('app.detail.title', 'Test Harness') + .put('app.detail.icon', 'https://i.imgur.com/r23Zhvu.png') + .put('app.detail.description', 'A test harness for FCL') + .put('app.detail.url', 'https://myapp.com') + .put('service.OpenID.scopes', 'email email_verified name zoneinfo') + .put('0xFlowToken', '0x7e60df042a9c0868'); +``` + +### Using `flow.json` for Contract Imports + +A simpler and more flexible way to manage contract imports in scripts and transactions is by using the `config.load` method in FCL. This lets you load contract configurations from a `flow.json` file, keeping your import syntax clean and allowing FCL to pick the correct contract addresses based on the network you're using. + +### Setting Up + +#### 1. Define Your Contracts in `flow.json` + +Here’s an example of a `flow.json` file with aliases for multiple networks: + +```json +{ + "contracts": { + "HelloWorld": { + "source": "./cadence/contracts/HelloWorld.cdc", + "aliases": { + "testnet": "0x1cf0e2f2f715450", + "mainnet": "0xf8d6e0586b0a20c7" + } + } + } +} +``` + +- **`source`**: Points to the contract file in your project. +- **`aliases`**: Maps each network to the correct contract address. + +#### 2. Configure FCL + +Load the `flow.json` file and set up FCL to use it: + +```javascript +import { config } from '@onflow/fcl'; +import flowJSON from '../flow.json'; + +config({ + 'flow.network': 'testnet', // Choose your network, e.g., testnet or mainnet + 'accessNode.api': 'https://rest-testnet.onflow.org', // Access node for the network + 'discovery.wallet': `https://fcl-discovery.onflow.org/testnet/authn`, // Wallet discovery +}).load({ flowJSON }); +``` + +With this setup, FCL will automatically use the correct contract address based on the selected network (e.g., `testnet` or `mainnet`). + +#### 3. Use Contract Names in Scripts and Transactions + +After setting up `flow.json`, you can import contracts by name in your Cadence scripts or transactions: + +```cadence +import "HelloWorld" + +access(all) fun main(): String { + return HelloWorld.sayHello() +} +``` + +FCL replaces `"HelloWorld"` with the correct address from the `flow.json` configuration. + +> **Note**: Don’t store private keys in your `flow.json`. Instead, use the [key/location syntax](../../../tools/flow-cli/flow.json/security.md) to keep sensitive keys in a separate, `.gitignore`-protected file. + +## Wallet Interactions + +These methods allows dapps to interact with FCL compatible wallets in order to authenticate the user and authorize transactions on their behalf. + +> ⚠️These methods are **async**. + +--- + +### `authenticate` + +> ⚠️**This method can only be used in web browsers.** + +Calling this method will authenticate the current user via any wallet that supports FCL. Once called, FCL will initiate communication with the configured `discovery.wallet` endpoint which lets the user select a wallet to authenticate with. Once the wallet provider has authenticated the user, FCL will set the values on the [current user](#currentuserobject) object for future use and authorization. + +#### Note + +⚠️`discovery.wallet` value **must** be set in the configuration before calling this method. See [FCL Configuration](#configuration). + +📣 The default discovery endpoint will open an iframe overlay to let the user choose a supported wallet. + +#### Usage + +```javascript +import * as fcl from '@onflow/fcl'; +fcl + .config() + .put('accessNode.api', 'https://rest-testnet.onflow.org') + .put('discovery.wallet', 'https://fcl-discovery.onflow.org/testnet/authn'); +// anywhere on the page +fcl.authenticate(); +``` + +#### Note + +⚠️ `authenticate` can also take a service returned from [discovery](#discovery) with `fcl.authenticate({ service })`. + +--- + +### `unauthenticate` + +> ⚠️**This method can only be used in web browsers.** + +Logs out the current user and sets the values on the [current user](#currentuserobject) object to null. + +#### Note + +⚠️The current user must be authenticated first. + +#### Usage + +```javascript +import * as fcl from '@onflow/fcl'; +fcl.config().put('accessNode.api', 'https://rest-testnet.onflow.org'); +// first authenticate to set current user +fcl.authenticate(); +// ... somewhere else & sometime later +fcl.unauthenticate(); +// fcl.currentUser.loggedIn === null +``` + +--- + +### `reauthenticate` + +> ⚠️**This method can only be used in web browsers.** + +A **convenience method** that calls [`fcl.unauthenticate()`](#unauthenticate) and then [`fcl.authenticate()`](#authenticate) for the current user. + +#### Note + +⚠️The current user must be authenticated first. + +#### Usage + +```javascript +import * as fcl from '@onflow/fcl'; +// first authenticate to set current user +fcl.authenticate(); +// ... somewhere else & sometime later +fcl.reauthenticate(); +// logs out user and opens up login/sign-up flow +``` + +--- + +### `signUp` + +> ⚠️**This method can only be used in web browsers.** + +A **convenience method** that calls and is equivalent to [`fcl.authenticate()`](#authenticate). + +--- + +### `logIn` + +> ⚠️**This method can only be used in web browsers.** + +A **convenience method** that calls and is equivalent to [`fcl.authenticate()`](#authenticate). + +--- + +### `authz` + +A **convenience method** that produces the needed authorization details for the current user to submit transactions to Flow. It defines a signing function that connects to a user's wallet provider to produce signatures to submit transactions. + +> 📣 You can replace this function with your own [authorization function](#authorization-function) if needed. + +#### Returns + +| Type | Description | +| ------------------------------------------- | -------------------------------------------------------------------------------------------------------- | +| [AuthorizationObject](#authorizationobject) | An object containing the necessary details from the current user to authorize a transaction in any role. | + +#### Usage + +**Note:** The default values for `proposer`, `payer`, and `authorizations` are already `fcl.authz` so there is no need to include these parameters, it is shown only for example purposes. See more on [signing roles](../../../build/basics/transactions.md). + +```javascript +import * as fcl from '@onflow/fcl'; +// login somewhere before +fcl.authenticate(); +// once logged in authz will produce values +console.log(fcl.authz); +// prints {addr, signingFunction, keyId, sequenceNum} from the current authenticated user. + +const txId = await fcl.mutate({ + cadence: ` + import Profile from 0xba1132bc08f82fe2 + + transaction(name: String) { + prepare(account: auth(BorrowValue) &Account) { + account.storage.borrow<&{Profile.Owner}>(from: Profile.privatePath)!.setName(name) + } + } + `, + args: (arg, t) => [arg('myName', t.String)], + proposer: fcl.authz, // optional - default is fcl.authz + payer: fcl.authz, // optional - default is fcl.authz + authorizations: [fcl.authz], // optional - default is [fcl.authz] +}); +``` + +--- + +## Current User + +Holds the [current user](#currentuserobject), if set, and offers a set of functions to manage the authentication and authorization of the user. + +> ⚠️**The following methods can only be used in web browsers.** + +--- + +### `currentUser.subscribe` + +The callback passed to subscribe will be called when the user authenticates and un-authenticates, making it easy to update the UI accordingly. + +#### Arguments + +| Name | Type | | +| ---------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------- | +| `callback` | function | The callback will be called with the [current user](#currentuserobject) as the first argument when the current user is set or removed. | + +#### Usage + +```javascript +import React, { useState, useEffect } from 'react'; +import * as fcl from '@onflow/fcl'; + +export function AuthCluster() { + const [user, setUser] = useState({ loggedIn: null }); + useEffect(() => fcl.currentUser.subscribe(setUser), []); // sets the callback for FCL to use + + if (user.loggedIn) { + return ( +
    + {user?.addr ?? 'No Address'} + {/* once logged out in setUser(user) will be called */} +
    + ); + } else { + return ( +
    + {' '} + {/* once logged in setUser(user) will be called */} + {/* once signed up, setUser(user) will be called */} +
    + ); + } +} +``` + +--- + +### `currentUser.snapshot` + +Returns the [current user](#currentuserobject) object. This is the same object that is set and available on [`fcl.currentUser.subscribe(callback)`](#currentusersubscribe). + +#### Usage + +```javascript +// returns the current user object +const user = fcl.currentUser.snapshot(); + +// subscribes to the current user object and logs to console on changes +fcl.currentUser.subscribe(console.log); +``` + +--- + +### `currentUser.authenticate` + +Equivalent to `fcl.authenticate`. + +--- + +### `currentUser.unauthenticate` + +Equivalent to `fcl.unauthenticate`. + +--- + +### `currentUser.authorization` + +Equivalent to `fcl.authz` + +--- + +### `currentUser.signUserMessage` + +A method to use allowing the user to personally sign data via FCL Compatible Wallets/Services. + +> ⚠️ This method requires the current user's wallet to support a signing service endpoint. Currently, only Blocto is compatible with this feature by default. + +#### Arguments + +| Name | Type | Description | +| --------- | --------------------- | --------------------------------- | +| `message` | string **(required)** | A hexadecimal string to be signed | + +#### Returns + +| Type | Description | +| ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `Array` | An Array of [CompositeSignatures](https://github.com/onflow/fcl-js/blob/master/packages/fcl-core/src/wallet-provider-spec/draft-v2.md#compositesignature): {`addr`, `keyId`, `signature`} | + +#### Usage + +```javascript +import * as fcl from '@onflow/fcl'; + +export const signMessage = async () => { + const MSG = Buffer.from('FOO').toString('hex'); + try { + return await currentUser.signUserMessage(MSG); + } catch (error) { + console.log(error); + } +}; +``` + +--- + +## Discovery + +### `discovery` + +Discovery abstracts away code so that developers don't have to deal with the discovery of Flow compatible wallets, integration, or authentication. Using `discovery` from FCL allows dapps to list and authenticate with wallets while having full control over the UI. Common use cases for this are login or registration pages. + +(Alternatively, if you don't need control over your UI you can continue to use the `discovery.wallet` config value documented in the [Quickstart](../../../build/getting-started/fcl-quickstart.md) for the simplest configuration.) + +> ⚠️**The following methods can only be used in web browsers.** + +#### Note + +⚠️`discovery.authn.endpoint` value **must** be set in the configuration before calling this method. See [FCL Configuration](#configuration). + +### Suggested Configuration + +| Environment | Example | +| ----------- | ---------------------------------------------------- | +| Mainnet | `https://fcl-discovery.onflow.org/api/authn` | +| Testnet | `https://fcl-discovery.onflow.org/api/testnet/authn` | + +If the Discovery endpoint is set in config, then you can iterate through authn services and pass the chosen service to [authenticate](#authenticate) to authenticate a user. + +#### Usage + +```javascript +import './config'; +import { useState, useEffect } from 'react'; +import * as fcl from '@onflow/fcl'; + +function Component() { + const [wallets, setWallets] = useState([]); + useEffect( + () => fcl.discovery.authn.subscribe((res) => setWallets(res.results)), + [], + ); + + return ( +
    + {wallets.map((wallet) => ( + + ))} +
    + ); +} +``` + +### authn + +#### More Configuration + +By default, limited functionality services or services that require developer registration, like Ledger or Dapper Wallet, require apps to opt-in in order to display to users. To enable opt-in services in an application, use the `discovery.authn.include` property in your configuration with a value of an array of services you'd like your app to opt-in to displaying for users. + +Additionally, you can use the `discovery.authn.exclude` property to exclude any services from being displayed to users. + +```javascript +import { config } from '@onflow/fcl'; + +config({ + 'discovery.authn.endpoint': + 'https://fcl-discovery.onflow.org/api/testnet/authn', // Endpoint set to Testnet + 'discovery.authn.include': ['0x9d2e44203cb13051'], // Ledger wallet address on Testnet set to be included + 'discovery.authn.exclude': ['0x123456789abcdef01'], // Example of excluding a wallet by address +}); +``` + +**Opt-In Wallet Addresses on Testnet and Mainnet** + +| Service | Testnet | Mainnet | +| --------------- | ------------------ | ------------------ | +| `Dapper Wallet` | 0x82ec283f88a62e65 | 0xead892083b3e2c6c | +| `Ledger` | 0x9d2e44203cb13051 | 0xe5cd26afebe62781 | + +For more details on wallets, view the [service list here](https://github.com/onflow/fcl-discovery/blob/87e172db85d185882d9fde007c95f08bc2a1cccb/data/services.json). + +--- + +### `discovery.authn.snapshot()` + +Return a list of `authn` services. + +### `discovery.authn.subscribe(callback)` + +The callback sent to `subscribe` will be called with a list of `authn` services. + +--- + +## On-chain Interactions + +> 📣 **These methods can be used in browsers and NodeJS.** + +These methods allows dapps to interact directly with the Flow blockchain via a set of functions that currently use the [Access Node API](../../../networks/access-onchain-data/index.md). + +--- + +### Query and Mutate Flow with Cadence + +If you want to run arbitrary Cadence scripts on the blockchain, these methods offer a convenient way to do so **without having to build, send, and decode interactions**. + +### `query` + +Allows you to submit scripts to query the blockchain. + +#### Options + +_Pass in the following as a single object with the following keys.All keys are optional unless otherwise stated._ + +| Key | Type | Description | +| --------- | ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `cadence` | string **(required)** | A valid cadence script. | +| `args` | [ArgumentFunction](#argumentfunction) | Any arguments to the script if needed should be supplied via a function that returns an array of arguments. | +| `limit` | number | Compute (Gas) limit for query. Read the [documentation about computation cost](../../../build/basics/fees.md) for information about how computation cost is calculated on Flow. | + +#### Returns + +| Type | Description | +| ---- | -------------------------------------- | +| any | A JSON representation of the response. | + +#### Usage + +```javascript +import * as fcl from '@onflow/fcl'; + +const result = await fcl.query({ + cadence: ` + access(all) fun main(a: Int, b: Int, addr: Address): Int { + log(addr) + return a + b + } + `, + args: (arg, t) => [ + arg(7, t.Int), // a: Int + arg(6, t.Int), // b: Int + arg('0xba1132bc08f82fe2', t.Address), // addr: Address + ], +}); +console.log(result); // 13 +``` + +#### Examples + +- [Additional Explanation](https://gist.github.com/orodio/3bf977a0bd45b990d16fdc1459b129a2) + +--- + +### `mutate` + +Allows you to submit transactions to the blockchain to potentially mutate the state. + +⚠️When being used in the browser, `fcl.mutate` uses the built-in `fcl.authz` function to produce the authorization (signatures) for the current user. When calling this method from Node.js, you will need to supply your own custom authorization function. + +#### Options + +_Pass in the following as a single object with the following keys. All keys are optional unless otherwise stated._ + +| Key | Type | Description | +| ---------- | ------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `cadence` | string **(required)** | A valid cadence transaction. | +| `args` | [ArgumentFunction](#argumentfunction) | Any arguments to the script if needed should be supplied via a function that returns an array of arguments. | +| `limit` | number | Compute (Gas) limit for query. Read the [documentation about computation cost](../flow-go-sdk/index.md#gas-limit) for information about how computation cost is calculated on Flow. | +| `proposer` | [AuthorizationFunction](#authorization-function) | The authorization function that returns a valid [AuthorizationObject](#authorizationobject) for the [proposer role](#transactionrolesobject). | + +#### Returns + +| Type | Description | +| ------ | ------------------- | +| string | The transaction ID. | + +#### Usage + +```javascript +import * as fcl from '@onflow/fcl'; +// login somewhere before +fcl.authenticate(); + +const txId = await fcl.mutate({ + cadence: ` + import Profile from 0xba1132bc08f82fe2 + + transaction(name: String) { + prepare(account: auth(BorrowValue) &Account) { + account.storage.borrow<&{Profile.Owner}>(from: Profile.privatePath)!.setName(name) + } + } + `, + args: (arg, t) => [arg('myName', t.String)], +}); +``` + +#### Examples + +- [Additional explanation](https://gist.github.com/orodio/3bf977a0bd45b990d16fdc1459b129a2) +- [Custom authorization function](#authorization-function) + +--- + +### `verifyUserSignatures` (Deprecated) + +Use `fcl.AppUtils.verifyUserSignatures` + +## AppUtils + +### `AppUtils.verifyUserSignatures` + +A method allowing applications to cryptographically verify a message was signed by a user's private key/s. This is typically used with the response from `currentUser.signUserMessage`. + +#### Note + +⚠️ `fcl.config.flow.network` or options override is required to use this api. See [FCL Configuration](#configuration). + +#### Arguments + +| Name | Type | Description | +| --------------------- | --------------------- | ---------------------------------------------------------------------------------------------------- | +| `message` | string **(required)** | A hexadecimal string | +| `compositeSignatures` | Array **(required)** | An Array of `CompositeSignatures` | +| `opts` | Object **(optional)** | `opts.fclCryptoContract` can be provided to override FCLCryptoContract address for local development | + +#### Returns + +| Type | Description | +| ------- | ----------------------------- | +| Boolean | `true` if verified or `false` | + +#### Usage + +```javascript +import * as fcl from '@onflow/fcl'; + +const isValid = await fcl.AppUtils.verifyUserSignatures( + Buffer.from('FOO').toString('hex'), + [ + { + f_type: 'CompositeSignature', + f_vsn: '1.0.0', + addr: '0x123', + keyId: 0, + signature: 'abc123', + }, + ], + { fclCryptoContract }, +); +``` + +#### Examples + +- [fcl-next-harness](https://github.com/onflow/fcl-next-harness) + +--- + +### `AppUtils.verifyAccountProof` + +A method allowing applications to cryptographically prove that a user controls an on-chain account. During user authentication, some FCL compatible wallets will choose to support the FCL `account-proof` service. If a wallet chooses to support this service, and the user approves the signing of message data, they will return `account-proof` data and a signature(s) that can be used to prove a user controls an on-chain account. +See [proving-authentication](https://github.com/onflow/fcl-js/blob/master/docs/reference/proving-authentication.mdx) documentaion for more details. + +⚠️ `fcl.config.flow.network` or options override is required to use this api. See [FCL Configuration](#configuration). + +#### Arguments + +| Name | Type | Description | +| ------------------ | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `appIdentifier` | string **(required)** | A hexadecimal string | +| `accountProofData` | Object **(required)** | Object with properties:
    `address`: `string` - A Flow account address.
    `nonce`: `string` - A random string in hexadecimal format (minimum 32 bytes in total, i.e 64 hex characters)
    `signatures`: `Object[]` - An array of composite signatures to verify | +| `opts` | Object **(optional)** | `opts.fclCryptoContract` can be provided to overide FCLCryptoContract address for local development | + +#### Returns + +| Type | Description | +| ------- | ----------------------------- | +| Boolean | `true` if verified or `false` | + +#### Usage + +```javascript +import * as fcl from "@onflow/fcl" + +const accountProofData = { + address: "0x123", + nonce: "F0123" + signatures: [{f_type: "CompositeSignature", f_vsn: "1.0.0", addr: "0x123", keyId: 0, signature: "abc123"}], +} + +const isValid = await fcl.AppUtils.verifyAccountProof( + "AwesomeAppId", + accountProofData, + {fclCryptoContract} +) + +``` + +#### Examples + +- [fcl-next-harness](https://github.com/onflow/fcl-next-harness) + +--- + +### Query and mutate the blockchain with Builders + +In some cases, you may want to utilize pre-built interactions or build more complex interactions than what the `fcl.query` and `fcl.mutate` interface offer. To do this, FCL uses a pattern of building up an interaction with a combination of builders, resolving them, and sending them to the chain. + +> ⚠️**Recommendation:** Unless you have a specific use case that require usage of these builders, you should be able to achieve most cases with `fcl.query({...options}` or `fcl.mutate({...options})` + +### `send` + +Sends arbitrary scripts, transactions, and requests to Flow. + +This method consumes an array of [builders](#builders) that are to be resolved and sent. The builders required to be included in the array depend on the [interaction](#interaction) that is being built. + +#### Note + +⚠️Must be used in conjuction with [`fcl.decode(response)`](#decode) to get back correct keys and all values in JSON. + +#### Arguments + +| Name | Type | Description | +| ---------- | ----------------------- | ---------------------- | +| `builders` | [[Builders](#builders)] | See builder functions. | + +#### Returns + +| Type | Description | +| --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | +| [ResponseObject](#responseobject) | An object containing the data returned from the chain. Should always be decoded with `fcl.decode()` to get back appropriate JSON keys and values. | + +#### Usage + +```javascript +import * as fcl from '@onflow/fcl'; + +// a script only needs to resolve the arguments to the script +const response = await fcl.send([fcl.script`${script}`, fcl.args(args)]); +// note: response values are encoded, call await fcl.decode(response) to get JSON + +// a transaction requires multiple 'builders' that need to be resolved prior to being sent to the chain - such as setting the authorizations. +const response = await fcl.send([ + fcl.transaction` + ${transaction} + `, + fcl.args(args), + fcl.proposer(proposer), + fcl.authorizations(authorizations), + fcl.payer(payer), + fcl.limit(9999), +]); +// note: response contains several values (Cad) +``` + +--- + +### `decode` + +Decodes the response from `fcl.send()` into the appropriate JSON representation of any values returned from Cadence code. + +#### Note + +📣 To define your own decoder, see [`tutorial`](https://github.com/onflow/fcl-js/tree/master/packages/sdk/src/decode). + +#### Arguments + +| Name | Type | Description | +| ---------- | --------------------------------- | ------------------------------------------------------ | +| `response` | [ResponseObject](#responseobject) | Should be the response returned from `fcl.send([...])` | + +#### Returns + +| Type | Description | +| ---- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| any | A JSON representation of the raw string response depending on the cadence code executed.
    The return value can be a single value and type or an object with multiple types. | + +#### Usage + +```javascript +import * as fcl from '@onflow/fcl'; + +// simple script to add 2 numbers +const response = await fcl.send([ + fcl.script` + access(all) fun main(int1: Int, int2: Int): Int { + return int1 + int2 + } + `, + fcl.args([fcl.arg(1, fcl.t.Int), fcl.arg(2, fcl.t.Int)]), +]); + +const decoded = await fcl.decode(response); + +assert(3 === decoded); +assert(typeof decoded === 'number'); +``` + +--- + +## Builders + +These methods fill out various portions of a transaction or script template in order to +build, resolve, and send it to the blockchain. A valid populated template is referred to as an [Interaction](#interaction). + +⚠️**These methods must be used with `fcl.send([...builders]).then(fcl.decode)`** + +### Query Builders + +### `getAccount` + +A builder function that returns the interaction to get an account by address. + +⚠️Consider using the pre-built interaction [`fcl.account(address)`](#account) if you do not need to pair with any other builders. + +#### Arguments + +| Name | Type | Description | +| --------- | ------------------- | ---------------------------------------------------------------------------------- | +| `address` | [Address](#address) | Address of the user account with or without a prefix (both formats are supported). | + +#### Returns after decoding + +| Type | Description | +| ------------------------- | ---------------------------------------- | +| [AccountObject](#account) | A JSON representation of a user account. | + +#### Usage + +```javascript +import * as fcl from '@onflow/fcl'; + +// somewhere in an async function +// fcl.account is the same as this function +const getAccount = async (address) => { + const account = await fcl.send([fcl.getAccount(address)]).then(fcl.decode); + return account; +}; +``` + +--- + +### `getBlock` + +A builder function that returns the interaction to get the latest block. + +📣 Use with `fcl.atBlockId()` and `fcl.atBlockHeight()` when building the interaction to get information for older blocks. + +⚠️Consider using the pre-built interaction [`fcl.getblock(isSealed)`](#getblock) if you do not need to pair with any other builders. + +#### Arguments + +| Name | Type | Default | Description | +| ---------- | ------- | ------- | ------------------------------------------------------------------------------ | +| `isSealed` | boolean | false | If the latest block should be sealed or not. See [block states](#interaction). | + +#### Returns after decoding + +| Type | Description | +| --------------------------- | ----------------------------------------------------- | +| [BlockObject](#blockobject) | The latest block if not used with any other builders. | + +#### Usage + +```javascript +import * as fcl from '@onflow/fcl'; + +const latestSealedBlock = await fcl + .send([ + fcl.getBlock(true), // isSealed = true + ]) + .then(fcl.decode); +``` + +--- + +### `atBlockHeight` + +A builder function that returns a partial interaction to a block at a specific height. + +⚠️Use with other interactions like [`fcl.getBlock()`](#getblock) to get a full interaction at the specified block height. + +#### Arguments + +| Name | Type | Description | +| ------------- | ------ | ------------------------------------------------------ | +| `blockHeight` | number | The height of the block to execute the interaction at. | + +#### Returns + +| Type | Description | +| ----------------------------------- | ----------------------------------------------------------------------------------------------------------- | +| [Partial Interaction](#interaction) | A partial interaction to be paired with another interaction such as `fcl.getBlock()` or `fcl.getAccount()`. | + +#### Usage + +```javascript +import * as fcl from '@onflow/fcl'; + +await fcl.send([fcl.getBlock(), fcl.atBlockHeight(123)]).then(fcl.decode); +``` + +--- + +### `atBlockId` + +A builder function that returns a partial interaction to a block at a specific block ID. + +⚠️Use with other interactions like [`fcl.getBlock()`](#getblock) to get a full interaction at the specified block ID. + +#### Arguments + +| Name | Type | Description | +| --------- | ------ | -------------------------------------------------- | +| `blockId` | string | The ID of the block to execute the interaction at. | + +#### Returns + +| Type | Description | +| ----------------------------------- | ----------------------------------------------------------------------------------------------------------- | +| [Partial Interaction](#interaction) | A partial interaction to be paired with another interaction such as `fcl.getBlock()` or `fcl.getAccount()`. | + +#### Usage + +```javascript +import * as fcl from '@onflow/fcl'; + +await fcl.send([fcl.getBlock(), fcl.atBlockId('23232323232')]).then(fcl.decode); +``` + +--- + +### `getBlockHeader` + +A builder function that returns the interaction to get a block header. + +📣 Use with `fcl.atBlockId()` and `fcl.atBlockHeight()` when building the interaction to get information for older blocks. + +#### Returns after decoding + +| Type | Description | +| --------------------------------------- | ------------------------------------------------------------ | +| [BlockHeaderObject](#blockheaderobject) | The latest block header if not used with any other builders. | + +#### Usage + +```javascript +import * as fcl from '@onflow/fcl'; + +const latestBlockHeader = await fcl + .send([fcl.getBlockHeader()]) + .then(fcl.decode); +``` + +### `getEventsAtBlockHeightRange` + +A builder function that returns all instances of a particular event (by name) within a height range. + +⚠️The block range provided must be from the current spork. + +⚠️The block range provided must be 250 blocks or lower per request. + +#### Arguments + +| Name | Type | Description | +| ----------------- | ----------------------- | ---------------------------------------------------------------- | +| `eventName` | [EventName](#eventname) | The name of the event. | +| `fromBlockHeight` | number | The height of the block to start looking for events (inclusive). | +| `toBlockHeight` | number | The height of the block to stop looking for events (inclusive). | + +#### Returns after decoding + +| Type | Description | +| ------------------------------ | ---------------------------------------------- | +| [[EventObject]](#event-object) | An array of events that matched the eventName. | + +#### Usage + +```javascript +import * as fcl from '@onflow/fcl'; + +const events = await fcl + .send([ + fcl.getEventsAtBlockHeightRange( + 'A.7e60df042a9c0868.FlowToken.TokensWithdrawn', + 35580624, + 35580624, + ), + ]) + .then(fcl.decode); +``` + +--- + +### `getEventsAtBlockIds` + +A builder function that returns all instances of a particular event (by name) within a set of blocks, specified by block ids. + +⚠️The block range provided must be from the current spork. + +#### Arguments + +| Name | Type | Description | +| ----------- | ----------------------- | ----------------------------------------- | +| `eventName` | [EventName](#eventname) | The name of the event. | +| `blockIds` | number | The ids of the blocks to scan for events. | + +#### Returns after decoding + +| Type | Description | +| ------------------------------ | ---------------------------------------------- | +| [[EventObject]](#event-object) | An array of events that matched the eventName. | + +#### Usage + +```javascript +import * as fcl from '@onflow/fcl'; + +const events = await fcl + .send([ + fcl.getEventsAtBlockIds('A.7e60df042a9c0868.FlowToken.TokensWithdrawn', [ + 'c4f239d49e96d1e5fbcf1f31027a6e582e8c03fcd9954177b7723fdb03d938c7', + '5dbaa85922eb194a3dc463c946cc01c866f2ff2b88f3e59e21c0d8d00113273f', + ]), + ]) + .then(fcl.decode); +``` + +--- + +### `getCollection` + +A builder function that returns all a collection containing a list of transaction ids by its collection id. + +⚠️The block range provided must be from the current spork. All events emitted during past sporks is current unavailable. + +#### Arguments + +| Name | Type | Description | +| -------------- | ------ | ------------------------- | +| `collectionID` | string | The id of the collection. | + +#### Returns after decoding + +| Type | Description | +| ------------------------------------- | --------------------------------------------------------------------------------- | +| [CollectionObject](#collectionobject) | An object with the id and a list of transactions within the requested collection. | + +#### Usage + +```javascript +import * as fcl from '@onflow/fcl'; + +const collection = await fcl + .send([ + fcl.getCollection( + 'cccdb0c67d015dc7f6444e8f62a3244ed650215ed66b90603006c70c5ef1f6e5', + ), + ]) + .then(fcl.decode); +``` + +--- + +### `getTransactionStatus` + +A builder function that returns the status of transaction in the form of a [TransactionStatusObject](#transactionstatusobject). + +⚠️The transactionID provided must be from the current spork. + +📣 Considering [subscribing to the transaction from `fcl.tx(id)`](#tx) instead of calling this method directly. + +#### Arguments + +| Name | Type | Description | +| --------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------- | +| `transactionId` | string | The transactionID returned when submitting a transaction. Example: `9dda5f281897389b99f103a1c6b180eec9dac870de846449a302103ce38453f3` | + +#### Returns after decoding + +#### Returns + +| Type | Description | +| --------------------------------------------------- | ------------------------------------------------------ | +| [TransactionStatusObject](#transactionstatusobject) | Object representing the result/status of a transaction | + +#### Usage + +```javascript +import * as fcl from '@onflow/fcl'; + +const status = await fcl + .send([ + fcl.getTransactionStatus( + '9dda5f281897389b99f103a1c6b180eec9dac870de846449a302103ce38453f3', + ), + ]) + .then(fcl.decode); +``` + +--- + +### `getTransaction` + +A builder function that returns a [transaction object](#transactionobject) once decoded. + +⚠️The transactionID provided must be from the current spork. + +📣 Considering using [`fcl.tx(id).onceExecuted()`](#tx) instead of calling this method directly. + +#### Arguments + +| Name | Type | Description | +| --------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------- | +| `transactionId` | string | The transactionID returned when submitting a transaction. Example: `9dda5f281897389b99f103a1c6b180eec9dac870de846449a302103ce38453f3` | + +#### Returns after decoding + +#### Returns + +| Type | Description | +| --------------------------------------- | -------------------------------------------------------------- | +| [TransactionObject](#transactionobject) | An full transaction object containing a payload and signatures | + +#### Usage + +```javascript +import * as fcl from '@onflow/fcl'; + +const tx = await fcl + .send([ + fcl.getTransaction( + '9dda5f281897389b99f103a1c6b180eec9dac870de846449a302103ce38453f3', + ), + ]) + .then(fcl.decode); +``` + +--- + +### `subscribeEvents` + + +The subscribeEvents SDK builder is for more advanced use cases where you wish to directly specify a starting block to listen for events. For most use cases, consider using the pre-built interaction [`fcl.events(eventTypes)`](#events). + + +A build that returns a [event stream connection](#eventstream) once decoded. It will establish a WebSocket connection to the Access Node and subscribe to events with the given parameters. + +#### Arguments + +| Name | Type | Description | +| ------------- | --------------------------- | --------------------------------- | +| `eventFilter` | [EventFilter](#eventfilter) | The event filter to subscribe to. | + +#### Returns after decoding + +#### Returns + +| Type | Description | +| ------------------------------------- | -------------------------------- | +| [EventStreamConnection](#eventstream) | A connection to the event stream | + +#### Usage + +```javascript +import * as fcl from '@onflow/fcl'; + +const eventStream = await fcl + .send([ + fcl.subscribeEvents({ + eventTypes: 'A.7e60df042a9c0868.FlowToken.TokensWithdrawn', + }), + ]) + .then(fcl.decode); + +eventStream.on('heartbeat', (heartbeat) => { + console.log(heartbeat); +}); + +eventStream.on('events', (event) => { + console.log(event); +}); + +eventStream.on('error', (error) => { + console.log(error); +}); + +eventStream.on('end', () => { + console.log('Connection closed'); +}); + +eventStream.close(); +``` + +--- + +### `getEvents` (Deprecated) + +Use [`fcl.getEventsAtBlockHeightRange`](#geteventsatblockheightrange) or [`fcl.getEventsAtBlockIds`](#geteventsatblockids). + +--- + +### `getLatestBlock` (Deprecated) + +Use [`fcl.getBlock`](#getblock). + +--- + +### `getBlockById` (Deprecated) + +Use [`fcl.getBlock`](#getblock) and [`fcl.atBlockId`](#atblockid). + +--- + +### `getBlockByHeight` (Deprecated) + +Use [`fcl.getBlock`](#getblock) and [`fcl.atBlockHeight`](#atblockheight). + +--- + +### Utility Builders + +These builders are used to compose interactions with other builders such as scripts and transactions. + +> ⚠️**Recommendation:** Unless you have a specific use case that require usage of these builders, you should be able to achieve most cases with `fcl.query({...options}` or `fcl.mutate({...options})` + +### `arg` + +A utility builder to be used with `fcl.args[...]` to create FCL supported arguments for interactions. + +#### Arguments + +| Name | Type | Description | +| ------- | --------------- | --------------------------------------------------------- | +| `value` | any | Any value that you are looking to pass to other builders. | +| `type` | [FType](#ftype) | A type supported by Flow. | + +#### Returns + +| Type | Description | +| --------------------------------- | ----------------------------------- | +| [ArgumentObject](#argumentobject) | Holds the value and type passed in. | + +#### Usage + +```javascript +import * as fcl from '@onflow/fcl'; + +await fcl + .send([ + fcl.script` + access(all) fun main(a: Int, b: Int): Int { + return a + b + } + `, + fcl.args([ + fcl.arg(5, fcl.t.Int), // a + fcl.arg(4, fcl.t.Int), // b + ]), + ]) + .then(fcl.decode); +``` + +--- + +### `args` + +A utility builder to be used with other builders to pass in arguments with a value and supported type. + +#### Arguments + +| Name | Type | Description | +| ------ | ------------------------------------- | --------------------------------------------------------------------- | +| `args` | [[Argument Objects]](#argumentobject) | An array of arguments that you are looking to pass to other builders. | + +#### Returns + +| Type | Description | +| ----------------------------------- | ------------------------------------------------------------------------------------------------------------------- | +| [Partial Interaction](#interaction) | An interaction that contains the arguments and types passed in. This alone is a partial and incomplete interaction. | + +#### Usage + +```javascript +import * as fcl from '@onflow/fcl'; + +await fcl + .send([ + fcl.script` + access(all) fun main(a: Int, b: Int): Int { + return a + b + } + `, + fcl.args([ + fcl.arg(5, fcl.t.Int), // a + fcl.arg(4, fcl.t.Int), // b + ]), + ]) + .then(fcl.decode); // 9 +``` + +--- + +### Template Builders + +> ⚠️**_Recommended:_** The following functionality is simplified by [`fcl.query({...options}`](#query) or [`fcl.mutate({...options})`](#mutate) and is reccomended to use over the functions below. + +### `script` + +A template builder to use a Cadence script for an interaction. + +📣 Use with `fcl.args(...)` to pass in arguments dynamically. + +#### Arguments + +| Name | Type | Description | +| ------ | ------ | ------------------------------- | +| `CODE` | string | Should be valid Cadence script. | + +#### Returns + +| Type | Description | +| --------------------------- | --------------------------------------------- | +| [Interaction](#interaction) | An interaction containing the code passed in. | + +#### Usage + +```javascript +import * as fcl from '@onflow/fcl'; + +const code = ` + access(all) fun main(): Int { + return 5 + 4 + } +`; +const answer = await fcl.send([fcl.script(code)]).then(fcl.decode); +console.log(answer); // 9 +``` + +--- + +### `transaction` + +A template builder to use a Cadence transaction for an interaction. + +⚠️Must be used with `fcl.payer`, `fcl.proposer`, `fcl.authorizations` to produce a valid interaction before sending to the chain. + +📣 Use with `fcl.args[...]` to pass in arguments dynamically. + +#### Arguments + +| Name | Type | Description | +| ------ | ------ | -------------------------------------- | +| `CODE` | string | Should be valid a Cadence transaction. | + +#### Returns + +| Type | Description | +| ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | +| [Partial Interaction](#interaction) | An partial interaction containing the code passed in. Further builders are required to complete the interaction - see warning. | + +#### Usage + +```javascript +import * as fcl from '@onflow/fcl'; + +const code = ` + access(all) fun main(): Int { + return 5 + 4 + } +`; +const answer = await fcl.send([fcl.script(code)]).then(fcl.decode); +console.log(answer); // 9 +``` + +--- + +## Pre-built Interactions + +These functions are abstracted short hand ways to skip the send and decode steps of sending an interaction to the chain. More pre-built interactions are coming soon. + +### `account` + +A pre-built interaction that returns the details of an account from their public address. + +#### Arguments + +| Name | Type | Description | +| --------- | ------------------- | ---------------------------------------------------------------------------------- | +| `address` | [Address](#address) | Address of the user account with or without a prefix (both formats are supported). | + +#### Returns + +| Type | Description | +| ------------------------------- | ---------------------------------------- | +| [AccountObject](#accountobject) | A JSON representation of a user account. | + +#### Usage + +```javascript +import * as fcl from '@onflow/fcl'; +const account = await fcl.account('0x1d007d755706c469'); +``` + +--- + +### `block` + +A pre-built interaction that returns the latest block (optionally sealed or not), by id, or by height. + +#### Arguments + +| Name | Type | Default | Description | +| -------- | ------- | ------- | ------------------------------------------------------------------------------ | +| `sealed` | boolean | false | If the latest block should be sealed or not. See [block states](#interaction). | +| `id` | string | | ID of block to get. | +| `height` | int | | Height of block to get. | + +#### Returns + +| Type | Description | +| --------------------------- | --------------------------------- | +| [BlockObject](#blockobject) | A JSON representation of a block. | + +#### Usage + +```javascript +import * as fcl from '@onflow/fcl'; +await fcl.block(); // get latest finalized block +await fcl.block({ sealed: true }); // get latest sealed block +await fcl.block({ + id: '0b1bdfa9ddaaf31d53c584f208313557d622d1fedee1586ffc38fb5400979faa', +}); // get block by id +await fcl.block({ height: 56481953 }); // get block by height +``` + +--- + +### `latestBlock` (Deprecated) + +A pre-built interaction that returns the latest block (optionally sealed or not). + +#### Arguments + +| Name | Type | Default | Description | +| ---------- | ------- | ------- | ------------------------------------------------------------------------------ | +| `isSealed` | boolean | false | If the latest block should be sealed or not. See [block states](#interaction). | + +#### Returns + +| Type | Description | +| --------------------------- | --------------------------------- | +| [BlockObject](#blockobject) | A JSON representation of a block. | + +#### Usage + +```javascript +import * as fcl from '@onflow/fcl'; +const latestBlock = await fcl.latestBlock(); +``` + +--- + +## Transaction Status Utility + +### `tx` + +A utility function that lets you set the transaction to get subsequent status updates (via polling) and the finalized result once available. +⚠️The poll rate is set at `2500ms` and will update at that interval until transaction is sealed. + +#### Arguments + +| Name | Type | Description | +| --------------- | ------ | ----------------------- | +| `transactionId` | string | A valid transaction id. | + +#### Returns + +| Name | Type | Description | +| ----------------- | -------- | --------------------------------------------------------------------------------------------------------- | +| `snapshot()` | function | Returns the current state of the transaction. | +| `subscribe(cb)` | function | Calls the `cb` passed in with the new transaction on a status change. | +| `onceFinalized()` | function | Provides the transaction once status `2` is returned. See [Tranasaction Statuses](#transaction-statuses). | +| `onceExecuted()` | function | Provides the transaction once status `3` is returned. See [Tranasaction Statuses](#transaction-statuses). | +| `onceSealed()` | function | Provides the transaction once status `4` is returned. See [Tranasaction Statuses](#transaction-statuses). | + +#### Usage + +```javascript +import * as fcl from '@onflow/fcl'; + +const [txStatus, setTxStatus] = useState(null); +useEffect(() => fcl.tx(txId).subscribe(setTxStatus)); +``` + +--- + +## Event Polling Utility + +### `events` + +A utility function that lets you set the transaction to get subsequent status updates (via polling) and the finalized result once available. +⚠️The poll rate is set at `10000ms` and will update at that interval for getting new events. + +Note: +⚠️`fcl.eventPollRate` value **could** be set to change the polling rate of all events subcribers, check [FCL Configuration](#configuration) for guide. + +#### Arguments + +| Name | Type | Description | +| ------------------- | ----------------------------------------- | ------------------------------------------------ | +| `eventNameOrFilter` | string | [EventFilter](#eventfilter) | The name of the event or an event filter object. | + +#### Returns + +| Name | Type | Description | +| --------------- | -------- | -------------------------------------------- | +| `subscribe(cb)` | function | Calls the `cb` passed in with the new event. | + +#### Usage + +```javascript +import * as fcl from '@onflow/fcl'; +// in some react component +fcl.events(eventName).subscribe((event) => { + console.log(event); +}); +``` + +#### Examples + +- [Flow-view-source example](https://github.com/orodio/flow-view-source/blob/master/src/pages/event.comp.js) + +--- + +## Types, Interfaces, and Definitions + +--- + +### `Builders` + +Builders are modular functions that can be coupled together with `fcl.send([...builders])` to create an [Interaction](#interaction). The builders needed to create an interaction depend on the script or transaction that is being sent. + +--- + +### `Interaction` + +An interaction is an object containing the information to perform an action on chain.This object is populated through builders and converted into the approriate access node API call. See the interaction object [here](https://github.com/onflow/fcl-js/blob/master/packages/sdk/src/interaction/interaction.ts). A 'partial' interaction is an interaction object that does not have sufficient information to the intended on-chain action. Multiple partial interactions (through builders) can be coupled to create a complete interaction. + +--- + +### `CurrentUserObject` + +| Key | Value Type | Default | Description | +| ----------- | ------------------- | --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `addr` | [Address](#address) | `null` | The public address of the current user | +| `cid` | string | `null` | Allows wallets to specify a [content identifier](https://docs.ipfs.io/concepts/content-addressing/) for user metadata. | +| `expiresAt` | number | `null` | Allows wallets to specify a time-frame for a valid session. | +| `f_type` | string | `'USER'` | A type identifier used internally by FCL. | +| `f_vsn` | string | `'1.0.0'` | FCL protocol version. | +| `loggedIn` | boolean | `null` | If the user is logged in. | +| `services` | `[ServiceObject]` | `[]` | A list of trusted services that express ways of interacting with the current user's identity, including means to further discovery, [authentication, authorization](https://gist.github.com/orodio/a74293f65e83145ec8b968294808cf35#you-know-who-the-user-is), or other kinds of interactions. | + +--- + +### `AuthorizationObject` + +This type conforms to the interface required for FCL to authorize transaction on behalf o the current user. + +| Key | Value Type | Description | +| ----------------- | ------------------- | ------------------------------------------------------------------------------------------------- | +| `addr` | [Address](#address) | The address of the authorizer | +| `signingFunction` | function | A function that allows FCL to sign using the authorization details and produce a valid signature. | +| `keyId` | number | The index of the key to use during authorization. (Multiple keys on an account is possible). | +| `sequenceNum` | number | A number that is incremented per transaction using they keyId. | + +--- + +### `SignableObject` + +An object that contains all the information needed for FCL to sign a message with the user's signature. + +| Key | Value Type | Description | +| ----------- | ------------------- | ---------------------------------------------------------------------------------------------------- | +| `addr` | [Address](#address) | The address of the authorizer | +| `keyId` | number | The index of the key to use during authorization. (Multiple keys on an account is possible). | +| `signature` | function | A [SigningFunction](#signing-function) that can produce a valid signature for a user from a message. | + +--- + +### `AccountObject` + +The JSON representation of an account on the Flow blockchain. + +| Key | Value Type | Description | +| ----------- | ----------------------------- | ------------------------------------------------------------------------------------------ | +| `address` | [Address](#address) | The address of the account | +| `balance` | number | The FLOW balance of the account in 10^8. | +| `code` | [Code](#code) | The code of any Cadence contracts stored in the account. | +| `contracts` | Object: [Contract](#contract) | An object with keys as the contract name deployed and the value as the the cadence string. | +| `keys` | [[KeyObject]](#keyobject) | Any contracts deployed to this account. | + +--- + +### `Address` + +| Value Type | Description | +| ----------------- | --------------------------------------------------------------------------------------------------------------------------------- | +| string(formatted) | A valid Flow address should be 16 characters in length.
    A `0x` prefix is optional during inputs.
    eg. `f8d6e0586b0a20c1` | + +--- + +### `ArgumentObject` + +An argument object created by `fcl.arg(value,type)` + +| Key | Value Type | Description | +| ------- | --------------- | ------------------------------------------------- | +| `value` | any | Any value to be used as an argument to a builder. | +| `xform` | [FType](#ftype) | Any of the supported types on Flow. | + +--- + +### `ArgumentFunction` + +An function that takes the `fcl.arg` function and fcl types `t` and returns an array of `fcl.arg(value,type)`. + +`(arg, t) => Array` + +| Parameter Name | Value Type | Description | +| -------------- | ---------------- | ------------------------------------------------------------------------- | +| `arg` | function | A function that returns an [ArgumentObject](#argumentobject) - `fcl.arg`. | +| `t` | [FTypes](#ftype) | An object with acccess to all of the supported types on Flow. | + +**Returns** + +| Value Type | Description | +| ------------ | -------------------- | +| `[fcl.args]` | Array of `fcl.args`. | + +--- + +### `Authorization Function` + +An authorization function must produce the information of the user that is going to sign and a signing function to use the information to produce a signature. + +⚠️This function is always async. + +📣 By default FCL exposes `fcl.authz` that produces the authorization object for the current user (given they are signed in and only on the browser). Replace this with your own function that conforms to this interface to use it wherever an authorization object is needed. + +| Parameter Name | Value Type | Description | +| -------------- | ------------------------------- | ---------------------------------------------- | +| `account` | [AccountObject](#accountobject) | The account of the user that is going to sign. | + +**Returns** + +| Value Type | Description | +| ------------------------------------------------------ | --------------------------------------------------------------------------------------------- | +| `Promise<[AuthorizationObject](#authorizationobject)>` | The object that contains all the information needed by FCL to authorize a user's transaction. | + +#### Usage + +--- + +```javascript +const authorizationFunction = async (account) => { + // authorization function need to return an account + const { address, keys } = account + const tempId = `${address}-${keys[process.env.minterAccountIndex]}`; + const keyId = Number(KEY_ID); + let signingFunction = async signable => { + return { + keyId, + addr: fcl.withPrefix(address), + signature: sign(process.env.FLOW_MINTER_PRIVATE_KEY, signable.message), // signing function, read below + } + } + return { + ...account, + address, + keyId, + tempId, + signingFunction, + } +``` + +- [Detailed explanation](https://github.com/onflow/fcl-js/blob/master/packages/fcl-core/src/wallet-provider-spec/authorization-function.md) + +--- + +### `Signing Function` + +Consumes a payload and produces a signature for a transaction. + +⚠️This function is always async. + +📣 Only write your own signing function if you are writing your own custom authorization function. + +#### Payload + +Note: These values are destructed from the payload object in the first argument. + +| Parameter Name | Value Type | Description | +| -------------- | ---------- | ------------------------------------------------------------------------------------------------------------------------------------ | +| `message` | string | The encoded string which needs to be used to produce the signature. | +| `addr` | string | The encoded string which needs to be used to produce the signature. | +| `keyId` | string | The encoded string which needs to be used to produce the signature. | +| `roles` | string | The encoded string which needs to be used to produce the signature. | +| `voucher` | object | The raw transactions information, can be used to create the message for additional safety and lack of trust in the supplied message. | + +**Returns** + +| Value Type | Description | +| -------------------------------------------- | --------------------------------------------------------------------------------------------- | +| `Promise<[SignableObject](#signableobject)>` | The object that contains all the information needed by FCL to authorize a user's transaction. | + +#### Usage + +```javascript +import * as fcl from '@onflow/fcl'; +import { ec as EC } from 'elliptic'; +import { SHA3 } from 'sha3'; +const ec: EC = new EC('p256'); + +const produceSignature = (privateKey, msg) => { + const key = ec.keyFromPrivate(Buffer.from(privateKey, 'hex')); + const sig = key.sign(this.hashMsg(msg)); + const n = 32; + const r = sig.r.toArrayLike(Buffer, 'be', n); + const s = sig.s.toArrayLike(Buffer, 'be', n); + return Buffer.concat([r, s]).toString('hex'); +}; + +const signingFunction = ({ + message, // The encoded string which needs to be used to produce the signature. + addr, // The address of the Flow Account this signature is to be produced for. + keyId, // The keyId of the key which is to be used to produce the signature. + roles: { + proposer, // A Boolean representing if this signature to be produced for a proposer. + authorizer, // A Boolean representing if this signature to be produced for a authorizer. + payer, // A Boolean representing if this signature to be produced for a payer. + }, + voucher, // The raw transactions information, can be used to create the message for additional safety and lack of trust in the supplied message. +}) => { + return { + addr, // The address of the Flow Account this signature was produced for. + keyId, // The keyId for which key was used to produce the signature. + signature: produceSignature(message), // The hex encoded string representing the signature of the message. + }; +}; +``` + +#### Examples: + +- [Detailed explanation](https://github.com/onflow/fcl-js/blob/master/packages/fcl-core/src/wallet-provider-spec/authorization-function.md) + +--- + +### `TransactionObject` + +| Key | Value Type | Description | +| -------------------- | ------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `args` | object | A list of encoded Cadence values passed into this transaction. These have not been decoded by the JS-SDK. | +| `authorizers` | [\[Address\]](#address) | A list of the accounts that are authorizing this transaction to mutate to their on-chain account state. [See more here](../../../build/basics/transactions.md#signer-roles). | +| `envelopeSignatures` | [\[SignableObject\]](#signableobject) | A list of signatures generated by the payer role. [See more here](../../../build/basics/transactions.md#signing-a-transaction). | +| `gasLimit` | number | The maximum number of computational units that can be used to execute this transaction. [See more here](../../../build/basics/fees.md). | +| `payer` | [Address](#address) | The account that pays the fee for this transaction. [See more here](../../../build/basics/transactions.md#signer-roles). | +| `payloadSignatures` | [\[SignableObject\]](#signableobject) | A list of signatures generated by the proposer and authorizer roles. [See more here](../../../build/basics/transactions.md#signing-a-transaction). | +| `proposalKey` | [\[ProposalKey\]](#proposalkeyobject) | The account key used to propose this transaction | +| `referenceBlockId` | string | A reference to the block used to calculate the expiry of this transaction. | +| `script` | string | The UTF-8 encoded Cadence source code that defines the execution logic for this transaction | + +### `TransactionRolesObject` + +| Key Name | Value Type | Description | +| ---------- | ---------- | -------------------------------------------------------------------------- | +| proposer | boolean | A Boolean representing if this signature to be produced for a proposer. | +| authorizer | boolean | A Boolean representing if this signature to be produced for an authorizer. | +| payer | boolean | A Boolean representing if this signature to be produced for a payer. | + +For more on what each transaction role means, see [singing roles](../../../build/basics/transactions.md#signer-roles). + +### `TransactionStatusObject` + +| Key | Value Type | Description | +| -------------- | ------------------------------------------ | ----------------------------------------------------------------------------------- | +| `blockId` | string | ID of the block that contains the transaction. | +| `events` | [[EventObject]](#event-object) | An array of events that were emitted during the transaction. | +| `status` | [TransactionStatus](#transaction-statuses) | The status of the transaction on the blockchain. | +| `statusString` | [TransactionStatus](#transaction-statuses) | The `status` as as descriptive text (e.g. "FINALIZED"). | +| `errorMessage` | string | An error message if it exists. Default is an empty string `''`. | +| `statusCode` | number | The pass/fail status. 0 indicates the transaction succeeded, 1 indicates it failed. | + +### `EventName` + +| Value Type | Description | +| ----------------- | ----------------------------------------------------------------------------------------------------------------------------------- | +| string(formatted) | A event name in Flow must follow the format `A.{AccountAddress}.{ContractName}.{EventName}`
    eg. `A.ba1132bc08f82fe2.Debug.Log` | + +### `Contract` + +| Value Type | Description | +| ----------------- | ---------------------------------------------------- | +| string(formatted) | A formatted string that is a valid cadence contract. | + +### `KeyObject` + +This is the JSON representation of a key on the Flow blockchain. + +| Key | Value Type | Description | +| ---------------- | ---------- | ---------------------------------------------------------------------------------------- | +| `index` | number | The address of the account | +| `publicKey` | string | The public portion of a public/private key pair | +| `signAlgo` | number | An index referring to one of `ECDSA_P256` or `ECDSA_secp256k1` | +| `hashAlgo` | number | An index referring to one of `SHA2_256` or `SHA3_256` | +| `weight` | number | A number between 1 and 1000 indicating the relative weight to other keys on the account. | +| `sequenceNumber` | number | This number is incremented for every transaction signed using this key. | +| `revoked` | boolean | If this key has been disabled for use. | + +### `ProposalKeyObject` + +ProposalKey is the account key used to propose this transaction. + +A proposal key references a specific key on an account, along with an up-to-date sequence number for that key. This sequence number is used to prevent replay attacks. + +You can find more information about sequence numbers [here](../../../build/basics/transactions.md#sequence-numbers) + +| Key | Value Type | Description | +| ---------------- | ------------------- | ------------------------------------------------------------------------- | +| `address` | [Address](#address) | The address of the account | +| `keyIndex` | number | The index of the account key being referenced | +| `sequenceNumber` | number | The sequence number associated with this account key for this transaction | + +### `BlockObject` + +The JSON representation of a key on the Flow blockchain. + +| Key | Value Type | Description | +| ---------------------- | --------------------------------------------------------- | ---------------------------------------------------------- | +| `id` | string | The id of the block. | +| `parentId` | string | The id of the parent block. | +| `height` | number | The height of the block. | +| `timestamp` | object | Contains time related fields. | +| `collectionGuarantees` | [[CollectionGuaranteeObject](#collectionguaranteeobject)] | Contains the ids of collections included in the block. | +| `blockSeals` | [SealedBlockObject] | The details of which nodes executed and sealed the blocks. | +| `signatures` | Uint8Array([numbers]) | All signatures. | + +### `BlockHeaderObject` + +The subset of the [BlockObject](#blockobject) containing only the header values of a block. + +| Key | Value Type | Description | +| ----------- | ---------- | ----------------------------- | +| `id` | string | The id of the block. | +| `parentId` | string | The id of the parent block. | +| `height` | number | The height of the block. | +| `timestamp` | object | Contains time related fields. | + +### `CollectionGuaranteeObject` + +A collection that has been included in a block. + +| Key | Value Type | Description | +| -------------- | ----------------------------------- | -------------------- | +| `collectionId` | string | The id of the block. | +| `signatures` | [SignatureObject](#SignatureObject) | All signatures. | + +### `CollectionObject` + +A collection is a list of transactions that are contained in the same block. + +| Key | Value Type | Description | +| ---------------- | ---------- | ------------------------------------------------------- | +| `id` | string | The id of the collection. | +| `transactionIds` | [string] | The ids of the transactions included in the collection. | + +### `ResponseObject` + +The format of all responses in FCL returned from `fcl.send(...)`. For full details on the values and descriptions of the keys, view [here](https://github.com/onflow/fcl-js/tree/master/packages/sdk/src/response). + +| Key | +| ------------------- | +| `tag` | +| `transaction` | +| `transactionStatus` | +| `transactionId` | +| `encodedData` | +| `events` | +| `account` | +| `block` | +| `blockHeader` | +| `latestBlock` | +| `collection` | + +### `Event Object` + +| Key | Value Type | Description | +| ------------------ | ----------------------- | ----------------------------------------------------------------------------------------------------- | +| `blockId` | string | ID of the block that contains the event. | +| `blockHeight` | number | Height of the block that contains the event. | +| `blockTimestamp` | string | The timestamp of when the block was sealed in a `DateString` format. eg. `'2021-06-25T13:42:04.227Z'` | +| `type` | [EventName](#eventname) | A string containing the event name. | +| `transactionId` | string | Can be used to query transaction information, eg. via a Flow block explorer. | +| `transactionIndex` | number | Used to prevent replay attacks. | +| `eventIndex` | number | Used to prevent replay attacks. | +| `data` | any | The data emitted from the event. | + +### `Transaction Statuses` + +The status of a transaction will depend on the Flow blockchain network and which phase it is in as it completes and is finalized. + +| Status Code | Description | +| ----------- | --------------------------------------------------------------------------------------------------------------------- | +| `0` | Unknown | +| `1` | Transaction Pending - Awaiting Finalization | +| `2` | Transaction Finalized - Awaiting Execution | +| `3` | Transaction Executed - Awaiting Sealing | +| `4` | Transaction Sealed - Transaction Complete. At this point the transaction result has been committed to the blockchain. | +| `5` | Transaction Expired | + +### `GRPC Statuses` + +The access node GRPC implementation follows the standard GRPC Core status code spec. View [here](https://grpc.github.io/grpc/core/md_doc_statuscodes.html). + +### `FType` + +FCL arguments must specify one of the following support types for each value passed in. + +| Type | Example | +| ------------ | -------------------------------------------------------------------------------------------------------------------- | +| `UInt` | `fcl.arg(1, t.UInt)` | +| `UInt8` | `fcl.arg(8, t.UInt8)` | +| `UInt16` | `fcl.arg(16, t.UInt16)` | +| `UInt32` | `fcl.arg(32, t.UInt32)` | +| `UInt64` | `fcl.arg(64, t.UInt64)` | +| `UInt128` | `fcl.arg(128, t.UInt128)` | +| `UInt256` | `fcl.arg(256, t.UInt256)` | +| `Int` | `fcl.arg(1, t.Int)` | +| `Int8` | `fcl.arg(8, t.Int8)` | +| `Int16` | `fcl.arg(16, t.Int16)` | +| `Int32` | `fcl.arg(32, t.Int32)` | +| `Int64` | `fcl.arg(64, t.Int64)` | +| `Int128` | `fcl.arg(128, t.Int128)` | +| `Int256` | `fcl.arg(256, t.Int256)` | +| `Word8` | `fcl.arg(8, t.Word8)` | +| `Word16` | `fcl.arg(16, t.Word16)` | +| `Word32` | `fcl.arg(32, t.Word32)` | +| `Word64` | `fcl.arg(64, t.Word64)` | +| `UFix64` | `fcl.arg("64.123", t.UFix64)` | +| `Fix64` | `fcl.arg("64.123", t.Fix64)` | +| `String` | `fcl.arg("Flow", t.String)` | +| `Character` | `fcl.arg("c", t.String)` | +| `Bool` | `fcl.arg(true, t.String)` | +| `Address` | `fcl.arg("0xABC123DEF456", t.Address)` | +| `Optional` | `fcl.arg("Flow", t.Optional(t.String))` | +| `Array` | `fcl.args([ fcl.arg(["First", "Second"], t.Array(t.String)) ])` | +| `Dictionary` | `fcl.args([fcl.arg([{key: 1, value: "one"}, {key: 2, value: "two"}], t.Dictionary({key: t.Int, value: t.String}))])` | +| `Path` | `fcl.arg({ domain: "public", identifier: "flowTokenVault" }, t.Path)` | + +--- + +### `EventFilter` + +An object that contains the parameters to filter events, used for event streaming in the [`fcl.events`](#events) function. + +| Name | Value Type | Description | +| ------------------------ | ------------------------- | ----------------------------------------------------------------------------------------------------------------------- | +| `startBlockId` | string | undefined | The block ID to start listening for events. Example: `9dda5f281897389b99f103a1c6b180eec9dac870de846449a302103ce38453f3` | +| `startHeight` | number | undefined | The block height to start listening for events. Example: `123` | +| `eventTypes` | string[] | undefined | The event types to listen for. Example: `A.7e60df042a9c0868.FlowToken.TokensWithdrawn` | +| `addresses` | string[] | undefined | The addresses to listen for. Example: `0x7e60df042a9c0868` | +| `contracts` | string[] | undefined | The contracts to listen for. Example: `0x7e60df042a9c0868` | +| `opts.heartbeatInterval` | number | undefined | The interval in milliseconds to send a heartbeat to the Access Node. Example: `10000` | + +### `StreamConnection` + +A stream connection is an object for subscribing to generic data from any WebSocket data stream. This is the base type for all stream connections. Two channels, `close` and `error`, are always available, as they are used to signal the end of the stream and any errors that occur. + +```ts +interface StreamConnection { + // Subscribe to a channel + on( + channel: C, + listener: (data: ChannelMap[C]) => void, + ): this; + on(event: 'close', listener: () => void): this; + on(event: 'error', listener: (err: any) => void): this; + + // Unsubscribe from a channel + off( + event: C, + listener: (data: ChannelMap[C]) => void, + ): this; + off(event: 'close', listener: () => void): this; + off(event: 'error', listener: (err: any) => void): this; + + // Close the connection + close(): void; +} +``` + +#### Usage + +```ts +import { StreamConnection } from "@onflow/typedefs" + +const stream: StreamConnection = ... + +stream.on("close", () => { + // Handle close +}) + +stream.on("error", (err) => { + // Handle error +}) + +stream.close() +``` + +### `EventStream` + +An event stream is a stream connection that emits events and block heartbeats. Based on the connection parameters, heartbeats will be emitted at least as often as some fixed block height interval. It is a specific variant of a [StreamConnection](#streamconnection). + +```ts +type EventStream = StreamConnection<{ + events: Event[]; + heartbeat: BlockHeartbeat; +}>; +``` + +#### Usage + +```ts +import { EventStream } from "@onflow/typedefs" + +const stream: EventStream = ... + +stream.on("events", (events) => { + // Handle events +}) + +stream.on("heartbeat", (heartbeat) => { + // Handle heartbeat +}) + +// Close the stream +stream.close() +``` + +### `BlockHeartbeat` + +```ts +export interface BlockHeartbeat { + blockId: string; + blockHeight: number; + timestamp: string; +} +``` + +#### Usage + +```ts +import { BlockHeartbeat } from "@onflow/typedefs" + +const heartbeat: BlockHeartbeat = ... +``` + +### SignatureObject + +Signature objects are used to represent a signature for a particular message as well as the account and keyId which signed for this message. + +| Key | Value Type | Description | +| ----------- | ------------------- | -------------------------------------------------------------------------------------------- | +| `addr` | [Address](#address) | the address of the account which this signature has been generated for | +| `keyId` | number | The index of the key to use during authorization. (Multiple keys on an account is possible). | +| `signature` | string | a hexidecimal-encoded string representation of the generated signature | + + +=== tools/clients/fcl-js/cross-vm/wagmi-adapter.mdx === +--- +sidebar_position: 1 +title: FCL Wagmi Adapter +description: FCL adapter for using Cadence-Owned Accounts (COAs) in Wagmi applications. +--- + +:::info + +This package is currently in alpha and is subject to change. + +::: + +# FCL Wagmi Adapter + +Provides a **Wagmi** connector that uses **@onflow/fcl-ethereum-provider** under the hood, allowing you to integrate Flow-based Cadence-Owned Accounts (COAs) seamlessly into Wagmi applications. + +## Installation + +```bash +npm install @onflow/fcl-wagmi-adapter +``` + +## Usage + +**Basic Example**: + +```ts +import { createClient, configureChains } from 'wagmi' +import { fclWagmiConnector } from '@onflow/fcl-wagmi-adapter' +import { flowTestnet } from 'wagmi/chains' +import { publicProvider } from 'wagmi/providers/public' +import * as fcl from '@onflow/fcl' + +// Configure FCL for Flow +fcl.config({ + "accessNode.api": "https://rest-testnet.onflow.org", + "discovery.wallet": "https://fcl-discovery.onflow.org/testnet/authn", +}) + +// Set up Wagmi for Flow Testnet +const { chains, provider } = configureChains( + [flowTestnet], + [publicProvider()] +) + +// Create a connector that uses FCL under the hood +const fclConnector = fclWagmiConnector({ + // optional: you can pass any config your provider or FCL needs +}) + +// Create the Wagmi client +const wagmiClient = createClient({ + autoConnect: true, + connectors: [fclConnector], + provider, +}) + +// The rest of your dApp logic... +``` + +## API + +### `fclWagmiConnector(options?: FclWagmiConnectorOptions): Connector` + +- **Parameters** + - `options?: object` – any additional configuration for the underlying FCL provider (gateway URL, custom FCL service, etc.) +- **Returns**: A Wagmi `Connector` object that can be used in `createClient` or `getDefaultConfig`. + +**Notes**: +- This connector essentially wraps `@onflow/fcl-ethereum-provider` as an EIP-1193 provider to talk to Flow EVM via Wagmi. +- The user’s authenticated COA is exposed as the “account” in Wagmi context. + +=== tools/clients/fcl-js/cross-vm/rainbowkit-adapter.mdx === +--- +sidebar_position: 1 +title: FCL Rainbowkit Adapter +description: FCL adapter for using Flow wallets in RainbowKit applications. +--- + +:::info + +This package is currently in alpha and is subject to change. + +::: + +# FCL RainbowKit Adapter + +Offers a **RainbowKit**-compatible wallet definition that uses Flow’s COA via FCL. Once installed, RainbowKit can display a “Flow Wallet” (or other FCL-enabled wallets) in its wallet selection modal. + +## Installation + +```bash +npm install @onflow/fcl-rainbowkit-adapter +``` + +## Usage + +Below is a typical usage example that shows how to set up a **RainbowKit** config for the Flow testnet, using this adapter. (From your provided sample.) + +```ts +import * as fcl from '@onflow/fcl' +import { createFclConnector, flowWallet } from '@onflow/fcl-rainbowkit-adapter' +import { connectorsForWallets } from '@rainbow-me/rainbowkit' +import { flowTestnet } from 'wagmi/chains' +import { createConfig, http } from 'wagmi' + +// Configure FCL (Flow testnet in this example) +fcl.config({ + "accessNode.api": "https://rest-testnet.onflow.org", + "discovery.wallet": "https://fcl-discovery.onflow.org/testnet/authn", + "walletconnect.projectId": "9b70cfa398b2355a5eb9b1cf99f4a981", // example WC projectId +}) + +// Create a list of connectors from your wallets +const connectors = connectorsForWallets([ + { + groupName: "Recommended", + wallets: [ + flowWallet(), + ], + }, +], { + appName: 'RainbowKit demo', + projectId: '9b70cfa398b2355a5eb9b1cf99f4a981', +}) + +// Wagmi config +export const config = createConfig({ + chains: [flowTestnet], + connectors, + ssr: true, + transports: { + [flowTestnet.id]: http(), + } +}); +``` + +## API + +### `flowWallet(options?: FlowWalletOptions): RainbowKitWallet` + +- Returns a RainbowKit-compatible wallet definition that integrates **@onflow/fcl-ethereum-provider**. +- **Parameters** + - `options?: FlowWalletOptions` – optional configuration, such as names/icons or custom gateway endpoints. +- **Returns**: A `RainbowKitWallet` object to be included in `connectorsForWallets`. + +### `createFclConnector(config?: CreateFclConnectorOptions): Connector` + +- A lower-level helper to build your own FCL-based EIP-1193 connectors for RainbowKit if you don’t want the preconfigured `flowWallet`. +- **Parameters** + - `config?: CreateFclConnectorOptions` – typical Wagmi + FCL config object (i.e., chain ID, network URL, FCL services, etc.). +- **Returns**: A valid Wagmi `Connector` for EVM interactions via FCL. + +=== tools/clients/fcl-js/cross-vm/index.md === +--- +title: Cross VM Packages +description: FCL packages for cross-VM (Flow + EVM) applications. +--- + +# FCL Cross-VM Packages + +These packages enable you to leverage Flow’s Cadence-Owned Account (COA) within Ethereum tooling (e.g., Wagmi, RainbowKit). They provide a unified approach for cross-VM apps on Flow and EVM, letting you perform EVM-like operations using Cadence accounts. + +For background and motivation, see the [FCL Ethereum Provider for Cross-VM Apps FLIP #316](https://github.com/onflow/flips/blob/c0fe9b71a9afb85fe70a69cf7c0870b5d327e679/application/20241223-fcl-ethereum-provider.md). + +| Package | Purpose | +|-----------------------------------------------|-------------------------------------------------------------------------------------------------| +| [@onflow/fcl-ethereum-provider](#onflowfcl-ethereum-provider) | Provides an EIP-1193-compliant Ethereum provider backed by an FCL-authenticated COA. | +| [@onflow/fcl-wagmi-adapter](#onflowfcl-wagmi-adapter) | Integrates Flow-based COAs with Wagmi, exposing them as Ethereum accounts in your dApp. | +| [@onflow/fcl-rainbowkit-adapter](#onflowfcl-rainbowkit-adapter)| Enables a Flow-based wallet option in your RainbowKit wallet selection modal. | + +## `@onflow/fcl-ethereum-provider` + +- **Description**: A drop-in EIP-1193 provider that authenticates users via [FCL](https://developers.flow.com/) and lets them sign transactions/messages with their COA. +- **Use Cases**: + - Integrate Flow EVM with any generic EVM library or framework. + - Direct control over JSON-RPC calls (e.g., `provider.request({ method: 'eth_sendTransaction' })`). +- **Link to Docs**: [Read the @onflow/fcl-ethereum-provider Reference »](ethereum-provider.mdx) + +## `@onflow/fcl-wagmi-adapter` + +- **Description**: A Wagmi connector that uses `@onflow/fcl-ethereum-provider` under the hood so you can sign in with your COA through standard Wagmi flows. +- **Use Cases**: + - Add Flow-based COAs to an existing Wagmi-powered dApp as if they were Ethereum wallets. +- **Link to Docs**: [Read the @onflow/fcl-wagmi-adapter Reference »](wagmi-adapter.mdx) + +## `@onflow/fcl-rainbowkit-adapter` + +- **Description**: A RainbowKit adapter that surfaces a Flow-based wallet in the wallet selection modal, making it easy to sign transactions via COAs in a RainbowKit environment. +- **Use Cases**: + - Offer Flow-based wallets (e.g., Flow Wallet) alongside popular Ethereum wallets in RainbowKit. +- **Link to Docs**: [Read the @onflow/fcl-rainbowkit-adapter Reference »](rainbowkit-adapter.mdx) + + +=== tools/clients/fcl-js/cross-vm/ethereum-provider.mdx === +--- +sidebar_position: 1 +title: FCL Ethereum Provider +description: An EIP-1193 provider that uses an FCL-authenticated Cadence Owned Account (COA) under the hood. +--- + +:::info + +This package is currently in alpha and is subject to change. + +::: + +# FCL Ethereum Provider + +Exposes a client-side [EIP-1193](https://eips.ethereum.org/EIPS/eip-1193) compatible Ethereum provider that uses an FCL-authenticated Cadence Owned Account (COA) under the hood. +If a wallet does not natively provide EVM capabilities, this provider emulates Ethereum JSON-RPC by delegating to FCL for signing and COA interactions. + +## Installation + +```bash +npm install @onflow/fcl-ethereum-provider +``` + +## Usage + +```ts +import * as fcl from "@onflow/fcl" +import { createEthereumProvider } from "@onflow/fcl-ethereum-provider" + +// Configure FCL (pointing to whichever Flow network you require) +fcl.config({ + "accessNode.api": "https://rest-testnet.onflow.org", + "discovery.wallet": "https://fcl-discovery.onflow.org/testnet/authn", +}) + +// Create the EIP-1193 provider +const provider = createEthereumProvider({ + // Optional configuration: + // service?: Service // Custom FCL service config + // gateway?: Eip1193Provider | string // EVM Gateway provider or URL +}) + +// Example: request EVM-style accounts (COA addresses) +const accounts = await provider.request({ method: "eth_requestAccounts" }) +console.log("EVM Accounts:", accounts) + +// Use the same session to sign a message +const signature = await provider.request({ + method: "personal_sign", + params: ["0x68656c6c6f20776f726c64", accounts[0]], // hex-encoded "hello world" +}) +console.log("Signature:", signature) + +// Or send transactions +const txHash = await provider.request({ + method: "eth_sendTransaction", + params: [ + { + from: accounts[0], + to: "0x1234...", + data: "0xabcd1234...", + value: "0x0", + }, + ], +}) +console.log("Transaction Hash:", txHash) +``` + +## API + +### `createEthereumProvider(config?: CreateEthereumProviderConfig): Eip1193Provider` + +- **Parameters** + - `config.service?: Service` + An [FCL “Service” object][fcl-service-docs] for custom FCL authentication flows. If omitted, the default FCL discovery service is used. + - `config.gateway?: Eip1193Provider | string` + An EIP-1193 provider (or a string URL) pointing to a Flow EVM gateway. Defaults to the public Flow EVM gateway if omitted. + +- **Returns**: An [EIP-1193](https://eips.ethereum.org/EIPS/eip-1193) provider instance you can pass into EVM tooling or interact with directly in your app. + +## Supported JSON-RPC Methods + +Below are the main request methods handled within the FCL Ethereum provider: + +1. **`eth_requestAccounts` / `eth_accounts`** + - **Behavior**: + - Invokes the FCL authentication flow (if not already authenticated) + - Returns the Cadence-Owned Account (COA) address + - Stores the COA at `/storage/evm` (creates if missing) + +2. **`eth_sendTransaction`** + - **Behavior**: + - Wraps the transaction in a Cadence transaction that invokes `coa.call(...)` in the Flow EVM + - Uses the user’s authenticated COA for signing + - Returns the resulting EVM transaction hash + +3. **`personal_sign`** + - **Behavior**: + - Requests a user signature via FCL’s `signUserMessage` or equivalent mechanism + - Returns an RLP-encoded [COA ownership proof](https://github.com/onflow/flow-go/blob/master/fvm/evm/types/proof.go#L139) in place of a raw secp256k1 signature + +4. **`eth_signTypedData_v4`** + - **Behavior**: + - Requests user signature for typed data (hash) via FCL + - Returns an RLP-encoded [COA ownership proof](https://github.com/onflow/flow-go/blob/master/fvm/evm/types/proof.go#L139) + +5. **`eth_chainId`** + - **Behavior**: + - Returns the numeric Flow EVM chain ID (e.g., `0x747` for Flow EVM Mainnet) + +6. **`wallet_switchEthereumChain`** + - **Behavior**: + - Allows dApps to request switching to a different Flow EVM chain (e.g. testnet to mainnet). + - Under the hood, this can trigger reconfiguration of FCL for a different Flow access node and Flow EVM gateway if recognized. + - If the requested chain ID is not recognized, the call will throw an error (matching EIP-1193 standard error codes). + +7. **`wallet_addEthereumChain`** + - **Behavior**: + - Allows a dApp to request adding a Flow EVM chain config. + - If the chain is recognized by the provider or is one the provider can handle, it will register it. Otherwise, it may reject with an EIP-1193 error. + - Since Flow EVM is typically a single chain per environment, usage is limited. However, in principle, custom EVM networks or local dev can be added if your provider/gateway supports them. + +### Fallback Behavior + +Any unknown or unsupported request methods will be proxied to the `gateway` (if you provided a standard JSON-RPC URL or EIP-1193 provider). If the gateway does not handle them, an error will be returned. + +## Provider Events + +- **`connect`**: Emitted once the user successfully authenticates via FCL, indicating that the provider is ready. +- **`disconnect`**: Emitted if the FCL session ends or user explicitly logs out, severing the session. +- **`accountsChanged`**: Emitted when the current user changes (e.g. re-authentication, or switching user in the wallet). +- **`chainChanged`**: Emitted when the user switches to a different Flow EVM chain (e.g. testnet to mainnet). + +=== templates/tutorial.md === +--- +title: Title, shorten if necessary, will be on sidebar +description: A one sentence description. +sidebar_position: 5 +keywords: + - keywords + - describing + - the main topics + - cursor is great at this +--- + +# Title + +1-2 Paragraphs describing what the tutorial will teach, why someone might learn it, and if possible, a link to a live version of the app demoing the techniques and content taught. + +## Objectives + +After completing this guide, you'll be able to: + +- 3-5 appropriate level Bloom's taxonomy verb objectives +- Don't wordsmith these +- It's ok of they're repetitive + +## Prerequisites + +### Next.js and Modern Frontend Development + +This tutorial uses [Next.js]. You don't need to be an expert, but it's helpful to be comfortable with development using a current React framework. You'll be on your own to select and use a package manager, manage Node versions, and other frontend environment tasks. If you don't have your own preference, you can just follow along with us and use [Yarn]. + +## Part 1 + +Text can go here. Usually it will be either an introduction to a long section with subsections, or a short section with no subsections that doesn't fit under a higher level. + +### Subsection 1 + +Divide each part into appropriate categories. + +**Avoid h4 and above** + +## Part 2 + +More text goes here + +## Conclusion + +In this tutorial, you ... + +Now that you have completed the tutorial, you should be able to: + +- Copy/paste the Objectives from above here + +(OPTIONAL) Now that you've completed this tutorial, you're ready to... + + + +[Cadence]: https://cadence-lang.org/docs +[Next.js]: https://nextjs.org/docs/app/getting-started/installation +[Yarn]: https://yarnpkg.com + + +=== networks/index.md === +--- +sidebar_position: 1 +--- + +import DocCardList from '@theme/DocCardList'; +import { isSamePath } from '@docusaurus/theme-common/internal'; +import { useDocsSidebar } from '@docusaurus/plugin-content-docs/client'; +import { useLocation } from '@docusaurus/router'; + +# Networks + + !isSamePath(item.href, useLocation().pathname))}/> + +=== networks/governance.md === +--- +title: Governance +description: Learn about Flow's governance model and how it's empowering our community of users and builders. +sidebar_position: 5 +sidebar_custom_props: + icon: 🏛️ +--- + +## Participation + +Participating in the governance process can take three forms: + +- Being elected as a council member on the governing committee +- Putting forth a proposal for the community to vote on +- Staking to receive voting rights + +Votes will be weighted based on locked tokens. All tokens staked by node operators will be eligible for voting, but other users can lock up their tokens to be given voting power. Anyone will be able to stake a Flow token to vote on issues (even if they aren’t participating as a staked node). + +## Token Holder Rights + +Tokens may be staked for operation or governance rights which gives holders the right to participate in running a node and/or to participate in public votes. + +## Process + +Proposals can be brought forward on a public forum where they will be evaluated by the governing committee. All decisions are made publicly and any stakeholder has the opportunity to organize grassroots action to veto specific decisions or to vote in or remove council members. + +To ensure the progress of the network, the elected council first assesses the proposal and selects an answer they agree to be the "default choice". Voters can freely vote how they choose, but having a well-considered default allows forward progress without being blocked by passive participants. All decisions are voted on by all participants and decisions made by the council must be ratified by a public vote on the network. + +### Timing + +Vote outcomes and upcoming votes will be published every Friday by 7am PT. All upcoming votes are available for review and voting for at least two weeks following their publication. + +## Protocol Set Parameters + +The following parameters will be set on the network on day 1 and will not be candidates for a public vote when the network first launches. + +- The staking ratio preserved between each node type +- The maximum inflation rate +- The role of FLOW as the main reserve asset for collateralized secondary tokens (e.g. stablecoins) +- The mechanism through which transaction inclusion, computation, and storage fees are determined and paid for + +## Early Governance of the Protocol + +Once governance is enabled, the community can participate in the following: + +- Protocol upgrades, including things like: - the consensus algorithm - the low-level network communication structure - the execution environment - the number of seats available for each node type +- Management of Ecosystem Development Fund, including: - issuance of grants - bug & feature bounties +- Selecting council members +- Committee budgets for each of the operational arms of the Foundation, including the executive, technical, operational, legal, pricing, financial, and marketing branches. +- Management of legal affairs, including: - enforcing license and patent infringements - issuing takedown notices and copyright infringement - freezing accounts if illegal activity occurs - updating the community, security, contribution policies + +During the Bootstrapping Phase, anyone may apply online to be set as a Validator by the Company. Approved Validators must then Stake a fixed minimum of FLOWs based on Validator type. Other FLOW holders may become “Delegators” when they dedicate or “Delegate” their FLOWs to approved Node Operators as a signal that they believe that Validator to be an effective and honest participant of the network. Staking and Delegation features are already enabled as of the Effective Date. + +Each Validator makes an individual decision of which Protocol Version they choose to use. Since the value of blockchain networks is primarily due to the collectively verified execution state, there is a strong incentive for Validators to choose a Protocol Version that is compatible with the Protocol Version selected by the majority of other Validators. As a practical matter, the Protocol Version chosen by the overwhelming majority of Validators is likely to be the most recent Protocol Version produced and recommended by the Core Team, provided the proposed changes are not contentious. However, if a significant fraction of the community disagrees with any aspect of the most recent Protocol Version, they can band together to use a previous Protocol Version, or some other Protocol Version defined independently from the Core Team. This process of a “contentious forking” is rare, but does have several precedents in other networks (REF: Ethereum Classic, Bitcoin Cash). + +The process by which the Core Team chooses the updates for each new Protocol Version follows the open process described above, using GitHub as an open discussion platform to gauge the priorities and needs of the entire Flow ecosystem. The proposed changes by the Core Team will be announced and discussed well before they are implemented, and any community member can propose their own changes or contribute code updates to implement any proposed changes. The details of a new Protocol Version are publicly available no less than 14 days before that version is formally recommended for use by Validators (a “Release”), with the complete implementation source code visible for no less than 7 days before a Release. + + +=== networks/staking/index.md === +--- +title: Epochs, Staking & Delegating on Flow +sidebar_label: Staking and Epochs +sidebar_position: 1 +description: Introduction to how staking works on Flow +--- + +This document provides an introduction to staking FLOW tokens on the Flow network +for token holders and node operators. +Staking is an important part of the security protocol of a proof-of-stake (PoS) blockchain. +Running nodes and staking tokens contributes to the blockchain's +security and is rewarded accordingly. + +## What is Staking? + +Flow is a global network of computers working together +to maintain the security and integrity of its users' data. + +This global network is made up of many individual nodes: software applications run by people. +Every node in the network shares a small part of the responsibility +to keep the network running smoothly and to ensure that other nodes are doing the same. +This shared responsibility is a core premise of decentralization, because no single central +node is solely responsible for the security and integrity of the network and the data it contains. + +Node operators are what we call the people who run nodes. +In order to connect their software applications as nodes on the network, +a node operator must first purchase tokens. Every node operator has to temporarily give (or ‘stake’) +a large number of their tokens to the network as a promise that they will not modify their node +to do something that is against the rules of the network, like steal funds from users' accounts. +This process of temporarily giving up tokens is called staking. + +If a node ever breaks the rules defined by the network, +a number of the node operator's staked tokens will be taken from them as a punishment. +This process is automatic. Every node knows the rules defined by the network +and automatically watches other nodes and reports them if they misbehave. +Meanwhile, the network pays the node operator a reward from a mixture of +transaction fees and newly minted tokens +on a regular basis provided their node does not break the rules. + +If a node operator breaks the rules, they lose the tokens they've staked. +If they operate their node with integrity, they get rewarded with more tokens! +This is the basic incentive that enables a decentralized proof-of-stake network, like Flow. + +## How Does Staking Work on Flow? + +The Flow protocol maintains a list of node operators. +The list contains important information about each node, like their public keys, node address, +and what kind of node they are running. +(Collection, Consensus, Execution, Verification, or Access) + +A node operator registers a node by submitting a transaction containing +their node information, a cryptographic proof that they control their node info, +and the FLOW they wish to stake. +If they meet the requirements to run a node, then will be accepted to join the network! + +Once a node is staking and operating properly, it will receive periodic reward payments, +assuming it stays online and actively participates in the protocol +without committing any actions that would harm the network, which we call slashable offenses. +Once nodes have registered, they are required to operate for a protocol-specified timeframe. +This timeframe is otherwise known as an **Epoch.** + +## Epochs + +An **Epoch** is a roughly week-long period that the network uses +to manage list of nodes and pay rewards. + +- Only a pre-determined set of nodes is authorized to participate in the protocol. +The set of authorized nodes is known to all network participants. +This set is referred to as the **Identity Table**. +- An **Epoch** is defined as a period of time, where the set of authorized nodes is constant +(or can only shrink due to ejection of malicious nodes). + +Every epoch, a list of committed nodes are chosen to be the staked nodes of the network. +This list is called the **Identity Table (ID Table)**. +The node's staked tokens are locked in and cannot change for the duration of the epoch. +At the end of the epoch, rewards are paid to each staked node based on how many tokens they had staked for that epoch +and how well they performed during the epoch. Nodes can choose to join or leave, but changes to the Identity Table +can only happen at end of an epoch, which is also the beginning of a new epoch. +This process repeats itself indefinitely, as long as the network remains functioning. + +To determine the list of nodes that are included as officially staked nodes in the next epoch, +the protocol looks at the records of all the nodes that have committed tokens. +It checks to make sure each node's information is correct and that the node is running properly. +Each node also has to have committed tokens above the minimum stake required for their node role +and be authorized by the service account. +If any of these checks are insufficient, the node is not included in the next epoch. + +Every epoch, some nodes also have to perform certain processes to initialize the state and communication +with other nodes for the next epoch. These processes are called **Cluster Quorum Certificate Generation (QC)**, +and **Distributed Key Generation (DKG)**. If any node does not perform this initialization properly, +it is not included in the next epoch's Identity Table. + +If a node passes all the checks and initializations, it is approved and included as an official node for the next epoch. + +Nodes (and users who delegate to them) do not have to continue to submit +staking registration transactions every epoch in order to remain staked. +As long as they continue to run their node properly, their tokens will remain staked. +A node operator only needs to take action if they want to stake more tokens +or if they want to unstake their staked tokens. + +If a node operator or delegator decides to stake or unstake tokens, +their requests are not carried out until the end of the current epoch. +In the case of unstaking requests, they also must wait an additional +epoch before their unstaked tokens are available to withdraw. +This allows the protocol to deal with any slashable offenses that may have happened in the previous epoch. + +See the [Epochs](./04-epoch-preparation.md) section of the documentation for in-depth explanations +of the identity table, epoch schedule, QC, and DKG. + +## Rewards + +Please see the [schedule](./03-schedule.md) section of the documentation +for information about reward calculations and schedule and +what you can do with the rewards you earn by staking a node! + +## Delegation + +Any account in the network may also participate in staking by delegating their tokens to a node operator. +Every node operator in the network is eligible to receive delegations, there is no opting out. + +To delegate to a node, a user simply specifies the ID of the node they want to delegate to +and the amount of tokens they want to delegate. +The tokens are committed and managed in the exact same way that normal staked tokens are managed. + +Rewards for delegators are also calculated in the exact same way that rewards for node operators are calculated, +with one difference in that 8% of the calculated amount is given to the delegatee (the node being delegated to). +The remaining 92% is awarded to the delegator. + +## How Do I Stake? + +So you have decided you want to be a part of the Flow network? Welcome! +You are joining a group of people from all around the world that are a part of a movement that is bringing decentralization and transparency into the world. + +### Staking using Flow Port + +[Flow Port](https://port.onflow.org/) is a simple browser-based app for the Flow blockchain +that provides functionality for sending, receiving, and staking tokens. +Any wallet that uses the [Flow Client Library](../../tools/clients/fcl-js/index.md) +is compatible with Flow Port. + +If you created your account using [Flow Port](https://port.onflow.org/), +you can also stake and earn rewards using the Flow Port. +Follow this [step-by-step guide](../../networks/flow-port/staking-guide.md) to stake using Flow Port. +Flow Port currently supports staking as a node, delegating, +and reward withdrawal using **Flow Reference Wallet**, **Ledger**, **Shadow**, **NuFi**, and any other FCL compatible accounts / wallets. + +### Staking via a Custody Provider + +If you are using a custody provider who controls your account and private keys for you, +such as Kraken, Finoa, or Coinlist, they all have different policies and processes +for what you need to do to stake your tokens, the rewards you receive, +and the fees that they take from your staking rewards. + +### Manual Staking or Building your own Staking Integration + +If you are self-custodying your Flow account and keys, or you want to build a staking service for customers, +you will need to learn more about how staking works, +the various methods for staking, and how you can participate safely and reliably. +See the [staking technical overview](./06-technical-overview.md) first +for information about technical integration. + + +=== networks/staking/15-staking-guide.md === +--- +title: Basic Staking with FLOW +sidebar_label: Basic Staking Guide (Deprecated) +--- + +This document outlines the steps a token holder can take to stake and manage +a Flow node with FLOW using only the types defined in the `FlowIDTableStaking` contract. +It only supports having one node or delegator object per account and is not supported by ledger +and will likely not be supported by other wallets, so it is recommended to use the staking collection +instead. + + +This guide covers staking with **FLOW tokens**. + + +# Staking + +## Setup + +### Register a New Staked Node + +To register as a node operator with FLOW, the token holder can use the **Register Node** ([SC.11](../../build/core-contracts/06-staking-contract-reference.md#staking)) +transaction with the following arguments: + +| Argument | Type | Description | +|-----------------------|----------|-------------| +| **id** | `String` | The ID of the new node. It must be a 32 byte `String`. The operator is free to choose this value, but it must be unique across all nodes. A recommended process to generate this is to hash the staking public key. | +| **role** | `UInt8` | The role of the new node. (1: collection, 2: consensus, 3: execution, 4: verification, 5: access) | +| **networkingAddress** | `String` | The IP address of the new node. (Length must be less than 255 bytes (510 Hex characters)) | +| **networkingKey** | `String` | The networking public key as a 64 byte hex-encoded `String` (128 hex characters) | +| **stakingKey** | `String` | The staking public key as a 96 byte hex-encoded `String` (192 hex characters) | +| **amount** | `UFix64` | The number of FLOW tokens to stake. | + +This transaction registers the account as a node operator with the specified node information +and creates a public link to query the nodes ID from the account address. + +--- + +Once the token holder has registered their node, +their tokens and node information are committed to the central staking contract for the next epoch. + +At this point, the token holder now has access to various staking operations that they can perform, +assuming they have the correct number of tokens to perform the action. + +## Stake Tokens + +The token holder can stake additional tokens at any time. + +_Note: this transaction stakes additional tokens to the same node that was registered in the setup phase._ + +To stake tokens, the token holder can use the **Stake FLOW** ([SC.12](../../build/core-contracts/06-staking-contract-reference.md#staking)) +transaction with the following arguments: + +| Argument | Type | Description | +|------------|----------|-------------| +| **amount** | `UFix64` | The number of FLOW tokens to stake. | + +This transaction commits tokens to stake from the token holder's account. + +## Re-stake Unstaked Tokens + +After tokens become unstaked, the token holder can choose to re-stake the unstaked tokens to the same node. + +To staked unstaked tokens, the token holder can use the **Re-stake Unstaked FLOW** ([SC.13](../../build/core-contracts/06-staking-contract-reference.md#staking)) +transaction with the following arguments: + +| Argument | Type | Description | +|------------|----------|-------------| +| **amount** | `UFix64` | The number of unstaked FLOW tokens to stake. | + +## Re-stake Rewarded Tokens + +After earning rewards from staking, the token holder can choose to re-stake the rewarded tokens to the same node. + +To stake rewarded tokens, the token holder can use the **Re-stake Rewarded FLOW** ([SC.14](../../build/core-contracts/06-staking-contract-reference.md#staking)) +transaction with the following arguments: + +| Argument | Type | Description | +|------------|----------|-------------| +| **amount** | `UFix64` | The number of rewarded FLOW tokens to stake. | + +## Request Unstake Tokens + +The token holder can submit a request to unstake some of their tokens at any time. +If the tokens aren't staked yet, they will be uncommitted and available to withdraw. + +To request to unstake staked tokens, the token holder can use +the **Request Unstaking** ([SC.15](../../build/core-contracts/06-staking-contract-reference.md#staking)) transaction. + +| Argument | Type | Description | +|------------|----------|-------------| +| **amount** | `UFix64` | The number of rewarded FLOW tokens to request to un-stake. | + +_Note: this transaction will not succeed if the node operator has delegators and the request +would put the node operator below the minimum required tokens staked for their node type. +Use the `Unstake All` transaction instead, which will also unstake all delegators._ + +_Note: unstaked tokens will be held by the central staking contract until the end of the following epoch. +Once the tokens are released (unstaked), they can be claimed via the +[Withdraw Unstaked Tokens](#withdraw-unstaked-tokens) action below._ + +## Unstake All Tokens + +The token holder can submit a request to unstake all their tokens at any time. +If the tokens aren't staked yet, they will be uncommitted and available to withdraw. + +To unstake all staked tokens, the token holder can use +the **Unstake All FLOW** ([SC.16](../../build/core-contracts/06-staking-contract-reference.md#staking)) transaction. + +This transaction requires no arguments. + +**Warning: this will unstake all of the user's staked tokens and unstake all of the tokens +from users that are delegating FLOW to the node.** + +## Withdraw Unstaked Tokens + +After tokens become unstaked, the token holder can withdraw them from the central staking contract. + +To withdraw unstaked tokens, +the token holder can use the **Withdraw Unstaked FLOW** ([SC.17](../../build/core-contracts/06-staking-contract-reference.md#staking)) +transaction with the following arguments: + +| Argument | Type | Description | +|------------|----------|-------------| +| **amount** | `UFix64` | The number of unstaked FLOW tokens to withdraw. | + +This transaction moves the unstaked tokens back into the `FlowToken.Vault` owned by the token holder. + +## Withdraw Rewarded Tokens + +After earning rewards from staking, the token holder can withdraw them from the central staking contract. + +To withdraw rewarded tokens, +the token holder can use the **Withdraw Rewarded FLOW** ([SC.18](../../build/core-contracts/06-staking-contract-reference.md#staking)) +transaction with the following arguments: + +| Argument | Type | Description | +|------------|----------|-------------| +| **amount** | `UFix64` | The number of rewarded FLOW tokens to withdraw. | + +This transaction moves the rewarded tokens back into the `FlowToken.Vault` owned by the token holder. + +## Stake Multiple Nodes from the Same Account + +Currently, the default staking transactions can only be used as they are to stake one node per account. + +If a token holder wants to create a second staking relationship using the transactions as is, they must create a new account +and transfer their tokens to the new account. + +It is possible to have multiple nodes per account by storing the node objects at different storage paths, +but this would require small changes to these transactions to use the new storage paths. + + +# Delegating + +## Setup + +## Register as a Delegator + +To register as a delegator, the token holder can use the **Register Delegator** ([SC.19](../../build/core-contracts/06-staking-contract-reference.md#delegating)) +transaction with the following arguments: + +| Argument | Type | Description | +|------------|----------|-------------| +| **id** | `String` | The ID of the node to delegate to. | +| **amount** | `UFix64` | The number of FLOW tokens to delegate. | + +This transaction registers the account as a delegator to the node ID they specified. + +--- + +## Delegate New Tokens + +The token holder can delegate additional tokens after registering as a delegator. + +_Note: this transaction delegates additional tokens to the same node that was registered in the setup phase._ + +To delegate new tokens, +the token holder can use the **Delegate New FLOW** ([SC.20](../../build/core-contracts/06-staking-contract-reference.md#delegating)) +transaction with the following arguments: + +| Argument | Type | Description | +|------------|----------|-------------| +| **amount** | `UFix64` | The number of FLOW tokens to delegate. | + +## Re-delegate Unstaked Tokens + +After delegated tokens become unstaked, the token holder can choose to re-delegate the unstaked tokens to the same node. + +To delegate unstaked tokens, +the token holder can use the **Re-delegate Unstaked FLOW** ([SC.21](../../build/core-contracts/06-staking-contract-reference.md#delegating)) +transaction with the following arguments: + +| Argument | Type | Description | +|------------|----------|-------------| +| **amount** | `UFix64` | The number of unstaked FLOW tokens to delegate. | + +## Re-delegate Rewarded Tokens + +After earning rewards from delegation, the token holder can choose to re-delegate the rewarded tokens to the same node. + +To delegate rewarded tokens, +the token holder can use the **Re-delegate Rewarded FLOW** ([SC.22](../../build/core-contracts/06-staking-contract-reference.md#delegating)) +| Argument | Type | Description | +| **amount** | `UFix64` | The number of rewarded FLOW tokens to delegate. | + +## Unstake Delegated Tokens + +The token holder can submit a request to unstake their delegated tokens at any time. +If the tokens aren't staked yet, they will be uncommitted and available to withdraw. + +To unstake delegated tokens, +the token holder can use the **Unstake Delegated FOW** ([SC.23](../../build/core-contracts/06-staking-contract-reference.md#delegating)) + +| Argument | Type | Description | +|------------|----------|-------------| +| **amount** | `UFix64` | The number of FLOW tokens to unstake. | + +_Note: unstaked delegated tokens will be held by the central staking contract for a period of time +(the rest of the current epoch plus all of the next epoch) before they are +released to the token holder. Once the tokens are released (unstaked), +they can be claimed via the [Withdraw Unstaked Tokens](#withdraw-unstaked-tokens) action below._ + +## Withdraw Unstaked Tokens + +After delegated tokens become unstaked, the token holder can withdraw them from the central staking contract. + +To withdraw unstaked tokens, +the token holder can use the **Withdraw Unstaked FLOW** ([SC.24](../../build/core-contracts/06-staking-contract-reference.md#delegating)) +transaction with the following arguments: + +| Argument | Type | Description | +|------------|----------|-------------| +| **amount** | `UFix64` | The number of unstaked FLOW tokens to withdraw. | + +This transaction moves the unstaked tokens back into the `FlowToken.Vault` owned by the token holder. + +## Withdraw Rewarded Tokens + +After earning rewards from delegation, the token holder can withdraw them from the central staking contract. + +To withdraw rewarded tokens, +the token holder can use the **Withdraw Rewarded FLOW** ([SC.25](../../build/core-contracts/06-staking-contract-reference.md#delegating)) +transaction with the following arguments: + +| Argument | Type | Description | +|------------|----------|-------------| +| **amount** | `UFix64` | The number of rewarded FLOW tokens to withdraw. | + +This transaction moves the rewarded tokens back into the `FlowToken.Vault` owned by the token holder. + +## Delegate to Multiple Nodes from the Same Account + +Currently, the default delegating transactions can only be used as they are to stake one node per account. + +If a token holder wants to create a second delegating relationship using the transactions as is, they must create a new account +and transfer their tokens to the new account. + +It is possible to have multiple delegator objects per account +by storing the node objects at different storage paths, +but this would require small changes to these transactions to use the new storage paths. + + +=== networks/staking/14-staking-collection.md === +--- +title: Manage a Staking Collection +sidebar_label: Staking Collection Guide +--- + +This document outlines the steps a token holder can take to stake +using [the `FlowIDTableStaking` contract](../../build/core-contracts/06-staking-contract-reference.md) +and [the `FlowStakingCollection` contract.](../../build/core-contracts/11-staking-collection.md) +This is the recommended and most supported way to stake FLOW. +It supports any number of nodes and delegators per account, supports locked and unlocked FLOW, +and supports easily interaction with a node's machine account for collector and consensus nodes. + +# Staking Collection Overview + +A Staking Collection is a resource that allows its owner to manage multiple staking +objects in a single account via a single storage path, and perform staking actions +using both locked and unlocked Flow. + +Before the staking collection, accounts could use the instructions in +[the unlocked staking guide](./15-staking-guide.md) +to stake with tokens. This was a bit restrictive, because that guide (and the corresponding transactions) +only supports one node and one delegator object +per account. If a user wanted to have more than one per account, +they would either have to use custom transactions with custom storage paths for each object, +or they would have had to use multiple accounts, which comes with many hassles of its own. + +The staking collection is a solution to both of these deficiencies. +When an account is set up to use a staking collection, the staking collection recognizes +the existing locked account capabilities (if they exist) and unlocked account staking objects, +and incorporates their functionality so any user can stake for a node or stake as a delegator +through a single common interface, regardless of if they have a brand new account, +or have been staking through the locked account or unlocked account before. + +The staking collection also easily allows a user to transfer their node or delegator objects +to other accounts without interrupting the staking process! + +## Staker Object Fields + +The staking collection resource has two main fields, +```cadence +access(self) var nodeStakers: @{String: FlowIDTableStaking.NodeStaker} +access(self) var nodeDelegators: @{String: FlowIDTableStaking.NodeDelegator} +``` +These dictionaries store the staking objects that are managed by the staking collection. +Access to these dictionaries are mediated by the staking methods. +When a user wants to perform a staking operation, +they specify the nodeID and/or delegatorID they want to stake for, and the function routes the function +call to the correct staking object and performs the specified operation. + +## Vault Capability Fields + +The staking collection also has a field that stores a capability for +the unlocked FLOW Vault and locked FLOW vault (if applicable) +```cadence +/// unlocked vault +access(self) var unlockedVault: Capability<&FlowToken.Vault> + +/// locked vault +/// will be nil if the account has no corresponding locked account +access(self) var lockedVault: Capability<&FlowToken.Vault>? +``` + +When a user performs staking operations like staking new tokens, +the staking collection tracks the number of unlocked tokens +and locked tokens (if applicable) that are used by the staking objects in the collection. +The collection will always try to stake any available locked tokens first. +Once all locked tokens are staked, if the user requested to stake more than the locked token balance, +the collection will then dip into the unlocked balance for the remaining tokens. +If the user has no locked tokens, the staking collection +will simply ignore the locked tokens part of the functionality and only use unlocked tokens. + +When a user withdraws tokens from a staking object, the collection +will always try to withdraw unlocked tokens first. +Any unlocked tokens are then deposited directly into the vault on the unlocked account, +and remaining locked tokens are deposited to the vault in the locked account. + +## Machine Account Support + +The staking collection also supports an important feature for epochs, machine accounts. +Machine accounts are where node operators store important resource objects +that are critical to the functionality of the epoch preparation protocol. +Every collector and consensus node should have an associated machine account that stores these objects, +and the staking collection helps the user create and manage these accounts. + +When a user registers a new collector or consensus node, +the staking collection also creates a machine account for them and registers +the required object that needs to go in the machine account. +The node operator is then responsible for adding keys to the account. +(the **Register Node** transaction includes this step). + +Once the machine account is created and set up, the node operator just has to +connect it to their node software and make sure the account has enough FLOW +to pay for transaction fees, which can be handled simply by submitting +a regular FLOW transfer to the machine account's address + +## Staking Collection Public Getter Methods + +The staking collection also defines many getter methods to query information +about an account's staking collection. You can simply call one of these methods on the contract, +providing the account address, and the contract will retrieve +the relevant info for you, like so: +```cadence +import FlowStakingCollection from 0xSTAKINGCOLLECTIONADDRESS +import FlowIDTableStaking from 0xIDENTITYTABLEADDRESS + +/// Gets an array of all the delegator metadata for delegators stored in the staking collection +access(all) fun main(address: Address): [FlowIDTableStaking.DelegatorInfo] { + return FlowStakingCollection.getAllDelegatorInfo(address: address) +} +``` + +Remember: A Staking Collection does not require an account +to have a secondary locked account or locked FLOW. +However, if an account does have an associated locked account, when the Staking Collection is initialized, +it will connect to that locked account's node and delegator objects +as well as it's locked token vault allowing it to perform staking actions with locked and unlocked FLOW. + + +Staking Collection is backwards compatible with other methods of staking on Flow. +Existing accounts with associated locked accounts +will still be able to stake in the same way as before, +but they will also be able to use the staking collection, if desired. + + + +# How to use the Staking Collection + +There is a standard set of transactions provided with the staking collection. + +## Setup + +### Setup a Staking Collection + +To set up a Staking Collection, you must run the **Setup Staking Collection** ([SCO.01](../../build/core-contracts/11-staking-collection.md)) transaction. + +This transaction requires no arguments and will perform the following actions: +1. Create private capabilities for the unlocked vault and locked vault (if applicable). +2. Create a new staking collection resource object, initializing it with the unlocked and locked vault capabilities. +3. Store the staking collection at a pre-defined storage path. +4. Create a public link to the staking collection so others can query metadata about it. +5. If there are any node or delegator objects in the unlocked account, the transaction stores those in the staking collection + so they can be used through the same interface as usual. + +**No arguments** are required for the **Setup Staking Collection** transaction. + +Once this transaction is complete, your existing staking objects (if any) from your unlocked account and locked account +will be available via the staking collection and you can use all the transactions described below to access them. + +### Create a Machine Account for an existing Node + +Many nodes will have been created before the staking collection was set up and before epochs were enabled, +meaning that they don't already have an associated machine account. +These nodes need a new transaction to create the machine account for the node and save it to the staking collection. + +To create a machine account for a node that doesn't already have one, +you must submit the **Create Machine Account** ([SCO.03](../../build/core-contracts/11-staking-collection.md)) +transaction with the following arguments: + +| Argument | Type | Description | +|----------------|-------------|-------------| +| **nodeID** | `String` | The ID of the node. | +| **publicKeys** | `[String]` | The public keys to add to the machine account.| + +If the node is a collector or consensus node, this transaction creates the associated machine account, +registers the QC or DKG object, stores it in the machine account, +and adds the provided public key(s) to the machine account. +If no public keys are provided, the transaction will fail. + +## Register Stakers + +### Register a New Staked Node + +To register a new staked node, you must submit the **Register Node** ([SCO.03](../../build/core-contracts/11-staking-collection.md)) +transaction with the following arguments: + +| Argument | Type | Description | +|-----------------------|-------------|-------------| +| **id** | `String` | The ID of the new node. It must be a 32 byte `String`. The operator is free to choose this value, but it must be unique across all nodes. A recommended process to generate this is to hash the staking public key. | +| **role** | `UInt8` | The role of the new node. (1: collection, 2: consensus, 3: execution, 4: verification, 5: access) | +| **networkingAddress** | `String` | The IP address of the new node. | +| **networkingKey** | `String` | The networking public key as a hex-encoded string. | +| **stakingKey** | `String` | The staking public key as a hex-encoded string. | +| **stakingKeyPoP** | `String` | The staking key Proof-of-Possesion as a hex-encoded string. | +| **amount** | `UFix64` | The number of FLOW tokens to stake. | +| **publicKeys** | `[String]?` | The public keys to add to the machine account. `nil` if no machine account | + +This transaction registers the account as a staker with the specified node information +and attaches a `NodeStaker` resource to the `Staking Collection`. +This `NodeStaker` resourece can then later be used to perform staking actions via the staking collection staking methods. + +If the node is a collector or consensus node, it also creates the associated machine account, +registers the QC or DKG object, stores it in the machine account, +and adds the provided public key(s) to the machine account. +If the node requires a machine account and no public keys are provided, the transaction will fail. + +Once the account has registered their node using their Staking Collection, +their tokens and node information are committed to the central staking contract for the next epoch. + +At this point, the Staking Collection now has access to various staking operations that they can perform, +assuming they have the correct number of tokens to perform the action. + +### Register a New Staked Delegator + +To register a new delegator, you must submit the **Register Delegator** ([SCO.02](../../build/core-contracts/11-staking-collection.md)) +transaction with the following arguments: + +| Argument | Type | Description | +|------------|----------|-------------| +| **id** | `String` | The ID of the node to delegate to. | +| **amount** | `UFix64` | The number of FLOW tokens to delegate. | + +This transaction registers the account as a delegator to the node identified by the supplied node id. +It also attaches a `NodeDelegator` resource to the `Staking Collection`. +This `NodeDelegator` resourece can then later be used to perform delegation actions. + +Once the account has registered their new delegator using their Staking Collection, +their tokens are committed to the central staking contract for the next epoch. + +At this point, the Staking Collection now has access to various delegator operations that they can perform, +assuming they have the correct number of tokens to perform the action. + + +## Staking Operations + +These transactions perform actions that directly interact with the staking contract. +Most of them will only succeed during the Staking Auction phase of the epoch. + +### Stake New Tokens + +The Staking Collection can stake additional tokens for any Node or Delegator managed by it at any time. + +The owner of a Staking Collection can use the **Stake New Tokens** ([SCO.06](../../build/core-contracts/11-staking-collection.md)) +transaction with the following arguments: + +| Argument | Type | Description | +|-------------------------|--------------------|-------------| +| **nodeID** | `String` | The nodeID of the node to stake new tokens to. | +| **delegatorID** | `Optional(UInt32)` | `nil` if staking for a node. If staking for a delegator, the delegator ID. | +| **amount** | `UFix64` | The number of FLOW tokens to stake. | + + +To stake new tokens for an active node, leave the delegatorID argument as nil. + + +If staking for a delegator, delegatorID should be the delegator ID you are staking for. + + +The amount may be any number of tokens up to the sum of an accounts locked and unlocked FLOW. + +### Re-stake Unstaked Tokens + +After tokens become unstaked, the owner of a Staking Collection can choose +to re-stake the unstaked tokens to the same Node or Delegator. + +The owner of a Staking Collection can use the **Stake Unstaked Tokens** ([SCO.08](../../build/core-contracts/11-staking-collection.md)) +transaction with the following arguments: + +| Argument | Type | Description | +|-------------------------|--------------------|-------------| +| **nodeID** | `String` | The nodeID of the node to stake the unstaked tokens to. | +| **delegatorID** | `Optional(UInt32)` | `nil` if staking for a node. If staking for a delegator, the delegator ID. | +| **amount** | `UFix64` | The number of FLOW tokens to restake. | + + +To stake unstaked tokens for an active node, leave the delegatorID argument as nil. + +If staking for a delegator, delegatorID should be the delegator ID you are staking for. + + +### Re-stake Rewarded Tokens + +After earning rewards from staking, the owner of a Staking Collection +can choose to re-stake the rewarded tokens to the same node or delegator. + +The owner of a Staking Collection can use the **Stake Unstaked Tokens** ([SCO.07](../../build/core-contracts/11-staking-collection.md)) +transaction with the following arguments: + +| Argument | Type | Description | +|-------------------------|--------------------|-------------| +| **nodeID** | `String` | The nodeID of the node to stake the rewarded tokens to. | +| **delegatorID** | `Optional(UInt32)` | `nil` if staking for a node. If staking for a delegator, the delegator ID. | +| **amount** | `UFix64` | The number of FLOW tokens to restake. | + + +To stake rewarded tokens for an active node, leave the delegatorID argument as nil. + + +### Request to Unstake Tokens at the end of the Epoch + +The owner of a Staking Collection can submit a request to unstake their tokens at any time for any Node or Delegator in their collection. + +If the tokens aren't staked yet, they will be uncommitted and available to withdraw. + +_Note: unstaked tokens will be held by the central staking contract until the end of the following epoch._ +_Once the tokens are released (unstaked), they can be claimed via the [Withdraw Unstaked Tokens](#withdraw-unstaked-tokens) action below._ + +The owner of a Staking Collection can use the **Unstake Tokens** ([SCO.05](../../build/core-contracts/11-staking-collection.md)) +transaction with the following arguments: + +| Argument | Type | Description | +|-------------------------|--------------------|-------------| +| **nodeID** | `String` | The nodeID of the chosen node. | +| **delegatorID** | `Optional(UInt32)` | `nil` if staking for a node. If staking for a delegator, the delegator ID. | +| **amount** | `UFix64` | The number of FLOW tokens to restake. | + + +To unstake tokens from an active node, leave the delegatorID argument as nil. + + +### Unstake All Tokens + +The owner of a Staking Collection can use the **Unstake All** ([SCO.09](../../build/core-contracts/11-staking-collection.md)) +transaction with the following arguments: + +| Argument | Type | Description | +|-------------------------|--------------------|-------------| +| **nodeID** | `String` | The nodeID of the node to unstake all tokens from. | +| **delegatorID** | `Optional(UInt32)` | `nil` if staking for a node. If staking for a delegator, the delegator ID. | + +### Withdraw Unstaked Tokens + +After tokens for an active Node or Delegator become unstaked, +the ownder of Staking Collection can withdraw them from the central staking contract. + +The owner of a Staking Collection can use the **Withdraw Unstaked Tokens** ([SCO.11](../../build/core-contracts/11-staking-collection.md)) +transaction with the following arguments: + +| Argument | Type | Description | +|-------------------------|--------------------|-------------| +| **nodeID** | `String` | The nodeID of the node to withdraw the unstaked tokens from. | +| **delegatorID** | `Optional(UInt32)` | `nil` if staking for a node. If staking for a delegator, the delegator ID. | +| **amount** | `UFix64` | The number of FLOW tokens to withdraw. | + + +To withdraw unstaked tokens from an active node, leave the delegatorID argument as nil. + + +### Withdraw Rewarded Tokens + +After earning rewards from staking, the token holder can withdraw them from the central staking contract. + +The owner of a Staking Collection can use the **Withdraw Rewarded Tokens** ([SCO.10](../../build/core-contracts/11-staking-collection.md)) +transaction with the following arguments: + +| Argument | Type | Description | +|-------------------------|--------------------|-------------| +| **nodeID** | `String` | The nodeID of the node to withdraw the rewarded tokens from. | +| **delegatorID** | `Optional(UInt32)` | `nil` if staking for a node. If staking for a delegator, the delegator ID. | +| **amount** | `UFix64` | The number of FLOW tokens to withdraw. | + + +To withdraw rewarded tokens from an active node, leave the delegatorID argument as nil. + + +## Staking Collection Modification + +### Close a Node or Delegator + +Once a Node or Delegator has no tokens staked, comitted or in an unstaking state, it is eligible to be closed. + +Closing a Node or Delegator first returns any unstaked or rewarded tokens +to the account for which the Staking Collection is stored in. +It then destroys the NodeStaker or NodeDelegator object from within the Staking Collection. + +_Note: Once a Node or Delegator has been closed, it cannot be accessed again,_ +_and no staking or delegation actions can be further preformed on it._ + +The owner of a Staking Collection can use the **Close Stake** ([SCO.12](../../build/core-contracts/11-staking-collection.md)) +transaction with the following arguments: + +| Argument | Type | Description | +|-------------------------|--------------------|-------------| +| **nodeID** | `String` | The nodeID of the node to close. | +| **delegatorID** | `Optional(UInt32)` | `nil` if staking for a node. If staking for a delegator, the delegator ID. | + + +To close an active node, leave the delegatorID argument as nil. + + +### Transfer a Node + +A user may transfer an existing Node to another another account's Staking Collection. + +The account to transfer the Node to must have a valid Staking Collection set up. + +Transferring a Node will remove it from the authorizer's Staking Collection +and deposit it to the receiver's Staking Collection. + +_Note: Once a Node or Delegator has been transferred, it cannot be accessed again by the sender._ +_As well, all staked tokens will be considered staked by the receiver's Staking Collection._ + + +Transferring a Node will result in loss of custody of any Staked tokens for the sender. + + +The owner of a Staking Collection can use the **Transfer Node** ([SCO.13](../../build/core-contracts/11-staking-collection.md)) +transaction with the following arguments: + +| Argument | Type | Description | +|-------------------------|--------------------|-------------| +| **nodeID** | `String` | The nodeID of the node to transfer. | +| **to** | `Address` | The address of the account which contains the Staking Collection to transfer the Node to. | + +### Transfer a Delegator + +A user may transfer an existing Delegator to another another account's Staking Collection. + +The account to transfer the Delegator to must have a valid Staking Collection set up. + +Transferring a Delegator will remove it from the authorizer's Staking Collection +and deposit it to the receiver's Staking Collection. + +_Note: Once a Node or Delegator has been transferred, it cannot be accessed again by the sender._ +_As well, all staked tokens will be considered staked by the receiver's Staking Collection._ + + +Transferring a Delegator will result in loss of custody of any Staked tokens for the sender. + + +The owner of a Staking Collection can use the **Transfer Delegator** ([SCO.14](../../build/core-contracts/11-staking-collection.md)) +transaction with the following arguments: + +| Argument | Type | Description | +|-------------------------|--------------------|-------------| +| **nodeID** | `String` | The nodeID of the delegator to transfer. | +| **delegatorID** | `UInt32` | The delegatorID of the delegator to transfer. | +| **to** | `Address` | The address of the account which contains the Staking Collection to transfer the Delegator to. | + + +### Update A Node's Networking Address + +A user may update their node's networking address if it has become inconsistent with the protocol state. + +This operation can only be performed in the staking auction phase of an epoch. + +_Note: Currently, if a node updates its networking address and the new address does not match_ +_what is stored in the protocol state for the node, the node will not be able to participate in the upcoming epoch_ +_Only update your networking address if you have already confirmed with the Flow team that you can._ +_This restriction will be removed once fully automated epochs are completely implemented_ + +The owner of a Staking Collection can use the **Update Networking Address** ([SCO.22](../../build/core-contracts/11-staking-collection.md)) +transaction with the following arguments: + +| Argument | Type | Description | +|-----------------|-----------|-------------| +| **nodeID** | `String` | The nodeID of the node to update. | +| **newAddress** | `String` | The new networking address | + + +# Staking Collection Scripts + +These scripts allow anyone to query information about an account's staking collection + +### Get All Node Info + +To return an array of structs representing the information associated with each node managed by an account's Staking Collection, anyone +can use the **Get All Node Info** ([SCO.15](../../build/core-contracts/11-staking-collection.md)) script with the following arguments: + +| Argument | Type | Description | +|-------------|------------|-------------| +| **address** | `Addresss` | The Address of the account holding the Staking Collection to query from | + +This script returns an array of `FlowIDTableStaking.NodeInfo` [structs](https://github.com/onflow/flow-core-contracts/blob/master/contracts/FlowIDTableStaking.cdc#L264) +representing the nodes managed by an accounts Staking Collection. + +### Get All Delegator Info + +To return an array of structs representing the information associated with each delegator managed by an account's Staking Collection, anyone +can use the **Get All Delegator Info** ([SCO.16](../../build/core-contracts/11-staking-collection.md)) script with the following arguments: + +| Argument | Type | Description | +|-------------|------------|-------------| +| **address** | `Addresss` | The Address of the account holding the Staking Collection to query from | + +This script returns an array of `FlowIDTableStaking.DelegatorInfo` [structs](https://github.com/onflow/flow-core-contracts/blob/master/contracts/FlowIDTableStaking.cdc#L264) +representing the delegators managed by an accounts Staking Collection. + +### Get All Node Ids + +To return an array of Strings representing the ids associated with each node managed by an account's Staking Collection, anyone +can use the **Get All Node Ids** ([SCO.17](../../build/core-contracts/11-staking-collection.md)) script with the following arguments: + +| Argument | Type | Description | +|-------------|------------|-------------| +| **address** | `Addresss` | The Address of the account holding the Staking Collection to query from | + +This script returns an array of `String` +representing each id of each node managed by an accounts Staking Collection. + +### Get All Delegator Ids + +To return an array of structs representing the delegator ids associated with each delegation managed by an account's Staking Collection, anyone +can use the **Get All Delegator Ids** ([SCO.22](../../build/core-contracts/11-staking-collection.md)) script with the following arguments: + +| Argument | Type | Description | +|-------------|------------|-------------| +| **address** | `Addresss` | The Address of the account holding the Staking Collection to query from | + +This script returns an array of `FlowStakingCollection.DelegatorIDs` [structs](https://github.com/onflow/flow-core-contracts/blob/master/contracts/FlowStakingCollection.cdc#L40) +representing the delegator Ids of each delegator managed by an accounts Staking Collection. + +### Get Locked Tokens Used + +To query how many Locked FLOW tokens an account has staked using their Staking Collection, anyone +can use the **Get Locked Tokens Used** ([SCO.19](../../build/core-contracts/11-staking-collection.md)) script with the following arguments: + +| Argument | Type | Description | +|-------------|------------|-------------| +| **address** | `Addresss` | The Address of the account holding the Staking Collection to query from | + +This script returns a `UFix64` representing the number of Locked FLOW tokens staked using an accounts Staking Collection. + + +Note: This number does not include Locked FLOW tokens staked not through an accounts Staking Collection. + + +### Get Unlocked Tokens Used + +To query how many Unlocked FLOW tokens an account has staked using their Staking Collection, anyone +can use the **Get Unlocked Tokens Used** ([SCO.20](../../build/core-contracts/11-staking-collection.md)) script with the following arguments: + +| Argument | Type | Description | +|-------------|------------|-------------| +| **address** | `Addresss` | The Address of the account holding the Staking Collection to query from | + +This script returns a `UFix64` representing the number of Unlocked FLOW tokens staked using an accounts Staking Collection. + + +Note: This number does not include Unlocked FLOW tokens staked not through an accounts Staking Collection. + + +### Get Does Node Exist + +To query if a Node or Delegator is managed by an accounts Staking Collection, anyone +can use the **Get Does Node Exist** ([SCO.21](../../build/core-contracts/11-staking-collection.md)) script with the following arguments: + +| Argument | Type | Description | +|-------------------------|--------------------|-------------| +| **address** | `Addresss` | The Address of the account holding the Staking Collection to query from | +| **nodeID** | `String` | The nodeID of the node to check, or the nodeID of the node delegating to to check. | +| **delegatorID** | `Optional(UInt32)` | The delegatorID of the delegator to check, if checking for a delegator. | + +This script returns a `Bool`. + + +To query if a Node is managed by an accounts Staking Collection, leave the delegatorID argument as nil. +Otherwise, fill it in with the delegatorID of the Delegator. + + +### Get Machine Account Info + +To query the machine account information for an account's staking collection, anyone +can use the **Get Machine Account Info** ([SCO.21](../../build/core-contracts/11-staking-collection.md)) script with the following arguments: + +| Argument | Type | Description | +|-------------------------|--------------------|-------------| +| **address** | `Addresss` | The Address of the account holding the Staking Collection to query from | + +This script returns a `{String: FlowStakingCollection.MachineAccountInfo}`, +which is a mapping of nodeIDs to the `FlowStakingCollection.MachineAccountInfo` struct. + + +=== networks/staking/13-staking-options.md === +--- +title: Options for Building Staking Integrations +sidebar_label: Technical Staking Options +--- + +This document describes two different methods for staking at a high level. + + + +We highly recommended you use the Staking Collection paradigm, +as this will be the most supported method for staking with any set up. + + + +# Staking Collection + +A Staking Collection is a resource that allows its owner to manage multiple staking +objects in a single account via a single storage path, and perform staking actions +using Flow. It also supports machine accounts, a necessary feature for Flow epoch node operation. + +The staking collection paradigm is the most flexible of the three choices +and will receive the most support in the future. It is the set-up that Flow Port and many other staking providers use. + +The staking collection setup and guide is detailed in the [staking collection guide.](./14-staking-collection.md) + +# Staking + +The basic method to stake is to stake directly with the `FlowIDTableStaking` smart contract. +This would involve calling the node or delegator registration functions directly in the staking +contract and storing the staking objects directly in account storage. + +This is probably the simplest way to implement this, but it is not very flexible +and not recommended. + +The basic staking guide is detailed [here](./15-staking-guide.md) + +=== networks/staking/12-faq.md === +--- +title: Staking FAQ +sidebar_label: FAQs +description: Frequently Asked Questions +--- + +### Where will users receive their staking reward for each staking option? + +Staking rewards are not deposited directly into a user's account. +They are deposited to the user's rewards pool in their connected staking object +and can be withdrawn or restaked at any time. + +If you staked using Flow Port, then you should be able to see your staking rewards there. +You can also withdraw the rewards or manually re-stake them through Flow Port. + +If you staked using a staking provider such as Kraken, Blocto or Finoa, +please ask them how they manage staking rewards. + +### Will staking rewards be automatically re-staked? + +There will be _no_ automatic re-staking of staking rewards with Flow Port (i.e. using Ledger or Blocto). +If you want to re-stake your rewards, you must manually do so yourself. + +If you staked using a staking provider such as Kraken, Blocto or Finoa, +please ask them what their policies are. + +DeFi liquid staking strategies such as offered by [incrementFi](https://app.increment.fi/staking) +are not managed by the protocol or nodes, but are more sophisticated ways +to manage your staking. + +### Does it make a difference as to what TYPE of node we delegate to in terms of rewards? + +No, rewards are calculated the same for every node type. + +### Can a validator change its fees? + +The network enforces a delegation fee of 8% which cannot be directly changed. +Any different fees that nodes claim they have are rebates that they +offer using their own methods and are not enforced by the protocol. + +### Can a token holder stake to multiple nodes? If yes, how is the stake split between them? + +A token holder can delegate to multiple nodes from a single account if they use the +[Staking Collection](./14-staking-collection.md). + +The staking collection is enabled by default on Flow port, and many custody providers also support it. + +### Is the wallet key transferred to the staked node? + +No - The keys on the node are different from the wallet keys. The wallet keys always stay in the wallet. +A node operator generates the staking and networking keys separately which will be used on the node. + +### Can I stake through multiple accounts to meet the minimum FLOW required for staking a node? + +No, the minimum stake must come from a single account for all node types. +Temporarily, the minimum for consensus nodes can come from a combination +of staking actions from two accounts controlled by the same party. + +### How can I reach the Consensus node minimum stake of 500K FLOW + +The consensus node minimum of 500K FLOW can be met with a minimum +250,000 FLOW staking action and additional delegation +adding a minimum of 250,000 more FLOW from the same entity. + +### Is rewards payout another spork? + +No, rewards payout is not a spork but is an automatic transaction that happens +at the beginning of every new epoch. + +### Can I query an account address of a node ID or delegator ID? + +The staking smart contract does not directly associate a node or delegator with an account address. +It associates it with the assigned resource object that corresponds to that entry in the contract. +There can be any number of these objects stored in the same account, +and they can be moved to different accounts if the owner chooses. +It is possible to query the information about a node that an address runs though, by using the +`get_node_info_from_address.cdc` script. + +=== networks/staking/11-machine-account.md === +--- +title: Machine Account +sidebar_label: Machine Account +description: Usage and Purpose of the Machine Account +--- + +### What is a Machine Account? + +A Machine Account is a Flow account which is used autonomously by a node to interact with +system smart contracts. Machine Accounts contain Cadence resources granted to network +participants which are used to participate in smart-contract-mediated protocols. Currently, +Machine Accounts are used in the [Epoch Preparation Protocol](./04-epoch-preparation.md), +which prepares the network for the next epoch. + +Your Machine Account is distinct from the account you use for staking your node (your Staking Account). +The Machine Account is intended for use by node software and does not have access to your staked tokens or staking rewards. + + + +Currently Machine Accounts are required only for `collection` and `consensus` nodes. + + + +#### Creation + +Machine Accounts are created during the [staking process](../../networks/flow-port/staking-guide.md) in Flow Port. + +#### Funding + +Machine Accounts must maintain a balance of liquid FLOW tokens to pay fees on transactions they +submit to system smart contracts. Typically very few transactions will be sent (about 1-5 per week) +however more may be required under certain circumstances and network conditions. + + + +Because some transactions sent by the Machine Account are system critical, we recommend maintaining +a balance sufficient to accommodate worst-case transaction submission numbers at all times. **See [here](./../node-ops/node-operation/monitoring-nodes.md#machine-account) for how to monitor.** + + + +When creating a new machine account, we recommend initially funding with 0.005 FLOW for collection nodes and +0.25 FLOW for consensus nodes. + +Machine account balances should be monitored and periodically refilled to ensure they have sufficient funds. +We recommend a minimum balance at all times of 0.002 FLOW for collection nodes and 0.1 FLOW for consensus nodes. + +A node operator can easily withdraw their FLOW from their machine account if they decide they don't need them there any more. + + +=== networks/staking/10-qc-dkg-scripts-events.md === +--- +title: Query QC/DKG Info with Scripts or Events +sidebar_label: QC/DKG Scripts and Events +--- + +# Introduction + +The Cluster Quorum Certificate (QC) and Distributed Key Generation (DKG) protocol smart contracts +store a lot of different state, and the state is constantly changing. +As an external party, there are two ways to keep track of these state changes. +You can either use Cadence scripts to query the state of the contract at any given time, +or you can monitor events that are emitted by the contracts to be notified of any important occurrences. + +# Query Information with Scripts + +These events can be queried using the Go or JavaScript SDKs to extract useful notifications and information about the +state of these processes. + +## QC Scripts + +These scripts allow anyone to query information about the state of the QC contract. + +### Get Clusters + +To return a struct representing the information associated with a collector cluster, +can use the **Get Cluster** ([QC.03](../../build/core-contracts/07-epoch-contract-reference.md#quorum-certificate-transactions-and-scripts)) script with the following argument: + +| Argument | Type | Description | +|------------------|----------|-------------| +| **clusterIndex** | `UInt16` | The index of the cluster to query | + +### Get QC Enabled + +To return a boolean representing if the QC is enabled, +can use the **Get QC Enabled** ([QC.04](../../build/core-contracts/07-epoch-contract-reference.md#quorum-certificate-transactions-and-scripts)) script with no arguments. + +### Get Node Has Voted + +To return a boolean representing if a node has voted for the current QC, you +can use the **Get Node Has Voted** ([QC.05](../../build/core-contracts/07-epoch-contract-reference.md#quorum-certificate-transactions-and-scripts)) script with the following argument: + +| Argument | Type | Description | +|------------------|----------|-------------| +| **nodeID** | `String` | The node ID to check for | + + +### Get Voting Complete + +To return a boolean representing if the voting for the QC phase is complete, +can use the **Get Voting Complete** ([QC.06](../../build/core-contracts/07-epoch-contract-reference.md#quorum-certificate-transactions-and-scripts)) script with no arguments. + +## QC Events + +Documentation coming soon + +## DKG Scripts + +### Get DKG Enabled + +To return a boolean representing if the DKG is enabled, you +can use the **Get DKG Enabled** ([DKG.04](../../build/core-contracts/07-epoch-contract-reference.md#dkg-transactions-and-scripts)) script with no arguments. + +### Get DKG Completed + +To return a boolean representing if the dkg is complete, you +can use the **Get DKG Complete** ([DKG.05](../../build/core-contracts/07-epoch-contract-reference.md#dkg-transactions-and-scripts)) script with no arguments. + +### Get Whiteboard Messages + +To return an array of structs representing all the whiteboard messages, you +can use the **Get DKG Whiteboard Messages** ([DKG.06](../../build/core-contracts/07-epoch-contract-reference.md#dkg-transactions-and-scripts)) script with no arguments. + +### Get Final Submissions + +To return an array of key vectors for the nodes' final submissions, you +can use the **Get Final Submissions** ([DKG.07](../../build/core-contracts/07-epoch-contract-reference.md#dkg-transactions-and-scripts)) script with no arguments. + +### Get Node Has Submitted + +To return a boolean representing if a node has sent their final submission for the DKG, you +can use the **Get Node Has Submitted** ([DKG.08](../../build/core-contracts/07-epoch-contract-reference.md#dkg-transactions-and-scripts)) script with the following argument: + +| Argument | Type | Description | +|------------------|----------|-------------| +| **nodeID** | `String` | The node ID to check for | + +## DKG Events + +```cadence +/// Emitted when the admin enables the DKG +access(all) event StartDKG() + +/// Emitted when the admin ends the DKG after enough submissions have been recorded +access(all) event EndDKG(finalSubmission: [String?]?) + +/// Emitted when a consensus node has posted a message to the DKG whiteboard +access(all) event BroadcastMessage(nodeID: String, content: String) +``` + +=== networks/staking/09-qc-dkg.md === +--- +title: Quorum Certificate and Distributed Key Generation +sidebar_label: QC and DKG +description: How the Flow protocol manages the Epoch Setup Phase +toc_max_heading_level: 4 +--- + +:::warning + + If you haven't read the Intro to Flow Staking document and the Epoch protocol document, + please read that first. Those documents provide an overview of epochs on Flow for + all users and are necessary prerequisites to this document. + +::: + +:::warning + + This document assumes you have some technical knowledge about the Flow + blockchain and programming environment. + +::: + +## Epoch Setup Phase + +**Purpose:** During the epoch setup phase, all nodes participating in the upcoming epoch +must perform setup tasks in preparation for the upcoming epoch, including +the Collector Cluster Quorum Certificate Generation and Consensus Committe Distributed Key Generation. + +**Duration:** The epoch setup phase begins right after the `EpochSetup` service event is emitted. +It ends with the block where `EpochCommit` service emitted. + +## Machine Accounts + +The processes described in this document are fully automated. + +They are expected to be performed entirely by the node software with no manual +interaction required by the node operator after the node has been set up and registered. + +To facilitate this, we recommend that node operators use a secondary "machine account" +that only stores the `FlowClusterQC.Voter` or `FlowDKG.Participant` resource objects +in addition to FLOW to pay for transaction fees. You can connect your node to this account +to participate in the Epoch Setup Phase without having to do the actions manually. + +If you are using the [Staking Collection](./14-staking-collection.md) for your node, +this functionality is built-in. When you register a node with the staking collection, +you also have to provide a public key or keys for your machine account for the node. + +If you have a node without a machine account (if you were operating a node from the time +before epochs and staking collection were enabled, for example) the staking collection +also provides a method to create a machine account for an existing node. + +See the [Staking Collection Docs](./14-staking-collection.md#machine-account-support) +for more information. + +## Collector Cluster Quorum Certificate Generation Protocol + +The collector nodes are organized into clusters and must bootstrap +the Hotstuff consensus algorithm for each cluster. To do this, +they generate the root block for their respective clusters +and submit a vote for the root block to a specialized smart contract, `FlowClusterQC`. +If 2/3 of the collectors in a cluster have voted with the same unique vote, +then the cluster is considered complete. +Once all clusters are complete, the QC is complete. + +### `FlowClusterQC` Transactions + +#### Create QC Voter Object + +A node uses the [`getClusterQCVoter()`](https://github.com/onflow/flow-core-contracts/blob/master/contracts/epochs/FlowEpoch.cdc#L905) +function in the `FlowEpoch` contract to create their Voter object and needs to provide +a reference to their `FlowIDTableStaking.NodeStaker` object to prove they are the node owner. + +When registering a node with the staking collection, this process is handled by +[the transaction to register.](./14-staking-collection.md#register-a-new-staked-node) +It also creates a machine account for the QC object. + +If a user already has a registered node with the staking collection, but hasn't created their QC Voter object yet, +they can use the [`create_machine_account.cdc` transaction.](./14-staking-collection.md#create-a-machine-account-for-an-existing-node) + +If a user is not using the staking collection, they can use the **Create QC Voter** ([QC.01](../../build/core-contracts/07-epoch-contract-reference.md#quorum-certificate-transactions-and-scripts)) +transaction. This will only store the QC Voter object in the account that stores the `NodeStaker` object. +It does not create a machine account or store it elsewhere, so it is not recommended to use. We encourage to use the staking collection instead. + +#### Submit Vote + +During the Epoch Setup Phase, the node software should submit the votes for the QC generation +automatically using the **Submit QC Vote** ([QC.02](../../build/core-contracts/07-epoch-contract-reference.md#quorum-certificate-transactions-and-scripts)) +transaction with the following arguments. + +| Argument | Type | Description | +|-------------------------|----------|-------------| +| **voteSignature** | `String` | The signed message (signed with the node's staking key) | +| **voteMessage** | `String` | The raw message itself. | + +## Consensus Committee Distributed Key Generation Protocol (DKG) + +The Random Beacon Committee for the next Epoch (currently all consensus nodes) +will run the DKG through a specialized smart contract, `FlowDKG`. +To do this, they post a series of messages to a public "whiteboard" to +collectively generate a shared key array. When each node has enough information +to generate their array of keys, they send the generated array to the smart contract +as their final submission. +If `(# of consensus nodes-1)/2` consensus nodes submit the same key array, +the DKG is considered to be complete. + +### `FlowDKG` Transactions + +#### Create DKG Participant Object + +A node uses the [`getDKGParticipant()`](https://github.com/onflow/flow-core-contracts/blob/master/contracts/epochs/FlowEpoch.cdc#L919) +function in the `FlowEpoch` contract to create their Voter object and needs to provide +a reference to their `FlowIDTableStaking.NodeStaker` object to prove they are the node owner. + +When registering a node with the staking collection, this process is handled by +[the transaction to register.](./14-staking-collection.md#register-a-new-staked-node) +It also creates a machine account for the DKG Object. + +If a user already has a registered node with the staking collection, but hasn't created their DKG Participant object yet, +they can use the [`create_machine_account.cdc` transaction.](./14-staking-collection.md#create-a-machine-account-for-an-existing-node) + +If a user is not using the staking collection, they can use the **Create DKG Participant** ([DKG.01](../../build/core-contracts/07-epoch-contract-reference.md#dkg-transactions-and-scripts)) +transaction. This will only store the DKG Participant object in the account that stores the `NodeStaker` object. +It does not create a machine account or store it elsewhere, so it is not recommended to use. +The staking collection is the recommended method. + +#### Post Whiteboard Message + +During the Epoch Setup Phase, the node software should post whiteboard messages to the DKG +automatically using the **Post Whiteboard Message** ([DKG.02](../../build/core-contracts/07-epoch-contract-reference.md#dkg-transactions-and-scripts)) +transaction with the following arguments. + +| Argument | Type | Description | +|-------------------|----------|-------------| +| **content** | `String` | The content of the whiteboard message | + +#### Send Final Submission + +During the Epoch Setup Phase, the node software should send its final submission for the DKG +automatically using the **Send Final Submission** ([DKG.03](../../build/core-contracts/07-epoch-contract-reference.md#dkg-transactions-and-scripts)) +transaction with the following arguments. + +| Argument | Type | Description | +|--------------------|-------------|-------------| +| **submission** | `[String?]` | The final key vector submission for the DKG. | + +## Monitor Events and Query State from the QC and DKG Contracts + +See the [QC and DKG events and scripts document](./10-qc-dkg-scripts-events.md) for information +about the events that can be emitted by these contracts and scripts you can use to query information. + + +=== networks/staking/08-staking-rewards.md === +--- +title: Staking and Delegation rewards +sidebar_label: How to Query Staking rewards +description: How to check the staking and delegation rewards +--- + +## Current method to check staking rewards + +Rewards payout happens automatically after the end of the epoch and without the need of an explicit transaction being submitted by the service account. +Instead of a separate reward payout transaction, the reward payout events will be recorded in the system chunk in the block that is produced at the time of the epoch transition without creating a regular transaction ID. + +The rewards payout can be queried by querying the block which contains the system chunk that contains the reward payout events. +``` +flow events get A.8624b52f9ddcd04a.FlowIDTableStaking.RewardsPaid A.8624b52f9ddcd04a.FlowIDTableStaking.DelegatorRewardsPaid --start --end -n mainnet + +where block height is the height of the block containing the rewards payout events +``` + +Example + +``` +$ flow events get A.8624b52f9ddcd04a.FlowIDTableStaking.RewardsPaid A.8624b52f9ddcd04a.FlowIDTableStaking.DelegatorRewardsPaid --start 51753836 --end 51753836 -n mainnet + +Events Block #51753836: + Index 6 + Type A.8624b52f9ddcd04a.FlowIDTableStaking.RewardsPaid + Tx ID f31815934bff124e332b3c8be5e1c7a949532707251a9f2f81def8cc9f3d1458 + Values + - nodeID (String): "a3075cf9280cab4fa0b7b1e639b675bdae3e8874557d98ee78963f0799338a5f" + - amount (UFix64): 1660.21200000 + + Index 9 + Type A.8624b52f9ddcd04a.FlowIDTableStaking.RewardsPaid + Tx ID f31815934bff124e332b3c8be5e1c7a949532707251a9f2f81def8cc9f3d1458 + Values + - nodeID (String): "cf0ff514b6aa659914b99ab1d17743edb2b69fbb338ab01945a08530a98c97d4" + - amount (UFix64): 3762.20370347 + + Index 12 + Type A.8624b52f9ddcd04a.FlowIDTableStaking.RewardsPaid + Tx ID f31815934bff124e332b3c8be5e1c7a949532707251a9f2f81def8cc9f3d1458 + Values + - nodeID (String): "de988efc8cb79d02876b7beffd404fc24b61c287ebeede567f90056f0eece90f" + - amount (UFix64): 939.85630919 + + Index 27 + Type A.8624b52f9ddcd04a.FlowIDTableStaking.RewardsPaid + Tx ID f31815934bff124e332b3c8be5e1c7a949532707251a9f2f81def8cc9f3d1458 + Values + - nodeID (String): "fa5f24a66c2f177ebc09b8b51429e9f157037880290e7858f4336479e57dc26b" + - amount (UFix64): 1660.21200000 + + Index 30 + Type A.8624b52f9ddcd04a.FlowIDTableStaking.RewardsPaid + Tx ID f31815934bff124e332b3c8be5e1c7a949532707251a9f2f81def8cc9f3d1458 + Values + - nodeID (String): "581525fa93d8fe4b334c179698c6e72baccb802593e55e40da61d24e589d85be" + - amount (UFix64): 1937.24727662 + ... + ... + + ... + ... + Index 50115 + Type A.8624b52f9ddcd04a.FlowIDTableStaking.DelegatorRewardsPaid + Tx ID f31815934bff124e332b3c8be5e1c7a949532707251a9f2f81def8cc9f3d1458 + Values + - nodeID (String): "95ffacf0c05757cff71a4ee49e025d5a6d1103a3aa7d91253079e1bfb7c22458" + - delegatorID (UInt32): 23 + - amount (UFix64): 0.10424555 + + Index 50118 + Type A.8624b52f9ddcd04a.FlowIDTableStaking.DelegatorRewardsPaid + Tx ID f31815934bff124e332b3c8be5e1c7a949532707251a9f2f81def8cc9f3d1458 + Values + - nodeID (String): "95ffacf0c05757cff71a4ee49e025d5a6d1103a3aa7d91253079e1bfb7c22458" + - delegatorID (UInt32): 18 + - amount (UFix64): 17.31047712 +``` + +Example using [Flow Go SDK](../../tools/clients/flow-go-sdk/index.md) +``` +package main + +import ( + "context" + "fmt" + client "github.com/onflow/flow-go-sdk/access/grpc" +) + +func main() { + + // the Flow testnet community Access node API endpoint + accessNodeAddress := "access.mainnet.nodes.onflow.org:9000" + + // create a gRPC client for the Access node + accessNodeClient, err := client.NewClient(accessNodeAddress) + if err != nil { + fmt.Println("err:", err.Error()) + panic(err) + } + + ctx := context.Background() + + blockEvents, err := accessNodeClient.GetEventsForHeightRange(ctx, + "A.8624b52f9ddcd04a.FlowIDTableStaking.RewardsPaid", + 51753836, + 51753836) + if err != nil { + panic(err) + } + + for _, blockEvent := range blockEvents { + fmt.Println("Block: " + blockEvent.BlockID.String()) + for _, event := range blockEvent.Events { + fmt.Println("\tEvent type: " + event.Type) + fmt.Println("\tEvent: " + event.Value.String()) + fmt.Println("\tEvent payload: " + string(event.Payload)) + } + } +} +``` + +## Check staking rewards before May 2023 + +Before May 2023, rewards payouts were done manually by the Flow governance committee. + +When the transactions executed, they generated events for the rewards paid to each node and delegator. +To check the staking and delegation rewards, those transactions should be queried directly. + +Example using [Flow cli](../../tools/flow-cli/index.md) +``` +$ flow transactions get 84eca4ff612ef70047d60510710cca872c8a17c1bd9f63686e74852b6382cc84 -n mainnet + +Status ✅ SEALED +ID 84eca4ff612ef70047d60510710cca872c8a17c1bd9f63686e74852b6382cc84 +Payer e467b9dd11fa00df +Authorizers [e467b9dd11fa00df] + +Proposal Key: + Address e467b9dd11fa00df + Index 11 + Sequence 118 + +No Payload Signatures + +Envelope Signature 0: e467b9dd11fa00df +Envelope Signature 1: e467b9dd11fa00df +Envelope Signature 2: e467b9dd11fa00df +Envelope Signature 3: e467b9dd11fa00df +Envelope Signature 4: e467b9dd11fa00df +Signatures (minimized, use --include signatures) + +Events: + Index 0 + Type A.1654653399040a61.FlowToken.TokensWithdrawn + Tx ID 84eca4ff612ef70047d60510710cca872c8a17c1bd9f63686e74852b6382cc84 + Values + - amount (UFix64): 64.59694884 + - from (Address?): 0xf919ee77447b7497 + + Index 1 + Type A.f919ee77447b7497.FlowFees.TokensWithdrawn + Tx ID 84eca4ff612ef70047d60510710cca872c8a17c1bd9f63686e74852b6382cc84 + Values + - amount (UFix64): 64.59694884 + + Index 2 + Type A.1654653399040a61.FlowToken.TokensMinted + Tx ID 84eca4ff612ef70047d60510710cca872c8a17c1bd9f63686e74852b6382cc84 + Values + - amount (UFix64): 1326397.40305116 + + Index 3 + Type A.1654653399040a61.FlowToken.TokensDeposited + Tx ID 84eca4ff612ef70047d60510710cca872c8a17c1bd9f63686e74852b6382cc84 + Values + - amount (UFix64): 1326397.40305116 + - to (Never?): nil + + Index 4 + Type A.1654653399040a61.FlowToken.TokensWithdrawn + Tx ID 84eca4ff612ef70047d60510710cca872c8a17c1bd9f63686e74852b6382cc84 + Values + - amount (UFix64): 1004.16460872 + - from (Never?): nil + + Index 5 + Type A.1654653399040a61.FlowToken.TokensDeposited + Tx ID 84eca4ff612ef70047d60510710cca872c8a17c1bd9f63686e74852b6382cc84 + Values + - amount (UFix64): 1004.16460872 + - to (Address?): 0x8624b52f9ddcd04a + ... + ... + +``` + +Example using [Flow Go SDK](../../tools/clients/flow-go-sdk/index.md) +``` +package main + +import ( + "context" + "fmt" + "github.com/onflow/flow-go-sdk" + client "github.com/onflow/flow-go-sdk/access/grpc" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" +) + +func main() { + + // the Flow mainnet community Access node API endpoint + accessNodeAddress := "access.mainnet.nodes.onflow.org:9000" + + maxGRPCMessageSize := 1024 * 1024 * 20 // to accommodate for the large transaction payload + + // create a gRPC client for the Access node + accessNodeClient, err := client.NewClient(accessNodeAddress, + grpc.WithTransportCredentials(insecure.NewCredentials()), + grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(maxGRPCMessageSize))) + if err != nil { + fmt.Println("err:", err.Error()) + panic(err) + } + + ctx := context.Background() + + txID := flow.HexToID("84eca4ff612ef70047d60510710cca872c8a17c1bd9f63686e74852b6382cc84") + + rewardsTxResult, err := accessNodeClient.GetTransactionResult(ctx, txID) + if err != nil { + panic(err) + } + + for _, event := range rewardsTxResult.Events { + fmt.Println("Event type: " + event.Type) + fmt.Println("Event: " + event.Value.String()) + fmt.Println("Event payload: " + string(event.Payload)) + } +} +``` + +=== networks/staking/07-staking-scripts-events.md === +--- +title: Query Staking Info with Scripts or Events +sidebar_label: Staking Scripts and Events +--- + +# Introduction + +The staking contract stores a lot of different state, and the state is constantly changing. +As an external party, there are two ways to keep track of these state changes. +You can either use Cadence scripts to query the state of the contract at any given time, +or you can monitor events that are emitted by the staking contract to be notified of any important occurances. + +# Query Information with Scripts + +## Get the list of proposed nodes for the next epoch: + +`FlowIDTableStaking.getProposedNodeIDs()`: Returns an array of node IDs for proposed nodes. +Proposed nodes are nodes that have enough staked and committed for the next epoch +to be above the minimum requirement and have been selected to participate in the next epoch. +This means that new access nodes that have not been selected with the random slot selection algorithm +will not be included in this list. + +You can use the **Get Proposed Table**([SC.05](../../build/core-contracts/06-staking-contract-reference.md#getting-staking-info-with-scripts)) script for retrieving this info. + +This script requires no arguments. + +## Get the list of all nodes that are currently staked: + +`FlowIDTableStaking.getStakedNodeIDs()` and ``FlowIDTableStaking.getParticipantNodeList()`: +Returns an array of nodeIDs that are currently staked. +Staked nodes are nodes that are staked and participating in the current epoch. + +You can use the **Get Current Table**([SC.04](../../build/core-contracts/06-staking-contract-reference.md#getting-staking-info-with-scripts)) script for retrieving this info. + +This script requires no arguments. + +## Get the list of all Candidate Nodes + +`getCandidateNodeList(): {UInt8: {String: Bool}}`: +Returns a dictionary of nodes that are candidates to stake in the next epoch +but are not staked in the current epoch. + +You can use the [**Get Candidate Node List**](https://github.com/onflow/flow-core-contracts/blob/master/contracts/FlowIDTableStaking.cdc#L1762) script for retrieving this info. + +This script requires no arguments. + +## Get all of the info associated with a single node staker: + +`FlowIDTableStaking.NodeInfo(nodeID: String)`: Returns a `NodeInfo` struct with all of the metadata +associated with the specified node ID. You can see the `NodeInfo` definition in the [FlowIDTableStaking +smart contract.](https://github.com/onflow/flow-core-contracts/blob/master/contracts/FlowIDTableStaking.cdc#L254) + +You can use the **Get Node Info**([SC.08](../../build/core-contracts/06-staking-contract-reference.md#getting-staking-info-with-scripts)) script +with the following arguments: + +| Argument | Type | Description | +| ---------- | -------- | -------------------------------------- | +| **nodeID** | `String` | The node ID of the node to search for. | + +You can also query the info from an address that uses the staking collection by using the **Get Node Info From Address**([SCO.15](../../build/core-contracts/11-staking-collection.md#scripts)) script +with the following arguments: + +| Argument | Type | Description | +| ----------- | --------- | ------------------------------------------------- | +| **address** | `Address` | The address of the account that manages the nodes. | + +## Get the total committed balance of a node (with delegators): + +`FlowIDTableStaking.NodeInfo(_ nodeID: String).totalCommittedWithDelegators()`: Returns the total committed balance for a node, +which is their total tokens staked + committed, plus all of the staked + committed tokens of all their delegators. + +You can use the **Get Node Total Commitment**([SC.09](../../build/core-contracts/06-staking-contract-reference.md#getting-staking-info-with-scripts)) script +with the following argument: + +| Argument | Type | Description | +| ---------- | -------- | -------------------------------------- | +| **nodeID** | `String` | The node ID of the node to search for. | + +## Get the total committed balance of a node (without delegators): + +`FlowIDTableStaking.NodeInfo(_ nodeID: String).totalCommittedWithoutDelegators()`: Returns the total committed balance for a node, +which is their total tokens staked + committed, plus all of the staked + committed tokens of all their delegators. + +You can use the **Get Only Node Total Commitment**([SC.11](../../build/core-contracts/06-staking-contract-reference.md#getting-staking-info-with-scripts)) script +with the following argument: + +| Argument | Type | Description | +| ---------- | -------- | -------------------------------------- | +| **nodeID** | `String` | The node ID of the node to search for. | + +## Get all the info associated with a single delegator: + +`FlowIDTableStaking.DelegatorInfo(nodeID: String, delegatorID: UInt32)`: Returns a `DelegatorInfo` struct with all of the metadata +associated with the specified node ID and delegator ID. You can see the `DelegatorInfo` definition in the [FlowIDTableStaking +smart contract.](https://github.com/onflow/flow-core-contracts/blob/master/contracts/FlowIDTableStaking.cdc#L375) + +You can use the **Get Delegator Info**([SC.10](../../build/core-contracts/06-staking-contract-reference.md#getting-staking-info-with-scripts)) +script with the following arguments: + +| Argument | Type | Description | +| --------------- | -------- | -------------------------------------------- | +| **nodeID** | `String` | The node ID that the delegator delegates to. | +| **delegatorID** | `String` | The ID of the delegator to search for. | + +You can also query the info from an address by using the **Get Delegator Info From Address**([SCO.16](../../build/core-contracts/11-staking-collection.md#scripts)) script +with the following arguments: + +| Argument | Type | Description | +| ----------- | --------- | ------------------------------------------------------ | +| **address** | `Address` | The address of the account that manages the delegator. | + +## Get the delegation cut percentage: + +`FlowIDTableStaking.getRewardCutPercentage(): UFix64`: Returns a `UFix64` number for the cut of delegator rewards that each node operator takes. + +You can use the **Get Cut Percentage**([SC.01](../../build/core-contracts/06-staking-contract-reference.md#getting-staking-info-with-scripts)) script to retrieve this info. + +This script requires no arguments. + +## Get the minimum stake requirements: + +`FlowIDTableStaking.getMinimumStakeRequirements(): {UInt8: UFix64}`: Returns a mapping +for the stake requirements for each node type. + +You can use the **Get stake requirements**([SC.02](../../build/core-contracts/06-staking-contract-reference.md#getting-staking-info-with-scripts)) script to retrieve this info. + +This script requires no arguments. + +## Get the total weekly reward payout: + +`FlowIDTableStaking.getEpochTokenPayout(): UFix64`: Returns a `UFix64` value for the total number of FLOW paid out each epoch (week). + +You can use the **Get weekly payout**([SC.03](../../build/core-contracts/06-staking-contract-reference.md#getting-staking-info-with-scripts)) script to retrieve this info. + +This script requires no arguments. + +## Get the total FLOW staked: + +You can use the **Get total FLOW staked**([SC.06](../../build/core-contracts/06-staking-contract-reference.md#getting-staking-info-with-scripts)) script to retrieve this info. + +This script requires no arguments. + +## Get the total FLOW staked by all the nodes of a single node role: + +You can use the **Get total FLOW staked by node type**([SC.07](../../build/core-contracts/06-staking-contract-reference.md#getting-staking-info-with-scripts)) script +with the following arguments: + +| Argument | Type | Description | +| ------------ | ------- | ------------------------------- | +| **nodeType** | `UInt8` | The type of node to search for. | + + +# Staking Events + +Staking events can be queried using the Go or JavaScript SDKs to extract useful notifications and information about the +state of the staking process. + +## Global Staking and Epoch Events + +### NewEpoch + +```cadence +access(all) event NewEpoch(totalStaked: UFix64, totalRewardPayout: UFix64, newEpochCounter: UInt64) +``` + +| Field | Type | Description | +| ---- | ---- | ----- | +| totalStaked | UFix64 | The total number of tokens staked for the new Epoch | +| totalRewardPayout | UFix64 | The total number of tokens that will be paid as rewards for this epoch | +| newEpochCounter | UInt64 | The epoch counter for this new epoch | + +Emitted by `FlowIDTableStaking.Admin.moveTokens()` when the tokens are moved between pools, which signals a new epoch. + +### NewWeeklyPayout + +```cadence +access(all) event NewWeeklyPayout(newPayout: UFix64) +``` + +| Field | Type | Description | +| --------- | ------ | ------------------------------------------------------------------ | +| newPayout | UFix64 | The new number of tokens that will be paid at the end of the epoch | + +Emitted by `FlowIDTableStaking.Admin.setEpochTokenPayout()` when the Admin changes the total tokens paid at the end of the epoch. + +After this event the `epochTokenPayout` is equal to the new value. + +## Node Events + +These are events that concern the operation of a node. + +### NewNodeCreated + +```cadence +access(all) event NewNodeCreated(nodeID: String, role: UInt8, amountCommitted: UFix64) +``` + +| Field | Type | Description | +| ---- | ------ | ------- | +| nodeID | String | The unique ID string for the node. 32 bytes. Usually the hash of the node's public key. | +| role | UInt8 | The node's role type. From 1 to 5 inclusive. | +| amountCommitted | UFix64 | The amount of FLOW tokens staked to register the node. This is determined by the `role`. | + +Emitted by `FlowIDTableStaking.NodeRecord.init()` when a new node is successfully created. + +After this event is emitted for your node, you can begin to perform staking transactions using it. + +### NodeRemovedAndRefunded + +```cadence +access(all) event NodeRemovedAndRefunded(nodeID: String, amount: UFix64) +``` + +| Field | Type | Description | +| ------ | ------ | --------------------------------------------------------------------------------------------------------------- | +| nodeID | String | The unique ID string for the node. 32 bytes. The same value emitted in the `NewNodeCreated` event for the node. | +| amount | UFix64 | The amount of FLOW tokens returned to the node. | + +Emitted by `FlowIDTableStaking.Admin.endStakingAuction()` if the node is being removed from the next epoch +due to a failure to meet the minimum requirements of committed tokens for the next epoch. + +After this event, the refunded FLOW tokens will be part of the node's `tokensUnstaked` balance. + +## Token Events + +These are events that concern the direct usage of FLOW tokens - staking or unstaking locked tokens, withdrawing rewards, etc. + +Events emitted when using delegation are described in the next section. + +### TokensCommitted + +```cadence +access(all) event TokensCommitted(nodeID: String, amount: UFix64) +``` + +| Field | Type | Description | +| ------ | ------ | ----------- | +| nodeID | String | The unique ID string for the node. 32 bytes. The same value emitted in the `NewNodeCreated` event for the node. | +| amount | UFix64 | The amount of additional FLOW tokens committed to the node. | + +Emitted whenever additional tokens are staked on the node for the following epoch. Specifically: + +1. By `FlowIDTableStaking.NodeStaker.stakeNewTokens()` when new tokens (tokens that have not previously been staked) are added to the system + to stake on the node during the next epoch. +2. By `FlowIDTableStaking.NodeStaker.stakeUnstakedTokens()` when unstaked tokens (tokens that were previously staked and then unstaked) + are staked again with the node for the next epoch. +3. By `FlowIDTableStaking.NodeStaker.stakeRewardedTokens()` when reward tokens (tokens paid in return for previous staking) + are staked with the node for the next epoch. + +After this event, the FLOW tokens will be part of the node's `tokensCommitted` balance. + +### TokensStaked + +```cadence +access(all) event TokensStaked(nodeID: String, amount: UFix64) +``` + +| Field | Type | Description | +| ------ | ------ | ---------- | +| nodeID | String | The unique ID string for the node. 32 bytes. The same value emitted in the `NewNodeCreated` event for the node. | +| amount | UFix64 | The amount of FLOW tokens staked to the node. | + +Emitted by `FlowIDTableStaking.Admin.moveTokens()` at the end of an epoch if committed tokens are being added to the node's tokensStaked balance. + +After this event, the tokens will be part of the node's staked balance. + +### TokensUnstaking + +```cadence +access(all) event TokensUnstaking(nodeID: String, amount: UFix64) +``` + +| Field | Type | Description | +| ------ | ------ | --------- | +| nodeID | String | The unique ID string for the node. 32 bytes. The same value emitted in the `NewNodeCreated` event for the node. | +| amount | UFix64 | The amount of FLOW tokens unstaked from the node. | + +Emitted by `FlowIDTableStaking.Admin.moveTokens()` at the end of an epoch if +a node operator's staked tokens are being unstaked in response to a request from the node operator. +After this event, the tokens will be a part of the node operator's `tokensUnstaking` balance, where they are held for a whole epoch "unstaking period" with no rewards. + +### TokensUnstaked + +```cadence +access(all) event TokensUnstaked(nodeID: String, amount: UFix64) +``` + +| Field | Type | Description | +| ------ | ------ | ---------- | +| nodeID | String | The unique ID string for the node. 32 bytes. The same value emitted in the `NewNodeCreated` event for the node. | +| amount | UFix64 | The amount of FLOW tokens unstaked from the node. | + +Emitted by `FlowIDTableStaking.NodeStaker.requestUnstaking()` and `FlowIDTableStaking.Admin.moveTokens()` +when tokens are deposited into the `tokensUnstaked` pool: + +### RewardsPaid + +```cadence +access(all) event RewardsPaid(nodeID: String, amount: UFix64) +``` + +| Field | Type | Description | +| ------ | ------ | ---------- | +| nodeID | String | The unique ID string for the node. 32 bytes. The same value emitted in the `NewNodeCreated` event for the node. | +| amount | UFix64 | The amount of FLOW tokens paid to the node this epoch as a reward. | + +Emitted by `FlowIDTableStaking.Admin.payRewards()` at the end of the epoch to pay rewards to node operators based on the tokens that they have staked. + +After this event, the reward tokens will be part of the node's tokensRewarded balance. + +The Delegator rewards are paid at the same time, see `DelegatorRewardsPaid` below. + +### UnstakedTokensWithdrawn + +```cadence +access(all) event UnstakedTokensWithdrawn(nodeID: String, amount: UFix64) +``` + +| Field | Type | Description | +| ------ | ------ | ---------- | +| nodeID | String | The unique ID string for the node. 32 bytes. The same value emitted in the `NewNodeCreated` event for the node. | +| amount | UFix64 | The amount of unstaked FLOW tokens that the node operator is withdrawing. | + +Emitted by `FlowIDTableStaking.NodeStaker.withdrawUnstakedTokens()` when the node operator calls that function to withdraw part or all of their +unstaked tokens balance. + +After this event, the FLOW tokens will be withdrawn to a newly created `FungibleToken.Vault` which the caller can deposit to the vault of their choice. + +### RewardTokensWithdrawn + +```cadence +access(all) event RewardTokensWithdrawn(nodeID: String, amount: UFix64) +``` + +| Field | Type | Description | +| ------ | ------ | ---------- | +| nodeID | String | The unique ID string for the node. 32 bytes. The same value emitted in the `NewNodeCreated` event for the node. | +| amount | UFix64 | The amount of rewarded FLOW tokens that the node operator is withdrawing. | + +Emitted by `FlowIDTableStaking.NodeStaker.withdrawRewardedTokens()` when the node operator calls that function to withdraw part or all of their +reward tokens balance. + +After this event, the FLOW tokens will be withdrawn to a newly created `FungibleToken.Vault` which the caller can deposit to the vault of their choice. + +## Delegator Events + +These are events that concern FLOW token delegation. + +### NewDelegatorCreated + +```cadence +access(all) event NewDelegatorCreated(nodeID: String, delegatorID: UInt32) +``` + +| Field | Type | Description | +| ----------- | ------ | ---------- | +| nodeID | String | The unique ID string for the node. 32 bytes. The same value emitted in the `NewNodeCreated` event for the node. | +| delegatorID | UFix64 | The ID for the new delegator. Unique within the node but not globally. | + +Emitted by `FlowIDTableStaking.Admin.registerNewDelegator()` when the node operator registers a new delegator for the node. + +Note that the delegatorID is unique within the node but is not globally unique. + +After this event, the new delegator is registered with the node. + +### DelegatorTokensCommitted + +```cadence +access(all) event DelegatorTokensCommitted(nodeID: String, delegatorID: UInt32, amount: UFix64) +``` + +| Field | Type | Description | +| ----------- | ------ | ---------- | +| nodeID | String | The unique ID string for the node. 32 bytes. The same value emitted in the `NewNodeCreated` event for the node. | +| delegatorID | UInt32 | The ID for the delegator. | +| amount | UFix64 | The amount of additional FLOW tokens committed to the node. | + +Emitted whenever additional tokens are committed for a delegator for the following epoch. Specifically: + +1. By `FlowIDTableStaking.NodeDelegator.delegateNewTokens()` when new tokens (tokens that have not previously been staked) are added to the system + to stake with the delegator during the next epoch. +2. By `FlowIDTableStaking.NodeDelegator.delegateUnstakedTokens()` when unstaked tokens (tokens that were previously staked and then unstaked) + are staked again with the delegator for the next epoch. +3. By `FlowIDTableStaking.NodeDelegator.delegateRewardedTokens()` when reward tokens (tokens paid in return for previous staking) + are staked with the delegator for the next epoch. + +After this event, the FLOW tokens will be part of the delegator's `tokensCommitted` balance. + +### DelegatorTokensStaked + +```cadence +access(all) event DelegatorTokensStaked(nodeID: String, delegatorID: UInt32, amount: UFix64) +``` + +| Field | Type | Description | +| ----------- | ------ | --------- | +| nodeID | String | The unique ID string for the node. 32 bytes. The same value emitted in the `NewNodeCreated` event for the node. | +| delegatorID | UInt32 | The ID for the delegator. | +| amount | UFix64 | The amount of FLOW tokens staked to the node. | + +Emitted by `FlowIDTableStaking.Admin.moveTokens()` at the end of an epoch if committed tokens are being added to the delegator's tokensStaked balance. + +After this event, the tokens will be part of the delegator's staked balance. + +### DelegatorTokensUnstaking + +```cadence +access(all) event DelegatorTokensUnstaking(nodeID: String, delegatorID: UInt32, amount: UFix64) +``` + +| Field | Type | Description | +| ----------- | ------ | -----------| +| nodeID | String | The unique ID string for the node. 32 bytes. The same value emitted in the `NewNodeCreated` event for the node. | +| delegatorID | UInt32 | The ID for the delegator. | +| amount | UFix64 | The amount of FLOW tokens unstaked from the node. | + +Emitted by `FlowIDTableStaking.Admin.moveTokens()` at the end of an epoch if +a delegator's staked tokens are being unstaked in response to a request from the delegator. +After this event, the tokens will be a part of the delegator's `tokensUnstaking` balance, where they are held for a whole epoch "unstaking period" with no rewards. + +### DelegatorTokensUnstaked + +```cadence +access(all) event DelegatorTokensUnstaked(nodeID: String, delegatorID: UInt32, amount: UFix64) +``` + +| Field | Type | Description | +| ----------- | ------ | ---------- | +| nodeID | String | The unique ID string for the node. 32 bytes. The same value emitted in the `NewNodeCreated` event for the node. | +| delegatorID | UInt32 | The ID for the delegator. | +| amount | UFix64 | The amount of FLOW tokens unstaked from the node. | + +Emitted by `FlowIDTableStaking.NodeDelegator.requestUnstaking()` and `FlowIDTableStaking.Admin.moveTokens()` +when tokens are deposited into the delegator's `tokensUnstaked` pool: + +### DelegatorRewardsPaid + +```cadence +access(all) event DelegatorRewardsPaid(nodeID: String, delegatorID: UInt32, amount: UFix64) +``` + +| Field | Type | Description | +| ----------- | ------ | ---------- | +| nodeID | String | The unique ID string for the node. 32 bytes. The same value emitted in the `NewNodeCreated` event for the node. | +| delegatorID | UFix64 | The ID for the delegator. Unique within the node but not globally. | +| amount | UFix64 | The amount of rewarded FLOW tokens that the delegator is paid. | + +Emitted by `FlowIDTableStaking.Admin.payRewards()` at the end of an epoch when rewards are being paid. + +After this event is emitted, the reward tokens will be part of the delegator's tokensRewarded balance. + +The Node rewards are paid at the same time, see `RewardsPaid` above. + +### DelegatorUnstakedTokensWithdrawn + +```cadence +access(all) event DelegatorUnstakedTokensWithdrawn(nodeID: String, delegatorID: UInt32, amount: UFix64) +``` + +| Field | Type | Description | +| ----------- | ------ | ---------- | +| nodeID | String | The unique ID string for the node. 32 bytes. The same value emitted in the `NewNodeCreated` event for the node. | +| delegatorID | UFix64 | The ID for the delegator. Unique within the node but not globally. | +| amount | UFix64 | The amount of unstaked FLOW tokens that the delegator is withdrawing. | + +Emitted by `FlowIDTableStaking.NodeDelegator.withdrawUnstakedTokens()` when the delegator calls that function to withdraw part or all of their +unstaked tokens balance. + +After this event, the FLOW tokens will be withdrawn to a newly created `FungibleToken.Vault` which the caller can deposit to the vault of their choice. + +### DelegatorRewardTokensWithdrawn + +```cadence +access(all) event DelegatorRewardTokensWithdrawn(nodeID: String, delegatorID: UInt32, amount: UFix64) +``` + +| Field | Type | Description | +| ----------- | ------ | ---------- | +| nodeID | String | The unique ID string for the node. 32 bytes. The same value emitted in the `NewNodeCreated` event for the node. | +| delegatorID | UFix64 | The ID for the delegator. Unique within the node but not globally. | +| amount | UFix64 | The amount of rewarded FLOW tokens that the delegator is withdrawing. | + +Emitted by `FlowIDTableStaking.NodeDelegator.withdrawRewardedTokens()` when the delegator calls that function to withdraw part or all of their +unstaked tokens balance. + +After this event, the FLOW tokens will be withdrawn to a newly created `FungibleToken.Vault` which the caller can deposit to the vault of their choice. + + +=== networks/staking/06-technical-overview.md === +--- +title: Staking Technical Overview +sidebar_label: Staking Technical Overview +description: Technical Overview of the Flow Staking Auction Phase +--- + + + If you haven't read the Introduction, please read that first. That document + provides a non-technical overview of staking on Flow for all users and is a + necessary prerequisite to this document. + + + This document assumes you have some technical knowledge about the Flow + blockchain and programming environment. + + +# Staking + +This document describes the functionality of the +[core identity table and staking smart contract](https://github.com/onflow/flow-core-contracts/blob/master/contracts/FlowIDTableStaking.cdc). +It gives an overview of the process of epochs, staking as a node, and delegation. It is an important prerequisite +to understand before proceeding with any other technical integration or interaction with the Flow Protocol, +but does not provide step-by-step instructions for how to perform specific actions. See the +[Staking Collection Docs for instructions](./14-staking-collection.md) + +This document also describes how to read public staking data from the contract. +Anyone can read public data from the staking smart contract with these instructions. + +The transactions described in this document are contained in the +[`flow-core-contracts/transactions/idTableStaking/`](https://github.com/onflow/flow-core-contracts/tree/master/transactions/idTableStaking) +directory. You can see the text of all the transactions used to interact with the smart contract there. + +## Smart Contract Summary + +The Flow staking smart contract manages a record of stakers who have staked tokens for the network. +Users who want to stake can register with the staking contract at any time during the staking auction, +and their tokens will be locked for staking until they request to unstake them. + +You should already understand from reading the [epoch documentation](./04-epoch-preparation.md) +that an epoch lasts roughly a week. The `FlowIDTableStaking` contract focuses on the identity table +and staking part of the epoch schedule. + +Epoch Schedule from the perspective of the `FlowIDTableStaking` contract: + +1. **Start of Epoch:** Generic metadata about the current epoch is updated and shared + and the staking auction is enabled. +2. **Staking Auction:** Stakers can perform any action they want to manage their stake, like + initially registering, staking new tokens, unstaking tokens, or withdrawing rewards. + This phase takes up the vast majority of time in the epoch. +3. **End Staking Auction:** Stakers cannot perform any more staking actions + until the start of the next epoch/staking auction. +4. **Remove Insufficiently Staked Nodes:** All node operators who don't meet the minimum + or are not operating their node properly will be removed. +5. **Randomly Assign Nodes to New Slots:** Each node type has a configurable + number of nodes that can operate during any given epoch. + The contract will randomly select nodes from the list of newly staked and approved nodes + to add them to the ID table. Once all the slots have been filled, the remaining nodes are refunded + and can apply again for the next epoch if there are slots available. +6. **Rewards Calculation:** Calculate rewards for all the node operators staked in the current epoch. +7. **Move tokens between pools.** (See the token pools section for the order of movements) +8. **End Epoch:** Set the reward payout for the upcoming epoch and go to the top of this list. +9. **Rewards Payout:** Pay rewards to all the node operators staked + from the previous epoch using the calculation from earlier in the epoch. + +The `FlowIDTableStaking` contract manages the identity table, and all of these phases. +Control of these phases is controlled by the `FlowIDTableStaking.Admin` resource +object stored in the Flow Epoch account storage. +The `FlowEpoch` smart contract uses this resource to autonomously manage the functioning of the network. It is decentralized and managed by the node software, smart contracts, +and democratically by all the stakers in the network. + +## Staking as a Node Operator + +For a node to stake, node operators first need to generate their staking key, +staking key proof-of-possesion, networking address, and networking key. + +The [node operation guide](../node-ops/index.md) +describes how to run a node and generate node information. + +To generate a node ID, simply hash the staking key. + +Node operators need to determine the role of node they will be running +(Collection, Consensus, Execution, Verification, or Access). + + + NOTE: Access Nodes are eligible to stake and have a staking minimum of 100 FLOW, + but will not receive rewards for their stake. + Please register as a different node type if you would like to receive rewards. + + +Once the info has been determined: + +- Node role: `UInt8` (1 = Collection, 2 = Consensus, 3 = Execution, 4 = Verification, 5 = Access) +- Node ID: 32 byte `String` (64 hex characters) +- Networking Address: `String` (Length must be less than 510 characters and be a properly formatted IP address or hostname) +- Networking Key: 64 byte `String` (128 hex characters, must be a valid ECDSA-P256 Key) +- Staking Key: 96 byte `String` (192 hex characters, must be a valid BLS key) +- Staking Key Proof of Possesion: (48 byte (96 hex characters) string) + +The node operator is ready to register their node. + + + NOTE: The staking smart contract validates that the strings for the keys are + valid public keys. The staking admin and node software also checks the keys + and networking address to make sure they are valid and if they are not, the + registered node will not be eligible to stake. + + +To register a node, the node operator calls the +[`addNodeRecord` function](https://github.com/onflow/flow-core-contracts/blob/master/contracts/FlowIDTableStaking.cdc#L1552) +on the staking contract, providing all the node info and the tokens that they want to immediately stake, if any. + +This registers the node in the Flow node identity table +and commits the specified tokens to stake during the next epoch. +This also returns a special node operator object that is stored in the node operator's account. +This object is used for staking, unstaking, and withdrawing rewards. + +Consensus and Collection nodes also need to create a separate machine account +for use in the DKG and QC processes, respectively. This machine account creation +is handled automatically by the staking collection smart contract. +More information is in the [machine account documentation](./11-machine-account.md#creation). + + + The register node transaction only needs to be submitted once per node. A node + does not need to register every epoch. A registration cannot be used to manage + multiple nodes. Multiple nodes need to be registered separately (with the + Staking Collection). + + + + Once a node operator has registered their node and its metadata, the metadata + cannot be modified. The only exception is the networking address, which can me + modified with the Update Networking Address transaction. If a node operator + wants to update any of their other metadata such as ID, keys, or role, they + need to unstake, withdraw their tokens, and register a completely new node. + + +Once node operators have registered and have the special node object, they will be able +to perform any of the valid staking options with it, assuming that they have +the required amount of tokens to perform each operation. + +When the staking auction ends, if a node operator has committed less than the minimum stake required, +[or if their node information is invalid and they haven't been approved by the network,](https://github.com/onflow/flow-core-contracts/blob/master/contracts/FlowIDTableStaking.cdc#L788) +their committed tokens are moved to their unstaked pool, which they can withdraw from at any time. + +Nodes who did have enough tokens committed and are approved will have their +[committed tokens moved to the staked state](https://github.com/onflow/flow-core-contracts/blob/master/contracts/FlowIDTableStaking.cdc#L923-L927) +at the end of the epoch if they are selected as a node operator +by the random node slot filling algorithm. +There is a configurable cap on the number of nodes of each type, +so if the number of selected nodes equals the cap, than newly registered nodes +will not be added to the network until the cap is raised or other nodes unstake. + +If a node operator has users delegating to them, they cannot withdraw their own tokens +such that their own staked tokens would fall below the minimum requirement for that node type. +If they have delegators and try to submit [an unstaking transaction](https://github.com/onflow/flow-core-contracts/blob/master/contracts/FlowIDTableStaking.cdc#L510-L514) +that would put their stake below the minimum, it will fail. + +If they want to unstake below the minimum, they must unstake all of their tokens using the special +[`unstakeAll` method,](https://github.com/onflow/flow-core-contracts/blob/master/contracts/FlowIDTableStaking.cdc#L538) +which also unstakes all of the tokens that have been delegated to them. + +Consequently, a node operator cannot accept delegation unless [their own stake is above the minimum.](https://github.com/onflow/flow-core-contracts/blob/master/contracts/FlowIDTableStaking.cdc#L1066) + +## Staking as a Delegator + +Every staked non-access node in the Flow network is eligible for delegation by any other user. +The user only needs to know the node ID of the node they want to delegate to. + +To register as a delegator, the delegator submits a **Register Delegator** +transaction that calls the [`registerNewDelegator function`](https://github.com/onflow/flow-core-contracts/blob/master/contracts/FlowIDTableStaking.cdc#L1590), +providing the ID of the node operator they want to delegate to. +This transaction should store the `NodeDelegator` object +in the user's account, which is what they use to perform staking operations. + +Users are able to get a list of possible node IDs to delegate to via on-chain scripts. +This information will also be provided off-chain, directly from the node operators or via +third-party services. [Available node IDs are listed in a public repo.](https://github.com/onflow/flow/blob/master/nodeoperators/NodeOperatorList.md) + +The fee that node operators take from the rewards their delegators receive is 8%. +A node operator cannot be delegated to unless the total tokens they have committed to stake +are above the minimum requirement for their node types. + +The delegation logic keeps track of the amount of tokens each delegator has delegated for the node operator. +When rewards are paid, the protocol [automatically takes the 8% cut](https://github.com/onflow/flow-core-contracts/blob/master/contracts/FlowIDTableStaking.cdc#L888-L898) +of the delegator's rewards for the node operator +and the delegator's rewards are deposited in the delegator's reward pool. + +## Staking Operations Available to All Stakers + +Regardless of whether they are a node operator or delegator, a staker has access +to all the same staking operations, outlined below. +Specific implementations of these transactions are detailed in the [Staking Collection Docs](./14-staking-collection.md) + +### Stake More Tokens + +A staker can commit more tokens to stake for the next epoch at any time during the staking auction, +and there are three different ways to do it. + +1. They can commit new tokens to stake by submitting a **stake_new_tokens** transaction, + which withdraws tokens from their account's flow token vault and commits them. +2. They can commit tokens that are in their unstaked token pool, which holds the tokens + that they have unstaked. Submit a **stake_unstaked_tokens** + transaction to move the tokens from the unstaked pool to the committed pool. +3. They can commit tokens that are in their rewarded token pool, which holds the tokens + they have been awarded. They submit a **stake_rewarded_tokens** + transaction to move the tokens from the rewards pool to the committed pool. + +### Cancel Committed Stake / Unstake Tokens + +At any time during the staking auction, a staker can submit a request to unstake tokens with a **request_unstaking** transaction. +If there are tokens that have been committed but are not staked yet, +they are moved to the unstaked pool and are available to withdraw. + +If the requested tokens are in the staked pool, +it marks the specified amount of tokens to be unstaked at the end of the epoch. +At the end of the epoch, the tokens are moved to the unstaking pool. +They will sit in this pool for one (1) additional epoch, +at which point they will be moved to the unstaked tokens pool. + +### Cancel an Unstake Request + +Unstaking requests are not fulfilled until the end of the epoch where they are submitted, +so a staker can cancel the unstaking request before it is carried out. +A staker can do this by submitting a **stake_unstaked_tokens** transaction, specifying +the number of tokens of their unstake request they would like to cancel. +If the specified number of tokens have been requested to unstake, the request will be canceled. + +### Withdraw Unstaked Tokens + +At any time, stakers are able to freely withdraw from their unstaked tokens pool +with the **withdraw_unstaked** transaction. + +### Withdraw Rewarded Tokens + +Staking rewards are paid out at the end of every epoch based on how many tokens +are in a users `tokensStaked` pool. Every staker's rewards +are deposited into their rewarded tokens pool. Rewards can be withdrawn +at any time by submitting a **withdraw_reward_tokens** transaction. + +These tokens are unlocked and can be transferred on-chain if desired, or re-staked. + +The source code for the staking contract and more transactions +can be found in the [Flow Core Contracts GitHub Repository](https://github.com/onflow/flow-core-contracts). + +# Monitor Events from the Identity Table and Staking Contract + +See the [staking events document](./07-staking-scripts-events.md) +for information about the events that can be emitted by the staking contract. + +# Appendix + +## Token Pools + +Each node operator has five token pools allocated to them: + +- **Committed Tokens:** Tokens that are committed for the next epoch. + They are automatically moved to the staked pool when the next epoch starts. +- **Staked Tokens:** Tokens that are staked by the node operator for the current epoch. + They are only moved at the end of an epoch and if the staker + has submitted an unstaking request. +- **Unstaking Tokens:** Tokens that have been unstaked, + but are not free to withdraw until the following epoch. +- **Unstaked Tokens:** Tokens that are freely available to withdraw or re-stake. + Unstaked tokens go to this pool. +- **Rewarded Tokens:** Tokens that are freely available to withdraw or re-stake. + Rewards are paid and deposited to the rewarded Pool after each epoch. + +At the end of every epoch, tokens are moved between pools in this order: + +1. All committed tokens will get moved either to the staked tokens pool, + or to the unstaked tokens pool (depending on if the registered node has met the minimum stake requirements). +2. All committed tokens get moved to staked tokens pool. +3. All unstaking tokens get moved to the unstaked tokens pool. +4. All requested unstaking tokens get moved from the staked pool to the unstaking pool. + + +=== networks/staking/05-epoch-scripts-events.md === +--- +title: Query Epoch Info with Scripts or Events +sidebar_label: Epoch Scripts and Events +toc_max_heading_level: 4 +--- + +## Introduction + +The epoch contract stores a lot of different state, and the state is constantly changing. +As an external party, there are two ways to keep track of these state changes. +You can either use Cadence scripts to query the state of the contract at any given time, +or you can monitor events that are emitted by the epoch contract to be notified of any important occurrences. + +## Monitor Epoch Service Events + +These events can be queried using the Go or JavaScript SDKs to extract useful notifications and information about the +state of the epoch preparation protocol. + +### What is a Service Event? + +Service events are special messages that are generated by smart contracts and included in execution results. +They enable communication between system smart contracts and the Flow protocol. +In other words, they serve as a communication mechanism between the execution state and the protocol state. + +Concretely, service events are defined and emitted as events like any other in Cadence. An event is considered a service event when it is: + +- emitted within the service chunk +- emitted from a smart contract deployed to the service account +- conformant to an event allowlist + +Each block contains a system chunk. For each system chunk, +all service events emitted are included in the corresponding execution result. + +When verifying the system chunk, verifier nodes will only produce result approvals +when the system chunks included in the execution result are correct. +Thus, the security of this communication mechanism is enforced by the verification system. + +When sealing a block containing a service event, the consensus committee will update the protocol state accordingly, +depending on the semantics of the event. + +For example, a service event may indicate that a node's stake has diminished to the point where they should be ejected, +in which case the consensus committee would mark that node as ejected in the protocol state. + +Service events are fundamentally asynchronous, due the lag between block execution and sealing. +Consequently they are handled slightly differently than other protocol state updates. + +The diagram below illustrates the steps each service event goes through to be included in the protocol state. + +![Flow Service Event Diagram](./epoch-service-event-diagram.png) + +For conciseness, we say a service event is `sealed` when the block in which it was emitted is sealed, +and we say a service event is `finalized` when the block containing the seal is finalized. + +### Event Descriptions + +#### `FlowEpoch.EpochStart` + +The Epoch Start service event is emitted by `FlowEpoch.startNewEpoch()` +when the epoch commit phase ends and the Epoch Smart Contracts transition +to the staking auction phase. +It contains the relevant metadata for the new epoch that was generated during the last epoch: + +```cadence + access(all) event EpochStart ( + + /// The counter for the current epoch that is beginning + counter: UInt64, + + /// The first view (inclusive) of the current epoch. + firstView: UInt64, + + /// The last view (inclusive) of the current epoch's staking auction. + stakingAuctionEndView: UInt64, + + /// The last view (inclusive) of the current epoch. + finalView: UInt64, + + /// Total FLOW staked by all nodes and delegators for the current epoch. + totalStaked: UFix64, + + /// Total supply of all FLOW for the current epoch + /// Includes the rewards that will be paid for the previous epoch + totalFlowSupply: UFix64, + + /// The total rewards that will be paid out at the end of the current epoch. + totalRewards: UFix64, + ) +``` + +#### `FlowEpoch.EpochSetup` + +The Epoch Setup service event is emitted by `FlowEpoch.startEpochSetup()` +when the staking auction phase ends and the Epoch Smart Contracts transition to the Epoch Setup phase. +It contains the finalized identity table for the upcoming epoch, +as well as timing information for phase changes. + +```cadence +access(all) event EpochSetup ( + + /// The counter for the upcoming epoch. Must be one greater than the + /// counter for the current epoch. + counter: UInt64, + + /// Identity table for the upcoming epoch with all node information. + /// Includes: + /// nodeID, staking key, networking key, networking address, role, + /// staking information, weight, and more. + nodeInfo: [FlowIDTableStaking.NodeInfo], + + /// The first view (inclusive) of the upcoming epoch. + firstView: UInt64, + + /// The last view (inclusive) of the upcoming epoch. + finalView: UInt64, + + /// The cluster assignment for the upcoming epoch. Each element in the list + /// represents one cluster and contains all the node IDs assigned to that + /// cluster, with their weights and votes + collectorClusters: [FlowClusterQC.Cluster], + + /// The source of randomness to seed the leader selection algorithm with + /// for the upcoming epoch. + randomSource: String, + + /// The deadlines of each phase in the DKG protocol to be completed in the upcoming + /// EpochSetup phase. Deadlines are specified in terms of a consensus view number. + /// When a DKG participant observes a finalized and sealed block with view greater + /// than the given deadline, it can safely transition to the next phase. + DKGPhase1FinalView: UInt64, + DKGPhase2FinalView: UInt64, + DKGPhase3FinalView: UInt64 +) +``` + +#### `FlowEpoch.EpochCommit` + +The `EpochCommit` service event is emitted when the Epoch Smart Contracts transition +from the Epoch Setup phase to the Epoch Commit phase. +It is emitted only when all preparation for the upcoming epoch (QC and DKG) has been completed. + +```cadence +access(all) event EpochCommit ( + + /// The counter for the upcoming epoch. Must be equal to the counter in the + /// previous EpochSetup event. + counter: UInt64, + + /// The result of the QC aggregation process. Each element contains + /// all the nodes and votes received for a particular cluster + /// QC stands for quorum certificate that each cluster generates. + clusterQCs: [FlowClusterQC.ClusterQC], + + /// The resulting public keys from the DKG process, encoded as by the flow-go + /// crypto library, then hex-encoded. + /// Group public key is the first element, followed by the individual keys + dkgPubKeys: [String], +) +``` + + +## Query Information with Scripts + +The `FlowEpoch` smart contract stores important metadata about the current, proposed, +and previous epochs. Metadata for all historical epochs is stored permanently +in the Epoch Smart Contract's storage. + +```cadence +access(all) struct EpochMetadata { + + /// The identifier for the epoch + access(all) let counter: UInt64 + + /// The seed used for generating the epoch setup + access(all) let seed: String + + /// The first view of this epoch + access(all) let startView: UInt64 + + /// The last view of this epoch + access(all) let endView: UInt64 + + /// The last view of the staking auction + access(all) let stakingEndView: UInt64 + + /// The total rewards that are paid out for the epoch + access(all) var totalRewards: UFix64 + + /// The reward amounts that are paid to each individual node and its delegators + access(all) var rewardAmounts: [FlowIDTableStaking.RewardsBreakdown] + + /// Tracks if rewards have been paid for this epoch + access(all) var rewardsPaid: Bool + + /// The organization of collector node IDs into clusters + /// determined by a round robin sorting algorithm + access(all) let collectorClusters: [FlowClusterQC.Cluster] + + /// The Quorum Certificates from the ClusterQC contract + access(all) var clusterQCs: [FlowClusterQC.ClusterQC] + + /// The public keys associated with the Distributed Key Generation + /// process that consensus nodes participate in + /// Group key is the last element at index: length - 1 + access(all) var dkgKeys: [String] +} +``` + +#### Get Epoch Metadata + +The `FlowEpoch` smart contract provides a public function, `FlowEpoch.getEpochMetadata()` +to query the metadata for a particular epoch. + +You can use the **Get Epoch Metadata**([EP.01](../../build/core-contracts/07-epoch-contract-reference.md#getting-epoch-info)) script +with the following arguments: + +| Argument | Type | Description | +| ---------------- | ---------| --------------------------------------------- | +| **epochCounter** | `UInt64` | The counter of the epoch to get metadata for. | + +#### Get Configurable Metadata + +The `FlowEpoch` smart contract also has a set of metadata that is configurable by the admin +for phase lengths, number of collector clusters, and inflation percentage. + +```cadence +access(all) struct Config { + /// The number of views in an entire epoch + access(all) var numViewsInEpoch: UInt64 + + /// The number of views in the staking auction + access(all) var numViewsInStakingAuction: UInt64 + + /// The number of views in each dkg phase + access(all) var numViewsInDKGPhase: UInt64 + + /// The number of collector clusters in each epoch + access(all) var numCollectorClusters: UInt16 + + /// Tracks the annualized percentage of FLOW total supply that is minted as rewards at the end of an epoch + /// Calculation for a single epoch would be (totalSupply * FLOWsupplyIncreasePercentage) / 52 + access(all) var FLOWsupplyIncreasePercentage: UFix64 +} +``` + +You can use the **Get Configurable Metadata**([EP.02](../../build/core-contracts/07-epoch-contract-reference.md#getting-epoch-info)) script +to get the list of configurable metadata: + +This script does not require any arguments. + +#### Get Epoch Counter + +The `FlowEpoch` smart contract always tracks the counter of the current epoch. + +You can use the **Get Epoch Counter**([EP.03](../../build/core-contracts/07-epoch-contract-reference.md#getting-epoch-info)) script +to get the current epoch counter. + +This script does not require any arguments. + +#### Get Epoch Phase + +The `FlowEpoch` smart contract always tracks the active phase of the current epoch. + +```cadence +access(all) enum EpochPhase: UInt8 { + access(all) case STAKINGAUCTION + access(all) case EPOCHSETUP + access(all) case EPOCHCOMMIT +} +``` + +You can use the **Get Epoch Phase**([EP.04](../../build/core-contracts/07-epoch-contract-reference.md#getting-epoch-info)) script +to get the current epoch phase. + +This script does not require any arguments. + +=== networks/staking/04-stake-slashing.md === +--- +title: Stake Slashing +sidebar_position: 4 +description: How Flow enforces honest node behaviour +--- + +Flow slashes nodes only for acts that directly impact +the security and integrity of the network and its shared execution state. +Nodes are not slashed for liveness infractions. +The protocol reserves slashing for maintaining the security of the protocol rather than its liveness. + +You can find more details on the conditions under which a node is slashed +in the [Flow whitepapers](https://www.onflow.org/technical-paper). + +Direct stake slashing is not currently enforced by the protocol and staking contract. +It will be handled on a case-by-case basis for the foreseeable future +to ensure network participants have time to participate in the testing and rollout of slashing. + +There is a very basic form of slashing that is currently used, where +nodes who have liveness issues during an epoch may have their rewards +and their delegators' rewards reduced by a pre-determinded amount based on +the severity of the liveness infractions. This amount is often 50% +and is only taken from the stakers' rewards for a given epoch. +Their staked FLOW is not touched at all. + +When slashing is enforced, slashable protocol violations must be adjudicated by a supermajority +of more than 2/3 of the staked consensus nodes in order to take effect. +If a node is found guilty of committing a slashable protocol violation, +the consensus nodes directly deduct a fine from the node's stake. + +It is still TBD where the slashed tokens will be deposited. + +The remaining un-slashed stake is deposited back into node's unstaked pool +at the end of the unstaking period. + + +=== networks/staking/04-epoch-preparation.md === +--- +title: Epoch Preparation Protocol +sidebar_label: Epoch Preparation Protocol +description: Technical Overview of the Flow Epoch Protocol +--- + + + If you haven't read the staking introduction, please read that + first. That document provides a non-technical overview of staking on Flow for + all users and is a necessary prerequisite to this document. + + + This document assumes you have some technical knowledge about the Flow + blockchain and programming environment. + + +# Epochs + +The epoch preparation protocol defines how information about the next epoch +is determined and propagated to the protocol state. + +There are two primary actors in this protocol, the Epoch Smart Contracts, and the Consensus Committee: + +- [`Epoch Smart Contracts`](https://github.com/onflow/flow-core-contracts/blob/master/contracts/epochs) - the smart contracts that manage epochs: + - `FlowClusterQC` : Manages the quorum certificate generation for bootstrapping + the hotstuff consensus algorithm for each collector cluster. + - `FlowDKG` : Manages the Distributed Key Generation that consensus nodes participate + in to initialize the random beacon for each epoch. + - `FlowIDTableStaking` : Manages the source of truth for the identity table, + and enforces rules related to staking FLOW, delegating, paying rewards, and allocating token movements between epochs. + - `FlowEpoch` : Ties all of the previously mentioned contracts together to manage + the high level epoch lifecycle. `FlowEpoch` acts as a state machine that transitions + between different epoch phases when specific conditions from the other contracts are met and triggers important operations in the other smart contracts when phase changes happen. +- `Consensus Committee` - the committee of consensus nodes for the current epoch + +This document describes the communication protocol between these two actors and the impact on the protocol state. + +It gives an overview of the process of epochs, the staking auction, and the epoch setup and commit phases. +It is an important prerequisite to understand before proceeding with any other technical integration or interaction with the Flow Protocol, +but does not provide step-by-step instructions for how to perform specific actions. + +The transactions described in this document are contained in the [`flow-core-contracts/transactions/epoch/`](https://github.com/onflow/flow-core-contracts/tree/master/transactions/epoch) +directory. You can see the text of all the transactions used to interact with the smart contracts there. + +## Epochs Overview + +Only a pre-determined set of nodes is authorized to participate in the protocol at any given time. +The set of authorized nodes is a-priori known to all network participants. +This set is referred to as the **Identity Table**. An **Epoch** is defined as a period of time +where the set of authorized nodes is constant (or can only shrink due to ejection of malicious nodes). + +At an Epoch switchover, which is the time when the network transitions from one epoch to the next, +the set of authorized nodes can change. For each of Flow's node roles, the Flow protocol admits a protocol-determined number of nodes. + +For each Epoch, there is a [Staking Auction](./06-technical-overview.md) in which new potential node operators may submit Staking Commitments. +All this is completely smart-contract based and handled through conventional transactions. + +After the Staking Auction is over, the protocol determines which commitments to accept and which to reject. +The node operators whose staking commitments were accepted are added to the Identity Table for the next epoch, +and become authorized participants at the next epoch switchover. +Staked Nodes also can submit other operations to modify their existing stake, which are all carried out at the end of the current epoch. + +The smart contract that determines the nodes for the next Epoch has special privileges. +Specifically, it is allowed to emit [Service Events](./05-epoch-scripts-events.md#monitor-epoch-service-events), +which are how the execution state updates the consensus node-based protocol state. + +At the end of the staking auction, the epoch smart contracts conclude that they have now determined +the set of nodes which will be running the network for the next Epoch, and the amount of FLOW that all the nodes have staked. +The smart contract then emits a service event with this information. + +When processing the block with seat assignment, all network nodes (including future ones which are supposed to monitor the chain in anticipation) +are thereby informed about the upcoming change. + + +Note: At this point in the epoch (end of the staking auction), +there is no change in participating nodes. +The change in participating nodes happens at the end of the epoch. + + +After the staking auction, there is an interim period of time until the new Epoch starts for the following tasks to be completed: +- The epoch smart contract runs the cluster assignment algorithm for all the collector nodes +and each collector node will vote for the root block of their respective clusters +- The Random Beacon Committee for the next Epoch (currently all consensus nodes) +will run the Distributed Key Generation (DKG), +- When completing the QC generation and DKG, the smart contracts will emit a service event. +After consensus nodes have collected all relevant information (public keys for the random beacon and cluster quorum certificates), +they can update the identity table to include the information for the next Epoch. + +If preparation for the next Epoch is not completed before the current Epoch ends, +the network goes into epoch fallback mode (EFM) and a special transaction, sometimes including +a spork, is required to transition to the next Epoch. + +## Epoch Length + +The length of an Epoch is measured in terms of consensus views. +The number of views in an epoch and in the various epoch phases are determined before +the Epoch begins and stored as a field in the main epoch smart contract (`FlowEpoch`). + +Generally, there is not a block for every view, so the view number will not change at the same rate as the block height. + +Because the length of a consensus view can vary depending on many different factors, +the wall-clock time of an epoch is expected to vary from week to week. +Under typical network conditions we expect the variance in epoch length to be less than 2 hours for a 1-week epoch (~1%). +Under adverse network conditions the variance in epoch length will increase (typically this will result in longer epochs). + +As the average view rate changes over time, the Service Account can change the epoch length to +target a 1 week wall-clock epoch length. + +# Phases + +The preparation for the next epoch is separated into distinct phases. +Each phase occurs completely within the current epoch. + +![Flow Epoch Schedule](https://storage.googleapis.com/flow-resources/documentation-assets/epoch-phase-diagram.png) + +The Epoch Smart Contract acts as a state machine. The smart contract keeps a record of the current phase, +the number of views in the current phase, and the conditions that need to be met in order to advance to the next phase, or next epoch. +A special `Heartbeat` resource is used to call the `advanceBlock()` method during every single new block in Flow. +During these regular method calls, if all of the conditions are met to advance to the next phase, +the smart contract performs any relevant retrieval and storage of information, emits a Service Event, +and transitions to the next phase, which often involves setting certain metadata +or enabling one of the connected smart contracts to begin its work. + +From the perspective of the consensus committee, the phase transitions within epochs +occur as a result of including a service event in a block, +thus the phase transition only applies to the fork containing the block with the service event. + +At the end of Phase 0 and beginning of Phase 1, the `EpochSetup` service event is emitted +that contains the identity table and other initial metadata for the upcoming epoch. + +At the end of Phase 1 and beginning of Phase 2, the `EpochCommit` service event +is emitted that contains the results of the Epoch Setup phase. + +The start of a new epoch is the first block with its view > the last view of the previous epoch, +and its parent view ≤ the last view of the last epoch. + +## Phase Transitions + +The **Consensus Committee** triggers the **phase transition coinciding with the Epoch switchover** +by publishing the block of the next Epoch. +This block's execution state will also detect the the end view of an epoch has arrived +and trigger the start of the new epoch. +The transition to a new epoch is also marked by the emission of [an event](https://github.com/onflow/flow-core-contracts/blob/master/contracts/epochs/FlowEpoch.cdc#L62) (`EpochStart`) +from the epoch smart contract. + +- +The state of the smart contracts reflect the latest epoch's new identity table and metadata. + +For the **Epoch-*internal* Phase transitions**, meaning the phase transitions within an epoch, +the **Epoch Smart Contract** provides the trigger by emitting a respective service event: + +- The `EpochSetup` service event triggers the phase transition +`Staking Auction Phase` → `Epoch Setup Phase` +- The `EpochCommit` service event triggers the phase transition +`Epoch Setup Phase` → `Epoch Committed Phase` + +Only one of each service event may be emitted each epoch, for a given fork. +`EpochCommit` may only be emitted after `EpochSetup` has been generated in the respective given fork. + +The `FlowEpoch` contract manages all of these phases, the `FlowIDTableStaking` contract +manages the identity table and staking auction, the `FlowClusterQC` contract manages +the Quorum Certificate generation for collector clusters, and the `FlowDKG` contract manages +the Distributed Key Generation protocol for the consensus nodes. + +Initially, control of these phases and contracts will be managed manually by the Flow Token Admin, +but control will eventually be completely decentralized and managed by the node software, smart contracts, +and democratically by all the stakers in the network. + +## Phase 0: Staking Auction + +**Purpose:** During the staking auction phase, operators can put up stake +in exchange for being a part of the upcoming epoch. +All voluntary commitments to register a new node, increase, or decrease stake for the next epoch +must occur before the end of this phase. + +**Duration:** The staking auction phase begins with the first block of the current Epoch +Its last block is the block in which the `EpochSetup` service event is emitted. + +### **Protocol Directives:** + +Epoch Smart Contract + +- The `FlowEpoch` Smart Contract is responsible for ensuring that staking, un-staking, +and stake-modification transactions for the next epoch are +are only executed during the staking auction and fail otherwise. +The contract enforces this by setting a `stakingEnabled` field in the staking contract. +Every staking method checks to see if this is set before executing. + +- The `FlowEpoch` Smart Contract must ensure that the subsequent phases +are sufficiently long to perform all required tasks before the epoch ends. +- As part of the execution result for the last block of the staking auction, +the `Epoch Smart Contract` computes the seat assignment information for the next epoch, +and emits a specialized service event, the `EpochSetup` event, +with the timing and identity table information about the next epoch. +See the [Epoch Setup Event Documentation](./05-epoch-scripts-events.md#flowepochepochsetup) +for a detailed breakdown of the epoch setup event. + +## Phase 1: Epoch Setup + +**Purpose:** During the epoch setup phase, all nodes participating in the upcoming epoch +must perform setup tasks in preparation for the upcoming epoch. + +**Duration:** The epoch setup phase begins right after the `EpochSetup` service event is emitted. +It ends with the block where `EpochCommit` service event is emitted. + +### **Protocol Directives:** + +Consensus: + +- When a primary constructs a block that seals the `EpochSetup` service event, +the primary includes an update to the protocol state in the block. +Specifically, it adds the nodes for the `PendingEpoch` to the list of authorized nodes. +When this block is propagated, all staked nodes will know about the participants +in the next epoch and can communicate with them. + +- Based on the `RandSeed` field in the `EpochSetup` event, all nodes compute: + - The seed to initialize the consensus node's primary selection algorithm for the next epoch + - The seeds to initialize the collector clusters' primary selection algorithm for the next epoch + +- The collector nodes generate the root block for their respective clusters +in the next Epoch and submit a vote for the root block to a specialized smart contract, `FlowClusterQC`. +- The Random Beacon Committee for the next Epoch (currently all consensus nodes) +will run the DKG through a specialized smart contract, `FlowDKG`. + +Epoch Smart Contract: + +- The `FlowEpoch` Smart Contract is responsible for ensuring that Epoch Setup transactions +are only executed during the Epoch Setup phase and fail otherwise. +The contract enforces this by setting an `enabled` field in the `FlowClusterQC` and `FlowDKG` contracts. +Every state-changing method from these contracts checks to see if this is set before executing. + +- The `FlowEpoch` Smart Contract must ensure that the subsequent phase +is sufficiently long to perform all required tasks before the epoch ends. + +- As part of the execution of the last block of the Epoch Setup phase, +the `FlowEpoch` Smart Contract computes the public key shares generated by the DKG +and the `QC`s for the collector clusters and publishes these as `EpochCommit` service event. +The `FlowEpoch` Smart Contract should emit this event as soon as the artifacts are determined. + +See the [Epoch Commit Event Documentation](./05-epoch-scripts-events.md#flowepochepochcommit) +for a detailed breakdown of the epoch commit event. + +## Phase 2: Epoch Committed + +**Purpose:** When the epoch committed phase starts, the precise role of each node is fully specified. +From a protocol-perspective, all information is available for each node +to start its operation for the next Epoch. +This phase provides some time for nodes to establish the communication channels +and synchronize with the network to seamlessly switch over to the next epoch. + +**Duration:** The epoch committed phase begins right *after* the `EpochCommit` service event +has been emitted. It ends when the epoch ends. + +### **Protocol Directives:** + +Consensus + +- When a primary constructs a block that seals the `EpochCommit` service event, +the primary includes an update to the protocol state in the block. Specifically, it: + - adds the information generated in the setup phase to the Protocol State and + - marks the updated Protocol State as `committed` in this respective fork. + +# Query Information from the Epoch Contract + +See the [epoch scripts and events document](./05-epoch-scripts-events.md#introduction) for detailed documentation about +you can use scripts events to learn information about the state of the epoch contracts. + + +=== networks/staking/03-schedule.md === +--- +title: Epoch and Reward Schedule +sidebar_label: Epoch and Reward Schedule +description: How the Flow protocol manages the schedule of an epoch and rewards payments +--- + + + +This information covers the current state of how epoch phases are ran and how +rewards are calculated and distributed to node operators and delegators. +All of the information in the document is still being designed and is subject to change +based on research and discussion by the Flow core team and community. +If any changes are proposed, the Flow community will be notified in advance. + + +# Schedule + +![Flow Epoch Schedule](./epoch-phase-diagram.png) + +An Epoch is a period of time when the node operators in the network are constant. At epoch +boundaries, newly staked node operators are able to join the network and existing node operators +which have unstaked may exit the network. + +Each epoch lasts approximately a week, and the **Epoch Switchover** is defined as the point in time +when one epoch ends and the next epoch begins, marking a possible change in the list of valid nodes. + + + +The exact timing of each epoch end is influenced by the number of blocks proposed during the epoch. +Therefore, epoch phase timing can very and will likely drift over time. + +**All quoted epoch end times are estimates and subject to some variance (up to several hours)**. +See [Epoch Preparation Protocol](./04-epoch-preparation.md#epoch-length) for details. + + + +**Staking Operations are disabled for approximately the last 6-12 hours of an epoch**, +typically around 00:00 US Pacific Daylight Time (07:00 UTC) on Wednesday every week until around 12:00 US Pacific Daylight Time (19:00 UTC). +See [Epoch Setup](./04-epoch-preparation.md#phase-1-epoch-setup) for more information on this phase. + +**Epoch Switchovers will happen around 12:00 pm PT on Wednesday (7:00 pm UTC)** every week. +Please note exact epoch ending time vary based on the performance of the network +& all staking operations that interact with staked tokens will be processed +by the protocol at the start of each epoch. + +## Rewards + +**Rewards are usually paid around 12 pm PT on Wednesday (7:00 pm UTC)**, every week, +to all users that have tokens staked. +This is close to the same time as the Epoch Switchover. See the Rewards Distribution section below +for more information about rewards calculation and schedule. + +## Staking Auction + +The first, and longest phase of an epoch is the [staking auction](./04-epoch-preparation.md#phase-0-staking-auction). +This phase is when nodes and delegators can register to stake and perform other staking operations +such as staking more tokens or unstaking their existing tokens. +None of these operations are fully executed until the **Epoch Switchover** though. + +**The Staking Auction lasts for at least the first 90% of the length of an Epoch** + +## Epoch Setup and Epoch Commit + +The [Epoch Setup](./04-epoch-preparation.md#phase-1-epoch-setup) +and [Epoch Commit](./04-epoch-preparation.md#phase-2-epoch-committed) +phases are the final phases of the epoch, when node operators who have been included +in the next epoch perform important setup functionality to prepare for the next epoch. + +**The Epoch Setup and Epoch Committed phases usually last less than 10% of the time of an epoch.** + +**Staking Operations will be rejected during the Epoch Setup and Epoch Commit phases.** +This is because the staking information has been finalized in preparation for the next epoch +and cannot be changed because these final phases rely on the staking information being constant. + +**The Staking Auction Ends every Wednesday near 00:00 PDT (07:00 UTC).** +**This means that staking operations will be disabled for ALL users** +**in the period between the end of the staking auction and the beginning of the next epoch, currently 6-12hrs.** + +## Rewards Distribution + +The rewards distribution schedule has been designed to ensure +there is enough liquid supply of FLOW available in the ecosystem +to empower a wide variety of use cases and promote fair and diverse participation in the Flow ecosystem. + +The numbers in this table represent the total amount of tokens that are paid +as staking rewards at each epoch to the entire pool of participants in the Flow network. +While the total staking reward amount is known and fixed per epoch, +rewards that individual stakers receive are variable depending on many factors. + +The total rewards for each epoch are fixed for that epoch, but where those rewards come from can change. +When the protocol pays rewards, it first pulls from the central pool of all the transaction fees +that have been paid by every user in the network since the last rewards payment. +Once that pool has been depleted, the protocol mints new tokens that are used as rewards. + +Please see the next section on how to calculate an individual staking reward. + +| | Dec 22, 2020 | Dec 29, Jan 5, 12, 19, 26 (2021) | Feb 2, 2021 weekly on Wednesdays indefinitely | +| ----------------------------- | ------------------- | -------------------------------- | --------------------------------------------- | +| Total Rewards % (Annual) | 5% | 20% | 5% | +| Total Rewards Amount Per Week | ~1.2M FLOW | ~4.4M FLOW | ~1.3M FLOW | + +## Individual Calculation + +Each user gets a percentage of the total rewards during each epoch +that is proportional to their percentage of all the tokens that are staked by all participants. + +The full reward calculation on a per-user basis is equal to: + +``` +New Reward(user) = Tr * (Sn / St) +``` + +where: +- `Tr` = Total staking rewards to be paid out during the current epoch. (See table above) +- `Sn` = Amount of FLOW Staked by the target user for the current Epoch. (Different for each staker) +- `St` = Sum of all the FLOW staked by all the participants in the network. (Changes every epoch) + +Rewards for delegators are also calculated in the exact same way that rewards for node operators are calculated, +with one difference in that 8% of the calculated reward amount is given to the node operator being delegated to +(effected as a protocol layer fee, which is the same for all node operators). +The remaining 92% is awarded to the delegator. +Note: the 8% fee is only applied to the staking reward, not to the tokens delegated. + +With this calculation, the node you choose to run or delegate to +DOES NOT affect the amount of rewards you receive every week. +The only variable that you can control is the number of tokens you have staked. +The more tokens you stake, the more rewards you will receive. + +Because of the variable nature of the rewards calculation, we cannot provide an expected weekly/yearly return +for a single staker. You can plug your own numbers into the formula to see some sample calculations, +but you won't be able to know exactly what you will earn until the beginning +of the epoch in which you are participating in staking or delegation. + +## Rewards History + +For the first two years of its existence, the staking rewards payments +were handled with manual transactions. You can find the history of those transactions +including their arguments and IDs in the +[Pay Rewards Section](https://github.com/onflow/service-account/tree/main/transactions/pay-rewards) +of the Flow Service Account Repo. The dates correspond to the date when the +rewards were paid at the end of an epoch and the network transitioned to a new epoch. + +Future rewards payments and epoch switchovers happen automatically via a system chunk transaction, +which does not create regular transaction IDs. + +=== networks/staking/02-epoch-terminology.md === +--- +title: Epoch and Staking Terminology +sidebar_label: Epoch and Staking Terminology +description: Important Definitions for Epochs +--- + + + If you haven't read the staking introduction, please read that + first. That document provides a non-technical overview of staking on Flow for + all users and is a necessary prerequisite to this document. + + + This document assumes you have some technical knowledge about the Flow + blockchain and programming environment. + + +## Terminology + +If any of the definitions are confusing, you can find more detail in the other sections of the technical docs. + +**Staker:** Any user who has staked tokens for the Flow network. +A node operator is a staker, and a delegator is a staker as well. + +**Node Operator:** A user who operates a node on the Flow network. Each node operator has a unique node resource +object they store in their account to perform staking operations. + +**Node Operator Metadata:** This information is tracked for each node operator in the Flow network. + - **Node ID:** 32 byte identifier for the node. Usually a hash of the node public key. + - **Role:** Indicates what role the node operator is. (Collection, Consensus, Execution, Verification, Access) + - **Networking Address:** The address that the node operator uses for networking. Using a hostname is highly encouraged. + - **Networking Key:** The 64 byte ECDSA-P256 node operator public key for networking. + - **Staking Key:** The 96 byte BLS12-381 public key for the node. + Used to sign node messages and votes for Quorum Certificate generation. + - **Proof of Possession:** A 48 byte (96 hex characters) string that acts as cryptographic + proof of ownership of the node's staking key. + +**Delegator:** A user who delegates tokens to a node operator and receives rewards for their staked tokens, minus a fee +taken by the node operator. Each delegator stores a unique delegator resource object in their account +that allows them to perform staking operations. + +- **Delegator Metadata:** This information is tracked for all delegators in the network. + - **id:** The ID associated with a delegator. These IDs are assigned to delegators automatically + by the staking contract and are only unique within an individual node operators' record. + - **nodeID:** The ID of the node operator a user delegates to. + +**Node Identity Table:** The record of all the nodes in the network, and their delegators. +The identity table keeps separate lists for the info about node operators and delegators. + + + NOTE: The staking smart contract does not associate a node or delegator with + an account address. It associates it with the assigned resource object that + corresponds to that entry in the contract. There can be any number of these + objects stored in the same account, and they can be moved to different + accounts if the owner chooses. + + +**Epoch:** The period of time between changes in the identity table and reward payments. +(Initially a week, measured in consensus views) +At the end of every epoch, insufficiently staked node operators are refunded their stake, +rewards are paid to those who are currently staked, committed tokens are marked as staked, +unstaking tokens are marked as unstaked, and unstaking requests are changed from staked to unstaking. + +**Consensus View:** A internal detail that the Flow consensus algorithm, HotStuff, uses to measure time. +Views count the number of rounds in the consensus algorithm. +Each round/view the counter is incremented and a new block may be proposed. + +**Seat/Slot:** The right to participate in the network as a node of a certain type +for a specific Epoch. There are a limited number of seats/slots for each node type per epoch. +Current Slot Limits (may be slightly different than what is shown here): +- Access Nodes: 167 +- Collection Nodes: 156 +- Consensus Nodes: 149 +- Execution Nodes: 10 +- Verification Nodes: 105 + +**Candidate:** A node that has committed tokens for the next epoch but has not been accepted yet. +There is a limited number of node slots per epoch and candidate nodes are selected randomly, +so there is a chance that a candidate node will not be chosen to participate in the next epoch +because there aren't enough slots even if they meet all the other regular requirements + +**Staking Auction Phase:** The period of time when nodes and delegators are able to submit staking operations +in preparation for the upcoming epoch. This phase is expected to take over 90% of the time of an epoch. + +**Epoch Setup Phase:** The period of time after the staking auction, where nodes have to perform certain processes +to initialize the state and communication with other nodes for the next epoch. +These processes are called **Cluster Quorum Certificate Generation (QC)**, and **Distributed Key Generation (DKG)**. +If any node does not perform this initialization properly, it is not included in the next epoch's Identity Table. +This phase is expected to take less than 10% of the time of an epoch, near the end. + +**Cluster Quorum Certificate Generation (QC):** A process by which nodes using the HotStuff consensus algorithm +submit signed messages in order to generate a certificate for bootstrapping HotStuff. Each collector cluster runs +a mini-version of HotStuff, and since clusters are randomized each epoch, a new quorum certificate is required +for each cluster each epoch. + +**Distributed Key Generation (DKG):** Process for generating a shared public key to initialize the random beacon. +Consensus nodes use a shared whiteboard to communicate and submit final key vectors to generate a shared key. + +**Epoch Commit Phase:** The final phase of an epoch, after the Epoch Setup Phase. In this phase, the identity table +has been finalized for the next epoch, all setup has been completed, and the network +is simply waiting for the next epoch to start. + +**Service Event:** Special messages that are generated by the epoch smart contracts and included in execution results. +They enable communication between system smart contracts and the Flow protocol. +In other words, they serve as a communication mechanism between the execution state and the protocol state. +Service events are not any different that other Cadence events, except in the fact that +Flow nodes treat them differently because they are being emitted by the service account. + +**Node and Delegator Staked Token Tracking Terms:** + - **Tokens Committed:** The tokens that a user has committed to stake in the next epoch, but that aren't currently staked. + - **Tokens Staked:** The tokens that a user has staked in the current epoch. + - **Tokens Requested to Unstake:** The amount of tokens that a user has requested to be unstaked + at the end of the current epoch (to be removed from the **tokens staked** pool). + - **Tokens Unstaking:** The tokens that were unstaked at the beginning of the current epoch and + are being held for an additional epoch holding period before being released. + - **Tokens Unstaked:** Tokens that used to be committed or staked and have been unstaked. + - **Tokens Rewarded:** Tokens that the user has received via staking rewards. + +**Delegation Rewards Cut:** The percentage of a delegator's rewards that the node operators take. Initially set to 8%. + +**Epoch Payout:** The total amount of tokens paid in rewards at the end of an epoch. +This value will change as the supply of FLOW changes. See the [rewards page](./03-schedule.md) for more details. + +**Minimum Stake Requirement:** Each node type AND delegator has a requirement for the minimum number of FLOW +they have to commit to stake to be considered a valid staker and receive rewards. +If a node operator or delegator does not meet the minimum stake, +they will not be included in the next epoch and will not receive any rewards. + +- Access Nodes: 100 FLOW +- Collection Nodes: 250,000 FLOW +- Consensus Nodes: 500,000 FLOW +- Execution Nodes: 1,250,000 FLOW +- Verification Nodes: 135,000 FLOW +- Delegators: 50 FLOW + +There is no maximum stake limit. + + + +=== networks/node-ops/index.md === +--- +title: Node Operations +sidebar_position: 1 +--- + +# Hello Node Operator! + +Flow nodes are vital components of the Flow blockchain. These nodes are responsible for a variety of network operations to maintain the distributed ledger. + +## Why Run a Node? + +--- + +By running your own node, you have direct access to the evolving state of the network, without having to rely on third parties. +This increases privacy and security, reduces reliance on external servers, and helps balance load distribution. +By running a node, you also directly contribute to the security and decentralization of the whole network. + +Flow multirole architecture makes it more scalable and provides several node types that you as a node operator can pick and choose from. + + +## Which Node Should You Run? + +--- + +The different types of nodes are described [here](./node-operation/node-roles.md). As node operator, you can choose to run any of the different types of node that best fits your needs. + +The nodes are classified as follows, + +![Flownodesdiagram.png](./node-operation/Flownodesdiagram.png) + +## Light Node A.K.A. Observer Node + +--- + +The light node is one of the easiest nodes to spin up and can be run by Dapp developers who need the latest block data available locally, e.g. a wallet application that needs to track the latest block ID and height. +In addition to supporting dapps, an observer node can also be run by access node operators who want to scale their access nodes' endpoints. Access node operators can spin up geographically dispersed observer nodes which can talk to their staked access nodes and to each other. + +The observer node is not staked but still provides the same API as the access node. + +:::info + +To run a light node, follow this [guide](./light-nodes/observer-node.md) + +::: + +## Full Node + +--- + +In a nutshell, Full Nodes are staked network participants that drive network progress, e.g. by creating and executing new blocks. They are the primary contributors to network safety (all of them validate the correctness of the consensus process and secure the network additionally through their role-specific tasks). In comparison, Light Nodes don't contribute to the networks progress. Though, they help to secure the network by also validating the integrity of the consensus process. +- The Access node is a full node that serves as an RPC node and acts as a gateway node for the network. +- The Validator node (Collection, Consensus, Verification and Execution) is a full node that plays a role in block generation. + + +### Access Node + +--- + +If you want local access to the protocol state data (blocks, collections, transactions) and do not want to use one of the community access nodes you can run an access node. +Dapp developers, chain explorers, chain analytics and others who want exclusive access to chain data and not be subject to the rate-limits on the community access node can choose to run an access node. + +An access node is minimally staked for network security. +The central goal for Access Nodes is to provide RPC functionality to its node operator. +In comparison, contributing to protocol progress (e.g. routing transactions to collector clusters, relaying blocks to the unstaked peer-to-peer network, etc.) should only take up a marginal fraction an Access Node's computational resources. +Furthermore, Access Node operators can freely rate-limit the amount of resources their Access Node dedicates to supporting the broader ecosystem. Therefore, Access Nodes do not receive staking rewards. + +:::info + +Launch an access node using QuickNode + +[https://www.quicknode.com/chains/flow](https://www.quicknode.com/chains/flow) + +::: + + +:::info + +To run a self-hosted access node, follow this [guide](./access-nodes/access-node-setup.md) + +::: + +:::tip + +Alternately, instead of running an access node, you can use the [Flow community](../access-onchain-data/index.md) access nodes or the ones run by any of the other node operators. + +::: + +### Validator Node + +--- + +You can also be a core participant in running the Flow network and contribute to securing it. Depending on your preference, you could run one or any combination of the following node roles: +- Collection Nodes collaboratively create batches of transactions (in Flow terminology collections). +- Consensus Nodes create blocks, schedule them for asynchronous execution, and commit execution results once they are verified (so called sealing). In addition, they orchestrate the Flow protocol and enforce protocol compliance. +- Execution Nodes asynchronously execute blocks. They are the power-houses in the protocol, providing the vast computational resources available to Flow transactions. +- Verification Nodes check the execution results in a distributed manner. + +Nodes with these roles are staked and also receive staking rewards. + +### Running a Staked Node + +--- + +To run a staked node (node type access, collection, consensus, verification or execution) the node must: +* be registered with sufficient stake +* be authorized by the governance working group + +Before proceeding, ensure you have the stake required for your new node and that your node will be authorized by the governance working group (apply [here](https://github.com/onflow/flow-validator)). + +To set up a new staked node after it has been authorized by the Flow governance working group, you will need to complete the following steps: + +1. [Provision](./node-operation/node-setup.md) the machine on which your node will run. + +2. [Generate and register](./node-operation/node-bootstrap.md) your node identity. + +3. [Start](./node-operation/node-bootstrap.md#step-3---start-your-flow-node) your node! + + +=== networks/node-ops/node-operation/upcoming-sporks.md === +--- +title: Upcoming Sporks +description: Information about upcoming Mainnet & Testnet sporks +sidebar_position: 16 +--- + +The following are the upcoming Spork dates. These dates indicate the intention to Spork. Announcements will be made regarding any delays or changes to these dates in our developer [Discord server](https://discord.gg/flow). + +
    + +| Mainnet Spork Date | Spork Info | Testnet Spork Date | Spork Info | +|:----------------------------|:---------------------------------------|------------------------------------------|------------| +| ~Q3 2024 (exact date tbd) | | Q3 2024 (exact date tbd) | | + | | | May 20, 2024 | Devnet50 | +| Nov 8, 2023 | Mainnet 24 | Nov 2, 2023 | Devnet49 | +| | | Aug 4, 2023 | Devnet48 | +| | | Aug 4, 2023 | Devnet47 | +| June 21, 2023 | Mainnet 23 | Jun 8, 2023 | Devnet46 | +| | | Jun 7, 2023 | Devnet45 | +| | | Apr 24, 2023 | Devnet44 | +| | | Apr 12, 2023 | Devnet43 | +| | | Apr 12, 2023 | Devnet42 | +| Feb 22, 2023 | Mainnet 22 | Jan 30, 2023 —> Feb 22, 2023 | Devnet41 | +| | | Jan 23, 2023 | Devnet40 | +| Jan 18, 2023 | Mainnet 21 | Jan 4, 2023 —> Jan 18, 2023 | Devnet39 | +| Nov 2, 2022 | Mainnet 20 | Oct 19, 2022 —> Nov 2, 2022 | Devnet38 | +| Aug 24, 2022 | Mainnet 19 | Aug 10, 2022 —> Aug 24, 2022 | Devnet37 | +| | | Jul 27, 2022 | Devnet36 | +| June 15, 2022 | [Mainnet 18](./past-upgrades#mainnet-18) | June 9, 2022 —> June 15, 2022 | Devnet35 | +| April 6, 2022 | [Mainnet 17](./past-upgrades#mainnet-17) | April 4, 2022 —> April 6, 2022 | Devnet34 | +| February 9, 2022 | [Mainnet 16](./past-upgrades#mainnet-16) | February 7, 2022 —> February 9, 2022 | Devnet33 | +| December 8, 2021 | [Mainnet 15](./past-upgrades#mainnet-15) | December 7, 2021 —> December 8, 2021 | Devnet32 | +| November 10, 2021 | Cancelled | November 9, 2021 —> November 10, 2021 | Devnet31 | +| October 6, 2021 | [Mainnet 14](./past-upgrades#mainnet-14) | October 5, 2021 —> October 6, 2021 | Devnet30 | +| September 15, 2021 | [Mainnet 13](./past-upgrades#mainnet-13) | September 14, 2021 —> September 15, 2021 | Devnet27 | +| August 18, 2021 | [Mainnet 12](./past-upgrades#mainnet-12) | August 12, 2021 —> August 18, 2021 | Devnet26 | +| July 21, 2021 | [Mainnet 11](./past-upgrades#mainnet-11) | July 20, 2021 —> July 21, 2021 | Devnet25 | +| June 23, 2021 | [Mainnet 10](./past-upgrades#mainnet-10) | June 22, 2021 —> June 23, 2021 | Devnet24 | +| May 26, 2021 | [Mainnet 9](./past-upgrades#mainnet-9) | May 25, 2021 —> May 26, 2021 | Devnet23 | +| April 28, 2021 | [Mainnet 8](./past-upgrades#mainnet-8) | April 27, 2021 —> April 28, 2021 | Devnet22 | +| April 7, 2021 | [Mainnet 7](./past-upgrades#mainnet-7) | March 30, 2021 —> March 31, 2021 | Devnet21 | +| March 10, 2021 | [Mainnet 6](./past-upgrades#mainnet-6) | March 9, 2021 —> March 10, 2021 | Devnet20 | + +
    + + +=== networks/node-ops/node-operation/spork.md === +--- +title: Network Upgrade (Spork) Process +description: Steps to be carried out by node operators during a network upgrade. +sidebar_position: 15 +--- + +## Overview + +A spork is a coordinated network upgrade process where node operators upgrade their node software and +re-initialize with a consolidated representation of the previous spork's state. This enables rapid development +on the Flow Protocol and minimizes the impact of breaking changes. + +The Flow network sporks approximately once every year. Upcoming sporks +are announced in advance on the `#flow-validators-announcements` **Discord** channel +and in [Upcoming Sporks](./upcoming-sporks.md). The `#flow-validators-announcements` channel is +also used to coordinate during the spork process. + +This guide is for existing operators participating in a spork. See [Node Bootstrap](./node-bootstrap.md) +for a guide to joining the network for the first time. + +## Step 1 - Cleaning Up Previous Spork State + +Once the spork start has been announced on, stop your node and clear your database. The node should stay stopped for the duration of the spork. + + + You can skip this step if it is your first time running a node on Flow. + + +1. Stop your Flow node +2. Clear the contents of your `data` directory that you have previously created. The default location is `/var/flow/data`. The `data` directory contains the Flow chain state. + +## Step 2 - Start Your Node + +Once you receive an announcement that the spork process is complete (via Discord), you will need to fetch the genesis info, update your runtime configuration and then boot your Flow node up! + + + +If you had set the [dynamic bootstrap arguments](https://developers.flow.com/networks/node-ops/node-operation/protocol-state-bootstrap) command line arguments (`--dynamic-startup-access-address`, `--dynamic-startup-access-publickey`, `--dynamic-startup-epoch-phase`) please remove them. + + + +1. Run the transit script to fetch the new genesis info: + `./boot-tools/transit pull -b ./bootstrap -t ${PULL_TOKEN} -r ${YOUR_NODE_TYPE} --concurrency 10 --timeout 15m` + +- `PULL_TOKEN` will be provided by the Flow team. + - For `collection`, `consensus`, `verification` node type it will generally be `testnet-x` or `mainnet-x` where x is the latest number of respective network upgrade. e.g. `testnet-52`, `mainnet-26`. + - For `execution` node type it will generally be `testnet-x-execution` or `mainnet-x-execution`. + - For `access` node: + - It will generally be `testnet-x` or `mainnet-x` if execution data indexing is not enabled. + - It will generally be `testnet-x-execution` or `mainnet-x-execution` if execution data indexing is enabled. + +- `YOUR_NODE_TYPE` should be one of `collection`, `consensus`, `execution`, `verification`, `access` based on the node(s) that you are running. + +```shell Example +$ ./boot-tools/transit pull -b ./bootstrap -t mainnet-16 -r consensus +Transit script Commit: a9f6522855e119ad832a97f8b7bce555a163e490 +2020/11/25 01:02:53 Running pull +2020/11/25 01:02:53 Downloading bootstrap/public-root-information/node-infos.pub.json +2020/11/25 01:02:54 Downloading bootstrap/public-root-information/root-protocol-snapshot.json +2020/11/25 01:02:54 Downloading bootstrap/random-beacon.priv.json.39fa54984b8eaa463e129919464f61c8cec3a4389478df79c44eb9bfbf30799a.enc +2020/11/25 01:02:54 SHA256 of the root block is: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 + +$ tree ./bootstrap/ + ./bootstrap/ + ├── private-root-information + │ └── private-node-info_39fa54984b8eaa463e129919464f61c8cec3a4389478df79c44eb9bfbf30799a + │ └── node-info.priv.json + ├── public-root-information + │ ├── node-id + │ ├── node-info.pub.39fa54984b8eaa463e129919464f61c8cec3a4389478df79c44eb9bfbf30799a.json + │ ├── node-infos.pub.json + │ └── root-protocol-snapshot.json + └── random-beacon.priv.json.39fa54984b8eaa463e129919464f61c8cec3a4389478df79c44eb9bfbf30799a +``` + +2. Pull the latest changes from [flow-go repository](https://github.com/onflow/flow-go) +3. Get your `node-id`, you can find it at `/path/to/bootstrap/public-genesis-information/node-id` +4. Update the `FLOW_GO_NODE_ID` inside [runtime-conf.env](https://github.com/onflow/flow-go/blob/master/deploy/systemd-docker/runtime-conf.env) to the `node-id` that you got from the previous step +5. Start your Flow node via `docker` or `systemd` + +See [Node Bootstrap](./node-bootstrap.md) for detailed information on Docker/Systemd configuration. + +## Common Issues + +### Error: cannot create connection + +```shell +20T18:34:21Z","message":"could not create connection"} +{"level":"error","node_role":"consensus","node_id":"6d3fac8675a1df96f4bb7a27305ae531b6f4d0d2bc13a233e37bb07ab6b852dc","target":"QmVcSQaCdhmk1CMeMN7HTgGiUY1i2KqgVE2vvEmQXK4gAA","error":"failed to dial : all dials failed + * [/ip4/155.138.151.101/tcp/3569] dial tcp4 155.138.151.101:3569: connect: connection refused","retry_attempt":2,"time":"2020-05-20T18:34:21Z","message":"could not create connection"} +``` + +This error is OK. Your fellow node operators have not turned on/joined the network yet. So no need to worry about it! + + +=== networks/node-ops/node-operation/slashing.md === +--- +title: Slashing Conditions +sidebar_position: 17 +--- + +## Introduction + +Flow is a proof-of-stake system, which means holders of FLOW can earn inflationary rewards +by staking their FLOW tokens to secure and operate the network. +A node can participate in the Flow network by depositing a specific amount of stake +(based on role types) thereby making a bonded pledge to participate +in the Flow protocol during the upcoming epoch. +(An epoch is a finite amount of time defined by the protocol, approximately one week, +during which the nodes participate to run the protocol and are responsible for their operations.) + +See the [Staking and Epochs section of the documentation](../../staking/index.md) to learn more +about the design and functionality of this part of the protocol. + +Flow nodes follow the procedures defined in the protocol (based on their role) +in order to receive rewards. Any deviation (see Slashing Challenges below) +from the protocol can result in decreased reward payments or punishments. +Severe infractions, which undermine the safety of the network, +can lead to “slashing”, where some or all of the staked tokens are confiscated from the offending node(s). + +This reward and punishment structure is designed to guarantee the security +of the protocol and optimize performance over time. +This document outlines the most severe infractions against the protocol +which result in some portion of a node’s stake being taken from them (“slashing conditions”). +Enforcing these slashing conditions is critical to ensure the cryptoeconomic security of the protocol. +Future documents will describe an incentive structure that encourages system-wide efficiency and speed, +by providing bonuses to the most performant nodes and withholding payments to nodes that are unresponsive. + +This document assumes a working understanding of the high-level architecture of the Flow blockchain. +Readers who are new to Flow or those looking for a refresher are encouraged +to read the Protocol Summary [here](../node-operation/node-roles.md) and the staking documentation. + +## Slashing Conditions + +Any violation of the Flow protocol that could result in staked tokens being seized +from the offending nodes is called **Slashable Behaviour.** +In order for the tokens to be seized, the data necessary to prove the occurrence of Slashable Behaviour +must be combined with the data necessary to attribute the behaviour +to the node(s) responsible into a **Slashing Witness**. +(A reduction of rewards, e.g. due to lack of active participation, +is not formally included in our definition of slashing.) +The Flow protocol considers only server threats to safety and liveness +to be slashable conditions and as such, there are no performance related slashing penalties. +The one exception is in the case of missing Collections (see the section on MCC below), +where a widespread failure to respond by a large number of nodes is presumed +to be coordinated and therefore punishable with slashing. + +Most Slashable Behaviour in Flow can be detected and attributed to the offender +by a single honest node observing that behaviour. +(In other words, one node can generate a Slashing Witness without coordinating with other nodes.) +However, some Slashable Behaviour can only be detected and attributed +by combining information from multiple nodes. In those situations, +the node that first detects the potential infraction raises a **Slashing Challenge**. +When a challenge is raised, other nodes are expected to provide additional information +which can be combined with the original challenge into a definitive Slashing Witness +that is used to adjudicate the challenge. Each type of Slashing Challenge depends +on different information provided from a different subset of nodes, +the details of which are provided below. + +Flow adheres to a number of principles in the design of its slashing rules: + +- Only Consensus Nodes can perform slashing, and only by following the BFT consensus mechanism +defined in the protocol. As such, a super-majority of Consensus Nodes must inspect +and confirm a Slashing Witness before any punishment is levied. + +- All Slashing Witnesses are objectively decidable. +Given the current protocol state (maintained by the Consensus Nodes) +and a well-formed Slashing Witness, all non-Byzantine Consensus Nodes will deterministically come +to the same conclusion as to which node or nodes should be slashed (if any) +and the amount of stake to be seized. + +- All Slashing Behaviour in Flow requires active malfeasance on the part of the offending node. +In other words, a node will only be slashed if it takes an action against the rules of the protocol, +and it will not be slashed if it fails to take an action prescribed by the protocol. +(“If your machine is crashed, you won’t get slashed.”) The one exception +is in the case of missing Collections (see the section on MCC below), +where a widespread failure to respond by a large number of nodes is presumed +to be coordinated and therefore punishable with slashing. + +- Flow makes no attempt to detect and punish liveness failures within the protocol. +A liveness failure across the network functionally slashes the stake of any participants +excluded from participating in the reboot (since their stake is locked in a non-functional network). +Community analysis can determine which nodes were responsible for the failure +and exclude those Byzantine actors from the new instance. + +- Any staked node of Flow can submit a Slashing Witness for any Slashable Behaviour, +regardless of its role. (For example, a Collection Node could submit a Slashing Witness +for an invalid execution receipt, even though the protocol doesn’t require Collection Nodes +to verify execution receipts.) + +- Submitting an invalid Slashing Witness is Slashable Behaviour. +We treat the invalid Slashing Witness itself as the Slashing Witness for that case. + +## Stages of Slashing + +Transitioning to a rigorous staking protocol in which all slashable conditions are checked, +enforced, and punished will take place over three phases. +The Slashing Challenges section below outlines the various challenges +which may be submitted against an offending node but these challenges +will not be fully enforced until Phase 3 of the network. + +### Phase 1: Beta + +- In the beta phase of the network, the expectation is that nodes are running error detection +and logging but not submitting formal challenges. Any errors found may be submitted +to the Flow team for additional testing and security improvements. + +### Phase 2: Testing Slashing Mechanics + +- At this time the slashing mechanisms will be implemented and require testing. +Formal challenges should be raised and the protocol will follow the complete, +formal mechanics for arbitrating challenges and slashing perpetrators, +but no real slashing will take place. + +### Phase 3: BFT + +- By now, the network has been security-hardened and tested and valid challenges +result in real slashing of the offending node. + +## Slashing Challenges + +### 0. All Nodes + +**Invalid Report Witness (IRW): **if any nodes report an invalid/inaccurate witness, +an invalid report witness will be reported by the Consensus Nodes, +and the node(s) reporting the witness get slashed. + +### 1. Collection Nodes + +**1.1 Missing Collection Challenge (MCC): ** Collection nodes are responsible +for storing collection content (all transactions) for any collection which they guarantee +during the current epoch and the first 1000 blocks of the next epoch. +During this time they have to respond to any collection request from staked execution, +verification and Consensus Nodes and should respond in a timely manner (specific timeout). +If an Execution Node or a Verification Node doesn't receive the response from any +of the collection guarantors (Collection Nodes who signed a collection), +they can raise a Missing Collection Challenge and broadcast it to the Consensus Nodes to evaluate. + +**Adjudication: **Consensus nodes randomly contact some of the guarantors. +If Collection Nodes don't respond, a portion of their stakes will be seized. +If the amount of their stake goes to less than half, they will be fully slashed. +Then the Consensus Nodes notify all the Execution Nodes to skip that collection. +If any of the Collection Nodes respond, Consensus Nodes redirect the collection content +to the Execution Nodes but will also set small penalties both +for all the guarantors and that Execution Node (according to their revenue ratio). + +**1.2 Invalid Collection Witness (ICW):** Collection nodes are responsible for responding +to collection content queries by collection hash from any staked nodes. +The collection hash is the hash of an ordered list of transaction hashes. +If a collection content sent by the Collection Node turns out to be invalid, +any staked node can report an Invalid Collection Witness. This includes cases where: + +- the content is malformed or incomplete, +- there exists an invalid transaction inside the collection, or +- the collection hash doesn't match (inside collection guarantee). + +**Adjudication:** Consensus nodes evaluate the content of the collection, +if the collection is found invalid, the Collection Node who signed the content is slashed. + +**1.3 Double Collection Proposal Witness (DCPW):** Collection nodes of a cluster run a mini consensus +inside the cluster to decide on a collection, which requires Collection nodes to propose +the collection and aggregate votes from others. During the collection consensus, +if a Collection Node proposes more than one proposal, any other Collection Node +inside the cluster can report a Double Collection Proposal Witness (including both proposals). + +**Adjudication: **Consensus nodes evaluate the content and signatures of these two proposals, +and if the witness turns out to be valid, the Collection Node who proposed two collections will get slashed. + +**1.4 Double Collection Voting Witness (DCVW):** Collection nodes of a cluster +run a mini consensus inside the cluster to decide on a collection, +which requires Collection nodes to propose the collection and aggregate votes from others. +During the collection consensus, if a Collection Node votes for more than one collection proposal +with identical collection number and size, any other Collection Node inside the cluster +can report a Double Collection Voting Witness (including both votes). + +**Adjudication: **Consensus nodes evaluate the signatures of these two votes and evaluate them, +and if the witness turns out to be valid, the Collection Node who voted two times will get slashed. + +### 2. Consensus Nodes + +**2.1 Double Block Proposal Witness (DBPW):** Consensus nodes run the consensus (HotStuff algorithm) over blocks. +During these consensus steps, if a Consensus Node proposes more than one variation of a block proposal, +any other Consensus Node can report a Double Block Proposal Witness (including both proposals). +This report will be broadcasted to all other Consensus Nodes. + +**Adjudication: **Consensus nodes evaluate content and signatures of both proposals. +If the witness turns out to be valid, the Consensus Node who submitted both proposals will get slashed. + +**2.2 Double Block Voting Witness (DBVW): ** Consensus nodes run the consensus (HotStuff algorithm) +over blocks. During the consensus steps, if a Consensus Node votes for +more than one block proposal with the same height, any other Consensus Node can report +a Double Block Voting Witness (including both votes). +This report will be broadcasted to all other Consensus Nodes. + +**Adjudication: **Consensus nodes evaluate content and signatures of both votes +and If the witness turns out to be valid, the Consensus Node who submitted both votes will get slashed. + +**2.3 Invalid Block Vote Witness (IBVW):** If a Consensus Node votes for an invalid block +or the content of the vote itself is invalid (e.g. vote for non-existing block), +any other Consensus Nodes can report an Invalid Block Vote Witness. + +**Adjudication: **Consensus nodes evaluate the vote content and signature. +If the witness turns out to be valid, the Consensus Node who submitted the faulty vote will get slashed. + +**2.4 Invalid Block Proposal Witness (IBPW):** If a Consensus Node proposes +an invalid block proposal (e.g. quorum certificate without 2/3 vote), +any other Consensus Nodes can raise an Invalid Block Proposal Witness. + +**Adjudication: **Consensus nodes evaluate the proposal content and signature, +If the witness turns out to be valid, the Consensus Node who submitted the invalid proposal +will get slashed. + +**2.5 Invalid Block Witness (IBW):** If the block contents returned by any Consensus Node is invalid, +any node can raise the Invalid Block Witness: + +- It is malformed or incomplete +- It doesn't match the payload hash provided by the block header + +**Adjudication: **Consensus nodes evaluate the block content and signatures. +If the witness turns out to be valid, the Consensus Node who signed the block content will get slashed. + +**2.6 Invalid Random Beacon Signature Witness (IRBSW):** +If any participant of the random beacon returns an invalid signature, +an Invalid Random Beacon Signature Witness can be reported by other Consensus Nodes. + +**Adjudication:** Consensus nodes evaluate the random beacon signature. +If the witness turns out to be valid, the Consensus Node who signed the invalid random beacon part +will get slashed. + +### 3. Execution Nodes + +**3.1 Faulty Computation Challenge (FCC): ** If any of the Verification Nodes +find a fault in the execution of transactions by an Execution Node it can raise an FCC challenge. +An FCC challenge includes a faulty chunk and all the evidence. + +**Adjudication: **Consensus nodes evaluate the challenge, by sending requests +for collection contents and chunk data needed to run the faulty chunk and comparing +the results against the expected state commitment. If Consensus Nodes detect any fault +in the execution of that chunk, the Execution Node(s) who signed the faulty execution receipts +will get slashed. If no fault is found, the Verification Node who raised the challenge will get slashed. + +**3.2 Conflicting Execution Results Challenge (CERC): ** +If two or more variations of execution results are reported by Execution Nodes for a given block. +Since only one can be valid, Consensus Nodes raise a conflicting execution results challenge. + +**Adjudication: **As soon as this challenge is raised, all the Verification Nodes +go into full check mode (checks all the chunks). The first execution result +that receives result approval from at least 2/3 of Verification Nodes is the accurate one, +and the other execution results will be considered faulty and Execution Nodes generating those +will get slashed. If none of the execution results receive majority approval +from Verification Nodes after a very long timeout, +all the Consensus Nodes start executing chunks to determine the correct output. + +**3.3 Invalid Chunk Data Package Witness (ICDPW):** If the contents of a chunk data package +doesn't match the hash provided inside the execution result, or the contents is invalid, +the Verification Nodes can report an Invalid Chunk Data Package Witness. + +**Adjudication: **Consensus nodes evaluate the content of the chunk data package. +If the witness turns out to be valid, the Execution Node(s) +who signed the faulty chunk data package will get slashed. + +**3.4 Missing Chunk Data Package Challenge (MCDPC):** +If an Execution Node doesn't respond to the chunk data package request by any staked Verification Node, +a Missing Chunk Data Package Challenge can be raised by the Verification Node. + +**Adjudication: **When this challenge is received by the Consensus Nodes, +they contact Execution Nodes and ask for the chunk data package. +If none of the Execution Nodes respond after a long timeout, all of them get slashed. +If any of the Execution Nodes responds with a valid chunk data package, +Consensus Nodes redirect the chunk data package to the Verification Nodes +but will also set small penalties both for all the Execution Nodes and the challenge raiser +(Verification Node) according to their revenue ratio. + +**3.5 Execution Results Timeout Challenge (ERTC):** +If no execution receipt received in X number of blocks after the submission of each block, +the liveness of the system is compromised and Consensus Nodes can raise +an Execution Results Timeout Challenge for all the Execution Nodes. + +**Adjudication: **When this challenge is received by the Consensus Nodes, +they contact Execution Nodes and ask for an update. If none of the Execution Nodes respond +after a long timeout, all of them get slashed. +If any of the Execution Nodes return the execution receipt, the case is dismissed. + +**3.6 Invalid Execution Receipt Witness (IERW):** +If an Execution Node provides an execution receipt that is not valid, +the Consensus Nodes can report an Invalid Execution Receipt Witness. + +**Adjudication: **Consensus nodes evaluate the content of the execution receipt. +If the witness turns out to be valid, the Execution Node(s) +who signed the invalid execution receipt will get slashed. + +**3.7 Non-Matching SPoCKs Challenge (NMSC): ** +If the SPoCKs provided by the Execution Node don't match the ones provided by the Verification Node, +the Consensus Nodes can raise a Non-Matching SPoCKs challenge. + +**Adjudication: **Consensus nodes have to re-execute the chunk +to be able to compute the accurate SPoCKs secret to be able to adjudicate the challenge. +This requires requesting the collection and all other data needed for execution from other nodes. +Any node which provided invalid SPoCKs will be slashed. + +### 4. Verification Nodes + +**4.1 Non-Matching SPoCKs Challenge (NMSC):** +If the SPoCKs provided by the Execution Node don't match the ones provided by the Verification Node, +the Consensus Nodes can raise a Non-Matching SPoCKs challenge. + +**Adjudication: **Consensus nodes have to re-execute the chunk to determine the accurate SPoCKs secret +which is needed to adjudicate the challenge. This requires requesting the collection +and all other data needed for execution from the other nodes. +Any node which provided invalid SPoCKs will be slashed. + +**4.2 Invalid Result Approval Witness (IRAW):** +If a Verification Node provides an invalid result approval, +the Consensus Nodes can report this witness. +This includes cases that a Verification Node sends a result approval +for a chunk that was not assigned to the Verification Node (excluding full check mode) +or if the SPoCK’s signature doesn't match the public key of the Verification Node. + +**Adjudication: **Consensus nodes evaluate the content and signatures of the result approval. +If the witness turns out to be valid, the Verification Node who signed that result approval be slashed. + + +=== networks/node-ops/node-operation/reclaim-disk.md === +--- +title: Managing disk space +description: How to manage the node disk space +--- + +As the chain advances, nodes receive chain data and store it on disk. +Hence, the disk usage of a node keeps increasing gradually over time. + +In addition to this, currently nodes also experience an intermittent 30-35% spike in disk usage caused by the compaction process of the Badger database used by the node software. + +> The spikes will be eliminated once the Badger database is replaced by the Pebble database in the future. + + +Hence, as a node operator, please make sure to do the following: + +1. Provision enough disk space as per the node role (see: [node-provisioning](./node-provisioning.md)) + + +2. Setup disk usage monitoring and ensure that the node has enough room to grow and to also accommodate those intermittent spikes. + + +3. If needed, please add more disk space to the node from time to time. + +> It highly recommended to setup alerting around disk usage to facilitate timely action and avoid any downtime and subsequent reward slashing for the node. + + +## Reclaiming disk space + +### Access, Collection, Consensus and Verification node + +If you are running any node other than an execution node and the node is close to running out of disk space or has already exhausted all of its disk, you can re-bootstrap the node's database. This frees up disk space by discarding historical data past a certain threshold. + +1. Stop the node. + +2. Back up the data folder to a tmp folder in case it is required to revert this change. The default location of the data folder is `/var/flow/data` unless overridden by the `--datadir` flag. +```sh +mv /var/flow/data /var/flow/data_backup +``` + +3. Configure the node to bootstrap from a new, more recent Root Snapshot. You may use either of the two methods described [here](./protocol-state-bootstrap.md) to configure your node. + +4. Start the node. The node should now recreate the data folder and start fetching blocks. + +5. If the node is up and running OK, delete the `data_backup` folder created in step 2. +```sh +rm -rf /var/flow/data_backup +``` + +#### Limitation for Access Node + +Re-bootstrapping allows the node to be restarted at a particular block height by deleting all the previous state. + +For an **Access Node**, this results in the node not being able to serve any API request before the height at which the node was re-bootstrapped. + +_Hence, if you require the access node to serve data from the start of the last network upgrade (spork), do not use this method of reclaiming disk space. Instead provision more disk for the node._ + +### Execution node + +For an execution node, the chunk data directory is the one that takes up most of the space. To reclaim space on an execution, do the following: + +1. Stop the Execution Node. + + +2. Remove the Chunk Data Pack Directory. The default is `/var/flow/data/chunk_data_pack` unless overridden by the `chunk-data-pack-dir` parameter. + + Do **not** delete the bootstrap folder. + + ``` rm -rf /var/flow/data/chunk_data_pack``` + + +3. Start the Execution Node. + +Upon restart, the chunk data pack directory will be automatically recreated. + + +> Note: Always exercise caution when performing system operations, and make sure you have a backup of important data before making any changes. + +=== networks/node-ops/node-operation/protocol-state-bootstrap.md === +--- +title: Protocol State Bootstrapping +description: How to bootstrap a new or existing node +--- + +When a node joins the network, it bootstraps its local database using a trusted initialization file, called a Root Snapshot. +Most node operators will use the `Spork Root Snapshot` file distributed during the [spork process](./spork.md). +This page will explain how the bootstrapping process works and how to use it in general. + +For guides covering specific bootstrapping workflows, see: +- [Node Bootstrap](./node-bootstrap.md) for bootstrapping a newly joined node. +- [Reclaim Disk](./reclaim-disk.md) for bootstrapping from a recent snapshot to recover disk space. + + + This page covers only Protocol State bootstrapping and applies to Access, Collection, Consensus, & Verification Nodes. + Execution Nodes also need to bootstrap an Execution State database, which is not covered here. + + +## Node Startup + +When a node starts up, it will first check its database status. +If its local database is already bootstrapped, it will start up and begin operating. +If its local database is not already bootstrapped, it will attempt to bootstrap using a Root Snapshot. + +There are two sources for a non-bootstrapped node to obtain a Root Snapshot: +1. Root Snapshot file in the `bootstrap` folder +2. Dynamic Startup flags, which will cause the node to download a Root Snapshot from a specified Access Node + +The node software requires that only one of the above options is provided. + +## Using a Root Snapshot File + + + If your node already has a bootstrapped database, the Root Snapshot file will be ignored. If both a Root Snapshot and Dynamic Startup flags are present, the node will not startup. + + +Using a Root Snapshot file is more flexible but more involved for operators compared to Dynamic Startup. + +A file in `$BOOTDIR/public-root-information` named `root-protocol-state-snapshot.json` will be read and used as the Root Snapshot for bootstrapping the database. + +### Instructions + +1. Obtain a Root Snapshot file (see below for options) +2. Ensure your node is stopped and does not already have a bootstrapped database. +3. Move the Root Snapshot file to `$BOOTDIR/public-root-information/root-protocol-state-snapshot.json`, where `$BOOTDIR` is the value passed to the `--bootstrapdir` flag. +4. Start your node. + +### Obtain Root Snapshot File using Flow CLI + +[Flow CLI](../../../tools/flow-cli/index.md) supports downloading the most recently sealed Root Snapshot from an Access Node using the [`flow snapshot save`](../../../tools/flow-cli/utils/snapshot-save.md) command. + +When using this method: +- ensure you connect to an Access Node you operate or trust +- ensure you use the [`--network-key`](../../../tools/flow-cli/utils/snapshot-save#network-key) flag so the connection is encrypted + +### Obtain Root Snapshot File from Protocol database + +If you have an existing node actively participating in the network, you can obtain a Root Snapshot using its database. + +1. Obtain a copy of the Flow `util` tool and ensure it is in your `$PATH`. This tool is distributed during sporks, or you can build a copy from [here](https://github.com/onflow/flow-go/tree/master/cmd/util). +2. Stop the existing node. +3. Construct a Root Snapshot using the `util` tool. The tool will print the JSON representation to STDOUT, so you can redirect the output to a file. + +Replace `$DATADIR` with the value passed to the `--datadir` flag. You can specify the desired reference block for the snapshot. + +Retrieve the snapshot for the latest finalized block: +```sh +util read-protocol-state snapshot -d $DATADIR --final > latest-finalized-snapshot.json +``` + +Retrieve the snapshot for a specific finalized block height: +```sh +util read-protocol-state snapshot -d $DATADIR --height 12345 > specific-height-snapshot.json +``` + +## Using Dynamic Startup + +Dynamic Startup is a startup configuration where your node will download a Root Snapshot and use it to bootstrap its local database. +Dynamic Startup is designed for nodes which are newly joining the network and need to [bootstrap from within a specific epoch phase](./node-bootstrap#timing), but can be used for other use-cases. + + + If your node already has a bootstrapped database, Dynamic Startup flags will be ignored. If both a Root Snapshot and Dynamic Startup flags are present, the node will not startup. + + +When using Dynamic Startup, we specify: +1. An Access Node to retrieve the snapshot from. +2. A target epoch counter and phase to wait for. + +After startup, your node will periodically download a candidate Root Snapshot from the specified Access Node. +If the Root Snapshot's reference block is either **within or after** the specified epoch phase, the node will bootstrap using that snapshot. +Otherwise the node will continue polling until it receives a valid Root Snapshot. + +See the [Epochs Schedule](./../../staking/03-schedule.md) for additional context on epoch phases. + +### Specifying an Access Node + +Two flags are used to specify which Access Node to connect to: +- `--dynamic-startup-access-address` - the Access Node's secure GRPC server address +- `--dynamic-startup-access-publickey` - the Access Node's networking public key + +Select an Access Node you operate or trust to provide the Root Snapshot, and populate these two flags. + +For example, to use the Access Node maintained by the Flow Foundation for Dynamic Startup, specify the following flags: +```shell ExampleDynamicStartupFlags + ... \ + --dynamic-startup-access-address=secure.mainnet.nodes.onflow.org:9001 \ + --dynamic-startup-access-publickey=28a0d9edd0de3f15866dfe4aea1560c4504fe313fc6ca3f63a63e4f98d0e295144692a58ebe7f7894349198613f65b2d960abf99ec2625e247b1c78ba5bf2eae +``` + +### Specifying an Epoch Phase + +Two flags are used to specify when to bootstrap: +- `--dynamic-startup-epoch-phase` - the epoch phase to start up in (default `EpochPhaseSetup`) +- `--dynamic-startup-epoch` - the epoch counter to start up in (default `current`) + +> You can check the current epoch phase of the network by running [this](https://github.com/onflow/flow-core-contracts/blob/master/transactions/epoch/scripts/get_epoch_phase.cdc) script. Alternatively, you can also check the current epoch phase [here](https://dashboard.flow.com/) under Epoch Phase. + +#### Bootstrapping Immediately + +If you would like to bootstrap immediately, using the first Root Snapshot you receive, then specify a past epoch counter: +```shell ExampleDynamicStartupFlags + ... \ + --dynamic-startup-epoch-phase=1 +``` +You may omit the `--dynamic-startup-epoch-phase` flag. + +### Instructions + +#### Example 1 +Use Dynamic Startup to bootstrap your node at the `Epoch Setup Phase` of the current epoch (desired behaviour for newly joining nodes): +1. Ensure your database is not already bootstrapped, and no Root Snapshot file is present in the `$BOOTSTRAPDIR` folder. +2. Add necessary flags to node startup command. +For example, using the Flow Foundation Access Node: +```sh + ... \ + --dynamic-startup-access-address=secure.mainnet.nodes.onflow.org:9001 \ + --dynamic-startup-access-publickey=28a0d9edd0de3f15866dfe4aea1560c4504fe313fc6ca3f63a63e4f98d0e295144692a58ebe7f7894349198613f65b2d960abf99ec2625e247b1c78ba5bf2eae +``` +3. Start your node. + +#### Example 2 +Use Dynamic Startup to bootstrap your node immediately, using the most recent Root Snapshot: +1. Ensure your database is not already bootstrapped, and no Root Snapshot file is present in the `$BOOTSTRAPDIR` folder. +2. Add necessary flags to node startup command. +For example, using the Flow Foundation Access Node: +```sh + ... \ + --dynamic-startup-access-address=secure.mainnet.nodes.onflow.org:9001 \ + --dynamic-startup-access-publickey=28a0d9edd0de3f15866dfe4aea1560c4504fe313fc6ca3f63a63e4f98d0e295144692a58ebe7f7894349198613f65b2d960abf99ec2625e247b1c78ba5bf2eae \ + --dynamic-startup-epoch=1 +``` +3. Start your node. + + +=== networks/node-ops/node-operation/past-upgrades.md === +--- +title: Past Network Upgrades +description: Information about Flow Mainnet and Testnet network upgrades. +sidebar_position: 14 +--- + +A JSON version of the information below can be found in [onflow/flow/sporks.json](https://github.com/onflow/flow/blob/master/sporks.json) + +## Mainnet Upgrades + +> Currently only includes HCUs from 2025. + +## Height Coordinated Upgrade 7 + +| HCU Info | +|:--------------------------------------------------------------------------------------| +| **Date**: April 10, 2025 | +| **Block Height**: 109384800 | +| **Git Commit**: 86c40b1ff20b3b7f17c4017bde083d26303c508d | +| **Branch/Tag**: v0.40.0 | +| **Docker Image Tag**: v0.40.0 | +| **Release Notes**: [v0.40.0](https://github.com/onflow/flow-go/releases/tag/v0.40.0) | + +## Rolling Upgrade 1 + +| RU Info | +|:-------------------------------------------------------------------------------------| +| **Date**: April 3, 2025 | +| **Block Height**: 108630638 | +| **Block View **: 20504725 | +| **Git Commit**: ad1076f0a36bb2d20cc36295d3573989edc15c6c | +| **Branch/Tag**: v0.39.0 | +| **Docker Image Tag**: v0.39.0 | +| **Release Notes**: [v0.39.0](https://github.com/onflow/flow-go/releases/tag/v0.39.0) | + +## Height Coordinated Upgrade 6 + +| HCU Info | +|:-------------------------------------------------------------------------------------| +| **Date**: Feb 18, 2025 | +| **Block Height**: 103983000 | +| **Git Commit**: 4e7e56b3a92e5772279f1304d88dd445c0ea5016 | +| **Branch/Tag**: v0.38.3 | +| **Docker Image Tag**: v0.38.3 | +| **Release Notes**: [v0.38.3](https://github.com/onflow/flow-go/releases/tag/v0.38.3) | + +## Height Coordinated Upgrade 5 + +| HCU Info | +|:-------------------------------------------------------------------------------------| +| **Date**: Feb 18, 2025 | +| **Block Height**: 103957477 | +| **Git Commit**: bcb8a2264fcde9dcd4c997f6b28d8184af19160b | +| **Branch/Tag**: v0.38.2 | +| **Docker Image Tag**: v0.38.2 | +| **Release Notes**: [v0.38.2](https://github.com/onflow/flow-go/releases/tag/v0.38.2) | + +## Height Coordinated Upgrade 4 + +| HCU Info | +|:---------------------------------------------------------------------------------------| +| **Date**: Jan 27, 2025 | +| **Block Height**: 101584244 | +| **Git Commit**: 5f6b25bd02257e3239341c4be0134b007f3deb49 | +| **Branch/Tag**: v0.37.26 | +| **Docker Image Tag**: v0.37.26 | +| **Release Notes**: [v0.37.26](https://github.com/onflow/flow-go/releases/tag/v0.37.26) | + +## Mainnet 26 + +| Spork Info | +|:----------------------------------------------------------------------------------------| +| **Access Node**: access.mainnet.nodes.onflow.org:9000 | +| **Date**: Sep 25, 2024 | +| **Root Height**: 88226267 | +| **Root Parent ID**: 71052eb6e774ae5065b31c604a85af47fa16d5c53e54b9a992581c1ecf0ecfac | +| **Root State Commit**: 3bba639062a723af1b44b1dfe07e795d158482f02f807f1df0b7c39edd6a8cca | +| **Git Commit**: 25d9c2a9b89bac8fa003ca67928eb79b1427ea17 | +| **Branch/Tag**: v0.37.16-patch.1 | +| **Docker Image Tag**: v0.37.16-patch.1 | + +## Mainnet 25 + +| Spork Info | +|:----------------------------------------------------------------------------------------| +| **Access Node**: access-001.mainnet25.nodes.onflow.org:9000 | +| **Date**: Sep 4, 2024 | +| **Root Height**: 85981135 | +| **Root Parent ID**: bc16d37060cb408163a04afe406b9c9398a31663c839de35b92e3c3b10bcf834 | +| **Root State Commit**: dead79e8f86d20ea3214735d4247b7fac1b4408e93e9b092fe0566cf40cecb9e | +| **Git Commit**: feabd3a4f9baaa5d7770a312e5b8dc1bd94b1edb | +| **Branch/Tag**: [v0.37.10](https://github.com/onflow/flow-go/releases/tag/v0.37.10) | +| **Docker Image Tag**: v0.37.10 | + +## Mainnet 24 + +| Spork Info | +|:----------------------------------------------------------------------------------------| +| **Access Node**: access-001.mainnet24.nodes.onflow.org:9000 | +| **Date**: Nov 8, 2023 | +| **Root Height**: 65264619 | +| **Root Parent ID**: aace2d9b6e66067989d0f71c2efff38fe30d88da61e3d80946c7e7b4ee2bbc2f | +| **Root State Commit**: 709530929e4968daff19c303ef1fc5f0a7649b3a1ce7d5ee5202056969524c94 | +| **Git Commit**: e63117642e34b215993d14d36622d45df249016c | +| **Branch/Tag**: [v0.32.7](https://github.com/onflow/flow-go/releases/tag/v0.32.7) | +| **Docker Image Tag**: v0.32.7 | + +## Mainnet 23 + +| Spork Info | +| :-------------------------------------------------------------------------------------- | +| **Access Node**: access-001.mainnet23.nodes.onflow.org:9000 | +| **Date**: Jun 20, 2023 | +| **Root Height**: 55114467 | +| **Root Parent ID**: dcaa1469c6cd67154942c70b594bdff407ea28eda1fc9c4a81a814f02dc2efc9 | +| **Root State Commit**: 5586f6b9af7c0d8efa7b403dbd3a894d71a18faad5a1abda48d3dfb7dcd4b017 | +| **Git Commit**: 0f6ea38efc91b7d27736b8b2c94091076c624796 | +| **Branch/Tag**: [v0.31.9](https://github.com/onflow/flow-go/releases/tag/v0.31.9) | +| **Docker Image Tag**: v0.31.9 | + +## Mainnet 22 + +| Spork Info | +| :-------------------------------------------------------------------------------------- | +| **Access Node**: access-001.mainnet22.nodes.onflow.org:9000 | +| **Date**: Feb 22, 2023 | +| **Root Height**: 47169687 | +| **Root Parent ID**: 60a976d4cc36d0a5150d3f81ede85809916d4af9eb791d9190af0a12c1fd8a17 | +| **Root State Commit**: c9c9d3da3fe059a616b13768da2374275bd1a35f94d753ee8e41c538a3cc92d8 | +| **Git Commit**: e644427a8e83e8cd2a307c40e4c8fd3066008cae | +| **Branch/Tag**: [v0.29.13](https://github.com/onflow/flow-go/releases/tag/v0.29.13) | +| **Docker Image Tag**: v0.29.13 | + +## Mainnet 21 + +| Spork Info | +| :-------------------------------------------------------------------------------------- | +| **Access Node**: access-001.mainnet21.nodes.onflow.org:9000 | +| **Date**: Jan 18, 2023 | +| **Root Height**: 44950207 | +| **Root Parent ID**: 52004adfa7854b1a515d0d905dd5317dc7f77a8dbb56058e04dde01e53e80a92 | +| **Root State Commit**: 905c5e9a576ba2cbe49b5fe5f64ae84c2dee1bc26a3e81932e573e06a722d08a | +| **Git Commit**: 7f02a642bb437b45326c4ace54a7f033b32832f8 | +| **Branch/Tag**: [v0.29.6](https://github.com/onflow/flow-go/releases/tag/v0.29.6) | +| **Docker Image Tag**: v0.29.6 | + +## Mainnet 20 + +| Spork Info | +| :-------------------------------------------------------------------------------------- | +| **Access Node**: access-001.mainnet20.nodes.onflow.org:9000 | +| **Date**: Nov 2, 2022 | +| **Root Height**: 40171634 | +| **Root Parent ID**: f66302ac43623a87d29dfdeb08fce5d19e3af7be2e4283d468f74ee10468f248 | +| **Root State Commit**: ec1e1cd34bb05b5abb3c4701a7f365d1dde46d9d908dc57420bde8b4a53d940a | +| **Git Commit**: b9b941db9a3949db0e299a40264d852980d35ddd | +| **Branch/Tag**: [v0.28.6](https://github.com/onflow/flow-go/releases/tag/v0.28.6) | +| **Docker Image Tag**: v0.28.6 | + +## Mainnet 19 + +| Spork Info | +| :-------------------------------------------------------------------------------------- | +| **Access Node**: access-001.mainnet19.nodes.onflow.org:9000 | +| **Date**: Aug 24, 2022 | +| **Root Height**: 35858811 | +| **Root Parent ID**: 5c030d4125f8ace0e0ab8255880143190d58aca4ddb7c4720c28eaf497adcae1 | +| **Root State Commit**: 96ff0d9a2b7d8264ea8727d4a104d7372efcfe18dc0c9111aff5c46b688eff04 | +| **Git Commit**: b6e9a988514d13e1e1ecd0802d7e02f9e9b1415b | +| **Branch/Tag**: [v0.27.4](https://github.com/onflow/flow-go/releases/tag/v0.27.4) | +| **Docker Image Tag**: v0.27.4 | + +## Mainnet 18 + +| Spork Info | +| :-------------------------------------------------------------------------------------- | +| **Access Node**: access-001.mainnet18.nodes.onflow.org:9000 | +| **Date**: Jun 15, 2022 | +| **Root Height**: 31735955 | +| **Root Parent ID**: 716d54edbb3d9b2ad290709a516f1ffe4290c7b7b33a49bd0480e0b193a45884 | +| **Root State Commit**: 5bdae9f5fb4cc5d63075547df5502e2bc3cb20707452389fb89ebbe71ecf7b68 | +| **Git Commit**: fdc732183233f1c577a9e529da6b453364431301 | +| **Branch/Tag**: [v0.26.9](https://github.com/onflow/flow-go/releases/tag/v0.26.9) | +| **Docker Image Tag**: v0.26.9 | + +## Mainnet 17 + +| Spork Info | +| :-------------------------------------------------------------------------------------- | +| **Access Node**: access-001.mainnet17.nodes.onflow.org:9000 | +| **Date**: Apr 6, 2022 | +| **Root Height**: 27341470 | +| **Root Parent ID**: dd7ed04e14559ed47ecc92896a5cb3dbb6b234065d9be7f816d99602238762aa | +| **Root State Commit**: 113e752ec0619b63187630b4fae308ec5405a00f56f25c2de0b139e283a95b14 | +| **Git Commit**: 5226c35eb14890db024b9193793b0c49d1b5ad04 | +| **Branch/Tag**: [v0.25.7](https://github.com/onflow/flow-go/releases/tag/v0.25.7) | +| **Docker Image Tag**: v0.25.7 | + +## Mainnet 16 + +| Spork Info | +| :-------------------------------------------------------------------------------------- | +| **Access Node**: access-001.mainnet16.nodes.onflow.org:9000 | +| **Date**: Feb 9, 2022 | +| **Root Height**: 23830813 | +| **Root Parent ID**: b0e7a891682dce277a41e87e2cef52af344ac614bf70c82a5a3a801e63960e88 | +| **Root State Commit**: 8964d1f74c2bed2d0fbb4a366fff1fd3c39b71653e9de4d4512090798631e5f8 | +| **Git Commit**: c78cac3573e0548611f29df7cfa2db92203554c1 | +| **Branch/Tag**: [v0.24.4](https://github.com/onflow/flow-go/releases/tag/v0.24.4) | +| **Docker Image Tag**: v0.24.4 | + +## Mainnet 15 + +| Spork Info | +| :-------------------------------------------------------------------------------------- | +| **Access Node**: access-001.mainnet15.nodes.onflow.org:9000 | +| **Date**: Dec 8, 2021 | +| **Root Height**: 21291692 | +| **Root Parent ID**: 8a28ddc6653a8991435dfbc95103d6be1a3b653cda3d664681215ee93112a203 | +| **Root State Commit**: 84d9b325d3f48f7f075eea0db6c246cb5adc759a2dd8561e461477a7ca1f7f22 | +| **Git Commit**: bfde54ae3324db5d18ebeaa22c70b5574a114f2e | +| **Branch/Tag**: [v0.23.4](https://github.com/onflow/flow-go/releases/tag/v0.23.4) | +| **Docker Image Tag**: v0.23.4 | + +## Mainnet 14 + +| Spork Info | +| :-------------------------------------------------------------------------------------- | +| **Access Node**: access-001.mainnet14.nodes.onflow.org:9000 | +| **Date**: Oct 6, 2021 | +| **Root Height**: 19050753 | +| **Root Parent ID**: ac4dbf344ce96e39e15081f1dc3fbbf6dc80532e402de9a57af847d3b35df596 | +| **Root State Commit**: 641eb088e3ce1a01ff56df2d3a14372c65a7fef44c08799eb92cd7759d1d1d2a | +| **Git Commit**: f019c1dbd778ce9f92dea61349ca36003678a9ad | +| **Branch/Tag**: [v0.22.9-patch-1-epoch-view-check-hotfix](https://github.com/onflow/flow-go/releases/tag/v0.22.9-patch-1-epoch-view-check-hotfix) | +| **Docker Image Tag**: v0.22.9-patch-1-epoch-view-check-hotfix | + +## Mainnet 13 + +| Spork Info | +| :-------------------------------------------------------------------------------------- | +| **Access Node**: access-001.mainnet13.nodes.onflow.org:9000 | +| **Date**: Sept 15, 2021 | +| **Root Height**: 18587478 | +| **Root Parent ID**: 2f708745fff4f66db88fac8f2f41d496edd341a2837d3e990e87679266e9bdb8 | +| **Root State Commit**: 51e3098d327df22fd005d960cb73167c83cb438c53e6c4363c07d8611ae44528 | +| **Git Commit**: 9535540110a4452231d044aceabab0e60f67708c | +| **Branch/Tag**: [v0.21.3](https://github.com/onflow/flow-go/releases/tag/v0.21.3) | +| **Docker Image Tag**: v0.21.3 | + +## Mainnet 12 + +| Spork Info | +| :-------------------------------------------------------------------------------------- | +| **Access Node**: access-001.mainnet12.nodes.onflow.org:9000 | +| **Date**: Aug 18, 2021 | +| **Root Height**: 17544523 | +| **Root Parent ID**: f6ca04ba5c6fa6ba690a77202a9fad8d3ec30c67762ae065f0f0f53e8fed84d0 | +| **Root State Commit**: b5cf1977b12de699d0e777af5be25095653735a153d1993f97ff07804b070917 | +| **Git Commit**: 4a0c10d74f1bcaadfdfec8c325efa411acd1a084 | +| **Branch/Tag**: [v0.20.5](https://github.com/onflow/flow-go/releases/tag/v0.20.5) | +| **Docker Image Tag**: v0.20.5 | + +## Mainnet 11 + +| Spork Info | +| :-------------------------------------------------------------------------------------- | +| **Access Node**: access-001.mainnet11.nodes.onflow.org:9000 | +| **Date**: July 21, 2021 | +| **Root Height**: 16755602 | +| **Root Parent ID**: de15461988000eddc6e507dc7b159dcd192ee3aa72f3bd3b0e31ae9c6538399f | +| **Root State Commit**: 4eb91bf34cb65b7537a6a95806f444f409308b2eaaa0ad28d1924b6cb8afa140 | +| **Git Commit**: 2644560c0562412a3c2209820be07f8f3f8b1846 | +| **Branch/Tag**: [v0.19.2](https://github.com/onflow/flow-go/releases/tag/v0.19.2) | +| **Docker Image Tag**: v0.19.2 | + +## Mainnet 10 + +| Spork Info | +| :-------------------------------------------------------------------------------------- | +| **Access Node**: access-001.mainnet10.nodes.onflow.org:9000 | +| **Date**: June 23, 2021 | +| **Root Height**: 15791891 | +| **Root Parent ID**: 1d4109bbb364d5cdd94640546dd1c423d792d962284665233d541e4ade921726 | +| **Root State Commit**: 9b6a1a5ab52fd3d5a19ea22f09cb607bba63671311f157b3e604dd265efb851a | +| **Git Commit**: 01f53ebd7df3101e337d9212736cff6ab1e0056d | +| **Branch/Tag**: [v0.18.4](https://github.com/onflow/flow-go/releases/tag/v0.18.4) | +| **Docker Image Tag**: v0.18.4 | + +## Mainnet 9 + +| Spork Info | +| :-------------------------------------------------------------------------------------- | +| **Access Node**: access-001.mainnet9.nodes.onflow.org:9000 | +| **Date**: May 26, 2021 | +| **Root Height**: 14892104 | +| **Root Parent ID**: 265d10ba3e36ed6539fd4d7f4322735aad4997c0378d75783e471437dd83ef33 | +| **Root State Commit**: fcc30a6664337ef534ad544ad7b17c5cc3b5470a8ef0d93f18573fddf6b25c4a | +| **Git Commit**: 2d81520c49a8865fa686c32c508d2261155c86bc | +| **Branch/Tag**: [v0.17.4](https://github.com/onflow/flow-go/releases/tag/v0.17.4) | +| **Docker Image Tag**: v0.17.4 | + +## Mainnet 8 + +| Spork Info | +| :-------------------------------------------------------------------------------------- | +| **Access Node**: access-001.mainnet8.nodes.onflow.org:9000 | +| **Date**: April 28, 2021 | +| **Root Height**: 13950742 | +| **Root Parent ID**: faa2a3a996c6efcc3ef562fe03d797e4b19dbe00f6beab082d6d37a447044abd | +| **Root State Commit**: 259836c7f74e6bbb803c9cfb516044bc701d99c2840e9b9f89609464867e7f0f | +| **Git Commit**: 4e733ba2038512e9d80bcd955e67e88ba6e3ecf2 | +| **Branch/Tag**: v0.16.2 | +| **Docker Image Tag**: v0.16.2 | + +## Mainnet 7 + +| Spork Info | +| :-------------------------------------------------------------------------------------- | +| **Access Node**: access-001.mainnet7.nodes.onflow.org:9000 | +| **Date**: April 7, 2021 | +| **Root Height**: 13404174 | +| **Root Parent ID**: 8b969d0babbb7d2043957b3d55a811f2c13344faa76565096d4ad901a466ecaa | +| **Root State Commit**: 1247d74449a0252ccfe4fd0f8c6dd98e049417b3bffc3554646d92f810e11542 | +| **Git Commit**: b6f47fd23ffe31e2fe714c6bff0b17d901e210b4 | +| **Branch/Tag**: v0.15.3-patch.4 | +| **Docker Image Tag**: v0.15.3-patch.4 | + +Releases compatible with Mainnet 7: No change from Mainnet 6 + +## Mainnet 6 + +| Spork Info | +| :-------------------------------------------------------------------------------------- | +| **Access Node**: access-001.mainnet6.nodes.onflow.org:9000 | +| **Date**: Mar 10, 2021 | +| **Root Height**: 12609237 | +| **Root Parent ID**: c68e63ca5b6f7ff61ef2b28d7da528c5b677b0f81f2782f067679c108d77932b | +| **Root State Commit**: ddfedbfaa2d858e6a8e3b142381a91b289f50e45622f5b5a86ac5c00ce61bf11 | +| **Git Commit**: c887bd343ca7db6351690007b87bec40d39d7b86 | +| **Branch/Tag**: v0.14.9 | +| **Docker Image Tag**: v0.14.9 | + +Releases compatible with Mainnet 6: + +### Network Implementations + +Flow Go: https://github.com/onflow/flow-go/releases/tag/v0.14.9
    +Emulator: https://github.com/onflow/flow-emulator/releases/tag/v0.16.1
    + +Emulator v0.16.1 is distributed in Flow CLI v0.15.0: https://github.com/onflow/flow-cli/releases/tag/v0.15.0 + +### SDK Compatibility + +#### Flow Go SDK + +Minimum version: https://github.com/onflow/flow-go-sdk/releases/tag/v0.16.1
    +Recommended version: https://github.com/onflow/flow-go-sdk/releases/tag/v0.16.1
    + +#### FCL (Flow Client Library) + +Minimum version: [v0.0.66](https://github.com/onflow/fcl-js/blob/master/packages/fcl/CHANGELOG.md#0066---2020-11-09)
    +Recommended version: [v0.0.67](https://github.com/onflow/fcl-js/blob/master/packages/fcl/CHANGELOG.md#0067-alpha0---2020-11-17) + +While FCL v0.0.67 is not strictly necessary to use Mainnet 6, we strongly recommend upgrading in order to adapt to wallet improvements that were introduced in v0.0.67. + +--- + +## Mainnet 5 + +| Spork Info | +| :--------------------------------------------------------------------------------------------------- | +| **Access Node**: access-001.mainnet5.nodes.onflow.org:9000 | +| **Date**: Feb 17, 2021 | +| **Root Height**: 12020337 | +| **Root Parent ID**: 9131733835702b0d6321088bddb4642a4964bb5c630440ccb0de47bdbc371d1a | +| **Root State Commit**: 54bef048a6c5574ef4eb452dd2698aeb2fe5eca6edd536aca6d0bc631c2daaa9 | +| **Git Commit**: 027569a9d76e41b1140b189fa1b9187c711ab241 | +| **Branch/Tag**: v0.14.1 for Access, Verification, Collection and v0.14.2 for Consensus and Execution | +| **Docker Image Tag**: v0.14.1 / v0.14.2 | + +--- + +## Mainnet 4 + +| Spork Info | +| :------------------------------------------------------------------------------------- | +| **Access Node**: access-001.mainnet4.nodes.onflow.org:9000 | +| **Date**: Dec 16, 2020 | +| **Root Height**: 9992020 | +| **Root Parent ID**: 691e35a4ac4d0d47e1be1ec81512ac9f6cdd04545b908fad1d6ceea58c76b560 | +| **Root State Commit**: 0011fda57f2f3aaa8e6bcc1e1deea9778a9543252f8b65bbd4ebca3687789420 | +| **Git Commit**: f4a73c7f20109209e9e2e999cf50fcf1ec41241b | +| **Branch/Tag**: v0.13.1 | +| **Docker Image Tag**: v0.13.1 | + +--- + +## Mainnet 3 + +| Spork Info | +| :------------------------------------------------------------------------------------- | +| **Access Node**: access-001.mainnet3.nodes.onflow.org:9000 | +| **Date**: Dec 9, 2020 | +| **Root Height**: 9737133 | +| **Root Parent ID**: 116751c904a7f868cd6e8c90522fdbd70fe826db6886b830338c68c6339df3e7 | +| **Root State Commit**: 1d2c91e801d0560024848a0c981e03120efc372436ada5f7909c4d44d4600f04 | +| **Git Commit**: badd5887512b955e7aa18b4e73dae980ca72fa22 | +| **Branch/Tag**: v0.12.6 | +| **Docker Image Tag**: v0.12.6 | + +--- + +## Mainnet 2 + +| Spork Info | +| :------------------------------------------------------------------------------------- | +| **Access Node**: access-001.mainnet2.nodes.onflow.org:9000 | +| **Date**: Nov 13, 2020 | +| **Root Height**: 8742959 | +| **Root Parent ID**: b35fdb189d21a95df7f19f941786f748d9854a8b93b1e555b51cda7d9f53a6e1 | +| **Root State Commit**: d6a25be552ed93213df0ffc2e8c7f39f6401c04cbf22bac7a4b84d3c9493f005 | +| **Git Commit**: 4ef68efb935c0e3393ae3966752ece5e7739bab4 | +| **Branch/Tag**: v0.11.1 | +| **Docker Image Tag**: v0.11.1 | + +--- + +## Mainnet 1 + +| Spork Info | +| :------------------------------------------------------------------------------------- | +| **Access Node**: access-001.mainnet1.nodes.onflow.org:9000 | +| **Date**: Oct 13, 2020 | +| **Root Height**: 7601063 | +| **Root Parent ID**: ab1ee18b6e1c0ee11cc021c26a17c694c627699a576e85f7013cd743bdbc7877 | +| **Root State Commit**: 6e1adf15689eaf5ea6859bcdd0b510f5eb4c34dac878d8577b3f65bc20c3f312 | +| **Git Commit**: 114d45436e7d9052e910c98a1e40f730e3fd12d7 | +| **Branch/Tag**: v0.10.1 | +| **Docker Image Tag**: v0.10.1 | + +--- + +## Candidate 9 + +| Spork Info | +| :------------------------------------------------------------------------------------- | +| **Access Node**: access-001.candidate9.nodes.onflow.org:9000 | +| **Date**: Sep 25, 2020 | +| **Root Height**: 6483246 | +| **Root Parent ID**: 9131733835702b0d6321088bddb4642a4964bb5c630440ccb0de47bdbc371d1a | +| **Root State Commit**: 90c6f406f5d21880d525ad4702cb249509b85e7f745db2de67e9fe541a56da4c | +| **Git Commit**: v0.9.3 | +| **Branch/Tag**: v0.9.3 | +| **Docker Image Tag**: | + +--- + +## Candidate 8 + +| Spork Info | +| :------------------------------------------------------------------------------------- | +| **Access Node**: access-001.candidate8.nodes.onflow.org:9000 | +| **Date**: Sep 9, 2020 | +| **Root Height**: 4972987 | +| **Root Parent ID**: 5bc2b0900a5138e39d9209a8fe32e14b3e5c884bd36d2a645620f746b7c8bd47 | +| **Root State Commit**: 6b9161a225b087a461ec95e710fdf4e73f6d6c9401ebf066207a021dced4ce5e | +| **Git Commit**: | +| **Branch/Tag**: | +| **Docker Image Tag**: | + +--- + +## Candidate 7 + +| Spork Info | +| :------------------------------------------------------------------------------------- | +| **Access Node**: access-001.candidate7.nodes.onflow.org:9000 | +| **Date**: Aug 24, 2020 | +| **Root Height**: 4132133 | +| **Root Parent ID**: 28f4f495aad016b519acf27fc9d9a328f6a4009807480e36e2df780eeccd99bc | +| **Root State Commit**: 001d173bfcf9c7f71684da89bff72b3ee582b39a69c7929360230faf73735c17| +| **Git Commit**: f811f8cd49369ae2bc559e0fbb781aff129484f5 | +| **Branch/Tag**: candidate7 | +| **Docker Image Tag**: v0.7.2 | + +--- + +## Candidate 6 + +| Spork Info | +| :------------------------------------------------------------------------------------- | +| **Access Node**: access-001.candidate6.nodes.onflow.org:9000 | +| **Date**: Aug 18, 2020 | +| **Root Height**: 3187931 | +| **Root Parent ID**: 2ff5f7424a448943a153001d2f0869d4fac330906ecb8e17b7ef7fe50e4c7b36 | +| **Root State Commit**: bd7f16dc5ef5eced849ab5f437547c14c1907059e1ecf89a942d0521166c5cbb | +| **Git Commit**: b30c48008c0ec1cc8ecb750aeb9ff9f3d712681d | +| **Branch/Tag**: | +| **Docker Image Tag**: | + +--- + +## Candidate 5 + +| Spork Info | +| :------------------------------------------------------------------------------------- | +| **Access Node**: access-001.candidate5.nodes.onflow.org:9000 | +| **Date**: Jul 28, 2020 | +| **Root Height**: 2033592 | +| **Root Parent ID**: a0efffb2beb1500419ae4f7c6e49bfbbe3a4d1d1c201bf925ccaec467ea30e91 | +| **Root State Commit**: 0190d417a26b9870f5bb2cf408ad31985b3aa7e57f6ababa6e543f0f90b99dcd | +| **Git Commit**: cd876653d20b398952af4002701a0ae2800fd5f2 | +| **Branch/Tag**: | +| **Docker Image Tag**: | + +--- + +## Candidate 4 + +| Spork Info | +|:----------------------------------------------------------------------------------------| +| **Access Node**: access-001.candidate4.nodes.onflow.org:9000 | +| **Date**: Jul 14, 2020 | +| **Root Height**: 1065711 | +| **Root Parent ID**: 68c2bbe68524b50f5d689bc2ac7ad2dd70e88ed7dd15ad6c3cdf6ea314cb1aa3 | +| **Root State Commit**: c05086e4d1d428d3b9af5bd8b81d8780054f783ef4eec3ca28b491202e9ac696 | +| **Git Commit**: b9b197280d6590576f1ef183bc3d04d41d6be587 | +| **Branch/Tag**: | +| **Docker Image Tag**: | + +--- + +## Testnet Upgrades + +> Currently only includes HCUs from 2025. + +## Height Coordinated Upgrade 9 + +| HCU Info | +|:-------------------------------------------------------------------------------------| +| **Date**: April 9, 2025 | +| **Block Height**: 252457666 | +| **Git Commit**: 86c40b1ff20b3b7f17c4017bde083d26303c508d | +| **Branch/Tag**: v0.40.0 | +| **Docker Image Tag**: v0.40.0 | +| **Release Notes**: [v0.40.0](https://github.com/onflow/flow-go/releases/tag/v0.40.0) | + +## Height Coordinated Upgrade 8 + +| HCU Info | +|:-------------------------------------------------------------------------------------| +| **Date**: Feb 18, 2025 | +| **Block Height**: 243615144 | +| **Git Commit**: 4e7e56b3a92e5772279f1304d88dd445c0ea5016 | +| **Branch/Tag**: v0.38.3 | +| **Docker Image Tag**: v0.38.3 | +| **Release Notes**: [v0.38.3](https://github.com/onflow/flow-go/releases/tag/v0.38.3) | + +## Height Coordinated Upgrade 7 + +| HCU Info | +|:-------------------------------------------------------------------------------------| +| **Date**: Feb 14, 2025 | +| **Block Height**: 242883902 | +| **Git Commit**: bcb8a2264fcde9dcd4c997f6b28d8184af19160b | +| **Branch/Tag**: v0.38.2 | +| **Docker Image Tag**: v0.38.2 | +| **Release Notes**: [v0.38.2](https://github.com/onflow/flow-go/releases/tag/v0.38.2) | + +## Height Coordinated Upgrade 6 + +| HCU Info | +|:---------------------------------------------------------| +| **Date**: Feb 11, 2025 | +| **Block Height**: 242365900 | +| **Git Commit**: bcb8a2264fcde9dcd4c997f6b28d8184af19160b | +| **Branch/Tag**: v0.38.1 | +| **Docker Image Tag**: v0.38.1 | +| **Release Notes**: N/A | + +## Height Coordinated Upgrade 5 + +| HCU Info | +|:---------------------------------------------------------------------------------------| +| **Date**: Jan 24, 2025 | +| **Block Height**: 239255500 | +| **Git Commit**: 5f6b25bd02257e3239341c4be0134b007f3deb49 | +| **Branch/Tag**: v0.37.26 | +| **Docker Image Tag**: v0.37.26 | +| **Release Notes**: [v0.37.26](https://github.com/onflow/flow-go/releases/tag/v0.37.26) | + +## Devnet 52 + +| Spork Info | +|:----------------------------------------------------------------------------------------| +| **Date**: Sept 24th, 2024 | +| **Root Height**: 218215349 | +| **Root Parent ID**: 20dd925a750399493cf7455f199c32c952e8010a6c0b4424dba00a193fa18e44 | +| **Root State Commit**: b0498700398cdc8c0c9368cc2f82fde62e8fe4b06e9c8af6c9bb619ab499e6c3 | +| **Git Commit**: 25d9c2a9b89bac8fa003ca67928eb79b1427ea17 | +| **Branch/Tag**: v0.37.16-patch.1 | +| **Docker Image Tag**: v0.37.16-patch.1 | + +## Devnet 51 + +| Spork Info | +|:----------------------------------------------------------------------------------------| +| **Date**: Aug 14th, 2024 | +| **Root Height**: 211176670 | +| **Root Parent ID**: c92e07e5d4fbb3a64e0091085a190a4a1119bfc628c71efe513e373dc0482f5a | +| **Root State Commit**: c3af77992f253f4dcfeac808912ff68e6f10923aa3fc4541a2e39eb9786c9eb3 | +| **Git Commit**: eeac47931cd6837ec6e29c4c0480609238959ccd | +| **Branch/Tag**: v0.37.1 | +| **Docker Image Tag**: v0.37.1 | + +## Devnet 50 + +| Spork Info | +|:----------------------------------------------------------------------------------------------------------------------------| +| **Date**: May 20th, 2024 | +| **Root Height**: 185185854 | +| **Root Parent ID**: cc4800bf44bc07864d156f829cfda2ae1964b5e103de7b9fa1bd879f9e92c10d | +| **Root State Commit**: 6a0ae7bf43660e813ee9c2d654f00476ac1bdc357ff47ad11f0e52fc1700d62f | +| **Git Commit**: 0585789483c4f5ea423bb11afcfe862c9a99711e | +| **Branch/Tag**: v0.33.23-failure-mode-revert-patch | +| **Docker Image Tag**: v0.33.23-failure-mode-revert-patch | + +## Devnet 49 + +| Spork Info | +|:----------------------------------------------------------------------------------------| +| **Date**: Nov 2nd, 2023 | +| **Root Height**: 129578013 | +| **Root Parent ID**: 91b039c1a5caf25776948270a6355017b8841bfb329c87460bfc3cf5189eba6f | +| **Root State Commit**: e10d3c53608a1f195b7969fbc06763285281f64595be491630a1e1bdfbe69161 | +| **Git Commit**: fce4ae31c8c90c6a21de9856a319c379bb797fc5 | +| **Branch/Tag**: v0.32.6-patch.1 | +| **Docker Image Tag**: v0.32.6-patch.1 | + +## Devnet 48 + +| Spork Info | +|:----------------------------------------------------------------------------------------| +| **Date**: Aug 4th, 2023 | +| **Root Height**: 127720466 | +| **Root Parent ID**: 2b30e75bd857f898456dcb296bea4b8bc8001cab7062eeee9e47876411b36d76 | +| **Root State Commit**: f2e5ebfca2fd519e49f7bd85bea81e92eeaa85a705b3376d8534e9c9649da710 | +| **Git Commit**: 692969b1718b3d21f95ee7f66e5061623d99e599 | +| **Branch/Tag**: v0.32.3 | +| **Docker Image Tag**: v0.32.3 | + +## Devnet 47 + +| Spork Info | +|:----------------------------------------------------------------------------------------| +| **Date**: Aug 4th, 2023 | +| **Root Height**: 113167876 | +| **Root Parent ID**: dbd59a00503707c8bc3c5fb3bcc7bd243da4bf8e24c86b6a496505e275b85311 | +| **Root State Commit**: 42006aedbfbfa9fcd949de8347b55166df77d8742bf5f273266a8dfcdf2b836b | +| **Git Commit**: db1c2584d6d8359b7ccf733c16bd5e1b9385c9bc | +| **Branch/Tag**: v0.31.13 | +| **Docker Image Tag**: v0.31.13 | + +## Devnet 46 + +| Spork Info | +|:----------------------------------------------------------------------------------------| +| **Date**: Jun 8th, 2023 | +| **Root Height**: 105155067 | +| **Root Parent ID**: daced0cdeed95cf143320db50ac904ed17dabe04898e988264af2a71e0d1ca48 | +| **Root State Commit**: e8c39b7a1672cb3f5f70da6f1d71a3a0322d3d6c3d7ebf8092ae2ae40d12c30b | +| **Git Commit**: 3d4159e93c92cc6331e69708b8c3270d40c09c5f | +| **Branch/Tag**: v0.31.4 | +| **Docker Image Tag**: v0.31.4 | + +## Devnet 45 + +| Spork Info | +|:----------------------------------------------------------------------------------------| +| **Date**: Jun 7th, 2023 | +| **Root Height**: 105032150 | +| **Root Parent ID**: 71df56106ee1492c055a60e2d951a6a8d1b7d1483b903f10146cec912e793e82 | +| **Root State Commit**: 0e2e053ca4436a4881f65acc031e12820b5260ef616446950650a1bc8fc9be2f | +| **Git Commit**: 8d32e5ea087fcceb0d1aa923c56be1d5a2d6538a | +| **Branch/Tag**: v0.31.2 | +| **Docker Image Tag**: v0.31.2 | + +## Devnet 44 + +| Spork Info | +|:----------------------------------------------------------------------------------------| +| **Date**: Apr 24th, 2023 | +| **Root Height**: 100675451 | +| **Root Parent ID**: 298854580771edc6ec2e2bbc8da3990ff7f746e2fc5cfe16e550d577bdd4bc5b | +| **Root State Commit**: 2a062531331b8214de4e900a26ff0f76c578481b4ce22b4b5d8e55bd9535abda | +| **Git Commit**: b5b65c9d43bf6bd12766eef06e870990c3963b7c | +| **Branch/Tag**: v0.30.6 | +| **Docker Image Tag**: v0.30.6 | + +## Devnet 43 + +| Spork Info | +|:----------------------------------------------------------------------------------------| +| **Date**: Apr 12th, 2023 | +| **Root Height**: 99452067 | +| **Root Parent ID**: 0e6bae31b2f34ffb0d64d4e1a33c2fbcebd80c936d77d70d2f5dd9321dc92393 | +| **Root State Commit**: 7cd69bb0a4448566dce42808efa8b1d03f322135f0bfce6f18037fca1294984c | +| **Git Commit**: d55ca8f48167e9669bdb1dc3173253936863e31e | +| **Branch/Tag**: v0.30.3 | +| **Docker Image Tag**: v0.30.3 | + +## Devnet 42 + +| Spork Info | +|:----------------------------------------------------------------------------------------| +| **Date**: Apr 12th, 2023 | +| **Root Height**: 99444465 | +| **Root Parent ID**: a3788d5c0ff1c45db38bca2625bf18bfc562e1bfdc9ebb7dc83ef080be31e697 | +| **Root State Commit**: a6e5bfc16a39109ef86caad4dab77ec3752680ef3813c3449f239d84fddc5aa1 | +| **Git Commit**: d55ca8f48167e9669bdb1dc3173253936863e31e | +| **Branch/Tag**: v0.30.3 | +| **Docker Image Tag**: v0.30.3 | + +## Devnet 41 + +| Spork Info | +|:----------------------------------------------------------------------------------------| +| **Date**: Jan 30th, 2023 | +| **Root Height**: 93156994 | +| **Root Parent ID**: 26ff2f7f2948a05c63e723eb42946565809b47dbef87079a8f0bae0cc36a0478 | +| **Root State Commit**: 08d712b4f7ed838d53b8699e2fd94d0ad010c4b1fa45735b6e80083ff8ef08ff | +| **Git Commit**: a7f2cd0ddd9fc7e1e56187327a84fec9efdc3c9d | +| **Branch/Tag**: v0.29.8 | +| **Docker Image Tag**: v0.29.8 | + +## Devnet 40 + +| Spork Info | +|:----------------------------------------------------------------------------------------| +| **Date**: Jan 23rd, 2023 | +| **Root Height**: 92473965 | +| **Root Parent ID**: 7c9812f414d9e9795c1cd7dbd27fc45baf880391452e0e948aaa80ba86dfc77d | +| **Root State Commit**: 0068a04843d2c8e007086abaaee90c8c8cae8aa78f240048cd4d43aeb0376d0b | +| **Git Commit**: 7f02a642bb437b45326c4ace54a7f033b32832f8 | +| **Branch/Tag**: v0.29.6 | +| **Docker Image Tag**: v0.29.6 | + +## Devnet 39 + +| Spork Info | +|:----------------------------------------------------------------------------------------| +| **Date**: Jan 4th, 2023 | +| **Root Height**: 90595736 | +| **Root Parent ID**: 3d09b9703019b40a065787fff3dd62e28eafa5efcfb69efbc2d713d73034cf38 | +| **Root State Commit**: afd47ff2a8e73efd51f0cbe7f572eefda25a66e77f1e6b9c4f3f4e7cdc46568f | +| **Git Commit**: e1c172aaee7da9e33828429757b44f51e59368a2 | +| **Branch/Tag**: v0.29.3 | +| **Docker Image Tag**: v0.29.3 | + +## Devnet 38 + +| Spork Info | +|:----------------------------------------------------------------------------------------| +| **Date**: Oct 19th, 2022 | +| **Root Height**: 83007730 | +| **Root Parent ID**: 1b914363c9a34c46b93974adeefb10c546578d7f3f4ac9291e01d746d2c84226 | +| **Root State Commit**: 79df428bc27f22d38c233777610d93d33e180f23cfbc640a95d144a508e0f080 | +| **Git Commit**: 3aae289f8f390f58ac481fd694254ea0e48960a8 | +| **Branch/Tag**: v0.28.4 | +| **Docker Image Tag**: v0.28.4 | + +## Devnet 37 + +| Spork Info | +|:----------------------------------------------------------------------------------------| +| **Date**: Aug 10th, 2022 | +| **Root Height**: 76159167 | +| **Root Parent ID**: 8f379a8a86f28c7adef276890874b17786cecf5efb9e71734b0a780bd38660a0 | +| **Root State Commit**: 7d1fe692ea2f857568dec54ddece094a68a9ba8ff8dd0de0664e6f73abb90dd8 | +| **Git Commit**: 959911cabd50e1a11be45e89726952a90f1a9c22 | +| **Branch/Tag**: v0.27.2 | +| **Docker Image Tag**: v0.27.2 | + +## Devnet 36 + +| Spork Info | +|:----------------------------------------------------------------------------------------| +| **Date**: July 27th, 2022 | +| **Root Height**: 74786360 | +| **Root Parent ID**: 9d9113ca8daa4f3be72e949ea9ead2d4b11db222b2ccd0dc897186ee5f8703ab | +| **Root State Commit**: aa2e12033129f27b5320fb973cf109f562db3ad7ddaf50dbfe9d8cc195a7ac0f | +| **Git Commit**: 13970fcae812bc04487422922f73eab39f53935c | +| **Branch/Tag**: v0.26.17 | +| **Docker Image Tag**: v0.26.17 | + +## Devnet 35 + +| Spork Info | +| :-------------------------------------------------------------------------------------- | +| **Date**: June 9th, 2022 | +| **Root Height**: 70072575 | +| **Root Parent ID**: cd76fd9d5ceb1b98b5f30b0108f40836593c533ffe32eef0c6f3ed6d50bf645b | +| **Root State Commit**: d933d73f48c9371f0a00ab7ffc1ed0daf5ba9e520d2d539e6b9494920c5ffd91 | +| **Git Commit**: 07057c8d5fe2f09bbe5a9a3f8de6209346d910d0 | +| **Branch/Tag**: v0.26.6 | +| **Docker Image Tag**: v0.26.6 | + +## Devnet 34 + +| Spork Info | +| :-------------------------------------------------------------------------------------- | +| **Date**: Apr 4th, 2022 | +| **Root Height**: 64904846 | +| **Root Parent ID**: 0cbb13d9e7ed7092b5f20d0a20a79d1cae96fd796fb2bc569b27ce49cc97d97e | +| **Root State Commit**: f2e77e16628543e285be8bac677db06e17b37f49e53a107af1e6bf99fbc17b30 | +| **Git Commit**: 5226c35eb14890db024b9193793b0c49d1b5ad04 | +| **Branch/Tag**: v0.25.7 | +| **Docker Image Tag**: v0.25.7 | + +## Devnet 33 + +| Spork Info | +| :-------------------------------------------------------------------------------------- | +| **Date**: Feb 7th, 2022 | +| **Root Height**: 59558934 | +| **Root Parent ID**: 099fbb7b645c3441ea830746ed67059bcc1091c88ff3fd78b331137cf917d15f | +| **Root State Commit**: 5b5578cb4ef6c34818ce2cfd9969720c7f17681f41dffa3a9e361935140d7c8e | +| **Git Commit**: bd3dca7bf20914f5c019a325b6939bbb662aa131 | +| **Branch/Tag**: v0.24.3 | +| **Docker Image Tag**: v0.24.3 | + +## Devnet 32 + +| Spork Info | +| :-------------------------------------------------------------------------------------- | +| **Date**: Dec 6th, 2021 | +| **Root Height**: 53376277 | +| **Root Parent ID**: f900db2ccff33f3bf353c8bf28ece0a9d2650f2805b23ddb7893e296774a5457 | +| **Root State Commit**: 843ea0b5498342dcf960376585eeafee8ebe008df3b03325351408a100cb830c | +| **Git Commit**: be20371fa8c5044a4e25e5629bbca91f1ed19731 | +| **Branch/Tag**: v0.23.3 | +| **Docker Image Tag**: v0.23.3 | + +## Devnet 31 + +| Spork Info | +| :-------------------------------------------------------------------------------------- | +| **Date**: Nov 5th, 2021 | +| **Root Height**: 50540412 | +| **Root Parent ID**: cfebaa6b8c19ec48a27eaa84c3469b23255350532b5ea4c7e4c42313386c07b6 | +| **Root State Commit**: 31a2b1eb05a6acb91560970e46b8f3f3171747245eae1ad2bf40290ce773806e | +| **Git Commit**: 3d060b90264d59ccd38b4500ae0cd6d72036cfe4 | +| **Branch/Tag**: v0.23-testnet | +| **Docker Image Tag**: v0.23.1 | + +## Devnet 30 + +| Spork Info | +| :-------------------------------------------------------------------------------------- | +| **Date**: Oct 6th, 2021 | +| **Root Height**: 47330085 | +| **Root Parent ID**: 0ec9172a21f84cbae15761ae4d59ab4a701f9d4fd15cd0632715befc8cf205cf | +| **Root State Commit**: e280f972c72c6b379ec3d4a7173953e596704d8d72f384ef1637d2f4f01ff901 | +| **Git Commit**: f019c1dbd778ce9f92dea61349ca36003678a9ad | +| **Branch/Tag**: v0.22.8-patch-1-scripts-and-errors | +| **Docker Image Tag**: v0.22.8-patch-1-scripts-and-errors | + +## Devnet 29 + +| Spork Info | +| :-------------------------------------------------------------------------------------- | +| **Date**: Oct 5th, 2021 | +| **Root Height**: 47242826 | +| **Root Parent ID**: 00f745576222a1e7e15ee79974b4b3eaddd760fb4f56e846cfaef3cb5ea59d50 | +| **Root State Commit**: 3c5bfb88a3fa184c9981e7677d1f2a2cd0a4eaa581bb2a7867b7b023ae015f38 | +| **Git Commit**: e1659aebc39b4a15c68112227fc8c32788a798b6 | +| **Branch/Tag**: v0.22.8 | +| **Docker Image Tag**: v0.22.8 | + +## Devnet 28 + +| Spork Info | +| :-------------------------------------------------------------------------------------- | +| **Date**: Sept 22, 2021 | +| **Root Height**: 45889254 | +| **Root Parent ID**: 1518c15f7078cb8fd4c636b9fc15ee847ac231a8631ed59a0b8c9d4a182fb5b2 | +| **Root State Commit**: 296001ee05ce3e6c6616ad9bcdc20e6d93d02c91354e57fff6054cff44c5afa3 | +| **Git Commit**: a979f4d25a79630581f6b350ad26730d4012cad4 | +| **Branch/Tag**: v0.21.6 | +| **Docker Image Tag**: v0.21.6 | + +## Devnet 27 + +| Spork Info | +| :-------------------------------------------------------------------------------------- | +| **Date**: Sept 14, 2021 | +| **Root Height**: 45051578 | +| **Root Parent ID**: 8525ac24717b5f42e29172f881e9a7439235e4cd443a8a59494dbecf07b9376a | +| **Root State Commit**: b3ef3b039f722130009b658e3f5faee43b3b9202fec2e976907012994a8fc9be | +| **Git Commit**: 4f903f1d45e6f8c997a60de47de62a74ede3c2e4 | +| **Branch/Tag**: v0.21.3 | +| **Docker Image Tag**: v0.21.3 | + +## Devnet 26 + +| Spork Info | +| :-------------------------------------------------------------------------------------- | +| **Date**: Aug 11, 2021 | +| **Root Height**: 41567027 | +| **Root Parent ID**: ea465f33266be26b21c82ec728c75cc0dcbb022405d83c44ed0082b0df9aa81d | +| **Root State Commit**: 9459485a2a640b1bdc3066916a9a46dc20bf2528a03f06ddc541d34444c3264c | +| **Git Commit**: 781ec414b892e2ccf7034aa263b5b19d97f82031 | +| **Branch/Tag**: v0.20.4 | +| **Docker Image Tag**: v0.20.4 | + +## Devnet 25 + +| Spork Info | +| :-------------------------------------------------------------------------------------- | +| **Date**: July 20, 2021 | +| **Root Height**: 39272449 | +| **Root Parent ID**: 2824828e7c87e1a89bc94daca9497625f1a35c8f9fc555f52d1f8b475179e125 | +| **Root State Commit**: bd50708e7808be0d43725a9eae6039558b32b679c5a584a2e6103bb027dad7eb | +| **Git Commit**: 2644560c0562412a3c2209820be07f8f3f8b1846 | +| **Branch/Tag**: v0.19.2 | +| **Docker Image Tag**: v0.19.2 | + +## Devnet 24 + +| Spork Info | +| :-------------------------------------------------------------------------------------- | +| **Date**: June 22, 2021 | +| **Root Height**: 36290422 | +| **Root Parent ID**: 8d6fad91536ec750d1bb44ebb59e030af2dca49d41c104e45f4f82433184e663 | +| **Root State Commit**: fdfd7a9fff481256972095ffc2c6cba300128f41d8c6aa971985de29427eb39d | +| **Git Commit**: 37d9ae7a309bf7d21063f57fce008d04828d4840 | +| **Branch/Tag**: v0.18.3 | +| **Docker Image Tag**: v0.18.3 | + +## Devnet 23 + +| Spork Info | +| :-------------------------------------------------------------------------------------- | +| **Date**: May 25, 2021 | +| **Root Height**: 33257098 | +| **Root Parent ID**: dafa3e7a9a93de8ceb0a3acd09b2cce4ad0e5d7ea8fe4237f27c4503e5ad416c | +| **Root State Commit**: decf340a722ba136c94ece029e9333d9fbcf216482cd1c81a274365e2abd6688 | +| **Git Commit**: fef838147fa70c94a254183e23e7e79f0d412ef6 | +| **Branch/Tag**: v0.17.3 | +| **Docker Image Tag**: v0.17.3 | + +## Devnet 22 + +| Spork Info | +| :-------------------------------------------------------------------------------------- | +| **Date**: Apr 27, 2021 | +| **Root Height**: 30171528 | +| **Root Parent ID**: 46c7c675f2ed413532009a6a6ecaa566d360a806e033693520d7add147ca89ea | +| **Root State Commit**: d88edf1b2a07dba9ef48214dbffb743c0b2e01f7c74e3e14d828ac076d30f1a6 | +| **Git Commit**: 8331b78d99eddea405076e3b6a7839ec5f6ea209 | +| **Branch/Tag**: v0.16.2 | +| **Docker Image Tag**: v0.16.2 | + +## Devnet 21 + +| Spork Info | +| :-------------------------------------------------------------------------------------- | +| **Date**: Mar 30, 2021 | +| **Root Height**: 26935025 | +| **Root Parent ID**: 3f92949a68c577b6d7d17267f00fc47304d1c44052f0c9a078b63fd344f636dd | +| **Root State Commit**: 21f48748d35178bd6ad89f6324321fa9d123ee7a07b07826acbce887260b2c70 | +| **Git Commit**: 8331b78d99eddea405076e3b6a7839ec5f6ea209 | +| **Branch/Tag**: v0.15.3-patch.1 | +| **Docker Image Tag**: v0.15.3-patch.1 | + +## Devnet 20 + +| Spork Info | +| :------------------------------------------------------------------------------------- | +| **Date**: Mar 9, 2021 | +| **Root Height**: 25450390 | +| **Root Parent ID**: febe212117a83f7f70ed6a5af285ff03332f81a1120ab2c306560c4cb42672f7 | +| **Root State Commit**: 828259e9cb895f7f8a7306debbe6de524500db65cb6b80e27b2db9040513b04e | +| **Git Commit**: b9b197280d6590576f1ef183bc3d04d41d6be587 | +| **Branch/Tag**: v0.14.19 | +| **Docker Image Tag**: v0.14.19 | + +--- + +## Devnet 19 + +| Spork Info | +| :------------------------------------------------------------------------------------- | +| **Date**: Feb 3, 2021 | +| **Root Height**: 16483518 | +| **Root Parent ID**: 4220911048404bd3a7733ab6219531a5945dc20020f86869bcd6422c3a6e3f76 | +| **Root State Commit**: f6eea9b652a7df433b80d8d647ba414aabcfa03153dd1cba33048c27ce888097 | +| **Git Commit**: eb11ae095df6db6e856b1a8e824f03ce4c713b19 | +| **Branch/Tag**: v0.14.0 | +| **Docker Image Tag**: v0.14.0 | + +--- + +## Devnet 18 + +| Spork Info | +| :------------------------------------------------------------------------------------- | +| **Date**: Dec 11, 2020 | +| **Root Height**: 17756122 | +| **Root Parent ID**: 52ace0d0c8d4e574213fe98e19a5043f215bee992659bd1ef35c5758acf54d1b | +| **Root State Commit**: b1412c9d453b1c10d3ace6111e00ac804d564ba3d3295002bedb077685c7da73 | +| **Git Commit**: 115ccee9cae920ee5bc309537cf43a9b152a1cf9 | +| **Branch/Tag**: v0.13.0 | +| **Docker Image Tag**: v0.13.0 | + +--- + +## Devnet 17 + +| Spork Info | +| :------------------------------------------------------------------------------------- | +| **Date**: Nov 27, 2020 | +| **Root Height**: 16483518 | +| **Root Parent ID**: 96d452f9d2a15fafab720f1809fc490b019b23e42c885590e62085e48b8c2b6b | +| **Root State Commit**: 0b45f6055a1f09b413d098997cc0e7c9a0ef19eac8b4d294085b0e2f436c6bff | +| **Git Commit**: ef54713595d0fe1e0bb4b14e9469c4a64dfaf6e7 | +| **Branch/Tag**: v0.12.1 | +| **Docker Image Tag**: v0.12.1 | + + +=== networks/node-ops/node-operation/node-setup.md === +--- +title: Setting Up a Flow Node +sidebar_label: Node Setup +description: How to run a Collection, Consensus, Verification and Execution node +sidebar_position: 12 +--- + +This guide is for running a Collection, Consensus, Verification and Execution node. +If you are planning to run an Access node then refer to [access node setup](../access-nodes/access-node-setup.md). + +First you'll need to provision a machine or virtual machine to run your node software. Please see follow the [node-provisioning](./node-provisioning.md) guide for it. + +## Pull the Flow Images + +The `flow-go` binaries are distributed as container images, and need to be pulled down to your host with your image management tool of choice. + +Replace `$ROLE` with the node type you are planning to run. Valid options are: + +- collection +- consensus +- execution +- verification +- access + +```shell + # Docker + docker pull gcr.io/flow-container-registry/${ROLE}:alpha-v0.0.1 + + # Containerd + ctr images pull gcr.io/flow-container-registry/${ROLE}:alpha-v0.0.1", +``` + +## Prepare Your Node to Start + +Your nodes will need to boot at startup, and restart if they crash. + +If you are running `systemd` you can use the service files provided by `flow-go`. +Find them in the [Flow Go](https://github.com/onflow/flow-go/tree/master/deploy). + +If you are using some other system besides Systemd, you need to ensure that the Flow container is started, +the appropriate key directories are mounted into the container, and that the container will +automatically restart following a crash. + +The `systemd` files pull runtime settings from `/etc/flow/runtime-config.env` and any `.env` +files under `/etc/flow/conf.d`. Examples of these files are also available in the github repo. +You will need to modify the runtime config file later. + +### Systemd + + +If you are not using Systemd, you can skip this step + + +1. Ensure that you pulled the latest changes from [flow-go repository](https://github.com/onflow/flow-go) via `git` + +```shell +## Clone the repo if you haven't already done so +git clone https://github.com/onflow/flow-go + +## Get latest changes +cd flow-go +git pull origin master +``` + +2. Copy your respective [systemd unit file](https://github.com/onflow/flow-go/tree/master/deploy/systemd-docker) to: `/etc/systemd/system` +3. Create directory `sudo mkdir /etc/flow` +4. Copy the [runtime-conf.env](https://github.com/onflow/flow-go/blob/master/deploy/systemd-docker/runtime-conf.env) file to: `/etc/flow/` +5. Enable your service `sudo systemctl enable flow-$ROLE.service` (replace `$ROLE` with your node role - eg. `collection`) + +### Docker Configuration + +If you are not using Systemd, sample commands for running each Docker container are below. +Be sure to replace `/path/to/data` and `/path/to/bootstrap` with the appropriate paths you are using. + +:::warning + +Do not run your node using `docker run` command directly without a mechanism for the node +to automatically restart following a crash. + +::: + +:::info + +The actual Docker image tag can be found [here](./past-upgrades) for appropriate spork. + +::: + +### System Configuration + +Flow nodes create connections to other nodes on the network, which are represented as file descriptors by the OS. Depending on the default +limits for your machine, you may need to increase the soft limit available to the node software. + +Make sure the soft limit is at least `8192`. + +You can configure the ulimit for the node's docker container. See the [Docker documentation](https://docs.docker.com/engine/networks/commandline/run/#ulimit) for more details. + +### Admin Server + +Each node can be configured with an admin server, which allows you to control some of the node's configuration, as well as view some of its internal state. You can find +a few of the commands in the Admin Server [README](https://github.com/onflow/flow-go/blob/master/admin/README.md). Two commands to highlight are: + +* `list-commands`: which returns a list of all of the available commands for your node +* `set-log-level`: which allows you to change the log level of your node at runtime + +You can enable the admin server by passing the `--admin-addr` flag with an interface and port. + +> ⚠️ _IMPORANT: The admin server can modify your node's configuration. DO NOT allow access to untrusted clients._ + +### Access + +```shell +docker run --rm \ + -v /path/to/bootstrap:/bootstrap:ro \ + -v /path/to/data:/data:rw \ + --name flow-go \ + --network host \ + --ulimit nofile=8192 \ + gcr.io/flow-container-registry/access: \ + --nodeid=${FLOW_GO_NODE_ID} \ + --bootstrapdir=/bootstrap \ + --datadir=/data/protocol \ + --secretsdir=/data/secrets \ + --execution-data-dir=/data/execution_data \ + --rpc-addr=0.0.0.0:9000 \ + --http-addr=0.0.0.0:8000 \ + --admin-addr=0.0.0.0:9002 \ + --collection-ingress-port=9000 \ + --script-addr=${FLOW_NETWORK_EXECUTION_NODE} \ + --bind 0.0.0.0:3569 \ + --loglevel=error +``` + +### Collection + +```shell +docker run --rm \ + -v /path/to/bootstrap:/bootstrap:ro \ + -v /path/to/data:/data:rw \ + --name flow-go \ + --network host \ + --ulimit nofile=8192 \ + gcr.io/flow-container-registry/collection: \ + --nodeid=${FLOW_GO_NODE_ID} \ + --bootstrapdir=/bootstrap \ + --datadir=/data/protocol \ + --secretsdir=/data/secrets \ + --ingress-addr=0.0.0.0:9000 \ + --admin-addr=0.0.0.0:9002 \ + --bind 0.0.0.0:3569 \ + --access-node-ids=4e17496619df8bb4dcd579c252d9fb026e54995db0dc6825bdcd27bd3288a990,7e3fe64ccc119f578a7795df8b8c512e05409bdc7de4f74259c6f48351fecb26,416c65782048656e74736368656c009530ef3ab4b8bf83b24df54fe5f81853de,416e647265772042757269616e00d219355d62b9adad8ebd3fab223a1cf84c22 \ + --gossipsub-peer-scoring-enabled=false \ + --gossipsub-peer-gater-enabled=true \ + --loglevel=error +``` + +### Consensus + +```shell +docker run --rm \ + -v /path/to/bootstrap:/bootstrap:ro \ + -v /path/to/data:/data:rw \ + --name flow-go \ + --network host \ + --ulimit nofile=8192 \ + gcr.io/flow-container-registry/consensus: \ + --nodeid=${FLOW_GO_NODE_ID} \ + --bootstrapdir=/bootstrap \ + --datadir=/data/protocol \ + --secretsdir=/data/secrets \ + --admin-addr=0.0.0.0:9002 \ + --bind 0.0.0.0:3569 \ + --access-node-ids=4e17496619df8bb4dcd579c252d9fb026e54995db0dc6825bdcd27bd3288a990,7e3fe64ccc119f578a7795df8b8c512e05409bdc7de4f74259c6f48351fecb26,416c65782048656e74736368656c009530ef3ab4b8bf83b24df54fe5f81853de,416e647265772042757269616e00d219355d62b9adad8ebd3fab223a1cf84c22 \ + --gossipsub-peer-scoring-enabled=false \ + --gossipsub-peer-gater-enabled=true \ + --loglevel=error +``` + +### Execution + +```shell +docker run --rm \ + -v /path/to/bootstrap:/bootstrap:ro \ + -v /path/to/data:/data:rw \ + --name flow-go \ + --network host \ + --ulimit nofile=500000 \ + gcr.io/flow-container-registry/execution: \ + --nodeid=${FLOW_GO_NODE_ID} \ + --bootstrapdir=/bootstrap \ + --datadir=/data/protocol \ + --secretsdir=/data/secrets \ + --triedir=/data/execution \ + --execution-data-dir=/data/execution_data \ + --rpc-addr=0.0.0.0:9000 \ + --admin-addr=0.0.0.0:9002 \ + --bind 0.0.0.0:3569 \ + --loglevel=error +``` + +For execution nodes, it is recommend to increase the open files limit in your operating system. To do that, add the following to your `/etc/security/limits.conf` or the equivalent `limits.conf` for your distribution: + +``` +* hard nofile 500000 +* soft nofile 500000 +root hard nofile 500000 +root soft nofile 500000 +``` + +Restart your machine to apply these changes. To verify that the new limits have been applied, run: + +``` +ulimit -n +``` + +### Verification + +```shell +docker run --rm \ + -v /path/to/bootstrap:/bootstrap:ro \ + -v /path/to/data:/data:rw \ + --name flow-go \ + --network host \ + --ulimit nofile=8192 \ + gcr.io/flow-container-registry/verification: \ + --nodeid=${FLOW_GO_NODE_ID} \ + --bootstrapdir=/bootstrap \ + --datadir=/data/protocol \ + --secretsdir=/data/secrets \ + --admin-addr=0.0.0.0:9002 \ + --bind 0.0.0.0:3569 \ + --loglevel=error +``` + +## Start the Node + +Now that your node is provisioned and configured, it can be started. + + + +Before starting your node, ensure it is [registered](./node-bootstrap.md#step-2---stake-your-node) and [authorized](./node-bootstrap.md#confirming-authorization). + + + +Ensure you start your node at the appropriate time. +See [Spork Process](./spork.md) for when to start up a node following a spork. +See [Node Bootstrap](./node-bootstrap.md#timing) for when to start up a newly registered node. + +### Systemd + +1. Check that your `runtime-conf.env` is at `/etc/flow/runtime-conf.env` +2. Update your environment variables: `source /etc/flow/runtime-conf.env` +3. Start your service: `sudo systemctl start flow` + +## Verify your Node is Running + + +Here are a few handy commands that you can use to check if your Flow node is up and running + +### Systemd + +- To get Flow logs: `sudo journalctl -u flow-YOUR_ROLE` +- To get the status: `sudo systemctl status flow` + +```shell +● flow-verification.service - Flow Access Node running with Docker +Loaded: loaded (/etc/systemd/system/flow-verification.service; enabled; vendor preset: enabled) +Active: active (running) since Wed 2020-05-20 18:18:13 UTC; 1 day 6h ago +Process: 3207 ExecStartPre=/usr/bin/docker pull gcr.io/flow-container-registry/verification:${FLOW_GO_NODE_VERSION} (code=exited, status=0/SUCCESS) +Main PID: 3228 (docker) +Tasks: 10 (limit: 4915) +Memory: 33.0M +CGroup: /system.slice/flow-verification.service + └─3228 /usr/bin/docker run --rm -v /var/flow/bootstrap:/bootstrap:ro -v /var/flow/data:/data:rw --rm --name flow-go --network host gcr.io/flow-container-registry/verification:candidate8 --nodeid=489f8a4513d5bd8b8b093108fec00327b683db545b37b4ea9153f61b2c0c49dc --bootstrapdir=/bootstrap --datadir=/data/protocol --alpha=1 --bind 0.0.0.0:3569 --loglevel=error +``` + +### Docker + +- To get Flow logs: `sudo docker logs flow-go` +- To get the status: `sudo docker ps` + +```shell +$ sudo docker ps +CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES +1dc5d43385b6 gcr.io/flow-container-registry/verification:candidate8 \"/bin/app --nodeid=4…\" 30 hours ago Up 30 hours flow-go +``` + +## Monitoring and Metrics + +This is intended for operators who would like to see what their Flow nodes are currently doing. Head over to [Monitoring Node Health](./monitoring-nodes.md) to get setup. + +### Node Status + +The metrics for the node should be able to provide a good overview of the status of the node. If we want to get a quick snapshot of the status of the node, and if it's properly participating in the network, you can check the `consensus_compliance_finalized_height` or `consensus_compliance_sealed_height` metric, and ensure that it is not zero and strictly increasing. + +```shell +curl localhost:8080/metrics | grep consensus_compliance_sealed_height + +# HELP consensus_compliance_sealed_height the last sealed height +# TYPE consensus_compliance_sealed_height gauge +consensus_compliance_sealed_height 1.132054e+06 +``` + + +=== networks/node-ops/node-operation/node-roles.md === +--- +title: Node Roles +sidebar_position: 11 +--- + +Unlike most blockchains, not all Flow nodes are equal. Flow nodes all specialize and fulfill a specific role in the operation of the network. +Collection, consensus, execution, verification and access nodes are all staked nodes while the observer node is not staked. + +## Collection + +Collection nodes are bandwidth-optimized nodes divided by the protocol into several cooperating Clusters. Their first task is managing the transaction pool and collecting well-formed transactions to propose to Consensus nodes. Transactions are assigned to a cluster pseudorandomly by transaction hash. A well-formed transaction must include credentials from the guarantor of the transaction. When a Collection Node sees a well-formed transaction, it hashes the text of that transaction and signs the transaction to indicate two things: first, that it is well-formed; and second, that it will commit to storing the transaction text until the Execution nodes have finished processing it. Each cluster collects transactions, assembles them into Collections and submits a Collection Guarantee signed by a super-majority of the cluster to the Consensus nodes. + +Collection nodes are required to stake a minimum of 250,000 FLOW to be a confirmed node operator. + +## Consensus + +Consensus nodes form and propose blocks in a manner similar to traditionally-structured proof-of-stake blockchains, using the HotStuff consensus algorithm to create a globally consistent chain of blocks. Consensus nodes validate that the signed collection hashes submitted to them by Collection nodes were, in fact, signed by the required majority of Collection nodes. Thereafter, the Consensus nodes assemble the transactions into blocks and finalize them through voting. +The more participants there are in this process, the more decentralized the network. However, consensus algorithms typically bottleneck the limit to the number of participants. The Flow protocol chose the HotStuff algorithm because it is flexible enough to add participants and currently supports about 100 operators. Adding more than 100 participants to the protocol by adapting HotStuff will continue to be an area of active development. + +Consensus nodes act as checkpoints against other Collection nodes. They are responsible for checking that a critical number of Collection nodes reviewed and signed for the transaction. Collection nodes are held accountable by Consensus nodes. A common concern with proof-of-work- and proof-of-stake based systems is that a small subset of the population of nodes can control important resources such as the mining or stake needed to produce and vote on blocks, which is a degradation of the security of the system. By lowering the requirements to participate, Flow makes it extremely difficult and expensive to coordinate a Byzantine majority of Consensus nodes. + +Consensus nodes have minimal bandwidth and computation requirements, allowing even a modest computing device (any consumer-grade hardware) to participate in the voting process and ensure the safety of the network. Many networks claim open participation, yet substantial resources — stake, computation, or otherwise — are needed to partake. Maintaining such barriers to entry undermines the security of the network. Lowering the participation requirements preserves the security of the network by providing a high degree of byzantine fault tolerance since it becomes exceedingly difficult for a subset of bad actors to subvert the network. + +Consensus nodes are required to stake a minimum of 500,000 FLOW to be a confirmed node operator. + +## Execution + +Execution nodes are the most resource-intensive nodes on the Flow network, responsible for executing transactions and maintaining the Execution State — a cryptographically-verifiable data store for all user accounts and smart contract states — as well as responding to queries related to it. Execution nodes compute the outputs of the blocks they are provided. They then ask the Collection nodes for the collections which contain transactions waiting to be executed. With this data they are able to compute the output, which is later verified by Verification nodes to ensure honesty (allocation of Verification nodes is via a sortition algorithm). The Execution nodes are primarily responsible for Flow's improvements in scale and efficiency because only a very small number of these powerful compute resources are required to compute and store the historical state. + +Execution nodes give the Flow network its performance characteristics: highly scalable within a single shared state environment (i.e., no sharding). However, the significant hardware requirements make them the least accessible option for participation as a Validator. Because the revenue pool splits between relatively few nodes, the revenue per-node should more than compensate for the high capital costs of operating this node. + +An Execution Node presents a hashed commitment once it has computed the output. The output is only revealed once its co-executors have also submitted their outputs. This is important to ensure nodes aren't spoofing each other's work. Once they've all submitted their answers, the output is revealed and subjected to random queries and checks run by Verification nodes. The Execution nodes have relatively low byzantine fault tolerance. However, this does not compromise the overall security of the system because the process they perform is deterministic -- any bad actor will easily be detected and punished by Verification nodes. + +This relatively small group of nodes has the most substantial technical requirements for processor speed and bandwidth because they are tasked with all the computations necessary to determine the output of the network. Allowing for this degree of specialization can reduce computation costs by at least one thousand times, and possibly much more, when compared to Ethereum. + +Execution nodes are required to stake a minimum of 1,250,000 FLOW to be a confirmed node operator. + +## Verification + +Verification nodes are responsible for confirming the correctness of the work done by Execution nodes. Individual Verification nodes only check a small amount of the total computation, but collectively they check every computation many times in parallel. Verification nodes verify Execution Receipts provided by Execution nodes and issue Result Approvals. A sortition algorithm determines which chunks of the Execution Receipt from the Execution nodes the Verification Node must query to check they were computed correctly. Ultimately, these nodes keep the Execution nodes honest; this balance of power maintains the access, security, and verifiability criteria of decentralization. It is highly byzantine fault tolerant because even if there is a substantial number of byzantine errors in the Verification Node +pool, the Consensus nodes are still required to approve that transactions they signed were reviewed by a critical amount of the network. + +Verification nodes are required to stake a minimum of 135,000 FLOW to be a confirmed node operator. + +## Access + +Access nodes act as a proxy to the Flow network. The Access node routes transactions to the correct collection node and routes state queries to execution nodes (while likely caching state to answer queries in a timely manner in the future). Clients submit their transactions to any Access node or run their own if they can't find a service provider they're happy with. + +Access nodes are required to stake 100 FLOW to be a confirmed node operator. However, since an access node does not participate in block production, it does not receive any staking rewards. + +## Observer + +An observer node provides locally accessible, continuously updated, verified copy of the block data. It serves the Access API but unlike an access node, an observer node does not need to be staked, and **anyone** can run it without being added to the approved list of nodes. + +[Get started running an observer node](../light-nodes/observer-node.md) + +## + +Here is a comparison of the different node roles, + +| Role | Staked | Recives Rewards | Permissioned | +| :---------------|:---------------:| :---------------:|:---------------:| +| Collection | Yes | Yes | Yes | +| Consensus | Yes | Yes | Yes | +| Execution | Yes | Yes | Yes | +| Verification | Yes | Yes | Yes | +| Access | Yes | No | No 🆕 | +| Observer | No | No | No | + + +=== networks/node-ops/node-operation/node-provisioning.md === +--- +title: Provisioning a Flow node +sidebar_label: Node Provisioning +description: Hardware, networking and Operating system setup for a Flow node +sidebar_position: 10 +--- + +## Hardware Requirements + +The hardware your Node will need varies depending on the role your Node will play in the Flow network. For an overview of the differences see the [Node Roles Overview](./node-roles.md). + +| Node Type | CPU | Memory | Disk | Example GCP Instance | Example AWS Instance | +|:----------------:| ---------:| ------:| ------:|:--------------:|:--------------:| +| **Collection** | 4 cores | 32 GB | 200 GB | n2-highmem-4 | r6i.xlarge | +| **Consensus** | 2 cores | 16 GB | 200 GB | n2-standard-4 | m6a.xlarge | +| **Execution** | 128 cores | 864 GB | 9 TB (with maintenance see: [pruning chunk data pack](https://forum.flow.com/t/execution-node-upgrade-to-v0-31-15-and-managing-disk-space-usage/5167) or 30 TB without maintenance) | n2-highmem-128 | | +| **Verification** | 2 cores | 16 GB | 200 GB | n2-highmem-2 | r6a.large | +| **Access** | 16 cores | 64 GB | 750 GB | n2-standard-16 | m6i.4xlarge | +| **Observer** | 2 cores | 4 GB | 300 GB | n2-standard-4 | m6i.xlarge | +| **EVM Gateway** | 2 cores | 32 GB | 30 GB | n2-highmem-4 | r6i.xlarge | + +_Note: The above numbers represent our current best estimate for the state of the network. These will be actively updated as we continue benchmarking the network's performance._ + +## Networking Requirements + +Most of the load on your nodes will be messages sent back and forth between other nodes on the network. Make sure you have a sufficiently fast connection; we recommend at _least_ 1Gbps, and 5Gbps is better. + +Each node will require a fixed DNS name and we will refer to this more generally as your 'Node Address' from here on out. + + + Your Node Address must be a publicly routable valid DNS name + that points to your node. This is how other nodes in the network will + communicate with you. + + +Your firewalls must expose **TCP/3569** for both, ingress and egress. + +If you are running an Access Node, you must also expose the GRPC port **9000** to your internal network traffic. Port 9000 is not required for external ingress/egress. + +![Flow Architecture](flow-architecture.png) + +## Operating System Requirements + +The Flow node code is distributed as a Linux container image, so your node must be running an OS with a container runtime like [docker](https://docker.com) or [containerd](https://containerd.io). + +The bootstrapping scripts we'll use later are compiled binaries targeting an `amd64` architecture, so your system must be 64-bit. Some of these scripts are bash based hence a shell interpreter that is bash compatible will also be needed. + +Flow also provides `systemd` service and unit files as a template for installation, though `systemd` is not required to run Flow. + + + Flow is distributed in such a way that makes it very system agnostic. You are + free to build your own orchestration around how you run your nodes and manage + your keys. + + For the remainder of this guide, we cover the most simple case, a single node being + hand deployed. This should give you a good sense of what's needed, and you can + modify to suit your needs from there. + + The Flow team has tested running nodes on Ubuntu 18.04 and GCP's Container + Optimized OS, which is based on Chromium OS. If you are unsure where to start, + those are good choices. + + +## Time synchronization + +You should also ensure you run **time synchronization** on the machine hosting the container, to avoid clock drift. In practice, this means configuring a client for the NTP protocol, and making sure it runs as a daemon. `ntpd` is one recommended example. To configure it, you just have to point it to an NTP server to query periodically. A default from your Linux distribution or cloud operator may already be set, and in the interest of decentralization, our recommendation would be to use it unless you have a specific reason to do otherwise. + + + + - **Leap-smearing**: Leap-smearing time servers and non-leap-smearing time servers are both acceptable for the magnitude of our time precision requirements - though considering very few providers offer leap smearing time servers, a "regular" time server helps ensure our pool of time providers is more diverse. + + - **Why not do it in the container itself? Why do we need to do this?**: Without special privileges and in all major container runtimes, a container will not run with the `CAP_SYS_TIME` capability. For Flow, this means that the node software itself cannot change the time of the host machine, making the in-container use of standard time synchronization protocols ineffective. + + - **Why does time matter in Flow?**: Time information comes up in consensus and in smart contracts. The consensus algorithm of Flow allows nodes to exit the influence of a corrupt or ineffective "leader" node by collectively deciding to switch to the next "phase" of the protocol at the right time. The smart contract language also allows developer access to block time stamps, which provide an approximation of time. To resist manipulation in each case, honest nodes must compute timing values from an aggregate of the information provided by all nodes. That approach, though resilient, is still sensitive to inaccurate time information. In other words, a node subject to clock drift but otherwise honest will not stop the consensus, but might make it slower. + + + +## Setup Data Directories & Disks + +Flow stores protocol state on disk, as well as execution state in the case of execution nodes. + +Where the data is stored is up to you. By default, the `systemd` files that ship with Flow use `/var/flow/data`. +This is where the vast majority of Flow's disk usage comes from, so you may wish to mount this directory on a separate disk from the OS. +The performance of this disk IO is also a major bottleneck for certain node types. +While all nodes need to make use of this disk, if you are running an execution node, you should make sure this is a high performing SSD. + +As a rough benchmark for planning storage capacity, each Flow block will grow the data directory by 3-5KiB. + +### Confidential Data & Files + +Flow stores dynamically generated confidential data in a separate database. We strongly recommend enabling encryption +for this database - see [this guide](./db-encryption-existing-operator.md) for instructions. + +Confidential information used by Flow is stored in the `private-root-information` subtree of the `bootstrap` folder. +In particular: +* the staking private key (`node-info.priv.json`) +* the networking private key (`node-info.priv.json`) +* the encryption key for the secrets database (`secretsdb-key`) +* (if applicable) the initial random beacon private key (`random-beacon.priv.json`) + +These files contain confidential data, and must be stored and accessed securely. + + + +=== networks/node-ops/node-operation/node-providers.md === +--- +sidebar_position: 18 +description: | + Easy access to Flow's blockchain. Providers handle the technical work, letting you use Flow's features without managing nodes yourself. +sidebar_custom_props: + icon: 📚 +--- + +# Node Providers + +## Quick Node + +[QuickNode](https://www.quicknode.com/chains/flow) offers convenient access to Flow's blockchain infrastructure, allowing developers and businesses to utilize Flow's capabilities without the complexities of managing nodes themselves. It offers reliable and fast connectivity to blockchain networks, sparing users from the resource-intensive task of running their own full nodes. + +### Supported Networks + +- Testnet +- Mainnet + +## Tatum + +[Tatum](https://tatum.io/) provides a comprehensive platform that simplifies the process of building, testing, and deploying blockchain applications. With Tatum, users can access infrastructure, an SDK, and a unified API to develop blockchain apps without the need to handle individual blockchain node configuration or maintenance. + +### Supported Networks + +- Testnet +- Mainnet + +=== networks/node-ops/node-operation/node-migration.md === +--- +title: Node Migration +description: How to migrate a Flow node from one machine to another +sidebar_position: 9 +--- + +There are a few different methods to migrate a running Flow node from one machine to the other. + +Choose the method depending upon what part of the staking data of the node is changing. + +### Method 1 - No change to the node staking data + +If there is no change to the network address or the staking and networking keys and only the hardware the node is running needs to be changed then do the following: +1. Stop the Flow node. +2. Copy over the bootstrap data (typically under `/var/flow/bootstrap`) which contains the node private key to the new machine. +3. Copy over the data folder (typically under `/var/flow/data`) which contains the state data. +4. Start the new node on the same network address as the old one. + +:::warning + +Please ensure that there is minimal downtime during this migration. + +::: + +:::warning + +The network address is currently part of the staking data that was submitted for the node. It is how other nodes in the network discover this node. +Hence, the network address of the node must stay the same between epochs otherwise the node will become unreachable for the other nodes and stop functioning. + +::: + +### Method 2 - Network address change + +A change to the node network address (IP or a hostname) can only be done during the spork process. + +To change the networking address: +1. A day before the [upcoming mainnet spork](./upcoming-sporks.md), change the network address for the nodes in Flow Port (using the update network address feature). +The change will not take effect till an epoch transition happens. +2. Change the addresses in the `/var/flow/bootstrap/private-root-information/private-node-info_/node-info.priv.json` json file on the node. +3. A spork also causes an epoch transition, and the new addresses will take effect after the spork immediately. + +### Method 3 - Staking or networking key change + +If the node after migration will be using new staking or networking keys then it needs to be unstaked and then re-staked with the new keys. + +1. Unstake the node via Flow Port. +2. Register the new node via Flow Port with the new staking information. +3. Run the new node with the new keys and network address. It should be able to join the network at the next epoch (see [timing](./node-bootstrap.md#timing)) + +:::warning + +Unstaking a node will result in the node [not earning rewards](../../staking/06-technical-overview.md#staking-operations-available-to-all-stakers) for the next epoch. +Delegators to the old node will have their tokens unstaked automatically. They will also stop earning rewards unless they withdraw their unstaked tokens and delegate them to a different node. + +::: + + +=== networks/node-ops/node-operation/node-economics.md === +--- +title: Node Economics +sidebar_label: Node Economics +description: Node Operator Economics - An illustration +sidebar_position: 8 +--- + +Node operators play a crucial role in securing the Flow network. Here’s a simple example to illustrate what node operators can expect in terms of node economics. + +## Node Operator Economics: An illustration + + +:::warning + +This illustration is strictly to serve as an example. Actual numbers will vary based on several factors. + +For real-time numbers, please refer to the [block explorer](https://www.flowscan.io/tokenomics). + +::: + + +| # | Parameter | Value | Explanation | +| -------- | ------------- | ------------- | ------------- | +| A| Node Operator’s Stake | 500,000 FLOW | Assuming minimum staking requirements for a consensus node. Remember there’s no upper cap on how much FLOW can be staked to a Flow node. | +| B| Delegation to node | 1,000,000 FLOW | Funds that individual/ institutional delegators delegate to your node. Assuming 1M FLOW for this example. | +| C | APY | 10% | Subject to change based on total ecosystem stake in each epoch. Remember APY = R / S, where S = Total FLOW Staked / Total FLOW Supply and R = 5% (”reward rate”) | +| D | Delegation Rate | 8% | Fee taken by the node operator from delegator rewards to cover their operating expenses, currently set at 8% of the rewards received by delegators. Note that the 8% fee is only applied to the staking reward, not to the tokens delegated. | +| E | Annual Staking Rewards | 50,000 FLOW | Product of A x C; the number shown is annualized but is paid each epoch (week). | +| F | Annual Delegator Fee | 8,000 FLOW | Product of B x C x D; ; the number shown is annualized but is paid each epoch (week). | +| G | Annual (Gross) Rewards | 58,000 FLOW | Sum of E and F | +| H | COGS | 4,190 FLOW | Assumed costs of running a consensus node in FLOW assuming 1US$/FLOW. The actual cost will vary depending on several factors such as self-hosted vs cloud, bare metal vs VM, the type of node, the FLOW exchange rate. | +| J | Net Annual Rewards | 53,810 FLOW | G less H | + +## Note + +1. Each year, 5% of the total Flow supply is distributed as rewards to incentivize validators and delegators. While the total rewards for each epoch are fixed, the rewards for individual stakers vary depending on the amount they stake and the total funds delegated to their node. +2. All Flow node types follow the same economic principles, with the only difference being their minimum staking requirements. For details on the minimum stakes needed for each node type, see [here](https://flow.com/flow-tokenomics/technical-overview). + + + +=== networks/node-ops/node-operation/node-bootstrap.md === +--- +title: Node Bootstrap +sidebar_label: Node Bootstrapping +description: How to get started running a node on Flow +sidebar_position: 8 +--- + +This guide is for getting a new node staked and running on Flow other than a permissionless Access node. For running a permissionless Access node see [Access node setup](../access-nodes/access-node-setup.md). For sporking documentation for existing node operators, see [Spork Process](./spork.md). + +## Timing + +New nodes are able to join the network each time a new epoch begins. +In order to join the network at epoch N+1, the node must be registered with sufficient stake and +authorized by the service account prior to the end of epoch N's Staking Auction Phase. +Confirmation of a new node's inclusion in epoch N+1 is included in the [`EpochSetup` event](../../staking/05-epoch-scripts-events.md#flowepochepochsetup). + +Nodes registered for epoch N+1 are able to participate in network communication on a limited basis starting in the `Epoch Setup Phase` of epoch N. + +![Flow Epoch Schedule](https://storage.googleapis.com/flow-resources/documentation-assets/epoch-startup-order.png) + +Once registered and confirmed to join the network at epoch N+1, the node must start up **before** epoch N+1 begins. +* Verification & Access nodes may start up any time during the `Epoch Setup Phase`. +* Consensus & Collection nodes must start up within the first **1000 views (~30mins)** +of the `Epoch Setup Phase` to participate in the [Epoch Preparation Protocol](../../staking/04-epoch-preparation.md#phase-1-epoch-setup). + +## Step 1 - Run Genesis Bootstrap + +:::info + + You will need to run this process for each node that you are operating + +::: + +### Download the Bootstrapping Kit + +:::warning + +If you have downloaded the bootstrapping kit previously, ensure you check the hash below still matches. If not, re-download to ensure you are using the most up-to-date version. + +::: + +```shell +curl -sL -O storage.googleapis.com/flow-genesis-bootstrap/boot-tools.tar +tar -xvf boot-tools.tar +chmod +x ./boot-tools/bootstrap +chmod +x ./boot-tools/transit +``` + +```shell CheckSHA256 +sha256sum ./boot-tools/bootstrapcmd +460cfcfeb52b40d8b8b0c4641bc4e423bcc90f82068e95f4267803ed32c26d60 ./boot-tools/bootstrap + +sha256sum ./boot-tools/transit +f146bdc82ce0cce73c0fb9de284b2e2639e851120f8b89a1dd9368e8442123b4 ./boot-tools/transit +``` + +### Generate Your Node Keys + +#### Network Address + +:::info + +Use a fully qualified domain name for the network address. Please also include the port number in the network address e.g. `example.com:3569` + +::: + +:::warning + +Do not include in `http://` format. + +::: + +:::info + +If you are running multiple nodes, please +ensure you have different addresses for each node. + +::: + +:::warning + +All your current keys and Flow genesis files should be in the `bootstrap` +folder created earlier. Please take a back up of the entire folder. + +::: + + +```shell +## Skip this section if this is your first time ## +# If you joined our network previously, make sure to take a backup of your previously generated keys! +cp -r /path/to/bootstrap /path/to/bootstrap.bak +######################################################### +# Generate Keys +$ mkdir ./bootstrap +# YOUR_NODE_ADDRESS: FQDN associated to your instance (do NOT use an IP address, use a hostname) +# YOUR_NODE_ROLE: The Flow nodes that you wish to run, it should be ONE of the following - [ access, collection, consensus, execution, verification ] +$ ./boot-tools/bootstrap key --address \"YOUR_NODE_ADDRESS_GOES_HERE:3569\" --role YOUR_NODE_ROLE_GOES_HERE -o ./bootstrap + +``` + +```shell Example +$./boot-tools/bootstrap key --address "consensus-001.nodes.flow.com:3569" --role consensus -o ./bootstrap + DBG will generate networking key + INF generated networking key + DBG will generate staking key + INF generated staking key + DBG will generate db encryption key + INF generated db encryption key + DBG assembling node information address=consensus-001.nodes.flow.com:3569 + DBG encoded public staking and network keys networkPubKey=7f31ae79017a2a58a5e59af9184f440d08885a16614b2c4e361019fa72a9a1a42bf85b4e3f9674782f12ca06afd9782e9ccf19496baed069139385b82f8f40f6 stakingPubKey=829d086b292d84de8e7938fd2fafa8f51a6e025f429291835c20e59d9e25665febf24fa59de12a4df08be7e82c5413180cc7b1c73e01f26e05344506aaca4fa9cc009dc1c33f8ba3d7c7509e86d3d3e7341b43b9bf80bb9fba56ae0b3135dd72 + INF wrote file bootstrap/public-root-information/node-id + INF wrote file bootstrap/private-root-information/private-node-info_ab6e0b15837de7e5261777cb65665b318cf3f94492dde27c1ea13830e989bbf9/node-info.priv.json + INF wrote file bootstrap/private-root-information/private-node-info_5e44ad5598bb0acb44784f629e84000ffea34d5552427247d9008ccf147fb87f/secretsdb-key + INF wrote file bootstrap/public-root-information/node-info.pub.ab6e0b15837de7e5261777cb65665b318cf3f94492dde27c1ea13830e989bbf9.json + DBG will generate machine account key + INF generated machine account key + DBG assembling machine account information address=consensus-001.nodes.flow.com:3569 + INF encoded machine account public key for entry to Flow Port machineAccountPubKey=f847b8406e8969b869014cd1684770a8db02d01621dd1846cdf42fc2bca3444d2d55fe7abf740c548639cc8451bcae0cd6a489e6ff59bb6b38c2cfb83e095e81035e507b02038203e8 + INF wrote file bootstrap/private-root-information/private-node-info_ab6e0b15837de7e5261777cb65665b318cf3f94492dde27c1ea13830e989bbf9/node-machine-account-key.priv.json + +$tree ./bootstrap/ +./bootstrap +├── private-root-information +│ └── private-node-info_ab6e0b15837de7e5261777cb65665b318cf3f94492dde27c1ea13830e989bbf9 +│ ├── node-info.priv.json +│ ├── node-machine-account-key.priv.json +│ └── secretsdb-key +└── public-root-information + ├── node-id + └── node-info.pub.ab6e0b15837de7e5261777cb65665b318cf3f94492dde27c1ea13830e989bbf9.json + +3 directories, 4 files +``` + +:::info + +For `consensus` and `collection` node types an additional key will be created for the Machine Account. +For all other node types this will not be needed. + +::: + +#### Machine Account Creation + +If you are running a collection and consensus node, you will have an additional private key file (`node-machine-account-key.priv.json`) +which contains the private key for your node's machine account. You can learn more about machine +accounts [here](../../staking/11-machine-account.md). + +In Step 2 of this guide, when you submit a transaction to stake your node, you will need to provide the +machine account public key, which can be found in the output of the previous `bootstrap key` command. + +```shell MachineAccountPublicKey +$./boot-tools/bootstrap key --address YOUR_NODE_ADDRESS_GOES_HERE --role YOUR_NODE_ROLE_GOES_HERE -o ./bootstrap +... + DBG encoded public machine account key machineAccountPubKey=1b9c00e6f0930792c5738d3397169f8a592416f334cf11e84e6327b98691f2b72158b40886a4c3663696f96cd15bfb5a08730e529f62a00c78e2405013a6016d + INF wrote file bootstrap/private-root-information/private-node-info_ab6e0b15837de7e5261777cb65665b318cf3f94492dde27c1ea13830e989bbf9/node-machine-account-key.priv.json +``` + +:::warning + +Copy the machine account public key somewhere safe. You will need it in a later step. + +::: + +## Step 2 - Stake Your Node + +Stake your node via [Flow Port](https://port.onflow.org/) + +The `node details` (`Node ID`, `Network Address`, `Networking Key` and `Staking Key`) that need to be submitted when staking the node on Flow Port, can be found in the file: `./bootstrap/public-root-information/node-info.pub..json`. + +```shell Example +$cat ./bootstrap/public-root-information/node-info.pub.39fa54984b8eaa463e129919464f61c8cec3a4389478df79c44eb9bfbf30799a.json +{ + "Role": "consensus", + "Address": "consensus-001.nodes.flow.com:3569", + "NodeID": "39fa54984b8eaa463e129919464f61c8cec3a4389478df79c44eb9bfbf30799a", + "Weight": 0, + "NetworkPubKey": "d92e3d5880abe233cf9fe9104db34bbb31251468a541454722b3870c04156a1b0504aef443bcaad124b997384b8fe7052847ce1e6189af1392d865e6be69835b", + "StakingPubKey": "917826e018f056a00b778a58ae83054906957ffd4b6f1b7da083551f7a9f35e02b76ace50424ed7d2c9fc69207a59f0f08a031048f5641db94e77d0648b24d150dedd54bab7cd44b4aa60cfd54be418647b0b3965f8ae54c0bcb48ae9d705162" +} +``` + +If you are running a collection or consensus node, you will need to provide an additional field `Machine Account Public Key`. +This value is found in the output of the `bootstrap key` command from Step 1. + +Staking a collection or consensus node will also create a machine account for the node. The machine account will be mentioned in the output of the staking transaction displayed by Flow Port. Please save the machine account for the next step. + +:::info + +Please let us know your node id via discord or email. + +::: + +### Finalize Machine Account Setup + +:::warning + +If you are not running a collection or consensus node, you can skip this step. + +::: + +You will now need to use the `bootstrap` utility to run `machine-account` with the created address to finalize the set up of your Machine account. + +```shell +$ ./boot-tools/bootstrap machine-account --address YOUR_MACHINE_ACCOUNT_ADDRESS_GOES_HERE -o ./bootstrap +``` + +```shell Example +$ ./boot-tools/bootstrap machine-account --address 0x1de23de44985c7e7 -o ./bootstrap + INF read machine account private key json + DBG encoded public machine account key machineAccountPubKey=2743786d1ff1bf7d7026d693a774210eaa54728343859baab62e2df7f71a370651f4c7fd239d07af170e484eedd4f3c2df47103f6c39baf2eb2a50f67bbcba6a + INF wrote file bootstrap/private-root-information/private-node-info_6f6e98c983dbd9aa69320452949b81abeab2ac591a247f55f19f4dbf0b477d26/node-machine-account-info.priv.json + +$tree ./bootstrap/ +./bootstrap +├── private-root-information +│ └── private-node-info_d60bd55ee616c5c297cae1d5cfb7f65e7e04014d9c4abe595af2fd83f3cfe160 +│ ├── node-info.priv.json +│ ├── node-machine-account-info.priv.json +│ ├── node-machine-account-key.priv.json +│ └── secretsdb-key +└── public-root-information + ├── node-id + └── node-info.pub.d60bd55ee616c5c297cae1d5cfb7f65e7e04014d9c4abe595af2fd83f3cfe160.json + +3 directories, 5 files +``` + +After running this step, you should see the `node-machine-account-info.priv.json` file in your `bootstrap` directory as shown above. + +### Verify Machine Account Setup + +After finalizing your machine account setup, you should verify its correctness with the `check-machine-account` command: + +```shell CheckMachineAccount +$ ./boot-tools/bootstrap check-machine-account --access-address access.mainnet.nodes.onflow.org:9000 -o ./bootstrap + DBG read machine account info from disk hash_algo=SHA3_256 key_index=0 machine_account_address=0x284463aa6e25877c machine_account_pub_key=f847b84051bad4512101640772bf5e05e8a49868d92eaf9ebed41030881d95485769afd28653c5c53216cdcda4554384bb3ff6396a2ac04842422d55f0562496ad8d952802038203e8 signing_algo=ECDSA_P256 + DBG checking machine account configuration... machine_account_address=0x284463aa6e25877c role=consensus + DBG machine account balance: 0.10000000 + INF 🤖 machine account is configured correctly +``` + +This command will detect and provide information about common misconfigurations, or confirm that the machine account is configured correctly. + +### Push transit keys (consensus node only) + +If you are running a consensus node, run the following command to generate the transit keys. + +```shell transit +$ ./boot-tools/transit prepare -b ./bootstrap -r consensus + INF running prepare + INF generating key pair + INF completed preparation role=consensus +``` + +This will generate the public and private transit keys under the bootstrap folder. +The transit keys are used to transfer the DKG keys after a network upgrade. + +Please share the **public** transit key with the Flow Foundation via [discord](https://discord.gg/flow) or [email](mailto::governance@flow.com). + +## Step 3 - Start Your Flow Node + +Ensure you have configured your node using the [Node Setup guide](./node-setup.md). + +### Confirming authorization + +You can confirm your node's successful registration and authorization by executing a Cadence script to query the [Staking Contract](../../../build/core-contracts/06-staking-contract-reference.md#contract). +At the end of the `Staking Auction Phase`, the members of the Proposed Identity Table are confirmed as authorized participants in the next epoch. +Therefore, if your node ID appears in the Proposed Identity Table during the `Staking Auction Phase`, your node will be a participant in the next epoch. + +You can read the current Proposed Identity Table using the [getProposedTable script](https://github.com/onflow/flow-core-contracts/blob/master/transactions/idTableStaking/scripts/get_proposed_table.cdc). + +You can read the current epoch phase using the [getEpochPhase script](https://github.com/onflow/flow-core-contracts/blob/master/transactions/epoch/scripts/get_epoch_phase.cdc). (A return value of `0` indicates the `Staking Auction Phase`.) + +### Trusted Root Snapshot + +Once your node has been registered and authorized by the service account, it will be able to participate in the next epoch. + +![Flow Epoch Schedule](https://storage.googleapis.com/flow-resources/documentation-assets/epoch-startup-order.png) + +A new node must bootstrap with a trusted root snapshot of the protocol state, where the node is a confirmed participant. +Since new nodes are confirmed at the end of the `Staking Auction Phase`, this means that, if the node is registered to join at epoch `N+1`, it must use a root snapshot from within the `Epoch Setup Phase` of epoch `N`. + +### Dynamic Startup + +Flow provides a mechanism called Dynamic Startup to simplify the process of obtaining the root snapshot. +When using Dynamic Startup, the node can be started **at any time during the `Staking Auction Phase`**. +The node will wait for the `Epoch Setup Phase` to begin, retrieve a valid root snapshot from a trusted Access Node, then bootstrap its state and join the network. +This is the recommended way to start your node for the first time. + +1. Remove any `root-protocol-state-snapshot.json` file from your `bootstrap` folder. (If this file is present the node will attempt to bootstrap with it rather than Dynamic Startup.) +2. Select a trusted Access Node to provide the root snapshot. You will need this node's **secure GRPC server address** and **Networking Public Key**. +3. Configure Dynamic Startup by adding flags: +```shell ExampleDynamicStartupFlags + ... \ + --dynamic-startup-access-address=secure.mainnet.nodes.onflow.org:9001 \ + --dynamic-startup-access-publickey=28a0d9edd0de3f15866dfe4aea1560c4504fe313fc6ca3f63a63e4f98d0e295144692a58ebe7f7894349198613f65b2d960abf99ec2625e247b1c78ba5bf2eae +``` +4. Start your node (see [guide](./node-setup#start-the-node)) + +:::info + +Once the node has bootstrapped, these flags will be ignored and may be removed. + +::: + +### Manually Provisioned Root Snapshot + +You can also provision the root snapshot file manually, then start the node without configuring Dynamic Startup. +See [here](./protocol-state-bootstrap.md) for the available options to provision a Root Snapshot. + +:::warning + +The snapshot must be within the `Epoch Setup Phase`. + +::: + +:::warning + +Since Collection and Consensus Nodes must start up in the first ~30mins of the `Epoch Setup Phase` (see [Timing](./node-bootstrap.md#timing)), +the snapshot must be provisioned within this time window. + +::: + +Once a valid root snapshot file is downloaded to the node's bootstrap folder, it can be started (see [guide](./node-setup.md#start-the-node)) + + +=== networks/node-ops/node-operation/monitoring-nodes.md === +--- +title: Monitoring Node Health +sidebar_label: Node Monitoring +sidebar_position: 7 +--- + +A Flow node generates logs and publishes metrics as it runs. These logs and metrics can be used to gain insights into the health of the node. + +## Logs + +Logs are emitted to `stdout` as JSON formed strings. Where these logs are available on your system depends on how you launch your containers. On `systemd` systems for example, the logs will be sent to the system journal daemon `journald`. Other systems may log to `/var/log`. + +## Metrics + +Flow nodes produce health metrics in the form of [Prometheus](https://prometheus.io) metrics, exposed from the node software on `/metrics`. + +If you wish to make use of these metrics, you'll need to set up a Prometheus server to scrape your Nodes. Alternatively, you can deploy the Prometheus Server on top of your current Flow node to see the metrics without creating an additional server. + +> The flow-go application doesn't expose any metrics from the underlying host such as CPU, network, or disk usages. It is recommended you collect these metrics in addition to the ones provided by flow using a tool like node exporter (https://github.com/prometheus/node_exporter) + +1. Copy the following Prometheus configuration into your current flow node + + ```yaml + global: + scrape_interval: 15s # By default, scrape targets every 15 seconds. + + scrape_configs: + # The job name is added as a label `job=` to any timeseries scraped from this config. + - job_name: 'prometheus' + + # Override the global default and scrape targets from this job every 5 seconds. + scrape_interval: 5s + + static_configs: + - targets: ['localhost:8080'] + ``` + +2. Start Prometheus server + ```shell + docker run \ + --network=host \ + -p 9090:9090 \ + -v /path/to/prometheus.yml:/etc/prometheus/prometheus.yml \ + prom/prometheus" + ``` +3. (optional) Port forward to the node if you are not able to access port 9090 directly via the browser + `ssh -L 9090:127.0.0.1:9090 YOUR_NODE` + +4. Open your browser and go to the URL `http://localhost:9090/graph` to load the Prometheus Dashboard + +### Key Metric Overview + +The following are some important metrics produced by the node. + +| Metric Name | Description | +| ------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | +| go\_\* | Go runtime metrics | +| consensus_compliance_finalized_height | Latest height finalized by this node; should increase at a constant rate. | +| consensus_compliance_sealed_height | Latest height sealed by this node; should increase at a constant rate. | +| consensus_hotstuff_cur_view | Current view of the HotStuff consensus algorith; Consensus/Collection only; should increase at a constant rate. | +| consensus_hotstuff_timeout_seconds | How long it takes to timeout failed rounds; Consensus/Collection only; values consistently larger than 5s are abnormal. | + +### Machine Account + +Collection and consensus nodes use a machine account that must be kept funded. See [here](../../staking/11-machine-account.md) for details. + +Nodes check their machine account's configuration and funding and produce metrics. + +| Metric Name | Description | +| ------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | +| machine_account_balance | The current balance (FLOW) | +| machine_account_recommended_min_balance | The recommended minimum balance (FLOW) | +| machine_account_is_misconfigured | 0 if the node is configured correctly; 1 if the node is misconfigured | + +To be notified when your node's machine account needs to be refilled or has a configuration error, you can set up alerts. + +When the machine account balance needs to be refilled: +``` +machine_account_balance < machine_account_recommended_min_balance +``` + +When the machine account has a configuration error: +``` +machine_account_is_misconfigured > 0 +``` + +The metrics include the account address of the machine account (`acct_address` label) for convenience: +``` +# HELP machine_account_balance the last observed balance of this node's machine account, in units of FLOW +# TYPE machine_account_balance gauge +machine_account_balance{acct_address="7b16b57ae0a3c6aa"} 9.99464935 +``` + + + +=== networks/node-ops/node-operation/machine-existing-operator.md === +--- +title: Machine Accounts for Existing Node Operators +sidebar_label: Machine Accounts for Existing Node Operators +description: Instructions for existing Node Operators to follow to create a machine account for their collection or consensus nodes. +sidebar_position: 6 +--- + +The [Flow Epoch Preparation Protocol](../../staking/04-epoch-preparation.md) requires that +`collection` and `consensus` nodes use an automated [machine account](../../staking/09-qc-dkg.md#machine-accounts) +to participate in important processes required to start the next epoch. (QC and DKG, respectively) + +Starting on Thursday, August 26th 2021, all collector and consensus nodes who register with Flow Port will +automatically create and initialize this machine account as part of their node registration. + +If you have an existing `consensus` or `collection` node that you registered with Flow Port before Thursday August 26th, +you will need to create this Machine Account manually in order to participate in epochs. +You will need to create one Machine Account for each `consensus` or `collection` node that you operate. + +This guide will walk you through creating a Machine Account and getting it set up. + + + During this process you will generate a new private key which will have sole control over your machine account. + This private key will be stored on the machine you use to run your node, alongside your staking and networking keys. + Loss of any of these keys (staking, networking, or machine account) will require you to un-stake your tokens, start a completely new node, and register the new node to continue participating in the Flow network, which takes multiple weeks. + + +## Downloading Bootstrap Utility + + + If you have downloaded the bootstrapping kit previously, ensure that you do + this step again to get the latest copy of the bootstrapping kit since there + have been significant changes to it. + + +Follow the instructions [here](./node-bootstrap.md#download-the-bootstrapping-kit) +to download the latest version of the bootstrapping kit, then return to this page. + +## Generate Machine Account key + +You will need to generate a Machine account private key using the `bootstrap` utility. + + + + Ensure you run the following commands on the machine you use to run your node software. + The bootstrap directory passed to the `-o` flag must be the same bootstrap directory used by your node. + The default location is `/var/flow/bootstrap`, but double-check your setup before continuing. + + + +```shell GenerateMachineAccountKey +$./boot-tools/bootstrap machine-account-key -o ./bootstrap + INF generated machine account private key + INF encoded machine account public key for entry to Flow Port machineAccountPubKey=f847b84031d9f47b88435e4ea828310529d2c60e806395da50d3dd0dd2f32e2de336fb44eb06488645673850897d7cc017701d7e6272a1ab7f2f125aede46363e973444a02038203e8 + INF wrote file bootstrap/private-root-information/private-node-info_6f6e98c983dbd9aa69320452949b81abeab2ac591a247f55f19f4dbf0b477d26/node-machine-account-key.priv.json + +$tree ./bootstrap/ +./bootstrap +├── private-root-information +│ └── private-node-info_ab6e0b15837de7e5261777cb65665b318cf3f94492dde27c1ea13830e989bbf9 +│ ├── node-info.priv.json +│ └── node-machine-account-key.priv.json +│ └── secretsdb-key +└── public-root-information + ├── node-id + └── node-info.pub.ab6e0b15837de7e5261777cb65665b318cf3f94492dde27c1ea13830e989bbf9.json + +3 directories, 4 files +``` + +## Create Machine Account + +You will now need to copy the Machine account public key displayed in the terminal output and +head over to [Flow Port](../../../networks/flow-port/staking-guide.md#stake-a-node) to submit a transaction to create a Machine Account. +For example, from the example above, we would copy `f847...` from this line: + +```shell Example + INF encoded machine account public key for entry to Flow Port machineAccountPubKey=f847b84031d9f47b88435e4ea828310529d2c60e806395da50d3dd0dd2f32e2de336fb44eb06488645673850897d7cc017701d7e6272a1ab7f2f125aede46363e973444a02038203e8 +``` + +This process will create your machine account for you and show you your machine account's address, which you will need to save for the next step. + +## Finalize Machine Account setup + +You will now need to use the `bootstrap` utility to run `machine-account` with the created address to finalize the set up of your Machine account. + +```shell +$ ./boot-tools/bootstrap machine-account --address ${YOUR_MACHINE_ACCOUNT_ADDRESS} -o ./bootstrap +``` + +```shell Example +$./boot-tools/bootstrap machine-account --address 0x1de23de44985c7e7 -o ./bootstrap + INF read machine account private key json + DBG encoded public machine account key machineAccountPubKey=2743786d1ff1bf7d7026d693a774210eaa54728343859baab62e2df7f71a370651f4c7fd239d07af170e484eedd4f3c2df47103f6c39baf2eb2a50f67bbcba6a + INF wrote file bootstrap/private-root-information/private-node-info_6f6e98c983dbd9aa69320452949b81abeab2ac591a247f55f19f4dbf0b477d26/node-machine-account-info.priv.json + +$tree ./bootstrap/ +./bootstrap +├── private-root-information +│ └── private-node-info_d60bd55ee616c5c297cae1d5cfb7f65e7e04014d9c4abe595af2fd83f3cfe160 +│ ├── node-info.priv.json +│ ├── node-machine-account-info.priv.json +│ └── node-machine-account-key.priv.json +│ └── secretsdb-key +└── public-root-information + ├── node-id + └── node-info.pub.d60bd55ee616c5c297cae1d5cfb7f65e7e04014d9c4abe595af2fd83f3cfe160.json + +3 directories, 5 files +``` + +After running this step, you should see the `node-machine-account-info.priv.json` file in your `bootstrap` directory as shown above. + +### Verify Machine Account Setup + +After finalizing your machine account setup, you should verify its correctness with the `check-machine-account` command: + +```shell CheckMachineAccount +$ ./boot-tools/bootstrap check-machine-account --access-address access.mainnet.nodes.onflow.org:9000 -o ./bootstrap + DBG read machine account info from disk hash_algo=SHA3_256 key_index=0 machine_account_address=0x284463aa6e25877c machine_account_pub_key=f847b84051bad4512101640772bf5e05e8a49868d92eaf9ebed41030881d95485769afd28653c5c53216cdcda4554384bb3ff6396a2ac04842422d55f0562496ad8d952802038203e8 signing_algo=ECDSA_P256 + DBG checking machine account configuration... machine_account_address=0x284463aa6e25877c role=consensus + DBG machine account balance: 0.10000000 + INF 🤖 machine account is configured correctly +``` + +This command will detect and provide information about common misconfigurations, or confirm that the machine account is configured correctly. + + +=== networks/node-ops/node-operation/hcu.md === +--- +title: Height coordinated upgrade (HCU) +sidebar_label: Height coordinated upgrade +--- + +## Overview + +To enables rapid development of the Flow Protocol, the height coordinated upgrade method is used to roll out non-breaking changes such as bug fixes, +feature implementations and security fixes. + +## HCU versus Spork + +A [spork](./spork.md) requires a coordinated network upgrade process where node operators upgrade their node software and +re-initialize with a consolidated representation of the previous spork's state. +It is used to roll out changes which may be non-backward compatible with respect to the protocol and the execution state. +Spork entails a network downtime as all nodes in the system are upgraded and brought back online. +Sporks are only executed once every quarter. + +A height coordinated upgrade (HCU) on the other hand allows the execution and the verification nodes to be upgraded without stopping the network. +There is no network downtime during an HCU but the transaction execution will stop for few minutes while the execution nodes restart. +Currently, an HCU is only used to update the execution and the verification nodes. +For other node types, a simple rolling upgrade is used where operators are asked to upgrade their nodes async. + +## HCU process + +The HCU is executed in two parts. + +The first part is executed by the service committee. In this, the version boundary at which the execution nodes and verification nodes should stop is set on chain by submitting the [set_version_boundary](https://github.com/onflow/flow-core-contracts/blob/master/transactions/nodeVersionBeacon/admin/set_version_boundary.cdc) transaction. +The version boundary includes the block height at which the two node types should stop and the new node software version that the nodes should compare after a restart. + + +The second part is executed by the node operator. In this the node operator, monitors the execution and verification node that they are running. When the nodes reach the height set on chain, they stop if their version is lower then the version specified in the version boundary. +At this point, the operator should update the node version to the new node software version and start the node again. The node will continue from where it left off. + +The block height and the node version will be announced by the Flow team on Discord as well as the [forum page](https://forum.onflow.org/c/mainnet-sporks/36). +It can also be directly queried from the chain using the following script. + +``` +TODO: insert flow cli command here to query the block version details. +``` + + +=== networks/node-ops/node-operation/faq.md === +--- +title: Operator FAQ +sidebar_position: 1 +--- + +# Operator FAQ + +### Can anybody run a node? What is the approval process? + +Anyone can run an [observer node](../light-nodes/observer-node.md). + +Anyone can run an Access Node after registering and staking. See [Access Node Setup](../access-nodes/access-node-setup.md) for detailed instructions. + +For the other node roles, individuals can go through an application process that involves asking about their background and experience contributing to decentralized projects. To pursue an application, please visit [the Flow website here to apply](https://www.onflow.org/node-validators). + +Pending approval, new node operators will be onboarded and invited to join a webinar to meet the team and share more about how they’ll grow the community. Node Operators are invited to join and participate in Flow's Node Validator Discord channel for setup questions and network announcements. + +In the long-term, anyone can run a node validator on Flow. + +### How do I generate keys? + +Please follow the instructions provided here: [Generate Your Node Keys](./node-bootstrap.md#generate-your-node-keys) + +### How do I check on the status of my node? + +Please follow the instructions provided here: [Monitoring nodes](./monitoring-nodes.md) + +### Can I bootstrap and run a node at any time? + +Flow allows nodes to join/leave the network each time a new epoch begins (roughly once per week). +See [Staking & Epochs](../../staking/index.md#epochs) for general information and [Node Setup](./node-bootstrap.md#timing) for a guide to running a new node. + +### Would it hurt the network to have a node that constantly spins up and down? + +All staked nodes except access nodes, have to be online at all time. A staked node, other than an access node, which is not online can cause severe degradation of network performance and will be subjected to slashing of rewards. +A way to prevent this is to check your equipment meets Flow's [recommended requirements](./node-provisioning.md#hardware-requirements), periodically checking for updates and announcements in Discord but also using a node monitoring system for when your node does go offline. + +### Does Flow has a regular schedule for Sporks? + +Yes, see [Upcoming Sporks](./upcoming-sporks.md) for the latest schedule. Currently, Flow has a Mainnet Spork and a Testnet Spork roughly every two months. + +### How do I update the Node Software? + +One of the reasons for a [spork](./spork.md) is to make sure all nodes update to the latest software version. Hence, you should have the latest software update as long as you are participating in each spork. +However, if we do release any software update in between a Spork (e.g. an emergency patch) we will announce it on Discord. + +### Is there any way to know if a node is currently online? + +To verify if a node is online, please [setup metrics](./faq.md#how-do-i-check-on-the-status-of-my-node) for the node. + +### Can I migrate a node to a new machine? + +Yes, as long as you retain the `boostrap` information which includes the node staking key, networking key, IP address and port from the old node to the new. +More on this [here](./node-migration.md) + +### Where can I find how many nodes are currently running Flow? + +If you are running a node, then you most definitely have this information on your node in the file `/public-root-information/node-infos.pub.json`. If you are not running a node, you can find this information by using a Cadence script to query the [Staking Smart Contract](../../../build/core-contracts/06-staking-contract-reference.md) (or check [Flowdiver](https://flowdiver.io/staking/overview)) + +### Why do I need to update my node's ulimit? + +Flow nodes create network connections to other nodes on the network to participate in the protocol. The node's operating system represents +these connections as file descriptors, and uses soft and hard limits to control the number of open files. The node software uses these limits +to manage how many connections it will open and accept from other nodes. If the limit is too low, the node will not be able to communicate +with its peers, preventing it from functioning properly. + + +=== networks/node-ops/node-operation/db-encryption-existing-operator.md === +--- +title: Database Encryption for Existing Node Operators +sidebar_label: Database Encryption for Existing Node Operators +description: Instructions for existing Node Operators to follow to create a machine account for their collection or consensus nodes. +sidebar_position: 4 +--- + +In Mainnet14, the DKG (distributed key generation) is turned on, requiring storage of +dynamically generated confidential data (random beacon keys). These are stored in a +separate database which is new with the Mainnet14 release. + +All node operators joining after Mainnet14 will generate encryption keys for this database +through the node bootstrapping and staking process. We strongly recommend all node operators +(especially consensus node operators) generate an encryption key for this database. This +guide demonstrates how to enable encryption for this database for existing operators. + +## Downloading Bootstrap Utility + + + If you have downloaded the bootstrapping kit previously, ensure that you do + this step again to get the latest copy of the bootstrapping kit since there + have been significant changes to it. + + +Follow the instructions [here](./node-bootstrap.md#download-the-bootstrapping-kit) +to download the latest version of the bootstrapping kit, then return to this page. + +## Generate Database Encryption Key + +You will need to generate an encryption key for the database using the `bootstrap` utility. + + + + Ensure you run the following commands on the machine you use to run your node software. + The bootstrap directory passed to the `-o` flag must be the same bootstrap directory used by your node. + The default location is `/var/flow/bootstrap`, but double-check your setup before continuing. + + + +```shell GenerateEncryptionKey +$./boot-tools/bootstrap db-encryption-key -o ./bootstrap + INF generated db encryption key + INF wrote file bootstrap/private-root-information/private-node-info_ab6e0b15837de7e5261777cb65665b318cf3f94492dde27c1ea13830e989bbf9secretsdb-key + +$tree ./bootstrap/ +./bootstrap +├── private-root-information +│ └── private-node-info_ab6e0b15837de7e5261777cb65665b318cf3f94492dde27c1ea13830e989bbf9 +│ ├── node-info.priv.json +│ └── secretsdb-key +└── public-root-information + ├── node-id + └── node-info.pub.ab6e0b15837de7e5261777cb65665b318cf3f94492dde27c1ea13830e989bbf9.json + +3 directories, 4 files +``` + + +=== networks/node-ops/node-operation/byzantine-node-attack-response.md === +--- +title: Byzantine Node Attack Response +sidebar_label: Byzantine Attack Response +description: How to respond to a byzantine node attack on the network +sidebar_position: 3 +--- + +Flow, like most blockchains, forms an open decentralized peer-to-peer network between all of the nodes +on the network. Due to its decentralized nature, there is a potential for nodes to behave maliciously +(byzantine) and intentionally try to harm the network. There are a variety of protections within the +node software to deal with invalid messages - message signatures, sender authorization, payload +validation, etc. These protections guard the network against many types of attacks. However, there +could still be a byzantine node that spams other nodes in the network with invalid messages at volumes +that are intended to impact node performance. While this will not compromise the security of the +network it could impact network liveness. + +This guide explains how to detect such a node and what actions you should take as a node operator +to deal with such byzantine nodes. + +Responding to an attack from a byzantine node requires the following: + +1. Immediate action to block network traffic originating from the byzantine node to your node. +2. Raising a governance FLIP to remove the node from the network as described in this [FLIP](https://github.com/onflow/flips/blob/main/governance/20230105-identify-errant-node.md). +3. A service account transaction to set the node weight to 0. + +This guide focuses on the first action. + +## Admin Server + +Flow nodes have an admin server which exposes a simple REST API for interacting with the node. +See the [README](https://github.com/onflow/flow-go/blob/master/admin/README.md) for some useful examples. +It is disabled by default. + +### Enable the Admin Server + +To enable to admin server, + +1. Add the following option to the node's CLI flags. +``` +--admin-addr=localhost:9002 +``` + +> Note: The port does not have to be 9002. You can choose any free port. + +> ⚠️ Do NOT expose the port outside the machine and always use localhost:port + +2. Reboot the node to apply the new setting. You can then verify it’s working by logging into +the machine via ssh and running, + +``` +curl localhost:9002 +``` + +This should return a json response message as below. +``` +{"code":5,"message":"Not Found","details":[]} +``` + +If you instead get a connection rejected message then it’s not configured correctly. + +## Detecting a Byzantine Node + +There are 2 general categories of byzantine attacks: +1. Safety attacks - are attacks where a node attempts to corrupt or modify the state of the +blockchain outside of normal protocol rules. +2. Liveness attacks - sometimes called spamming attacks, are when a node attempts to disrupt the +network by abusing their access to waste network and node resources. This generally results in +degraded performance. + +Flow nodes are protected against safety attacks, but liveness attacks are extremely difficult to +completely prevent. To close the gap, we rely on coordination between node operators to detect +and block abusive nodes. + +### Metrics + +Flow nodes generate a variety of metrics that can be used to measure the node's performance and +identify abnormal behavior. Most metrics are only useful in the context of "normal" operation, +so it is a good idea to regularly review them to build an understanding of what is "normal". + +Metrics to watch: +* CPU, memory, network connections, network I/O, file descriptors +* `network_authorization_*` - counts the number of unauthorized/invalid messages received +* `network_queue_message_queue_size` - measures the number of incoming messages waiting to be processed +* `network_engine_messages_received_total` - measures the number of messages received from the network + +There are many other metrics, but these are a good starting point. If you notice any anomalous trends, +review the logs for additional context. + +### Logs + +Log events related to suspicious activity are logged with the label `"suspicious":true`. This is +helpful to identify the most relevant logs, but there are legitimate cases when these logs are +emitted, so they cannot be used as a definitive indicator of malicious activity. Two examples of +expected log messages are: +* `rejected inbound connection` - You may see this error if an operator unstaked their node between +sporks, but never shut it down. The node will continue to operate as usual, but peers will not have +it in their identity table and will (correctly) reject incoming connections. +* `middleware does not have subscription for the channel ID indicated in the unicast message received` - +This is commonly logged during node startup when receiving messages before all of the components +have finished registering their channels with the network layer. It is NOT expected after startup. + +The following is an example of a log message indicating an Access node attempted to send a message it +is not authorized to send: +``` +{ + "level": "error", + "node_role": "collection", + "node_id": "4a6f7264616e20536368616c6d00a875801849f2b5bea9e9d2c9603f00e5d533", + "module": "network_slashing_consumer", + "peer_id": "QmY2kby3xt3ugu2QqJP5w24rP4HSakYgDFpAJy1ifSRkF7", + "networking_offense": "unauthorized_sender", + "message_type": "messages.BlockProposal", + "channel": "sync-committee", + "protocol": "publish", + "suspicious": true, + "role": "access", + "sender_id": "f9237c896507b8d654165c36b61c9a3080e6dd042dea562a4a494fbd73133634", + "time": "2023-01-24T21:10:32.74684667Z", + "message": "potential slashable offense: sender role not authorized to send message on channel" +} +``` + +### Identifying the Source of Malicious Traffic + +Most log messages include either the node ID or peer ID. Peer ID is the ID used to identify nodes on +by the libp2p library. Peer IDs are derived from the node's networking public key, so there is a 1:1 +mapping between node ID and peer ID. + +The two simplest ways to match a node ID to a peer ID: +1. `inbound connection established` and `outbound connection established` log messages contain both +the node and peer IDs +2. The following admin command will return the node info for a given peer ID: +``` +curl localhost:9002/admin/run_command \ + -H 'Content-Type: application/json' \ + -d '{"commandName": "get-latest-identity", "data": { "peer_id": "QmY2kby3xt3ugu2QqJP5w24rP4HSakYgDFpAJy1ifSRkF7" }}' +``` + +If you cannot find any log messages at the current log level, you may need to enable debug logging. +See the admin server's [README](https://github.com/onflow/flow-go/blob/master/admin/README.md) for +an example. + +## Reporting the Byzantine Node + +Report the suspicious node on Discord in the `#flow-validators-alerts` channel along with all the +evidence you have collected (log messages, other networking related metrics, etc). +This will alert other node operators who can review their nodes to corroborate the report. Using +evidence from multiple operators, a consensus can be reached about the suspicious node, and +appropriate action can be taken. + +## Blocking a Byzantine Node + +Once a consensus is reached about the suspicious node on Discord among the node operators, the +suspicious node can be blocked using the admin command. + +``` +curl localhost: 9002/admin/run_command \ + -H 'Content-Type: application/json' \ + -d '{"commandName": "set-config","data": {"network-id-provider-blocklist": [""]}} +``` + +After blocking the node, all traffic coming from the node will be rejected and you should only see +logs about reject messages and connections for that node ID. + +## Unblocking a Node + +If you need to unblock a node, you can use the same command to remove the node ID from the blocklist. +Simply run it again with an empty list to remove all blocked nodes, or an existing list with the +specific node ID you want to unblock removed. + +The following command returns a list of the currently blocked nodes. +``` +curl localhost: 9002/admin/run_command \ + -H 'Content-Type: application/json' \ + -d '{"commandName": "get-config", "data": "network-id-provider-blocklist"} +``` + +After unblocking the node, connections and traffic coming from the node should resume. + + +=== networks/node-ops/node-operation/guides/starting-nodes.md === +--- +title: Starting Your Nodes +--- + +Prior to starting up your nodes make sure you have the following items completed: + +1. Bootstrap process completed with the bootstrap directory handy (default: `/var/flow/bootstrap`) +2. Flow `data` directory created (default: `/var/flow/data`) +3. [node config](../node-bootstrap.md) ready +4. Firewall exposes TCP/3569, and if you are running `access` node also the GRPC port (default: TCP/9000) + +For more details head back to [Setting up your node](../node-setup.md#prepare-your-node-to-start) + +When you have all the above completed, you can start your Flow node via `systemd` or `docker`. + +## systemd + +Ensure that you downloaded the systemd unit file. If you haven't, follow the [Set your node to start](../node-setup.md#prepare-your-node-to-start) guide to get your unit file and enabled. + +Once you have your Flow service enabled you can now start your service: `systemctl start flow` + +## Docker + +If you don't have have systemd on your system, or prefer not to use systemd, you can run the following `docker` commands for your respective Flow role to start your node! + +### Access + +``` +docker run --rm \ + -v /path/to/bootstrap:/bootstrap:ro \ + -v /path/to/data:/data:rw \ + --name flow-go \ + --network host \ + gcr.io/flow-container-registry/access:v0.0.6-alpha \ + --nodeid=${FLOW_GO_NODE_ID} \ + --bootstrapdir=/bootstrap \ + --datadir=/data/protocol \ + --rpc-addr=0.0.0.0:9000 \ + --ingress-addr=${FLOW_NETWORK_COLLECTION_NODE} \ + --script-addr=${FLOW_NETWORK_EXECUTION_NODE} \ + --bind 0.0.0.0:3569 \ + --loglevel=error +``` + +### Collection + +``` +docker run --rm \ + -v /path/to/bootstrap:/bootstrap:ro \ + -v /path/to/data:/data:rw \ + --name flow-go \ + --network host \ + gcr.io/flow-container-registry/collection:v0.0.6-alpha \ + --nodeid=${FLOW_GO_NODE_ID} \ + --bootstrapdir=/bootstrap \ + --datadir=/data/protocol \ + --rpc-addr=0.0.0.0:9000 \ + --nclusters=${FLOW_NETWORK_COLLECTION_CLUSTER_COUNT} \ + --bind 0.0.0.0:3569 \ + --loglevel=error +``` + +### Consensus + +``` +docker run --rm \ + -v /path/to/bootstrap:/bootstrap:ro \ + -v /path/to/data:/data:rw \ + --name flow-go \ + --network host \ + gcr.io/flow-container-registry/consensus:v0.0.6-alpha \ + --nodeid=${FLOW_GO_NODE_ID} \ + --bootstrapdir=/bootstrap \ + --datadir=/data/protocol \ + --nclusters=${FLOW_NETWORK_COLLECTION_CLUSTER_COUNT} \ + --bind 0.0.0.0:3569 \ + --loglevel=error +``` + +### Execution + +``` +docker run --rm \ + -v /path/to/bootstrap:/bootstrap:ro \ + -v /path/to/data:/data:rw \ + --name flow-go \ + --network host \ + gcr.io/flow-container-registry/execution:v0.0.6-alpha \ + --nodeid=${FLOW_GO_NODE_ID} \ + --bootstrapdir=/bootstrap \ + --datadir=/data/protocol \ + --ingress-addr=0.0.0.0:9000 \ + --nclusters=${FLOW_NETWORK_COLLECTION_CLUSTER_COUNT} \ + --bind 0.0.0.0:3569 \ + --loglevel=error +``` + +### Verification + +``` +docker run --rm \ + -v /path/to/bootstrap:/bootstrap:ro \ + -v /path/to/data:/data:rw \ + --name flow-go \ + --network host \ + gcr.io/flow-container-registry/verification:v0.0.6-alpha \ + --nodeid=${FLOW_GO_NODE_ID} \ + --bootstrapdir=/bootstrap \ + --datadir=/data/protocol \ + --nclusters=${FLOW_NETWORK_COLLECTION_CLUSTER_COUNT} \ + --bind 0.0.0.0:3569 \ + --loglevel=error +``` + +### Additional Flags +#### Networking Layer +All networking layer settings are initialized to default values from the [config/default-config.yml](https://github.com/onflow/flow-go/blob/master/config/default-config.yml) file when the Flow node starts up. Each attribute in this YAML file matches a flag name, allowing you to override the default setting by specifying the corresponding flag in the `docker run` command. For instance, to change the `networking-connection-pruning` setting, use its matching flag name (`networking-connection-pruning`) and desired value in the `docker run` command. + + +=== networks/node-ops/node-operation/guides/spork-practice.md === +--- +title: Spork Practice +--- + +## Sporking + +The actual process of Sporking will mostly be covered by the Node Operators Quick Guide, and will not be covered here. + +[Spork](../spork.md) + +Instead, we'll aim to give some instructions for those that want to Practice the process themselves, before joining the Mainnet Spork. + +This guide assumes you have access to the Flow-Go repo, which you'll need to build up-to-date containers and run code snippets. + +[](https://github.com/onflow/flow-go) + +## Local Testnet + +One way to get a good feel of the network without too much interaction with infrastructure is to play with the local testnet, which we've named the Flow Local Instrumented Test Environment (FLITE). + +[https://github.com/onflow/flow-go/blob/master/integration/localnet/README.md](https://github.com/onflow/flow-go/blob/master/integration/localnet/README.md) + +FLITE will allow you to start a full flow network locally, which means starting all 5 roles required for a functioning network. Instructions for initializing and starting the local network are provided in the README above. + +When Starting FLITE, it will build all the docker images required for the network. This can also be done manually ahead of time, using `make docker-build-flow` from the root directory of `flow-go` + +## Remote Testnet + +If you would like more control over the nodes, beyond what docker compose can provide, or you wish to deploy the docker images to separate VMs, to more closely imitate Mainnet, you will have to manually run bootstrapping for a specific configuration of nodes that you would like to test. + +[](https://github.com/onflow/flow-go/blob/master/cmd/bootstrap/README.md) + +Example files are available in the `cmd/bootstrap/example_files` folder. + +Where the `node-config.json` will usually store all flow's nodes, whereas partner node info usually goes into a separate folder. The last file, which will need to be manually populated, is the partner stakes file, which takes the IDs of all the partner nodes and associates a stake. For now, this can be arbitrary. + +Once you have all the information, you can make use of the `finalize` command: + +[](https://github.com/onflow/flow-go/tree/master/cmd/bootstrap#example-1) + +And generate the bootstrapping folder required to start up your nodes. + +Once you have the bootstrapping folder, you'll be able to start up all the nodes that were included in the bootstrapping process. + +[Node Setup Docker](../node-setup.md#docker) + +The startup command will look very similar to what is provided in the quick guide. One such example, assuming we named our bootstrap folder `bootstrap`: + +```shell +docker run --rm \ + -v /path/to/bootstrap:/bootstrap:ro \ + -v /path/to/data:/data:rw \ + --name flow-go \ + --network host \ + gcr.io/flow-container-registry/execution:latest \ + --nodeid=${FLOW_GO_NODE_ID} \ + --bootstrapdir=/bootstrap \ + --datadir=/data/protocol \ + --rpc-addr=0.0.0.0:9000 \ + --nclusters=${FLOW_NETWORK_COLLECTION_CLUSTER_COUNT} \ + --bind 0.0.0.0:3569 \ + --loglevel=error +``` + +The two missing pieces of info here are `FLOW_GO_NODE_ID` which will have been generated from the bootstrap process, and will depend on which node you're trying to run, and `FLOW_NETWORK_COLLECTION_CLUSTER_COUNT` which we've been defaulting to `2` + +## Practice Testnet + +Lastly, if the goal is to practice the entire Sporking procedure, including `transit` of staking and networking keys, and joining a network, we can help spin up a Testnet temporarily for this purpose. This will require quite a bit of coordination, and will basically be the same steps as the Mainnet spork, so please let us know if this is something you'd like to do and we’ll connect to plan accordingly. + + +=== networks/node-ops/node-operation/guides/genesis-bootstrap.md === +--- +title: Genesis Bootstrapping +--- + + + + All nodes joining the network in May are required to go through this process as part of the Genesis Bootstrapping. + + +## Overview + +To kickstart the Flow network and build the first block, all the nodes that will participate in the first round of consensus need to be known and have exchanged some metadata in advance. + +This guide will take you through setting up your nodes, running the initial metadata and key generation, exchanging data back and forth with the Flow team, and then finally starting your nodes to join the network. + +## Before You Begin + +The Flow consensus algorithm depends on there always being a previous block, which means your nodes cannot start until _after_ the Genesis block has been signed. The process of signing that block will be done by the Flow team, and can only be done after every node has completed the first half of the bootstrapping process, which assures that all the identities are included. Since the Flow team needs to wait for metadata from all participants, it will take hours to even days until the Flow network can start. + +The bootstrapping process will be in 2 phases, with the Flow team signing the Genesis block between the two. + + + The bootstrapping process deals with a number of different keys. Make sure you understand their usage and terminology by reviewing the [Node Keys Guide](../node-bootstrap.md#generate-your-node-keys). + + +## Download the Bootstrapping Toolkit + +Both phases of the bootstrapping are automated with scripts. Pull a copy onto each of your nodes and extract it. + +```shell Pull-boot-tools +~ $ curl -sL -O storage.googleapis.com/flow-genesis-bootstrap/boot-tools.tar +~ $ tar -xvf boot-tools.tar +``` + +## Generate Your Node Keys + +Start the bootstrapping process by generating your Staking Key and Networking Key. Use your Node Address that you generated in [Setting Up a Node](../node-setup.md) in the `--address` flag, and the node role. + +Your Node Address must be a publicly routable IPv4 address or valid DNS name that points to your node. This is how other nodes in the network will communicate with you. + +```shell Generate-bootstrap-keys" +~ $ mkdir ./bootstrap +~ $ ./boot-tools/bootstrap key --address \"${YOUR_NODE_ADDRESS}:3569\" --role ${YOUR_NODE_ROLE} -o ./bootstrap +``` + + + By default, the bootstrap script uses the kernel entropy source, either via a `getrandom` syscall or `/dev/urandom`. If you have a more secure source of entropy, like a hardware device, you can specify `--staking-seed` and `--networking-seed`, to provide your own seeds. + + Run the `bootstrap` command with no flags to print usage information." + + + + The key pairs generated in the bootstrapping process are extremely sensitive and must be managed securely. This guide does not deal with storing the keys in a secure backup or controlling access, as the right approach to this will vary from user to user, but it is something you must consider. + + Private keys are suffixed with `.priv.json`, their public counterparts are not sensitive and can be shared freely. + + +This command generates two keys, a Staking Key and a Network Key, and stores them both in a `.node-info` file. Both these keys are needed during runtime and must be present as a file to start your flow node. + +For more details around all the keys that are needed to run nodes and their usage, see the [Node Keys](../node-bootstrap.md#generate-your-node-keys) overview. + +The bootstrapping process will create a file structure similar to the following + +```text bootstrap-directory +~ +└──bootstrap + ├──{id}.node-info.priv.json + └──{id}.node-info.pub.json", +``` + +## Upload Public Keys + +To mint the Genesis Block, the Flow team will need the public Staking and Network keys from all your nodes. + +**If you have previously joined our networks, and you are generating your keys again. Ensure that you take a backup of your keys before generating it again** + +To facilitate this, the boot-tools directory comes with a script `push-keys` that will bundle your `*.pub.json` files and send it to the flow team. You can inspect this script to make sure no private key material is being bundled or uploaded. The data not encrypted before being sent as the public keys involved are not sensitive. + +In phase 2 of the bootstrapping process, the Flow team will need to securely issue each node a Random Beacon key. This key is again sensitive and unique to your node. To enable this, the `push-keys` script also generates another key pair called the Transit Key. The public key of this pair will be uploaded along with the Staking and Network keys, and your Random Beacon key will be encrypted with it before being sent to you. You must keep your Transit Key until you have received and decrypted your Random Beacon key from the Flow team. + + + The transit script here need a `-t` token parameter flag. This token will have been provided to you by the Flow team out of band. Reach out to your contact if you don't have your token. + + +```shell Upload-public-keys +# If you joined our network previously, make sure to take a backup! +cp /path/to/bootstrap /path/to/bootstrap.bak +$ ./boot-tools/transit push -d ./bootstrap -t ${TOKEN} -role ${YOUR_NODE_ROLE} +Running push +Generating keypair +Uploading ... +Uploaded 400 bytes + +``` + + + Once you've run the bootstrap and are confident in your setup, run the transit push command only once. If you bootstrap again and transit push again with a new node ID, it will count against your quota of Nodes. Exceeding your quota will result in a long back and forth with the Flow team to see which node is the extra one. + + +## Update Node Config + +As flow node requires a `--nodeid` flag to start. You will need to pass in the contents of the `node-id` into either your container, `runtime-config.env` file, or hard coded into the `systemd` unit file which the flow team provides. + +You can get the `node-id` from the metadata that you pulled. It will be at: `/path/to/bootstrap/public-genesis-information/node-id` + +### Wait + +Now the ball is in the Flow team's court. As soon as all nodes have completed the above steps, the Genesis block will be created and distributed to you. + +Join the [Flow discord server](https://chat.onflow.org) if you haven't already and stay tuned for updates. Your nodes need not be online during this waiting period if you want to suspend them to reduce cost, but you must not lose your key material. + + + For the Genesis Block, your nodes will start pre-staked, which means no action on your part is needed to get your nodes staked. + + For more details on staking check the guide on [Staking and Rewards](../../../staking/08-staking-rewards.md). + + +## Receive Your Random Beacon Keys + +When the Flow team gives the go-ahead, your Random Beacon keys will be available for retrieval. Each Node will need to pull their own keys down individually. + +```shell Pull-beacon-keys +~ $ ./boot-tools/transit pull -d ./bootstrap -t ${TOKEN} -role ${YOUR_NODE_ROLE} +Fetching keys for node ID FEF5CCFD-DC66-4EF6-8ADB-C93D9B6AE5A4 +Decrypting Keys +Keys available +``` + +Pulling your keys will also pull a bunch of additional metadata needed for the bootstrapping process. +In the end, your bootstrap directory should look like this: + +```text bootstrap-directory +~ +bootstrap/ +├── private-genesis-information +│ └── private-node-info_{node id} +│ ├── node-info.priv.json +│ └── random-beacon.priv.json +├── public-genesis-information +│ ├── dkg-data.pub.json +│ ├── genesis-block.json +│ ├── genesis-cluster-block.{cid}.json +│ ├── genesis-cluster-block.{cid}.json +│ ├── genesis-cluster-qc.{cid}.json +│ ├── genesis-cluster-qc.{cid}.json +│ ├── genesis-commit.json +│ ├── genesis-qc.json +│ ├── node-id +│ ├── node-info.pub.{node id}.json +│ └── node-infos.pub.json +├── +``` + + + + Unlike staking and account keys, the beacon keys are not randomly generated, and depend on inputs from all consensus nodes on the network. In typical Flow network operation, these keys will be dynamically generated on demand by the consensus nodes communicating. However for genesis, as the consensus nodes aren't communicating yet, the Flow team will generate and distribute them to kickstart the process. + + +## Move Genesis Data + +This bootstrapping data is needed by your node at each startup, so it must be present on disk. + +Where in the filesystem you store this data is up to you, but you may not change the folder structure generated by the bootstrapping process. By default, flow stores this data under `/var/flow/bootstrap`. + +## New Images + +Once the Genesis block has been minted, it will be included into the official container images so that it's available to all nodes. Pull the new images, which should now be version `v1.0.0`. + +## Start Your Nodes + +Once every node has puled its keys and fetched the new images, the network is ready to start. + +Make sure you're part of the [Discord Chat](https://chat.onflow.org). Once all nodes are ready, updates will be provided to everyone. + +Start your systems, let's make some blocks! + + +=== networks/node-ops/light-nodes/observer-node.md === +--- +title: Light Node a.k.a Observer Node +sidebar_label: Light Node Setup +sidebar_position: 1 +--- + +A light node also known as the observer node is similar to an access node and provides a locally accessible, continuously updated, verified copy of the block data. It serves the [gRPC Access API](../../access-onchain-data/index.md) but unlike an access node, an light node does not need to be staked, and **anyone** can run it without being added to the approved list of nodes. + +The light node bootstraps by connecting to an access node and becoming part of the public network comprised of access nodes and other light nodes. It then continuously receives blocks, which the consensus nodes are adding to the chain, either directly from access nodes or from other light nodes that are part of the public network. However, it makes no trust assumption of the upstream access node or the light node which is providing the block and locally verifies that the blocks that are received are the correct extension of the chain e.g. after receiving valid blocks A, B and C when it receives block D, it verifies that block D is indeed signed by the consensus nodes and is a valid next block. The received block data is indexed and made available via the Access API. For Collection, Transactions and Account queries, it delegates those requests to the upstream access node. Similarly, transactions and scripts sent to a light node are also forwarded to the upstream access node. Future versions of the light node will be able to serve this data locally as well. + +Since the light node is not staked, it does not produce or execute blocks but instead serves as an _unstaked access node_ that can be easily run on any consumer-grade computer which has enough disk space. + +![Observer nodes](../node-operation/observer.png) + +## Who should run a light node? + +The light node provides an alternative to running an access node. Hence, it is ideal for Dapps that need access to the latest block data locally on a machine they control. Examples include a wallet application that needs to track the latest block ID and height. Alternatively, access node operators that want to scale their access node endpoints geographically can spin up light nodes in different regions, which can talk to their staked access node and to each other. + +## Running an light node + +### Hardware + +In general, any consumer-grade computer with a decent network connection and sufficient disk space should be able to run a light node. + +Minimum requirements + +- CPU with 2+ cores +- 4 GB RAM minimum +- 300 GB SSD disk +- 10Mbps network connection + +### Steps to run a light node + +> [Here](https://www.loom.com/share/990a725531754106b91d8ccec6244219) is video walk-though of these 👇 steps. + +#### Step 1 - Generate the node directory structure +The light node requires the following directory structure, +```shell +$ tree flow_observer +flow_observer/ +├── bootstrap +│ ├── network.key (file containing the node private network key) +│ └── public-root-information +│ └── root-protocol-state-snapshot.json (the genesis data of the current spork) +└── data (directory used by the light node to store block data) +``` + +Create the parent and the sub-directories +e.g. +```shell +mkdir -p flow_observer/bootstrap/public-root-information +mkdir flow_observer/data +``` + +#### Step 2 - Generate the network key + +Like any other Flow node, the light node also needs a networking [ECDSA key](https://github.com/onflow/flow-go/blob/master/cmd/bootstrap/utils/key_generation.go#L52-L54) to talk to the network. +Download the Bootstrapping kit, and generate the networking key. + +```shell +curl -sL -O storage.googleapis.com/flow-genesis-bootstrap/boot-tools.tar +tar -xvf boot-tools.tar +./boot-tools/bootstrap observer-network-key --output-file ./flow_observer/bootstrap/network.key +``` + +_If you are running on a mac, download the boot-tools for mac to generate the key_ +```shell +# For M1 +curl -sL -O storage.googleapis.com/flow-genesis-bootstrap/boot-tools-m1.tar +# For Intel Mac +curl -sL -O storage.googleapis.com/flow-genesis-bootstrap/boot-tools-intel-mac.tar +``` + +#### Step 3 - Download the root-protocol-state-snapshot.json file for the current spork + +The `root-protocol-state-snapshot.json` is generated for each [spork](../node-operation/spork.md) and contains the genesis data for that spork. +It is published and made available after each spork. The download location is specified [here](https://github.com/onflow/flow/blob/master/sporks.json) under [rootProtocolStateSnapshot](https://github.com/onflow/flow/blob/master/sporks.json#L16) and can be downloaded as follows, + +For mainnet find the latest spork version from [sporks.json](https://github.com/onflow/flow/blob/master/sporks.json) and then download the `root-protocol-state-snapshot.json` and the signature file for it. + +```shell +wget -P ./flow_observer/bootstrap/public-root-information https://storage.googleapis.com/flow-genesis-bootstrap/mainnet--execution/public-root-information/root-protocol-state-snapshot.json +wget -P ./flow_observer/bootstrap/public-root-information https://storage.googleapis.com/flow-genesis-bootstrap/mainnet--execution/public-root-information/root-protocol-state-snapshot.json.asc +``` + +Similarly, for testnet find the latest spork version from [sporks.json](https://github.com/onflow/flow/blob/master/sporks.json) and then download the `root-protocol-state-snapshot.json` and the signature file for it. +```shell +wget -P ./flow_observer/bootstrap/public-root-information https://storage.googleapis.com/flow-genesis-bootstrap/testnet-/public-root-information/root-protocol-state-snapshot.json +wget -P ./flow_observer/bootstrap/public-root-information https://storage.googleapis.com/flow-genesis-bootstrap/testnet-/public-root-information/root-protocol-state-snapshot.json.asc +``` + +##### Verify the PGP signature + +Add the `flow-signer@onflow.org` public key +```shell +gpg --keyserver keys.openpgp.org --search-keys flow-signer@onflow.org + +gpg: data source: http://keys.openpgp.org:11371 +(1) Flow Team (Flow Full Observer node snapshot verification master key) < + 256 bit ECDSA key CB5264F7FD4CDD27, created: 2021-09-15 +Keys 1-1 of 1 for "flow-signer@onflow.org". Enter number(s), N)ext, or Q)uit > 1 +``` + +Verify the root-snapshot file +```shell +gpg --verify ./flow_observer/bootstrap/public-root-information/root-protocol-state-snapshot.json.asc + +gpg: assuming signed data in 'bootstrap/public-root-information/root-protocol-state-snapshot.json' +gpg: Signature made Wed Sep 15 11:34:33 2021 PDT +gpg: using ECDSA key 40CD95717AC463E61EE3B285B718CA310EDB542F +gpg: Good signature from "Flow Team (Flow Full Observer node snapshot verification master key) " [unknown] +gpg: WARNING: This key is not certified with a trusted signature! +gpg: There is no indication that the signature belongs to the owner. +Primary key fingerprint: 7D23 8D1A E6D3 2A71 8ECD 8611 CB52 64F7 FD4C DD27 + Subkey fingerprint: 40CD 9571 7AC4 63E6 1EE3 B285 B718 CA31 0EDB 542F +``` + +Alternately, if you don't care about the blocks before the current block, you can request the current root-snapshot file via the [Flow CLI](../../../tools/flow-cli/index.md). + +For mainnet +```shell + flow snapshot save ./flow_observer/bootstrap/public-root-information/root-protocol-state-snapshot.json --host secure.mainnet.nodes.onflow.org:9001 --network-key 28a0d9edd0de3f15866dfe4aea1560c4504fe313fc6ca3f63a63e4f98d0e295144692a58ebe7f7894349198613f65b2d960abf99ec2625e247b1c78ba5bf2eae +``` + +For testnet +```shell +flow snapshot save ./flow_observer/bootstrap/public-root-information/root-protocol-state-snapshot.json --host secure.testnet.nodes.onflow.org:9001 --network-key ba69f7d2e82b9edf25b103c195cd371cf0cc047ef8884a9bbe331e62982d46daeebf836f7445a2ac16741013b192959d8ad26998aff12f2adc67a99e1eb2988d +``` + +#### Step 4 - Start the node + +The light node can be run as a docker container + +##### Observer for Flow Mainnet + +```shell +docker run --rm \ + -v $PWD/flow_observer/bootstrap:/bootstrap:ro \ + -v $PWD/flow_observer/data:/data:rw \ + --name flow_observer \ + -p 80:80 \ + -p 3569:3569 \ + -p 9000:9000 \ + -p 9001:9001 \ + gcr.io/flow-container-registry/observer:v0.27.2 \ + --bootstrapdir=/bootstrap \ + --datadir=/data/protocol \ + --bind 0.0.0.0:3569 \ + --rest-addr=:80 \ + --loglevel=error \ + --secretsdir=/data/secrets \ + --upstream-node-addresses=secure.mainnet.nodes.onflow.org:9001 \ + --upstream-node-public-keys=28a0d9edd0de3f15866dfe4aea1560c4504fe313fc6ca3f63a63e4f98d0e295144692a58ebe7f7894349198613f65b2d960abf99ec2625e247b1c78ba5bf2eae \ + --bootstrap-node-addresses=secure.mainnet.nodes.onflow.org:3570 \ + --bootstrap-node-public-keys=28a0d9edd0de3f15866dfe4aea1560c4504fe313fc6ca3f63a63e4f98d0e295144692a58ebe7f7894349198613f65b2d960abf99ec2625e247b1c78ba5bf2eae \ + --observer-networking-key-path=/bootstrap/network.key +``` + +##### Observer for Flow Testnet + +```shell +docker run --rm \ + -v $PWD/flow_observer/bootstrap:/bootstrap:ro \ + -v $PWD/flow_observer/data:/data:rw \ + --name flow_observer \ + -p 80:80 \ + -p 3569:3569 \ + -p 9000:9000 \ + -p 9001:9001 \ + gcr.io/flow-container-registry/observer:v0.27.2 \ + --bootstrapdir=/bootstrap \ + --datadir=/data/protocol \ + --bind 0.0.0.0:3569 \ + --rest-addr=:80 \ + --loglevel=error \ + --secretsdir=/data/secrets \ + --upstream-node-addresses=secure.devnet.nodes.onflow.org:9001 \ + --upstream-node-public-keys=ba69f7d2e82b9edf25b103c195cd371cf0cc047ef8884a9bbe331e62982d46daeebf836f7445a2ac16741013b192959d8ad26998aff12f2adc67a99e1eb2988d \ + --bootstrap-node-addresses=secure.devnet.nodes.onflow.org:3570 \ + --bootstrap-node-public-keys=ba69f7d2e82b9edf25b103c195cd371cf0cc047ef8884a9bbe331e62982d46daeebf836f7445a2ac16741013b192959d8ad26998aff12f2adc67a99e1eb2988d \ + --observer-networking-key-path=/bootstrap/network.key +``` + +The light node acts as a DHT client and bootstraps from upstream access nodes which run the DHT server. +The upstream bootstrap server is specified using the `bootstrap-node-addresses` which is the comma-separated list of hostnames of the access nodes. +The `bootstrap-node-public-keys` is the list of the corresponding networking public key of those nodes. + +The light node delegates many of the API calls to the upstream access nodes. +The `upstream-node-addresses` is the list of access node hostnames to which this light node can delegate to. The list can be different from the bootstrap node list. +The `bootstrap-node-public-key` is the list of the corresponding networking public key of those nodes. + +> In the above docker commands, the Flow community access nodes are being used as the upstream access nodes. However, any other Flow access node that supports a light node can be used + +_All parameters and their explanation can be found [here](https://github.com/onflow/flow-go/blob/82da35141ff095fbf75ce2c950efec240ad38565/cmd/access/node_builder/access_node_builder.go#L523-L558)_ + +🚀 **The node should now be up and running** + +You can now query the node for blocks, transaction etc. similar to how you would query an access node. + +e.g. querying the gRPC API endpoint using Flow CLI +```shell +flow blocks get latest --host localhost:9000 +``` + +e.g. querying the REST API endpoint using curl +```shell +curl "http://localhost/v1/blocks?height=sealed" +``` + +The light node, like the other type of Flow nodes, also produces Prometheus metrics that can be used to monitor node health. More on that [here](../node-operation/node-setup.md#monitoring-and-metrics) + + +## FAQs + +### Does the light node need to be staked? + +No, the light node is not a staked node. + +### Can any access node be used to bootstrap a light node? + +No, only Access nodes which have explicitly turned ON support for light nodes can be used to bootstrap a light node. + +The public access nodes that support light nodes are listed below. Apart from these, other public access nodes run by node operators other than the Flow foundation team may choose to support light nodes. + +### How can an access node turn ON support for light node? + +An access node can support a light node by passing in the following two parameters when starting the access node +```shell + --supports-observer=true --public-network-address=0.0.0.0:3570 +``` +`public-network-address` is the address the light nodes will connect to. + +### Are light nodes subject to rate limits? + +The light node serves all the [Block related queries](https://github.com/onflow/flow/blob/master/protobuf/flow/access/access.proto#L24-L42) from is local database. These are not subjected to any rate limits. + +However, it proxies all the other requests to the access node and those will be rate limited as per the rate limits defined on that access node. + + +### Flow community access nodes that support connections from light nodes + +#### For mainnet + +Access-007: +* Host: `access-007.[current mainnet spork].nodes.onflow.org` +* Public Key: `28a0d9edd0de3f15866dfe4aea1560c4504fe313fc6ca3f63a63e4f98d0e295144692a58ebe7f7894349198613f65b2d960abf99ec2625e247b1c78ba5bf2eae` + +Access-008: +* Host: `access-008.[current mainnet spork].nodes.onflow.org` +* Public Key: `11742552d21ac93da37ccda09661792977e2ca548a3b26d05f22a51ae1d99b9b75c8a9b3b40b38206b38951e98e4d145f0010f8942fd82ddf0fb1d670202264a` + +#### For testnet + +Access-001: +* Host: `access-001.[current devnet spork].nodes.onflow.org` +* Public Key: `ba69f7d2e82b9edf25b103c195cd371cf0cc047ef8884a9bbe331e62982d46daeebf836f7445a2ac16741013b192959d8ad26998aff12f2adc67a99e1eb2988d` + +Access-003: +* Host: `access-003.[current devnet spork].nodes.onflow.org` +* Public Key: `b662102f4184fc1caeb2933cf87bba75cdd37758926584c0ce8a90549bb12ee0f9115111bbbb6acc2b889461208533369a91e8321eaf6bcb871a788ddd6bfbf7` + + +While the public keys remain the same, the hostnames change each spork to include the spork name. Substitute `[current mainnet spork]` and `[current devnet spork]` with the appropriate spork name (e.g. `mainnet20`). +See [Past Sporks](../node-operation/past-upgrades) for the current spork for each network. + + +=== networks/node-ops/evm-gateway/evm-gateway-setup.md === +--- +title: Setting up an EVM Gateway node +sidebar_label: EVM Gateway Setup +sidebar_position: 2 +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +This guide is for running the [EVM Gateway](https://github.com/onflow/flow-evm-gateway) node on Flow. The EVM Gateway implements the +[Ethereum JSON-RPC specification](https://ethereum.org/en/developers/docs/apis/json-rpc/) and is the only node type which accepts EVM +client connections. + +The EVM Gateway consumes Flow protocol state from the configured Flow Access Node and persists the indexed EVM state locally to +service EVM client requests. It submits EVM transactions it receives into the Flow network, wrapped in a Cadence transaction, and +mutating EVM state when executed. Non-mutating RPC methods only query the local state index of the gateway and are never forwarded +to Access Nodes. It does not participate in the block production process and requires no stake. + +## Anyone can run EVM Gateway + +The EVM Gateway can serve as a dedicated private RPC, a performance scaling solution, and a free gas provider offering similar capabilities +to centralized middleware providers like Infura, Alchemy, etc. at a fraction of the cost. EVM Gateway nodes connect directly to the Flow network +with no middleware, giving you full control. + +If you are just getting started building your application, you can use the [public EVM Gateway](https://developers.flow.com/evm/networks). +Applications generating high call volumes to the JSON-RPC may have hit rate limits on Flow public EVM Gateway and may benefit from running their +own gateway to remove rate limits. Self-hosted gateways connect directly to public Flow Access Nodes, which may also optionally be [run](../access-nodes/access-node-setup.md). + +:::info + +Apps can use EVM gateway to subsidize user transaction fees for smoother onboarding + +::: + +Alternatively, you can also choose from any of the following providers who provide the EVM Gateway as a managed service along with other value added services on top. + +1. [Alchemy](https://www.alchemy.com/flow) +2. [ThirdWeb](https://thirdweb.com/flow) +3. [Moralis](https://docs.moralis.com/web3-data-api/evm/chains/flow) +4. [QuickNode](https://www.quicknode.com/chains/flow) + +## Hardware specifications + +The EVM Gateway is a lightweight node which runs on commodity hardware and cloud VMs. It can be run on GCP **standard** and AWS **large** +VM types for low to moderate volume app co-location use-cases. However, higher volume use cases may require larger instance types and more +testing. An inactive node requires less than 200MB memory when run in Docker and data storage growth corresponds with Flow EVM transaction +growth. Listed below are theoretical RPS maximums based on Flow mainnet CPU and memory resource utilization metrics and linear scaling assumptions. + +### Google Cloud Platform (GCP) VM Types + +| VM Type | vCPUs | Memory (GB) | Estimated Max Requests/s | +| --------- |-------|-------------|--------------------------| +| n2-standard-2 | 2 | 8 | ~2,950 | +| c4a-standard-1 | 1 | 4 | ~1,475 | +| c4a-standard-2 | 2 | 8 | ~2,950 | +| n2-highmem-4 | 4 | 32 | ~11,800 | +| c3-standard-8 | 8 | 32 | ~29,500 | + +### Amazon Web Services (AWS) EC2 Instance Types +| Instance Type | vCPUs | Memory (GB) | Estimated Max Requests/s | +| --------- |--------|-------------|--------------------------| +| m6i.large | 2 | 8 | ~2,950 | +| c6i.large | 2 | 4 | ~3,687 | +| m6i.xlarge | 4 | 16 | ~11,800 | +| c6i.2xlarge | 8 | 16| ~29,500 | +| t3.2xlarge | 8 | 32 | ~17,700 | + +# How To Run EVM Gateway + +## Step 1 - Account Creation + +The EVM Gateway's role in mediating EVM transactions over to Cadence is how it accrues fees from handling client transactions. Since +the gateway submits Cadence transactions wrapping EVM transaction payloads to the Flow Access Node the transaction fee for that must +be paid by the EVM Gateway. + +The account used for funding gateway Cadence transactions must be a COA, not an EOA. `--coa-address` is configured with the Cadence address +of the COA account and the `--coa-key` must belong to the same account. The `--coinbase` account accrues EVM Gateway fees from EVM client +transactions and can be either an EVM EOA or COA address. + +It is acceptable to create a single Cadence account for the COA and use the EVM address associated with that for the COINBASE address. + +### Create Flow account to use for COA + +If you don't already have a Flow account you will need to create one. + + + + + 1. Install [Flow Wallet](https://wallet.flow.com/) + 2. Once installed you will be able to copy the wallet address, similar to _0x1844efeb3fef2242_ + 3. Obtain account private key from +
    Settings -> Account List -> Choose Main account -> Private Key -> [Password prompt]
    + 4. Ensure the wallet is funded from a CEX or other wallet + +
    + + +Install [Flow CLI](https://developers.flow.com/tools/flow-cli/install) if not already installed. + +```bash +flow keys generate +``` +This will output something similar to: +` +```bash +🔴️ Store private key safely and don't share with anyone! +Private Key 3cf8334d.....95c3c54a28e4ad1 +Public Key 33a13ade6....85f1b49a197747 +Mnemonic often scare peanut ... boil corn change +Derivation Path m/44'/539'/0'/0/0 +Signature Algorithm ECDSA_P256 +``` + +Visit https://faucet.flow.com/, and use the generated `Public Key`, to create and fund your Flow testnet account. + + +
    + +## Step 2 - Build the gateway + +To run EVM Gateway on bare metal or in a VM without the use of docker, select the '_Build from source_' tab otherwise refer to the +'_Build using Docker_' tab. + + + + +This will build the EVM gateway binary from source. + +```bash +git clone https://github.com/onflow/flow-evm-gateway.git + +cd flow-evm-gateway +git checkout $(curl -s https://api.github.com/repos/onflow/flow-evm-gateway/releases/latest | jq -r .tag_name) +CGO_ENABLED=1 go build -o evm-gateway cmd/main/main.go +chmod a+x evm-gateway +mv evm-gateway /usr/bin +``` + + + + +```bash +git clone https://github.com/onflow/flow-evm-gateway.git + +cd flow-evm-gateway +git checkout $(curl -s https://api.github.com/repos/onflow/flow-evm-gateway/releases/latest | jq -r .tag_name) +make docker-build +``` + + + + +Registry versions available for download can be found [here](https://console.cloud.google.com/artifacts/docker/dl-flow-devex-production/us-west1/development/flow-evm-gateway). +```bash +docker pull us-west1-docker.pkg.dev/dl-flow-devex-production/development/flow-evm-gateway:${VERSION} +``` + + + + +## Step 3 - Start Your Node + +Operators will need to refer to the gateway [configuration flags](https://github.com/onflow/flow-evm-gateway?tab=readme-ov-file#configuration-flags) and make adjustments that align with the desired +deployment topology. + +### EVM Coinbase address + +If this is your first time setting up the gateway we need to ensure that an EVM COA or EOA address is available to configure the `COINBASE`. This account +can be an account created using Metamask or other web3.js wallet, or otherwise can be the EVM address corresponding to the Flow Wallet COA account created above. + +If you haven't already got an EVM address and you have the COA account created by Flow Wallet above then follow the steps below: + +* Click top left burger icon to show current profile +* Click 'Enable the path to Flow EVM' button +* Your EVM account will now be available to use in the left nav account view +* When you switch to that account you can obtain its EVM address + +### COA Address and Key + +COA address and private key is configured for `--coa-address` & `--coa-key` configuration flags. If running multiple EVM Gateway hosts it is standard to +share the same COA address and key across _n_ hosts. + +### Run the gateway + +Ensure that the following ENV variables have been set. Add/update as required if your configuration differs from those listed. + +```bash +# Set required environment variables +export ACCESS_NODE_GRPC_HOST="access.mainnet.nodes.onflow.org:9000" # or access.devnet.nodes.onflow.org:9000 for testnet +export FLOW_NETWORK_ID="flow-mainnet" # or flow-testnet +export INIT_CADENCE_HEIGHT="85981135" # 211176670 for testnet +export COINBASE="${EVM_ADDRESS_WITHOUT_0x}" +export COA_ADDRESS="${CADENCE_ACCOUNT_ADDRESS_WITHOUT_0x}" +export COA_KEY="${CADENCE_ACCOUNT_PRIVATE_KEY_WITHOUT_0x}" +export GAS_PRICE="100" # operators can set this to 0 for zero cost transactions. The linked COA account will pay for transactions on users behalf + +# $\{ACCESS_NODE_SPORK_HOSTS\} are comma separated +# testnet: access-001.devnet51.nodes.onflow.org:9000 +# mainnet: access-001.mainnet25.nodes.onflow.org:9000 +``` +ACCESS_NODE_SPORK_HOSTS is used by the gateway to track state across Flow sporks. These are generally infrequent with only one planned +spork per year. A canonical list of required hosts can be found in the EVM Gateway [Makefile](https://github.com/onflow/flow-evm-gateway/blob/main/Makefile#L9). + + + + +**Create EVM Gateway service** + +```bash +sudo tee </dev/null /etc/systemd/system/gateway.service +[Unit] +Description=Gateway daemon +After=network-online.target + +[Service] +User=$USER +ExecStart=/usr/bin/evm-gateway \ +--access-node-grpc-host=$ACCESS_NODE_GRPC_HOST \ +--access-node-spork-hosts=$ACCESS_NODE_SPORK_HOSTS \ +--flow-network-id=$FLOW_NETWORK_ID \ +--init-cadence-height=$INIT_CADENCE_HEIGHT \ +--ws-enabled=true \ +--coinbase=$COINBASE \ +--coa-address=$COA_ADDRESS \ +--coa-key=$COA_KEY \ +--rate-limit=9999999 \ +--rpc-host=0.0.0.0 \ +--gas-price=$GAS_PRICE \ +--tx-state-validation=local-index +Restart=always +RestartSec=3 +LimitNOFILE=4096 + +[Install] +WantedBy=multi-user.target +EOF + +cat /etc/systemd/system/gateway.service +sudo systemctl enable gateway +``` + +**Start all services** + +```bash +sudo systemctl daemon-reload +sudo systemctl restart access-node +sudo systemctl restart gateway +``` + +**Check logs** + +```bash +# change log settings to persistent if not already +sed -i 's/#Storage=auto/Storage=persistent/g' /etc/systemd/journald.conf +sudo systemctl restart systemd-journald + +journalctl -u gateway.service -f -n 100 +``` + + + + +It may be necessary to make local changes to the `docker-run` target to add params which are needed for your requirements. If you pulled a +specific image from the gateway container registry ensure that the `$VERSION` environment variable is set to the same as the image version +you pulled. + +```bash +cd flow-evm-gateway +make docker-run +``` +Additional options are available as follows + +```bash +DOCKER_RUN_DETACHED=true +DOCKER_HOST_MOUNT=[host mount directory] +DOCKER_HOST_PORT=[desired port to expose on host] +DOCKER_HOST_METRICS_PORT=[desired port to expose on host for metrics] + +# Example usage + +make DOCKER_RUN_DETACHED=true DOCKER_HOST_PORT=1234 DOCKER_HOST_MOUNT=/my/host/dir docker-run +``` + + + + +### Startup bootstrap indexing + +Once your EVM Gateway is up and running you will see it indexing the Flow network which was configured. At the present time this +is a lengthy process (possibly 1-3 days, depending on CPU core count) during which time the gateway will not respond to queries. +Once the data is fully indexed the gateway can serve requests to clients. + +To speed up gateway setup we recommend backing up the `/${GATEWAY_HOME_DIR}/data` directory to use when creating additional nodes +using the same release version. We are currently working on an export/import feature that will enable gateway operators to +store state snapshots to bootstrap newly created nodes without the delay. + +:::note + +If you are upgrading the gateway from pre-v1.0.0 release versions the indexed data directory will need to be reindexed from genesis. +You will not be able to re-use the DB data dir from the previous versions. + +::: + +### Account and Key Management + +When operating an EVM Gateway it is important to understand how keys are configured and used. Each gateway instance +must be configured with a Flow account address, which is sufficiently funded and which it uses to pay to wrap EVM transactions into a +Cadence transaction when submitting to the Flow Access Node. This can be configured with a standalone private key file for +the `--coa-key` config flag. Alternatively, you may also use cloud KMS providers per the guidance below. + +#### COA Account signing key rotation + +The gateway implements a signing key rotation scheme to scale the use of the `COA_KEY` and enable it to be used across many +EVM client transactions. This is configured by reusing the COA public key to create new on-chain signing keys. Although it may seem +counter-intuitive to use the same COA public key when creating new signing keys, the newly added keys all occupy different +key slots on the account which enables the gateway to support concurrent transaction signing without causing [nonce collisions](https://developers.flow.com/build/advanced-concepts/scaling#problem) +for EVM clients. + +Assuming there is already one key on the account, the following example transaction adds 100 copies of that key: +```swift +transaction { + prepare(signer: auth(AddKey) &Account) { + let firstKey = signer.keys.get(keyIndex: 0)! + let range: InclusiveRange = InclusiveRange(1, 100, step: 1) + for element in range { + signer.keys.add( + publicKey: firstKey.publicKey, + hashAlgorithm: HashAlgorithm.SHA2_256, + weight: 1000.0 + ) + } + } +} +``` +Signing keys which are added to the COA account are required to use the same hashing algorithm as the key being copied. + +If keys are added while the gateway is running it will need to be restarted to make use of the new keys. + +:::note + +If you are operating your EVM Gateway(s) to relay traffic for Flow EVM, or if you otherwise anticipate high volumes of +transactions we recommend configuring 2000 signing keys or more. Signing key utilization increases proportionately +with transaction throughput growth. + +A large number of keys are recommended for live networks because keys have a lengthy cool down period of 600 blocks (approx 10 minutes) +before they are re-used. This is to avoid nonce collisions from re-using the key too soon. + +::: + +You can track signing key utilization as a metric, see `evm_gateway_available_signing_keys` below. + + +#### KMS Configuration + +EVM Gateway allows for Google and AWS Key Management Service (KMS) integration, which is the recommended way of setting up the gateway +for live networks. It is only required to configure a single KMS key for the Flow account configured as the gateway `COA_ACCOUNT`. + +``` +--coa-cloud-kms-project-id=your-project-kms-id \ +--coa-cloud-kms-location-id=global \ +--coa-cloud-kms-key-ring-id=your-project-kms-key-ring-id \ +--coa-cloud-kms-key=example-gcp-kms@1 \ +``` + +### Monitoring and Metrics + +The EVM Gateway reports Prometheus metrics which are a way to monitor the gateway's availability and progress. The database folder +size may also need to be monitored to prevent disk full issues. + +**Metric labels** +```bash +evm_gateway_api_errors_total # Total count of API errors for period +evm_gateway_api_request_duration_seconds_bucket # Histogram metric buckets for API request durations +evm_gateway_api_request_duration_seconds_count # Histogram metric API request count for period +evm_gateway_api_request_duration_seconds_sum # Histogram metric API request sum of values for period +evm_gateway_api_server_panics_total # Total count of server panics for period +evm_gateway_blocks_indexed_total # Total count of EVM blocks indexed +evm_gateway_cadence_block_height # Cadence block height +evm_gateway_evm_account_interactions_total # Count of unique accounts observed for period +evm_gateway_evm_block_height # EVM block height +evm_gateway_operator_balance # Gateway node COA operator account balance +evm_gateway_trace_download_errors_total # Total count of trace download errors +evm_gateway_txs_indexed_total # Total count of indexed transactions +evm_gateway_available_signing_keys # Total count of available COA signing keys +``` + +Alerts are recommended to be configured on server panics, low operator balance, available signing keys and disk usage metrics. + +**Metrics port** + +``` +--metrics-port 8080 \ +``` +### Node Status + +For basic node status or keepalive monitoring we recommend automated checks on the following monotonically increasing counter: +``` +curl -s -XPOST 'your-evm-gw-host:8545' --header 'Content-Type: application/json' --data-raw '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' | jq -r '.result' | xargs printf "%d\n" +10020239 +``` + +## Troubleshooting + +Join our [Discord](https://discord.com/invite/J6fFnh2xx6) and use the `#flow-evm` channel to ask any questions you may have about +EVM Gateway. + +### No signing keys available + +```bash +Failed to send transaction: no signing keys available +``` +This message indicates that the GW has used all its available signing keys. Please refer to the [Account and Key Management](./evm-gateway-setup#account-and-key-management) documentation to add more signing keys to your COA. + +### Database version inconsistency/corruption + +If you see a similar message to this from an aborted startup the gateway database directory is not compatible with the schema versions of the runtime, or there may be corruption. In this instance we recommend that you delete the contents of the EVM GW data directory. + +```bash +Jan 16 17:00:57 nodename docker[6552]: {"level":"error","error":"failed to open db for dir: /flow-evm-gateway/db, with: pebble: manifest file \"MANIFEST-018340\" for DB \"/flow-evm-gateway/db\": comparer name from file \"leveldb.BytewiseComparator\" != comparer name from Options \"flow.MVCCComparer\"","time":"2025-01-16T17:00:57Z","message":"Gateway runtime error"} +``` + +### State stream configuration + +If you are running an Access Node on the same logical host as the EVM Gateway you may see the following log entries. + +```bash +failure in event subscription at height ${INIT-CADENCE-HEIGHT}, with: recoverable: disconnected: error receiving event: rpc error: code = Unimplemented desc = unknown service flow.executiondata.ExecutionDataAPI” +``` +```bash +component execution data indexer initialization failed: could not verify checkpoint file: could not find expected root hash e6d4f4c755666c21d7456441b4d33d3521e5e030b3eae391295577e9130fd715 in checkpoint file which contains: [e10d3c53608a1f195b7969fbc06763285281f64595be491630a1e1bdfbe69161] +``` + +To resolve this configure `--state-stream-addr` to use the same address/port combination which is set for Access Node `--rpc-addr`. +This is required by the gateway to allow both the streaming and non-streaming APIs to query using the same connection. + +### Access Node not fully synced + +The following log entry will occur when the EVM Gateway attempts to sync with the Access Node but it has not yet synced up to latest block +```bash +failure in event subscription at height ${INIT-CADENCE-HEIGHT}, with: recoverable: disconnected: error receiving event: rpc error: code = FailedPrecondition desc = could not get start height: failed to get lowest indexed height: index not initialized +``` + + +=== networks/node-ops/access-nodes/access-node-setup.md === +--- +title: Setting Up a Flow Access Node +sidebar_label: Access Node Setup +sidebar_position: 1 +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +This guide is for running a permissonless Access node on Flow. If you are planning to run a different type of staked node then see [node bootstrap](../node-operation/node-bootstrap.md). + +Permissionless Access nodes allow any operator to run a Flow Access node. +Unlike the other staked nodes, a permissionless access node does not have to be approved by the service account before it can join the network, hence the term "permissionless". The goal is to make all node types permissionless and this is the first step towards achieving that goal. + +## Who Should Run a Permissionless Access Node? +dApp developers can choose to run their own private permissionless access node and move away from using the community access nodes. This will also allow them to not be subjected to the API rate limits of the public access nodes. + +Node operators can also run their own permissionless access node and provide access to that node as a service. + +Chain analytics, audit and exploration applications can run such an access node and do not have to rely on third parties for the state of the network. + +## Timing + +New nodes are able to join the network each time a new epoch begins. +An epoch is a period of time (approximately one week) when the node operators in the network are constant. +At epoch boundaries, newly staked node operators are able to join the network and existing node operators which have unstaked may exit the network. +You can read more about epochs [here](../../staking/03-schedule.md). + + +In order to join the network at epoch N+1, the access node **must** be registered with at least 100 FLOW staked prior to the end of epoch N's Staking Auction Phase. + +Currently on mainnet, the staking auction starts every Wednesday at around 20:00 UTC and ends on the next Wednesday at around 12:00 UTC. +Since this deadline may shift slightly from epoch to epoch, we recommend the node be staked by _Wednesday, 8:00 UTC_ to be able to join the network in the next epoch. + +Confirmation of a new node's inclusion in epoch N+1 is included in the [`EpochSetup` event](../../staking/05-epoch-scripts-events.md#flowepochepochsetup). + +![Flow Epoch Schedule](../node-operation/epoch-startup-order.png) + +## Limitations + +There are five open slots for access nodes every epoch. +You can view the exact epoch phase transition time [here](https://dashboard.flow.com/) under `Epoch Phase`. + +To summarize, + +| **Epoch** | **Epoch Phase** | | +|:----------:|:----------------------:|:---------------------------------------------------:| +| N | Staking auction starts | Three new access node slots are opened. Anyone can register their access nodes | +| N | Staking auction ends | Three of the nodes registered during this epoch are randomly selected to be a part of the network in the next epoch. No more nodes can register until the next epoch starts. | +| N+1 | Epoch N+1 starts | The newly selected nodes can now participate in the network. Three new slots are opened. | + +## How To Run a Permissionless Access Node? + +:::note + +To run an access node you will need to provision a machine or virtual machine to run your node software. Please follow the [node-provisioning](../node-operation/node-provisioning.md) guide for it. +You can provision the machine before or after your node has been chosen. + +::: + +At a high level, to run a permissionless Access node, you will have to do the following steps: +1. Generate the node identity (private and public keys, node ID etc.). +2. Stake the node with 100 FLOW by the end of the staking phase of the current epoch (see [timing](#timing)) by providing the node information generated in step 1. +3. You can verify if your node ID was selected by the on-chain random selection process on Wednesday at around 20:00 UTC when the next epoch starts. +4. If your node ID was selected, you can provision and start running the node. If your node wasn't selected, your tokens will have been refunded to your unstaked bucket in the staking smart contract. When the next epoch begins, you can try committing tokens again in a future epoch to get a new spot. + +Following is a detail explanation of these four steps. +If you want to run multiple access nodes, you will have to run through these steps for each node. + +## Step 1 - Generate Node Information + +### Download the Bootstrapping Kit + +```shell +curl -sL -O storage.googleapis.com/flow-genesis-bootstrap/boot-tools.tar +tar -xvf boot-tools.tar +``` + +```shell CheckSHA256 +sha256sum ./boot-tools/bootstrap +460cfcfeb52b40d8b8b0c4641bc4e423bcc90f82068e95f4267803ed32c26d60 ./boot-tools/bootstrap +``` + +> If you have downloaded the bootstrapping kit previously, ensure the SHA256 hash for it still matches. If not, re-download to ensure you are using the most up-to-date version. + +### Generate Your Node Identity + +```shell +######################################################### +# Generate Keys +$ mkdir ./bootstrap +# YOUR_NODE_ADDRESS: FQDN associated to your instance +$ ./boot-tools/bootstrap key --address ":3569" --role access -o ./bootstrap +``` + +```shell Example +$./boot-tools/bootstrap key --address "flowaccess.mycompany.com:3569" --role access -o ./bootstrap + DBG will generate networking key + INF generated networking key + DBG will generate staking key + INF generated staking key + DBG will generate db encryption key + INF generated db encryption key + DBG assembling node information address=flowaccess.mycompany.com:3569 + DBG encoded public staking and network keys networkPubKey=f493a74704f6961ae7903e062ecd58d990672858eff99aece7bfbccf3aa02de8f1a624ecbf21a01e8b2f4a5854c231fbe218edd7762a34fea881f3958a215305 stakingPubKey=ae8dcf81f3a70d72036b7ba2c586ed37ed0eb82b9c0a4aab998a8420f98894f94c14f84fa716e93654d3940fc0c8ff4d19b504c90a5b4918b28f421e9d3659dc2b7e246025ebeffea0d83cceefe315d7ed346dbe412fdac51b64997d97d29f7e + INF wrote file bootstrap/public-root-information/node-id + INF wrote file bootstrap/private-root-information/private-node-info_e737ec6efbd26ef43bf676911cdc5a11ba15fc6562d05413e6589fccdd6c06d5/node-info.priv.json + INF wrote file bootstrap/private-root-information/private-node-info_e737ec6efbd26ef43bf676911cdc5a11ba15fc6562d05413e6589fccdd6c06d5/secretsdb-key + INF wrote file bootstrap/public-root-information/node-info.pub.e737ec6efbd26ef43bf676911cdc5a11ba15fc6562d05413e6589fccdd6c06d5.json + +$tree ./bootstrap/ +./bootstrap/ +├── private-root-information +│ └── private-node-info_e737ec6efbd26ef43bf676911cdc5a11ba15fc6562d05413e6589fccdd6c06d5 +│ ├── node-info.priv.json +│ └── secretsdb-key +└── public-root-information + ├── node-id + └── node-info.pub.e737ec6efbd26ef43bf676911cdc5a11ba15fc6562d05413e6589fccdd6c06d5.json + +3 directories, 4 files +``` + +:::warning + +_Use a fully qualified domain name for the network address. Please also include the port number in the network address e.g. `flowaccess.mycompany.com:3569`_ + +::: + +:::warning + +_Do not include the prefix `http://` in the network address._ + +::: + +:::tip + +If you would like to stake multiple access nodes, please ensure you generate a unique identity for each node. + +::: + +Your node identity has now been generated. Your node ID can be found in the file `./bootstrap/public-root-information/node-id`. + +```shell Example +$cat ./bootstrap/public-root-information/node-id +e737ec6efbd26ef43bf676911cdc5a11ba15fc6562d05413e6589fccdd6c06d5 +``` + +:::info + +All your private keys should be in the `bootstrap` folder created earlier. Please take a back up of the entire folder. + +::: + +## Step 2 - Stake the Node + +You need to now register the node on chain by staking the node via [Flow Port](https://port.onflow.org/). + +[Here](../../flow-port/staking-guide.md) is a guide on how to use Flow port if you are not familiar with it. +If you are staking via a custody provider or would like to directly submit a staking transaction instead follow this [guide](../../staking/index.md#how-do-i-stake). + +Fund you Flow account with at least 100.01 FLOW tokens, which covers the required stake plus the storage deposit. + +On Flow port, choose `Stake and Delegate` -> `Start Staking` or `Stake Again` and then choose Access node as the option. + +![choose_access_flowport](../node-operation/choose_access_flowport.png) + +On the next screen, provide the node details of you node. + +Those node details (`Node ID`, `Network Address`, `Networking Key` and `Staking Key`) can be found in the file: `./bootstrap/public-root-information/node-info.pub..json`. + +```shell Example +$cat ./bootstrap/public-root-information/node-info.pub. e737ec6efbd26ef43bf676911cdc5a11ba15fc6562d05413e6589fccdd6c06d5.json +{ + "Role": "access", + "Address": "flowaccess.mycompany.com:3569", + "NodeID": "e737ec6efbd26ef43bf676911cdc5a11ba15fc6562d05413e6589fccdd6c06d5", + "Weight": 0, + "NetworkPubKey": "f493a74704f6961ae7903e062ecd58d990672858eff99aece7bfbccf3aa02de8f1a624ecbf21a01e8b2f4a5854c231fbe218edd7762a34fea881f3958a215305", + "StakingPubKey": "ae8dcf81f3a70d72036b7ba2c586ed37ed0eb82b9c0a4aab998a8420f98894f94c14f84fa716e93654d3940fc0c8ff4d19b504c90a5b4918b28f421e9d3659dc2b7e246025ebeffea0d83cceefe315d7ed346dbe412fdac51b64997d97d29f7e" +} +``` + +#### Example + +![node_details_permissionless_an](../node-operation/node_details_permissionless_an.png) + +On the next screen, ensure that you stake 100 FLOW token. + +#### Example + +![transaction_register_node_permissionless_an](../node-operation/transaction_register_node_permissionless_an.png) + +Submit the Transaction. + +## Step 3 - Verify That Your Node ID Was Selected + +On Wednesday at around 12:00 UTC, the staking auction for the current epoch will end and five nodes from candidate list of nodes will be chosen at random by the staking contract to be part of the next epoch. + +:::note + +If all 5 slots have been taken from the previous epoch, then no new access nodes will be chosen (see #limitations) + +::: + +There are several ways to verify whether your node was chosen as explained below. + +When you stake the node, the tokens will show up under the `tokensCommitted` bucket. After the staking auction ends, if the node is selected, the tokens remain in the `tokensCommitted` bucket and are moved to the `tokensStaked` bucket at the end of the epoch. +If the node is not selected, the tokens are moved to the `tokensUnstaked` bucket. + +### Check Using Flow Port +You can check these balances on Flow Port before and after the epoch transition that will occur on Wednesday (see [timing](#timing)). + +When you stake the node, you should see the following on Flow Port under `Stake & Delegate` + +![Staked_node](../node-operation/Staked_FlowPort.png) + +After the epoch transition, if you see you token balance under the Staked Amount then your node got chosen. + +![Staked_node](../node-operation/Selected_FlowPort.png) + +Instead, if you see that your token balance is under the Unstaked Amount, then your node did not get chosen. + +![Unstaked_node](../node-operation/Unstaked_FlowPort.png) + +### Check Using Flow CLI + +You can also check these balance using [Flow Cli](https://github.com/onflow/flow-cli). Once you have downloaded and installed Flow Cli, you can query the account balance using the command, +```shell +flow accounts staking-info -n mainnet +``` + +For Example, the following node was chosen as Tokens staked is 100. + +```shell Example +$ flow accounts staking-info 0xefdfb20806315bfa -n testnet + +Account staking info: + ID: "e737ec6efbd26ef43bf676911cdc5a11ba15fc6562d05413e6589fccdd6c06d5" + Initial Weight: 100 + Networking Address: "flowaccess.mycompany.com:3569" + Networking Key: "f493a74704f6961ae7903e062ecd58d990672858eff99aece7bfbccf3aa02de8f1a624ecbf21a01e8b2f4a5854c231fbe218edd7762a34fea881f3958a215305" + Role: 5 + Staking Key: "ae8dcf81f3a70d72036b7ba2c586ed37ed0eb82b9c0a4aab998a8420f98894f94c14f84fa716e93654d3940fc0c8ff4d19b504c90a5b4918b28f421e9d3659dc2b7e246025ebeffea0d83cceefe315d7ed346dbe412fdac51b64997d97d29f7e" + Tokens Committed: 0.00000000 + Tokens To Unstake: 100.00000000 + Tokens Rewarded: 0.00000000 + Tokens Staked: 100.00000000 + Tokens Unstaked: 0.00000000 + Tokens Unstaking: 0.00000000 + Node Total Stake (including delegators): 0.00000000 +``` + +### Epoch Setup Event + +Alternatively, if you can monitor events, look for [the epoch setup event](../../staking/05-epoch-scripts-events.md#flowepochepochsetup) that gets emitted by the epoch contract. That event is emitted at the end of epoch N's staking auction and contains a list of node IDs that are confirmed for the next epoch. + +## Step 4 - Start Your Node + +If your node was selected as part of Step 3, you can now start your node. + +First you'll need to provision a machine or virtual machine to run your node software. Please see follow the [node-provisioning](../node-operation/node-provisioning.md) guide for it. + +The access node can be run as a Docker container with the following command. + +Be sure to set `$VERSION` below to the version tag (e.g. `v1.2.3`) corresponding to the latest **released** version [here](https://github.com/onflow/flow-go/releases) for version releases). Set `$NODEID` to your node's ID (see [Generate Your Node Identity](#generate-your-node-identity) section above). + + + + +```shell +docker run --rm \ +-v $PWD/bootstrap:/bootstrap:ro \ +-v $PWD/data:/data:rw \ +--name flow-go \ +--network host \ +gcr.io/flow-container-registry/access:$VERSION \ +--nodeid=$NODEID \ +--bootstrapdir=/bootstrap \ +--datadir=/data/protocol \ +--secretsdir=/data/secrets \ +--rpc-addr=0.0.0.0:9000 \ +--http-addr=0.0.0.0:8000 \ +--rest-addr=0.0.0.0:80 \ +--rpc-metrics-enabled=true \ +--bind 0.0.0.0:3569 \ +--dynamic-startup-access-address=secure.mainnet.nodes.onflow.org:9001 \ +--dynamic-startup-access-publickey=28a0d9edd0de3f15866dfe4aea1560c4504fe313fc6ca3f63a63e4f98d0e295144692a58ebe7f7894349198613f65b2d960abf99ec2625e247b1c78ba5bf2eae \ +--dynamic-startup-epoch-phase=EpochPhaseStaking \ +--loglevel=error +``` + + + + +```shell +docker run --rm \ +-v $PWD/bootstrap:/bootstrap:ro \ +-v $PWD/data:/data:rw \ +--name flow-go \ +--network host \ +gcr.io/flow-container-registry/access:$VERSION \ +--nodeid=$NODEID \ +--bootstrapdir=/bootstrap \ +--datadir=/data/protocol \ +--secretsdir=/data/secrets \ +--rpc-addr=0.0.0.0:9000 \ +--http-addr=0.0.0.0:8000 \ +--rest-addr=0.0.0.0:80 \ +--rpc-metrics-enabled=true \ +--bind 0.0.0.0:3569 \ +--dynamic-startup-access-address=secure.testnet.nodes.onflow.org:9001 \ +--dynamic-startup-access-publickey=ba69f7d2e82b9edf25b103c195cd371cf0cc047ef8884a9bbe331e62982d46daeebf836f7445a2ac16741013b192959d8ad26998aff12f2adc67a99e1eb2988d \ +--dynamic-startup-epoch-phase=EpochPhaseStaking \ +--loglevel=error +``` + + + + +For example, if your Node ID is `e737ec6efbd26ef43bf676911cdc5a11ba15fc6562d05413e6589fccdd6c06d5` and the software version is `v1.2.3`, the Docker command would be the following: +```shell Example +docker run --rm \ + -v $PWD/bootstrap:/bootstrap:ro \ + -v $PWD/data:/data:rw \ + --name flow-go \ + --network host \ + gcr.io/flow-container-registry/access:v1.2.3 \ + --nodeid=e737ec6efbd26ef43bf676911cdc5a11ba15fc6562d05413e6589fccdd6c06d5 \ + --bootstrapdir=/bootstrap \ + --datadir=/data/protocol \ + --secretsdir=/data/secrets \ + --rpc-addr=0.0.0.0:9000 \ + --http-addr=0.0.0.0:8000 \ + --rest-addr=0.0.0.0:80 \ + --rpc-metrics-enabled=true \ + --bind 0.0.0.0:3569 \ + --dynamic-startup-access-address=secure.mainnet.nodes.onflow.org:9001 \ + --dynamic-startup-access-publickey=28a0d9edd0de3f15866dfe4aea1560c4504fe313fc6ca3f63a63e4f98d0e295144692a58ebe7f7894349198613f65b2d960abf99ec2625e247b1c78ba5bf2eae \ + --dynamic-startup-epoch-phase=EpochPhaseStaking \ + --loglevel=error +``` + +> If you would like your node to sync from the start of the last network upgrade, then please see the instructions [here](https://developers.flow.com/networks/node-ops/node-operation/spork) + +Alternatively, you can build a binary for the access node to run it without using Docker. +To build the access node binary, see the instructions [here](https://github.com/onflow/flow-go?tab=readme-ov-file#building-a-binary-for-the-access-node). +Please make sure to git checkout the latest release tag before building the binary. + + + + +```shell +$PWD/flow-go/flow_access_node \ +--nodeid=e1a8b231156ab6f2a5c6f862c933baf5e5c2e7cf019b509c7c91f4ddb0a13398 \ +--bootstrapdir=$PWD/bootstrap \ +--datadir=$PWD/data/protocol \ +--secretsdir=$PWD/data/secrets \ +--execution-data-dir=$PWD/data/execution_data \ +--rpc-addr=0.0.0.0:9000 \ +--secure-rpc-addr=0.0.0.0:9001 \ +--http-addr=0.0.0.0:8000 \ +--rest-addr=0.0.0.0:8070 \ +--admin-addr=localhost:9002 \ +--bind=0.0.0.0:3569 \ +--dht-enabled=false \ +--grpc-compressor=gzip \ +--profiler-dir=$PWD/data/profiler \ +--dynamic-startup-access-address=secure.mainnet.nodes.onflow.org:9001 \ +--dynamic-startup-access-publickey=28a0d9edd0de3f15866dfe4aea1560c4504fe313fc6ca3f63a63e4f98d0e295144692a58ebe7f7894349198613f65b2d960abf99ec2625e247b1c78ba5bf2eae \ +--dynamic-startup-epoch-phase=EpochPhaseStaking +``` + + + + +```shell +$PWD/flow-go/flow_access_node \ +--nodeid=e1a8b231156ab6f2a5c6f862c933baf5e5c2e7cf019b509c7c91f4ddb0a13398 \ +--bootstrapdir=$PWD/bootstrap \ +--datadir=$PWD/data/protocol \ +--secretsdir=$PWD/data/secrets \ +--execution-data-dir=$PWD/data/execution_data \ +--rpc-addr=0.0.0.0:9000 \ +--secure-rpc-addr=0.0.0.0:9001 \ +--http-addr=0.0.0.0:8000 \ +--rest-addr=0.0.0.0:8070 \ +--admin-addr=localhost:9002 \ +--bind=0.0.0.0:3569 \ +--dht-enabled=false \ +--grpc-compressor=gzip \ +--profiler-dir=$PWD/data/profiler \ +--dynamic-startup-access-address=secure.testnet.nodes.onflow.org:9001 \ +--dynamic-startup-access-publickey=ba69f7d2e82b9edf25b103c195cd371cf0cc047ef8884a9bbe331e62982d46daeebf836f7445a2ac16741013b192959d8ad26998aff12f2adc67a99e1eb2988d \ +--dynamic-startup-epoch-phase=EpochPhaseStaking +``` + + + + +For a more mature setup, it is recommended that you run the container using systemd as described [here](../node-operation/node-setup.md#systemd) + +> 🚀 The access node should now be up and running, and you should be able to query the node using Flow CLI or curl, + +```shell Example +flow blocks get latest --host localhost:9000 +``` + +```shell Example +curl http://localhost/v1/blocks?height=sealed +``` + +## Monitoring and Metrics + +The node publishes several Prometheus metrics. See [Monitoring Node Health](../node-operation/monitoring-nodes.md) to setup node monitoring. + +### Node Status + +The metrics for the node should be able to provide a good overview of the status of the node. If we want to get a quick snapshot of the status of the node, and if it's properly participating in the network, you can check the `consensus_compliance_finalized_height` or `consensus_compliance_sealed_height` metric, and ensure that it is not zero and strictly increasing. + +```shell +curl localhost:8080/metrics | grep consensus_compliance_sealed_height + +# HELP consensus_compliance_sealed_height the last sealed height +# TYPE consensus_compliance_sealed_height gauge +consensus_compliance_sealed_height 1.132054e+06 +``` + +## FAQs + +### Will the access node receive rewards? + +No, the access nodes do not receive any rewards. + +### Why is there a 100 FLOW token minimum? + +As mentioned in the [FLIP](https://github.com/onflow/flips/blob/main/protocol/20220719-automated-slot-assignment.md), the minimum is required to prevent certain vulnerabilities +in the smart contract that are a result of having a zero minimum stake requirement. + +### Can the Access node be unstaked? + +Yes, like any other staked node, the Access node can be unstaked. The staked tokens will be moved to the unstaked bucket in the subsequent epoch. + +### How to see all the access nodes that have staked? + +When the nodes are initially staked, they are all added to the candidate list of nodes before the end of the epoch staking phase. +The list can be retrieved from the chain by executing the [get_candidate_nodes](https://github.com/onflow/flow-core-contracts/blob/48ba17d3386023d70817197a20effbc5d16339b3/transactions/idTableStaking/scripts/get_candidate_nodes.cdc) script which returns the candidate list for the current epoch. + +```shell +$ flow scripts execute ./transactions/idTableStaking/scripts/get_candidate_nodes.cdc -n mainnet +``` + +### How to check the availability of open access nodes slots for the next epoch? + +The limits for the open slots are defined in the staking contract and can be queried from the chain by executing the [get_slot_limits](https://github.com/onflow/flow-core-contracts/blob/master/transactions/idTableStaking/scripts/get_slot_limits.cdc) script. + +Node types are defined [here](https://github.com/onflow/flow-core-contracts/blob/5696ec5e3e6aa5fc10762cbfeb42b9c5c0b8ddbe/contracts/FlowIDTableStaking.cdc#L114-L119) + +```shell + +$ flow scripts execute ./transactions/idTableStaking/scripts/get_slot_limits.cdc --args-json '[{ "type":"UInt8", "value":"5"}]' -n mainnet +Result: 118 +``` + +Example: there are 115 access nodes already part of the network. Hence, the total number of new nodes that can join are 118 - 115 = 3. + + +=== networks/node-ops/access-nodes/access-node-configuration-options.md === +--- +title: Serving execution data +sidebar_label: Execution Data +sidebar_position: 2 +--- + +Flow chain data comprises of two parts, +1. Protocol state data - This refers to the blocks, collection, transaction that are being continuously added to the chain. +2. Execution state data - This refers to what makes up the execution state and includes transaction events and account balances. + +The access node by default syncs the protocol state data and has been now updated to also sync the execution state data. +This guide provides an overview of how to use the execution data sync feature of the Access node. + + + + +## Setup node’s directory + +The access node typically has the following directory structure: + +```bash +$ tree flow_access + flow_access/ + ├── bootstrap + │ ├── private-root-information (with corresponding AN data) + │ └── execution-state + │ └── public-root-information + │ ├── node-id + │ └── node-info.pub.NODE_ID.json + │ └── root-protocol-state-snapshot.json (the genesis data) + └── data (directory used by the node to store block data) + │ └── execution-data + │ └── execution-state + +``` + +## Setup execution data indexing + +First, your node needs to download and index the execution data. There are 3 steps: + +1. Enable Execution Data Sync +2. Download the root checkpoint file +3. Configure the node to run the indexer +4. Use the indexed data in the Access API. + +As of **`mainnet24`** / **`devnet49`**, Access nodes can be configured to index execution data to support local script execution, and serving all of the Access API endpoints using local data. There are different setup procedures depending on if you are enabling indexing immediately after a network upgrade, or at some point between upgrades. + +# Enable Execution Data Sync + +This is enabled by default, so as long as you didn’t explicitly disable it, the data should already be available. + +1. Make sure that either `--execution-data-sync-enabled` is not set, or is set to `true` +2. Make sure that you have a path configured for `--execution-data-dir`, otherwise the data will be written to the running user’s home directory, which is most likely inside the container’s volume. For example, you can create a folder within the node’s data directory `/data/execution-data/`. + +There are some additional flags available, but you most likely do not need to change them. + +## **Option 1: Enabling Indexing at the Beginning of a Spork** + +### Download the root protocol state snapshot + +The `root-protocol-state-snapshot.json` is generated for each [spork](https://developers.flow.com/networks/node-ops/node-operation/spork) and contains the genesis data for that spork. It is published and made available after each spork. The download location is specified [here](https://github.com/onflow/flow/blob/master/sporks.json) under [rootProtocolStateSnapshot](https://github.com/onflow/flow/blob/master/sporks.json#L16). + +Store the **`root-protocol-state-snapshot.json`** into the **`/bootstrap/public-root-information/`** folder. + +### Download the root checkpoint + +The root checkpoint for the network is used by Execution nodes and Access nodes to bootstrap their local execution state database with a known trusted snapshot. The checkpoint contains 18 files that make up the merkle trie used to store the blockchain’s state. + +The root checkpoint for each spork is hosted in GCP. You can find the link for the specific network in the [`sporks.json`](https://github.com/onflow/flow/blob/master/sporks.json) file. Here’s the URL for `mainnet24`: + +[https://github.com/onflow/flow/blob/52ee94b830c2d413f0e86c1e346154f84c2643a4/sporks.json#L15](https://github.com/onflow/flow/blob/52ee94b830c2d413f0e86c1e346154f84c2643a4/sporks.json#L15) + +The URL in that file will point to a file named `root.checkpoint`. This is the base file and is fairly small. There are 17 additional files that make up the actual data, named `root.checkpoint.000`, `root.checkpoint.001`, …, `root.checkpoint.016`. If you have `gsutil` installed, you can download them all easily with the following command. + +```bash +gsutil -m cp "gs://flow-genesis-bootstrap/[network]-execution/public-root-information/root.checkpoint*" . +``` + +Where `[network]` is the network you are downloading for. For example, `mainnet-24` or `testnet-49`. + +Once the files are downloaded, you can either move them to `/bootstrap/execution-state/` within the node’s bootstrap directory or put them in any mounted directory and reference the location with this cli flag: `--execution-state-checkpoint=/path/to/root.checkpoint`. The naming of files should be `root.checkpoint.*`. + +## **Option 2: Enabling Indexing Mid-Spork** + +### Identify the root checkpoint + +The root checkpoint for the network is used by Execution and Access nodes to bootstrap their local execution state database with a known trusted snapshot. The checkpoint contains 18 files that make up the merkle trie used to store the blockchain’s state. + +Root checkpoints are periodically generated on Flow Foundation execution nodes and uploaded to a GCP bucket. You can see +a list of available checkpoints [here](https://console.cloud.google.com/storage/browser/flow-genesis-bootstrap/checkpoints), +or list them using the [gsutil](https://cloud.google.com/storage/docs/gsutil) command + +```bash +gsutil ls "gs://flow-genesis-bootstrap/checkpoints/" +``` + +The checkpoint paths are in the format `flow-genesis-bootstrap/checkpoints/[network]/[epoch number]-[block height]/`. +Where +* `[network]` is the network the checkpoint is from. For example, `mainnet` or `testnet`. +* `[epoch number]` is the epoch number when the checkpoint was taken. You can find the current epoch number on the [flowscan.io](https://flowscan.io/) home page. +* `[block height]` is the block height at which the checkpoint was taken. +Make sure that the checkpoint you select is from an epoch when your node was part of the network. + +### Download the root checkpoint + +Once you have selected the checkpoint to download, you can download the files. If you have `gsutil` installed, you can download them all easily with the following command. + +```bash +gsutil -m cp "gs://flow-genesis-bootstrap/checkpoints/[network]/[epoch number]-[block height]/root.checkpoint*" . +``` + +Once the files are downloaded, you can either move them to `/bootstrap/execution-state/` within the node’s bootstrap directory or put them in any mounted directory and reference the location with this cli flag: `--execution-state-checkpoint=/path/to/root.checkpoint`. The naming of files should be `root.checkpoint*`. + +### Download the root protocol state snapshot + +Access nodes require that the data in the root checkpoint corresponds to the root block in the `root-protocol-state-snapshot.json` file. +It's important to download the snapshot for the correct height, otherwise bootstrapping will fail with an error described in the Troubleshooting section. + +You can download the `root-protocol-state-snapshot.json` file generated by the Execution from the same GCP bucket. + +```bash +gsutil cp "gs://flow-genesis-bootstrap/checkpoints/[network]/[epoch number]-[block height]/root-protocol-state-snapshot.json" . +``` + +Alternatively, you can download it directly from a trusted Access node using the `GetProtocolStateSnapshotByHeight` gRPC endpoint +with the corresponding height. You will get a `base64` encoded snapshot which decodes into a json object. At this time, this endpoint is only support using the grpc API. + +Store the **`root-protocol-state-snapshot.json`** into the **`/bootstrap/public-root-information/`** folder. + + +# Configure the node to run the indexer + +Now you have the execution sync setup and the root checkpoint in place, it’s time to configure the node to index all of the data so it can be used for script execution. + +There are 2 cli flags that you will need to add: + +- `--execution-data-indexing-enabled=true` This will enable the indexer. +- `--execution-state-dir` This defines the path where the registers db will be stored. A good default is on the same drive as the protocol db. e.g. `/data/execution-state` + + +# Start your node + +Now that all of the settings to enable indexing are in place, you can start your node. + +At a minimum, you will need the following flags: + +``` +--execution-data-indexing-enabled=true +--execution-state-dir=/data/execution-state +--execution-data-sync-enabled=true +--execution-data-dir=/data/execution-data +``` + +For better visibility of the process, you can also add + +`-p 8080:8080` - export port 8080 from your docker container, so you could inspect the metrics + +`--loglevel=info` - for checking logs. + +Notes on what to expect: + +- On startup, the node will load the checkpoint into the `execution-state` db. For `devnet48`, this takes 20-30 min depending on the node’s specs. For `mainnet24`, it takes >45 min. The loading time will increase over time. You can follow along with the process by grepping your logs for `register_bootstrap`. +- After the checkpoint is loaded, the indexer will begin ingesting the downloaded execution data. This will take several hours to days depending on if the data was already downloaded and the hardware specs of the node. +- If your node already had all the data, it will index all of it as quickly as possible. This will likely cause the node to run with a high CPU. + +When you restart the node for the first time with syncing enabled, it will sync execution data for all blocks from the network. + +# Use the indexed data in the Access API + +### Setup Local Script Execution + +Local execution is controlled with the `--script-execution-mode` flag, which can have one of the following values: + +- `execution-nodes-only` (default): Requests are executed using an upstream execution node. +- `failover` (recommended): Requests are executed locally first. If the execution fails for any reason besides a script error, it is retried on an upstream execution node. If data for the block is not available yet locally, the script is also retried on the EN. +- `compare`: Requests are executed both locally and on an execution node, and a comparison of the results and errors are logged. +- `local-only`: Requests are executed locally and the result is returned directly. + +There are a few other flags available to configure some limits used while executing scripts: + +- `--script-execution-computation-limit`: Controls the maximum computation that can be used by a script. The default is `100,000` which is the same as used on ENs. +- `--script-execution-timeout`: Controls the maximum runtime for a script before it times out. Default is `10s`. +- `--script-execution-max-error-length`: Controls the maximum number of characters to include in script error messages. Default is `1000`. +- `--script-execution-log-time-threshold`: Controls the run time after which a log message is emitted about the script. Default is `1s`. +- `--script-execution-min-height`: Controls the lowest block height to allow for script execution. Default: `no limit`. +- `--script-execution-max-height`: Controls the highest block height to allow for script execution. Default: `no limit`. +- `--register-cache-size`: Controls the number of registers to cache for script execution. Default: `0 (no cache)`. + +### Setup Using Local Data with Transaction Results and Events + +Local data usage for transaction results and events are controlled with the `--tx-result-query-mode` and `--event-query-mode` corresponding flags, which can have one of the following values: + +- `execution-nodes-only` (default): Requests are forwarded to an upstream execution node. +- `failover` (recommended): - `failover` (recommended): Requests are handled locally first. If the processing fails for any reason, it is retried on an upstream execution node. If data for the block is not available yet locally, the script is also retried on the EN. +- `local-only`: Requests are handled locally and the result is returned directly. + +# Troubleshooting + +- If the root checkpoint file is missing or invalid, the node will crash. It must be taken from the same block as the `root-protocol-state-snapshot.json` used to start your node. +- If you don’t set one the `--execution-data-dir` and `--execution-state-dir` flags, the data will be written to the home directory inside the container (likely `/root`). This may cause your container to run out of disk space and crash, or lose all data each time the container is restarted. +- If your node crashes or restarts before the checkpoint finishes loading, you will need to stop the node, delete the `execution-state` directory, and start it again. Resuming is currently not supported. +- If you see the following message then your `checkpoint` and `root-protocol-state-snapshot` are not for the same height. + +```json +{ + "level":"error", + ... + "module":"execution_indexer", + "sub_module":"job_queue", + "error":"could not query processable jobs: could not read job at index 75792641, failed to get execution data for height 75792641: blob QmSZRu2SHN32d9SCkz9KXEtX3M3PozhzksMuYgNdMgmBwH not found", + "message":"failed to check processables" +} +``` + +- You can check if the execution sync and index heights are increasing by querying the metrics endpoint: + ``` + curl localhost:8080/metrics | grep highest_download_height + curl -s localhost:8080/metrics | grep highest_indexed_height + ``` + +# Execution Data Sync + +The Execution Sync protocol is enabled by default on Access nodes, and uses the bitswap protocol developed by Protocol Labs to share data trustlessly over a peer-to-peer network. When enabled, nodes will download execution data for each block as it is sealed, and contribute to sharing the data with its peers. The data is also made available to systems within the node, such as the `ExecutionDataAPI`. + +Below is a list of the available CLI flags to control the behavior of Execution Sync requester engine. + +| Flag | Type | Description | +| --- | --- | --- | +| execution-data-sync-enabled | bool | Whether to enable the execution data sync protocol. Default is true | +| execution-data-dir | string | Directory to use for Execution Data database. Default is in the user’s home directory. | +| execution-data-start-height | uint64 | Height of first block to sync execution data from when starting with an empty Execution Data database. Default is the node’s root block. | +| execution-data-max-search-ahead | uint64 | Max number of heights to search ahead of the lowest outstanding execution data height. This limits the number non-consecutive objects that will be downloaded if an earlier block is unavailable. Default is 5000. | +| execution-data-fetch-timeout | duration | Initial timeout to use when fetching execution data from the network. timeout increases using an incremental backoff until execution-data-max-fetch-timeout. Default is 10m. | +| execution-data-max-fetch-timeout | duration | Maximum timeout to use when fetching execution data from the network. Default is 10s | +| execution-data-retry-delay | duration | Initial delay for exponential backoff when fetching execution data fails. Default is 1s | +| execution-data-max-retry-delay | duration | Maximum delay for exponential backoff when fetching execution data fails. Default is 5m | + + + +# Execution Data Indexer + +Below is a list of the available CLI flags to control the behavior of Execution Data Indexer. + +| Flag | Type | Description | +| --- | --- | --- | +| execution-data-indexing-enabled | bool | Whether to enable the execution data indexing. Default is false | +| execution-state-dir | string | Directory to use for execution-state database. Default is in the user’s home directory. | +| execution-state-checkpoint | string | Location of execution-state checkpoint (root.checkpoint.*) files. | +| event-query-mode | string | Mode to use when querying events. one of [local-only, execution-nodes-only(default), failover] | +| tx-result-query-mode | string | Mode to use when querying transaction results. one of [local-only, execution-nodes-only(default), failover] | + +Below is a list of the available CLI flags to control the behavior of Script Execution. + +| Flag | Type | Description | +| --- | --- | --- | +| script-execution-mode | string | Mode to use when executing scripts. one of [local-only, execution-nodes-only, failover, compare ] | +| script-execution-computation-limit | uint64 | Maximum number of computation units a locally executed script can use. Default: 100000 | +| script-execution-max-error-length | int | Maximum number characters to include in error message strings. additional characters are truncated. Default: 1000 | +| script-execution-log-time-threshold | duration | Emit a log for any scripts that take over this threshold. Default: 1s | +| script-execution-timeout | duration | The timeout value for locally executed scripts. Default: 10s | +| script-execution-min-height | uint64 | Lowest block height to allow for script execution. Default: no limit | +| script-execution-max-height | uint64 | Highest block height to allow for script execution. default: no limit | +| register-cache-type | string | Type of backend cache to use for registers [lru, arc, 2q] | +| register-cache-size | uint | Number of registers to cache for script execution. Default: 0 (no cache) | +| program-cache-size | uint | [experimental] number of blocks to cache for cadence programs. use 0 to disable cache. Default: 0. Note: this is an experimental feature and may cause nodes to become unstable under certain workloads. Use with caution. | + +# Resources + +FLIP: [https://github.com/onflow/flips/blob/main/protocol/20230309-accessnode-event-streaming-api.md](https://github.com/onflow/flips/blob/main/protocol/20230309-accessnode-event-streaming-api.md) + +Protobuf: [https://github.com/onflow/flow/blob/master/protobuf/flow/executiondata/executiondata.proto](https://github.com/onflow/flow/blob/master/protobuf/flow/executiondata/executiondata.proto) + +=== networks/network-architecture/user-safety.md === +--- +title: User safety +sidebar_label: User safety +sidebar_position: 4 +--- + +# User Safety with Flow + +The monolithic node design of common L1s such as Bitcoin and Ethereum overly privileges operator control over block production. +This makes the chain vulnerable to censorship and MEV attacks. This problem is exacerbated by L2s with centralized sequencers. ERC-4337 is also susceptible to MEV on the user operations via bundlers. + +![mev](images/mev_attack.png) + +Flow’s multi-role architecture provides censorship & MEV resistance by design: +- Transactions are randomly assigned to collection nodes for inclusion in collections and eventually in blocks. Each collection node only sees a subset of transactions. + + +- There is already a distinct separation between the proposers (represented by the collection nodes) and the builders (represented by the consensus nodes). This separation essentially provides an inherent implementation of "proposer-builder separation," a concept currently being explored by Ethereum. With this separation, even if the collection nodes were to reorder the transactions, there is no incentive for the consensus nodes to prefer one collection node’s proposal over another. + +![mev_protection](images/mev_protection_in_flow.png) + + +=== networks/network-architecture/sustainability.md === +--- +title: Sustainability +sidebar_label: Sustainability +sidebar_position: 3 +--- + +# Sustainability with Flow + +It's no secret that Proof of Stake blockchains are better for the environment. +As Web3 becomes more widely adopted, we engaged with Deloitte Canada to validate how much energy it uses. +And the results are astounding: Flow uses just 0.18 GWh annually, based on 2021 usage – or in simpler terms, minting an NFT on Flow takes less energy than a Google search or Instagram post. + + +In addition to operating on a Proof of Stake consensus system, Flow’s multi-role node architecture securely divides the processing between specialized node types, making the network significantly more efficient than other blockchain architectures. +As network usage grows, vertical scaling is only needed for the execution nodes (as they execute transactions and persist all the chain state). +Because the increase in energy and hardware consumption over time is restricted to a small subset of the nodes in the network, this drastically limits the environmental footprint of the chain. + +The overall energy use of the network won’t increase significantly even if the activity increases by 100x or more, making the per-transaction energy footprint decrease over time. + +Read more about it [here](https://flow.com/post/flow-blockchain-sustainability-energy-deloitte-report-nft). + +=== networks/network-architecture/solving-blockchain-trilemma.md === +--- +title: Solving the blockchain trilemma +sidebar_label: Solving the blockchain trilemma +sidebar_position: 2 +--- + +# Solving the blockchain trilemma + +In a monolithic architecture, all nodes perform every task. As network usage grows, the transaction processing capacity of the individual nodes becomes a limiting factor, restricting the network’s throughput and latency. The amount of data that can be stored on-chain is limited since nodes have a finite storage capacity. The only way to scale monolithic blockchains is by increasing the capacity of each node by adding more CPU, memory, and storage (i.e. vertical scaling, an approach taken by Solana). However, this solution comes at the cost of decentralization. As nodes scale vertically, they become more expensive to run, and eventually, only a few operators can afford to run such high-performance, high-capacity nodes. Worse, energy consumption for every node in the network increases over time, making the chain environmentally unsustainable. + +Through its multi-role architecture, Flow implements a modular pipeline for processing transactions. This design allows the network to scale by tuning the level of decentralization at each specific step without sharding the state and fragmenting the network into smaller security zones. + +The modular pipeline is composed of Collection, Consensus, Execution and Verification Nodes. + +![pipeline](images/pipeline.png) + + +## Separating Consensus from Compute + +At a high level, the pipeline essentially separates consensus from transaction computation. Non-deterministic (or “subjective”) processes such as determining the inclusion and order of transactions are decided by the broadly decentralized consensus committee. The deterministic (or “objective”) task of computing the result of those ordered transactions is done independently by a small number of specialized execution nodes. + +Collection and consensus are highly decentralized and achieve high levels of redundancy through a large number of lightweight, cost-effective nodes, numbering in the thousands, operated by several hundred different operators. These steps guarantee resilient transaction ordering (assuming that a malicious actor can only compromise a limited number of nodes). + +In comparison, transaction execution has low decentralization and redundancy (10 or less) with more powerful and expensive nodes. To accommodate for the anticipated growth of on-chain state without sharding, only the execution nodes have to be scaled vertically. All other node types can continue to run low-cost hardware. The execution nodes may eventually be scaled up to small data centers. + +![scaling_flow](images/scaling_flow.png) + +Low decentralization for transaction execution might appear to compromise decentralization of the whole network, as it is conceivable that a malicious actor might compromise a dominant fraction of nodes participating in execution. However, correctness of the transaction results is still guaranteed by the verification step, which also requires reasonably high redundancy, again with a large number of lighter and less expensive verification nodes to withstand compromisation attempts. + +Every node in Flow makes the protocol stronger, and the network can grow as needed to achieve different objectives: +- More censorship resistance? Add more collection nodes +- More decentralized block production? Add more consensus nodes +- Need to accommodate higher transaction throughput and state storage? Scale up execution nodes +- Do node operators want to reinforce network security with modest node hardware and low stake? Add more verification nodes. +- Need access to chain data locally? Add access nodes. + +In contrast, when traditional Layer 1 blockchains add more nodes to increase decentralization, they do so without providing any additional benefits. + +![verying_redundancy](images/varying_redudancy.png) + +> Flow’s architectural goals are to provide a throughput of at least 1M TPS, ingest at least ½ GB of transaction data per second and store and serve a very large state of one Patebyte and beyond. + +Thus, Flow’s multi-role architecture solves the blockchain trilemma: + +1. **Scalability**: Scale to thousands of times higher throughput and on-chain storage capacity. + +2. **Decentralization**: Except for the execution nodes, all nodes are light weight and low cost, lowering the barrier to entry and ensuring participation from a diverse set of node operators—big and small + +3. **Security**: Maintain a shared non-sharded execution environment for all operations on the network and use a secure in-built platform to build on. + +![trilemma_solved](images/flow_trillema_solved.png) + +=== networks/network-architecture/index.md === +--- +title: Flow's Network Architecture +sidebar_position: 1 +--- + +Flow has pioneered a new paradigm of multi-role architecture that solves the core problem of today’s blockchains. +The result is a scalable, decentralized, and secure network which ensures user safety and long-term sustainability. + +
    + +![flow_gif](images/flow_node_types_1.gif) + +
    + +To better understand the architecture, lets first understand the problems with the current blockchain. Then lets look at how Flow multi-role architecture solves these problems. + +# What are the biggest problems solved by Flow's Multi-role Architecture? + +## 1. The blockchain trilemma + +A blockchain should be fully decentralized, highly scalable and extremely secure. However a well-known problem with all blockchain is the blockchain trilemma - optimizing for any one edge comes at the cost of the other two. + +You can have a chain that is decentralized and secure but not scalable e.g. Bitcoin and Ethereum or you can have a chain that is scalable and secure but not as decentralized e.g. Solana, Aptos and Sui. +While multi-chain systems like Cosmos, Layer 2 solutions (L2s) like Polygon, and cross-chain bridges offer innovative approaches to address these challenges, they divide the trust into separate and independent security zones and such zones with fewer validators can be more vulnerable to attacks and therefore less secure. + +![scenario_1](images/trilemma.png) + +## 2. Disadvantaging end-users +Most blockchains, regardless of the number of participating nodes, inherently disadvantage individual end-users. This is because (colluding) nodes can censor user transactions or unfairly extract value from users in a phenomenon commonly known as Miner Extractable Value [MEV]. As a result, individual end users can end up paying an “invisible tax” or otherwise seeing their transactions fail due to MEV. + + +## 3. Energy inefficient and unsustainable +It is well established that Proof-of-Work chains like Bitcoin consume massive amounts of energy, require perpetual hardware upgrades for the miners to stay competitive, and are therefore extremely harmful to the environment. A Proof-of-Stake chain’s environmental impact is less severe, but as web3 applications achieve mainstream adoption, every node in these chains will have to provide more and more hardware resources to meet the increasing throughput demand and the ever growing on-chain state. Vertically scaling the nodes implies higher energy consumption and environmental footprint. + +## Multi-role Architecture on Flow + +![banner](./images/banner.png) + +In first-generation smart contract blockchains like Ethereum and Bitcoin, every node in the network performs all of the work associated with processing every transaction (including the entire network’s history, account balances, smart contract code, etc.). While highly secure, it’s also incredibly inefficient, and does not scale throughput (transaction per second, transaction latency) and capacity (on-chain data storage). + +Most second-generation blockchain networks focus on improving performance in one of two ways: + +1. They compromise decentralization by requiring that participating nodes run on powerful servers (e.g. Solana); or +2. They dramatically increase smart developer complexity by breaking up the network through mechanisms such as sharding (e.g. L2s such as Polygon). + +The first approach is vulnerable to platform risk and cartel-like behavior. The second approach outsources the challenges of scaling the platform, effectively handing off the complexities of bridging the different strongly-federated ecosystems to application developers. + +Flow offers a new path: pipelining applied to blockchain networks. + +Pipelining is a well-established technique across various fields, from manufacturing to CPU design, for significantly increasing productivity. +Flow leverages this concept by distributing the tasks typically handled by a full node in a monolithic blockchain architecture across four specialized roles: Collection, Consensus, Execution, and Verification. +This division of labor between nodes occurs within the different validation stages for each transaction, rather than distributing transactions across different nodes as is done with sharding. +In other words, every Flow node still participates in the validation of every transaction, but they do so only at one of the stages of validation. +They can therefore specialize—and greatly increase the efficiency—for their particular stage of focus. + +### Flow node roles and what they do + +| | Node type | Responsibility | What do the nodes of this role do? | +|------------------------------------------|:--------------:|:--------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------| +| ![collection](images/collection.png) | Collection | Collection nodes act as a censorship-resistant data availability layer, which caches transactions for subsequent execution. | Collection nodes order transactions into batches known as collection. | +| ![consensus](images/consensus.png) | Consensus | The consensus committee serves as the security authority in the network and orchestrates Flow's transaction processing pipeline. | Consensus nodes order collections into blocks and commit execution results after verification. | +| ![execution](images/execution.png) | Execution | Execution nodes provide the computational resources for executing transactions and maintaining the state. | Execution nodes execute the transaction and record state changes. | +| ![verification](images/verification.png) | Verification | Verification nodes ensure that transactions are truthfully executed. | Verification nodes verify the work of the execution nodes. They either approve or disagree with their results, reporting their findings to the consensus nodes. | +| ![access](images/access.png) | Access | Access Nodes route transactions into the network and replicate (parts of) the state and transaction results for external clients to query. | Access node serve the API calls to send and read data from the chain. | + +### Further reading +1. [Primer on multi-role architecture](https://flow.com/primer#primer-multinode) +2. [Technical papers](https://flow.com/technical-paper) +3. [Core protocol vision](https://flow.com/core-protocol-vision) +4. [Medium article from Jan which deep dives into the Flow architecture](https://jan-bernatik.medium.com/introduction-to-flow-blockchain-7532977c8af8) + +In the next section, lets look at how Flow multi-role architecture solves those three big problems with blockchains. + +=== networks/flow-port/staking-guide.md === +--- +title: Flow Port Staking Guide +--- + +This guide provides step-by-step instructions for using the Flow Port to stake your FLOW tokens and start earning rewards. +Currently, Flow Port only supports staking or delegating using tokens held in Blocto or Ledger wallets. +If you're new to the concepts of staking and delegating you can [read this guide](../../networks/staking/index.md) to learn more. + +## First Step + +When you arrive in Port, select **Stake & Delegate** from the left-hand menu. You should be taken to this page. + +![Flow Port Staking pt. 0](port-stake-0-00.png) + +From here you can decide whether to stake or delegate. + +- Select **Stake** if you plan to stake a node you're running. +- Select **Delegate** to delegate your stake to another Node Operator. You don't need to know which Node Operator, you'll be provided with a list to choose from. If you are not running your own node you scan skip directly to the [delegation section](#delegating) + +## Stake a Node + +Users who will be running their own nodes can stake them using the Flow Port. + +#### Prerequisites + +In order to stake your node, you'll need to have the required amount of FLOW for your node type. +You'll also need the following information about your node: + +- Node ID +- Network Address +- Networking Key +- Staking Key +- Machine Account Public Key (for collection/consensus nodes only) + +If you don't have this information, go [here](../../networks/node-ops/node-operation/node-bootstrap.md#step-1---run-genesis-bootstrap) for instructions on how to acquire it. + +### Begin Staking + +First, select the type of node you'll be running by choosing from the list. You must have the required amount of locked FLOW in your account. + +![Flow Port Staking](port-stake-0-02.png) + +Once you selected your node type, click next and specify how much you'd like to stake. The minimum amount for your node type is required, +but you may stake as much as you like beyond that. Here's the screen you should see: + +![Flow Port Staking](port-stake-0-03.png) + +Clicking next will take you to the final screen, where you'll need to enter information about your node you previously obtained. +If you don't have this information, go [here](../../networks/node-ops/node-operation/node-bootstrap.md#step-1---run-genesis-bootstrap) for instructions on how to acquire it. +Here's the screen you should see: + +![Flow Port Staking](port-stake-0-04.png) + +Clicking next will take you to a confirmation screen. This is your chance to double-check that you've entered your information correctly. If you're ready, check the +box confirming your information and click submit to send the transaction that will stake your node! You should see a transaction status screen like this: + +![Flow Port Staking](port-stake-0-05.png) + +**Note:** If your transaction fails, double-check the information you provided.

    + +If you return to the home screen, you'll be able to see your staking request in progress! + +![Flow Port Staking](port-stake-4.png) + +## Delegating + +Delegating is the process of staking your locked FLOW to nodes which are being run by another party. + +#### Prerequisites + +In order to delegate your stake to another node, you'll need to know the **node operator ID** of the operator who is running the nodes you wish to stake. +Here is a list of node operator IDs you can delegate to: [List of Available Node Operators](https://github.com/onflow/flow/blob/master/nodeoperators/NodeOperatorList.md) + +### Enter a Node Operator ID + +Simply enter the ID of the node operator of your choice and click next. + +![Flow Port Staking](port-delegate-1.png) + +### Enter an amount + +Next you'll enter an amount of FLOW you would like to delegate. When delegating you may send any amount to the node operator. + +![Flow Port Staking](port-delegate-2.png) + +Click next to reach the confirmation screen. Confirm the details of your delegation request and click submit! + +![Flow Port Staking](port-delegate-3.png) + +Once your transaction is submitted, you can monitor its status from this screen, or return to the Flow Port home screen. + +![Flow Port Staking](port-delegate-4.png) + +**Note:** If you transaction fails, double-check the information you provided.

    + +That's it! You've successfully delegated stake to your chosen node operator! + +## Returning to Port + +Within Flow Port, navigate to the ‘Stake & Delegate’ page to see details about your existing staked and/or delegated tokens. +This will also show you the rewards you have earned for your staked/delegated tokens. + +![Flow Port Staking pt. 1](port-stake-1.png) + +From here, you can do a few different things with your rewards: + +- You can choose to **re-stake** them to the associated node. +- You can choose to **withdraw** them to your wallet. + +## Re-staking + +Flow Port will not automatically re-stake your rewards. +To re-stake your rewards, simply hover your cursor over the 3 dots next to the rewards field: + +![Flow Port Re-Staking](port-stake-2.png) + +Click on the Restake option. This will take you to a screen that looks like the below. Input the amount of rewards you want to re-stake, acknowledge the transaction inputs and click submit: + +![Flow Port Re-Staking](port-stake-3.png) + +Once the transition is processed, you can reference the Stake & Delegate page again to see the pending stake now: + +![Flow Port Re-Staking](port-stake-4.png) + +## Withdraw your Rewards + +To withdraw your rewards, simply hover your cursor over the 3 dots next to the rewards field, and click on ‘Withdraw’. + +![Flow Port Re-Staking](port-stake-5.png) + +Input the amount that you want to withdraw to your wallet, acknowledge the transaction inputs and click submit: + +![Flow Port Re-Staking](port-stake-6.png) + +Once the transition is processed, you can now see the withdrawn rewards in your balance and you are now free to do other actions with them (send them to other accounts, delegate to a node, etc). + + +=== networks/flow-port/index.md === +--- +title: Flow Port +description: How to use Flow Port +--- + +Flow Port is an account management tool for Flow. Flow Port allows you to create an account using a wallet provider, manage your account and assets across Flow's VMs and perform staking and delegating actions on Flow. + +Typically, your wallet provider will support most of these features. However, should your wallet provider not do so, or should you wish to use this tool for any other reason, Flow Foundation makes it available for you. + +## Creating an Account +In order to access Flow Port, you must have a valid Flow address. If you do not have a Flow address you can create one by installing a [Flow compatible wallet](../../ecosystem/wallets). + +### Flow Wallet + +#### Creating Account Through Flow Port: Navigate To Flow Port + + 1. Using Google Chrome, Navigate to [Flow Port](https://port.onflow.org/). + + 2. Click on 'Sign Up' + + 3. Click on Flow Wallet and choose Chrome extension or Mobile + + 4. You should be logged into Flow Port! You can now see your account address in Flow Port and access Flow features for your account + +### Ledger +#### Before You Start + + 1. Ensure you have: + + - a.) [Ledger Live](https://www.ledger.com/ledger-live) installed on your computer + + - b.) [Initialized](https://support.ledger.com/hc/en-us/articles/360017362160-Flow-FLOW-?support=true) your Ledger Device. + +#### Install the Flow App + + 1. Connect your Ledger Device to your computer and open Ledger Live. + + 2. Make sure your Ledger device firmware is up to date. You can check this by clicking on **‘Manager’** from the side navigation bar. Choose to install the update if one is available + + - a.) NOTE: Sometimes the install option doesn't show up, or it is not clickable. If this is the case, wait for a little bit of time to see if it appears, or restart the ledger live app if necessary. + + 3. On the Manager screen in Ledger Live and search for ‘Flow’. + + 4. You should see the Flow App. Install it and follow the instructions on the device. + + - a.) NOTE: If the Flow App does not appear, it may be because you are on an outdated version. Please ensure you are on the most updated version. + +#### Navigate to Flow Port to Create an Address + + 1. Navigate to [Flow Port](https://port.onflow.org/). + + 2. Click on 'Sign Up' if you need to create a new Flow Account. + + 3. Click on Ledger. + + 4. Follow the prompts on the screen. Plug in your Ledger device and open the Flow App. + + 5. Click on Create an account. Follow the prompts on your Ledger device. + + 6. Once your account address is created, you will be automatically logged into Flow Port. + +## Staking & Delegating + +For a detailed walkthrough on how to use Flow Port for staking and delegating, please read the [Flow Port staking walkthrough](./staking-guide.md) +### How Do I Stake or Delegate? + +So you have decided you want to be a part of the Flow Network. Welcome! You are joining a group of people from all around the world that are a part of a movement centered around bringing decentralization, user empowerment, and transparency into the world. Below is a step-by-step guide that will assist you in the staking & delegation process. + +### Staking via a Custody Provider + +If you are using a custody provider who controls your account and private keys for you, such as Kraken, Finoa, or Coinlist, they all have different policies and processes for what you need to do to stake your tokens, the rewards you receive, and the fees that they take from your staking rewards. + +### Starting a Manual Staking Transaction + 1. You need to have FLOW in order to stake. Please see the [FLOW Token](../../build//core-contracts//03-flow-token.md) reference for information on how to become a FLOW holder. + + 2. Once you have FLOW tokens in your account, you can start staking through [Flow Port](https://port.onflow.org/) or, if applicable, with your [custody provider](#staking-via-a-custody-provider). + + 3. If you are using Flow Port, log-in with your Flow account address and navigate to the Stake/Delegate page. See the Manual Staking/Delegating section below for more information about what to do next. + +### Manual Staking/Delegating +If you are not using a custody provider, there is more responsibility that you have to accept, because you have complete control of your tokens. You need to ensure that you are well informed about the staking process and potentially node operation process because you will have to manage those on your own. Please read the [staking documentation](../../networks/staking/index.md) before continuing with this guide. + +Below are the various options you can choose. Please be aware, that at this time you can only have 1 stake or 1 delegate per account. This means that if you want to do multiple stakes, multiple delegates, or a mixture of stakes and delegates, you will need to create multiple accounts to do so. Please read them carefully as it will help you understand which route is best for your situation: +- Staking your own Node: You are responsible for running and maintaining a Flow Node. You are also solely responsible for providing the minimum stake for your selected node (minimum 135,000 FLOW) and you have the technical know-how and bandwidth to run and operate a node in the Flow protocol. +- Delegating: You have FLOW tokens and you want to stake, without having to run your own node and/or have the full minimum stake required to run your own node. You can ‘delegate’ any amount of your FLOW tokens to an existing node operator and you will earn rewards. + +Please see a list [here](https://github.com/onflow/flow/blob/master/nodeoperators/NodeOperatorList.md) for all node operators that you can delegate to. This list will be updated as new node operators are onboarded onto the network.' + +### Staking Your Own Node + 1. Once you have navigated to the staking/delegating page in Flow Port, click on the 'Stake a Node' option. + + 2. Next, select the type of node you will be running. + + 3. Input the amount of Flow you wish to stake with that node. You must stake at least the minimum in order for your stake request to be successfully processed. You are able to provide the minimum stake across multiple transactions. Meaning, you could execute your stake transaction with half of the minumum required. Then, before the next epoch, you can choose to 'Add Flow' to that pending stake to get it to the minimum stake required. + + 4. Run the [bootstrapping instructions](../../networks/node-ops/node-operation/node-bootstrap.md) and provide the remaining technical details needed to stake a node. + +### Delegating + 1. Once you have navigated to the staking/delegating page in Flow Port, click on the Delegate option. + + 2. Next, you will specify which node operator you would like to delegate to and how many tokens you want to delegate to them. + + 3. Execute the transaction. You will now see your pending delegation that will be processed during the next epoch. + + 4. At this point, you can also cancel the pending delegation. On the pending delegation, you will see an `X` that you can click to initiate the cancelation transaction. + +## I Have Successfully Executed a Stake Transaction, Now What? + - Now that you have executed a stake transaction in either Flow Port or your custody provider’s portal, that transaction will sit in a pending status until it is processed, which will be at the next [Epoch](../../networks/staking/index.md#epochs) Date (which is currently weekly). + - During the next [Epoch](../../networks/staking/index.md#epochs), the transaction will be processed. If successful, the provided FLOW will be staked and the associated Node would be either **a)** included in the network protocol if it is a new node or **b)** continue to operate as is in the network protocol. + - You are now a part of Flow, and will begin to earn rewards for being a valued member of the network! + +## What Else Can I Do? + - Add additional stake to your existing stake. Any added FLOW will again sit in a pending status and be processed at the next epoch. + - Withdraw/re-stake your earned rewards. If you decide to withdraw your rewards, this action will happen instantly. If you decide to re-stake your rewards, the request will again sit in a pending status and will be processed at the next [Epoch](../../networks/staking/index.md#epochs). + - Withdraw Rewards and send your earnings to other accounts. If you decide that you want to withdraw your rewards and send those earnings to other accounts via the 'Send FLOW' function, you should first withdraw your rewards. Once in your account, you can send these funds to any other account via the 'Send FLOW' option. + - Request to be unstaked from the network. The unstake request will sit in a pending status for two epochs. Once it is processed, the amount that has been unstaked will sit in your unstaked FLOW amount and can now be withdrawn or re-staked. + - Change the node you are staked/delegated to. If your staked/delegated node has no FLOW actively staked and you have completely withdrawn all unstaked amounts and rewards associated with the node, then you can move your stake to a different node. Click on the `Change Node` button to initiate this process. Please note that this feature is only visible once you get your active stake/delegate into the appropriate status. + +## FAQs + 1. Why do I have multiple 'Keys' on my account? + + If you created your account with Blocto, you will see that you have multiple keys that exist on your account in the 'Dashboard': + + 1 with weight 1 (device key): This is generated on Blocto and sent to users' device when they login with email. + 1 with weight 999 (Blocto service key): This is kept in Blocto's secure key management service and is used to sign transaction. + 1 with weight 1000 (recovery key): This is kept in Blocto's secure key management service and is only used when user wants to switch to non-custodial mode. + + Normally if a user wants to send a Flow transaction, it requires signature from both the key on users' device and a key from Blocto service. Making it harder for hackers to steal your assets. + + 2. Where can I find a list of node operators to delegate to? + + - a.) Please see a list [here](https://github.com/onflow/flow/blob/master/nodeoperators/NodeOperatorList.md) for all node operators that you can delegate to. This list will be updated as new node operators are onboarded onto the network. + + 3. I am currently running a node on the network already and have already gone through the staking process once. Do I need to execute a new stake every time there is a new epoch? + + - a.) Once you successfully stake your node and become part of the network, you do not need to submit a new staking request each and every epoch. Your node will be automatically staked from epoch to epoch. This also means that your Node ID will remain the same from epoch to epoch. If you want to unstake your node from the network, then you will follow the process of unstaking your node. + + 4. I have a Blocto account and I see that I can stake both in Flow Port and in Blocto's mobile app. What is the difference? + + - a.) If you go through Flow Port, you can choose any node operator within the Flow network to delegate any amount of your Flow Tokens to. If you go through Blocto's mobile site, you will only be able to stake to Blocto run nodes. You can read more about Blocto's staking process by referencing [here](https://guide.blocto.app/article/stake-flow-tokens-step-by-step-with-blocto). + + 5. Do I need to use my Ledger device to view information about my account (e.g. my balance and current staked or delegated FLOW)? + + - a.) No you do not! You only need your Ledger device to sign transactions. If you want to view your account, you can do so without your Ledger. You can do this by navigating directly to the appropriate desired page URL, while inputting your address into the URL itself. For quick reference, below is a list of these URLs and where you would input your address: + - Dashboard: https://port.onflow.org/account/[AccountAddress] + - Stake & Delegate: https://port.onflow.org/stake-delegate/[AccountAddress] + + 6. I am clicking 'submit' to execute a transaction, but nothing is happening. How can I unblock myself? + + - a.) Please disable any pop-up blockers and ad blockers you have and refresh the page. If you are still experiencing issues, please reach out via [Discord](https://discord.gg/flow) in the appropriate channel. + + +=== networks/flow-networks/index.md === +--- +title: Flow Networks +sidebar_position: 1 +--- + +## About Flow Networks + +:::note + +This page provides information on Flow network RPCs. Flow EVM network RPCs can be found [here](../evm/networks) + +::: + +In addition to Mainnet, developers have access to the Testnet environment, which serves as an essential testing ground for applications and smart contracts prior to their deployment on Mainnet. This ensures that any potential issues can be identified and resolved in a controlled setting, mitigating risks associated with live deployment. + +Furthermore, during network upgrades, Testnet receives updates ahead of Mainnet. This preemptive update process allows developers to comprehensively test their apps against the latest versions of the nodes, enhancements to the Cadence programming language, and core contract upgrades. This strategy guarantees that when these updates are eventually applied to Mainnet, applications and smart contracts will operate seamlessly, enhancing overall network stability and user experience. + +### How To Access These Networks? + +| Network | GRPC | Web GRPC | REST | +| ------- | -------------------------------------- | -------------------- | ------------------------- | +| Mainnet | `access.mainnet.nodes.onflow.org:9000` | `mainnet.onflow.org` | `rest-mainnet.onflow.org` | +| Testnet | `access.devnet.nodes.onflow.org:9000` | `testnet.onflow.org` | `rest-testnet.onflow.org` | + +For more information on how to access these networks, refer to the following guides: + +- [Flow Testnet](./accessing-testnet.md) +- [Flow Mainnet](./accessing-mainnet.md) + +### Network + +There are two primary ways to access on-chain data within the Flow network; Access Nodes and Light nodes. Access Nodes are the node type that are most useful for developers, as they provide access to the Flow network via the following API endpoints: + +- [Flow Access API](../access-onchain-data/index.md) + - [Mainnet](./accessing-mainnet.md): `access.mainnet.nodes.onflow.org:9000` + - [Testnet](./accessing-testnet.md): `access.devnet.nodes.onflow.org:9000` +- [Status Page](https://status.onflow.org/) - Network status page + +### Rate limits + +Rate limits for Flow Public Access nodes hosted by QuickNode are detailed [here](https://www.quicknode.com/docs/flow#endpoint-rate-limits). + +### Running Your Own Node + +If you’re getting started you don’t need to run your own node and you can use the above public nodes. The public access nodes are rate-limited, so as your product matures you might want to run your own node. There are multiple options available: + +- Start with a [Light (Observer) Node](../node-ops/light-nodes/observer-node.md). +- You can also use a third-party provider like [Quicknode](https://www.quicknode.com/docs/flow). + +Check out [Running a Node](../node-ops/light-nodes/observer-node.md) for more information. + + +=== networks/flow-networks/accessing-testnet.md === +--- +title: Flow Testnet +sidebar_label: Testnet +sidebar_position: 3 +description: Guide to Testnet access +--- + +## About Flow Testnet + +Flow Testnet is Flow's official testing and development network. It is intended to provide a staging and testing environment for dApp developers. +It aims to balance similarity with Mainnet with being a productive development environment, resulting in the following key differences: + +- Testnet has significantly fewer validator nodes, resulting in a faster block rate compared to Mainnet +- Testnet is configured with shorter epochs (about 12 hours, compared to 7 days on Mainnet) +- Testnet receives software upgrades up to 2 weeks before Mainnet + +## Accessing Flow Testnet + +Flow Testnet is available for access at this URL: + +``` +access.devnet.nodes.onflow.org:9000 +``` + +For example, to access the network using the [Flow Go SDK](https://github.com/onflow/flow-go-sdk): + +```go +import "github.com/onflow/flow-go-sdk/client" + +func main() { + flowAccessAddress := "access.devnet.nodes.onflow.org:9000" + flowClient, _ := client.New(flowAccessAddress, grpc.WithInsecure()) + // ... +} +``` + +### Generating Testnet Key Pair + +You can generate a new key pair with the [Flow CLI](https://github.com/onflow/flow-cli) as follows: + +```sh +> flow keys generate + +🙏 If you want to create an account on Testnet with the generated keys use this link: +https://testnet-faucet.onflow.org/?key= cc1c3d72... + + +🔴️ Store private key safely and don't share with anyone! +Private Key 246256f3... +Public Key cc1c3d72... +``` + +**Note: By default, this command generates an ECDSA key pair on the P-256 curve. Keep in mind, the CLI is intended for development purposes only and is not recommended for production use. Handling keys using a Key Management Service is the best practice.** + +## Account Creation and Token Funding Requests + +Accounts and tokens for testing can be obtained through the [testnet faucet](https://testnet-faucet.onflow.org/). If you generated the keypair through the CLI, you can click on the URL provided to create an account and request testnet FLOW tokens. + +## Important Smart Contract Addresses + +You can review [all available core contracts](../../build/core-contracts/index.md) deployed to the Testnet to identify which ones you want to import. + + +=== networks/flow-networks/accessing-mainnet.md === +--- +title: Flow Mainnet +sidebar_label: Mainnet +sidebar_position: 2 +description: Guide to mainnet access +--- + +## Accessing Flow Mainnet + +The Flow Mainnet is available for access at this URL: + +``` +access.mainnet.nodes.onflow.org:9000 +``` + +For example, to access the network using the [Flow Go SDK](https://github.com/onflow/flow-go-sdk): + +```go +import "github.com/onflow/flow-go-sdk/client" + +func main() { + flowAccessAddress := "access.mainnet.nodes.onflow.org:9000" + flowClient, _ := client.New(flowAccessAddress, grpc.WithInsecure()) + // ... +} +``` + +## Account Creation + +You can follow the [Flow Port account creation steps](../../networks/flow-port/index.md) to create a new mainnet account. + +If you prefer watching a video, check out this tutorial: + + + +## Generating a Non-Custodial Account + +A non-custodial account will make sure you are the only one holding the keys to your account. + +You can follow the following steps to add a non-custodial account: + +First, generate a new key pair with the [Flow CLI](https://github.com/onflow/flow-cli): + +```sh +> flow keys generate --network=mainnet + +🔴️ Store private key safely and don't share with anyone! +Private Key 5b438... +Public Key 1bdc5... +``` + +> **Note**: By default, this command generates an ECDSA key pair on the P-256 curve. Keep in mind the CLI is intended for development purposes only and is not recommended for production use. Handling keys using a Key Management Service is the best practice. + +Take a note of the public key and go back to Flow Port. Open the ["Create a new account" page](https://port.onflow.org/transaction?hash=a0a78aa7821144efd5ebb974bb52ba04609ce76c3863af9d45348db93937cf98&showcode=false&weight=1000&halg=3). + +On the page, enter your public key from the CLI, ensure the hash algorithm is set to `SHA3_256` and the weight is set to `1000`. Finally, check the box confirming correctness and hit 'Submit'. + +> **Important**: Your account needs to have at least 0.002 FLOW for the account creation. More details can be found [in this guide](../../build/basics/fees.md#storage). + +Once the transaction is sealed, you should scroll down to the events section and locate the `flow.AccountCreated` event with the newly generated address. + +![flow-port-sealed](port-sealed-tx.png) + +Make sure to take a note of the address. If you want to verify the public key for this address, you can visit [flow-view-source](https://flow-view-source.com/). + +## Important Mainnet Smart Contract Addresses + +You can review [all available core contracts](../../build/core-contracts/index.md) deployed to the mainnet to identify which ones you want to import. + + +=== networks/access-onchain-data/index.md === +--- +title: Flow Access API Specification +sidebar_label: Access API +sidebar_position: 1 +--- + +The Access API is implemented as a [gRPC service](https://grpc.io/). + +A language-agnostic specification for this API is defined using [Protocol Buffers](https://developers.google.com/protocol-buffers), which can be used to generate client libraries in a variety of programming languages. + +- [Flow Access API protobuf source files](https://github.com/onflow/flow/tree/master/protobuf) + +## Flow Access Node Endpoints + +| Network | GRPC | Web GRPC | REST | +| ------- | -------------------------------------- | -------------------- | ------------------------- | +| Mainnet | `access.mainnet.nodes.onflow.org:9000` | `mainnet.onflow.org` | `rest-mainnet.onflow.org` | +| Testnet | `access.devnet.nodes.onflow.org:9000` | `testnet.onflow.org` | `rest-testnet.onflow.org` | + +--- + +## Ping + +`Ping` will return a successful response if the Access API is ready and available. + +```proto +rpc Ping(PingRequest) returns (PingResponse) +``` + +If a ping request returns an error or times out, it can be assumed that the Access API is unavailable. + +#### Request + +```proto +message PingRequest {} +``` + +#### Response + +```proto +message PingResponse {} +``` + +--- + +## Block Headers + +The following methods query information about [block headers](#block-header). + +### GetLatestBlockHeader + +`GetLatestBlockHeader` gets the latest sealed or unsealed [block header](#block-header). + +```proto +rpc GetLatestBlockHeader (GetLatestBlockHeaderRequest) returns (BlockHeaderResponse) +``` + +#### Request + +```proto +message GetLatestBlockHeaderRequest { + bool is_sealed = 1; +} +``` + +#### Response + +```proto +message BlockHeaderResponse { + entities.BlockHeader block = 1; + entities.BlockStatus block_status = 2; + entities.Metadata metadata = 3; +} +``` + +### GetBlockHeaderByID + +`GetBlockHeaderByID` gets a [block header](#block-header) by ID. + +```proto +rpc GetBlockHeaderByID (GetBlockHeaderByIDRequest) returns (BlockHeaderResponse) +``` + +#### Request + +```proto +message GetBlockHeaderByIDRequest { + bytes id = 1; +} +``` + +#### Response + +```proto +message BlockHeaderResponse { + entities.BlockHeader block = 1; + entities.BlockStatus block_status = 2; + entities.Metadata metadata = 3; +} +``` + +### GetBlockHeaderByHeight + +`GetBlockHeaderByHeight` gets a [block header](#block-header) by height. + +```proto +rpc GetBlockHeaderByHeight (GetBlockHeaderByHeightRequest) returns (BlockHeaderResponse) +``` + +#### Request + +```proto +message GetBlockHeaderByHeightRequest { + uint64 height = 1; +} +``` + +#### Response + +```proto +message BlockHeaderResponse { + entities.BlockHeader block = 1; + entities.BlockStatus block_status = 2; + entities.Metadata metadata = 3; +} +``` + +--- + +## Blocks + +The following methods query information about [full blocks](#block). + +### GetLatestBlock + +`GetLatestBlock` gets the full payload of the latest sealed or unsealed [block](#block). + +```proto +rpc GetLatestBlock (GetLatestBlockRequest) returns (BlockResponse) +``` + +#### Request + +```proto +message GetLatestBlockRequest { + bool is_sealed = 1; + bool full_block_response = 2; +} +``` + +#### Response + +```proto +message BlockResponse { + entities.Block block = 1; + entities.BlockStatus block_status = 2; + entities.Metadata metadata = 3; +} +``` + +### GetBlockByID + +`GetBlockByID` gets a [full block](#block) by ID. + +```proto +rpc GetBlockByID (GetBlockByIDRequest) returns (BlockResponse) +``` + +#### Request + +```proto +message GetBlockByIDRequest { + bytes id = 1; + bool full_block_response = 2; +} +``` + +#### Response + +```proto +message BlockResponse { + entities.Block block = 1; + entities.BlockStatus block_status = 2; + entities.Metadata metadata = 3; +} +``` + +### GetBlockByHeight + +`GetBlockByHeight` gets a [full block](#block) by height. + +```proto +rpc GetBlockByHeight (GetBlockByHeightRequest) returns (BlockResponse) +``` + +#### Request + +```proto +message GetBlockByHeightRequest { + uint64 height = 1; + bool full_block_response = 2; +} +``` + +#### Response + +```proto +message BlockResponse { + entities.Block block = 1; + entities.BlockStatus block_status = 2; + entities.Metadata metadata = 3; +} +``` + +--- + +## Collections + +The following methods query information about [collections](#collection). + +### GetCollectionByID + +`GetCollectionByID` gets a [collection](#collection) by ID. + +```proto +rpc GetCollectionByID (GetCollectionByIDRequest) returns (CollectionResponse) +``` + +#### Request + +```proto +message GetCollectionByIDRequest { + bytes id = 1; +} +``` + +#### Response + +```proto +message CollectionResponse { + entities.Collection collection = 1; + entities.Metadata metadata = 2; +} +``` + +--- + +### GetFullCollectionByID + +`GetFullCollectionByID` gets a collection by ID, which contains a set of [transactions](#transaction). + +```proto +rpc GetFullCollectionByID(GetFullCollectionByIDRequest) returns (FullCollectionResponse); +``` + +#### Request + +```proto +message GetFullCollectionByIDRequest { + bytes id = 1; +} +``` + +#### Response + +```proto +message FullCollectionResponse { + repeated entities.Transaction transactions = 1; + entities.Metadata metadata = 2; +} +``` + +--- + +## Transactions + +The following methods can be used to submit [transactions](#transaction) and fetch their results. + +### SendTransaction + +`SendTransaction` submits a transaction to the network. + +```proto +rpc SendTransaction (SendTransactionRequest) returns (SendTransactionResponse) +``` + +`SendTransaction` determines the correct cluster of collection nodes that is responsible for collecting the transaction based on the hash of the transaction and forwards the transaction to that cluster. + +#### Request + +`SendTransactionRequest` message contains the transaction that is being request to be executed. + +```proto +message SendTransactionRequest { + entities.Transaction transaction = 1; +} +``` + +#### Response + +`SendTransactionResponse` message contains the ID of the submitted transaction. + +```proto +message SendTransactionResponse { + bytes id = 1; + entities.Metadata metadata = 2; +} +``` + +### GetTransaction + +`GetTransaction` gets a [transaction](#transaction) by ID. + +If the transaction is not found in the access node cache, the request is forwarded to a collection node. + +_Currently, only transactions within the current epoch can be queried._ + +```proto +rpc GetTransaction (GetTransactionRequest) returns (TransactionResponse) +``` + +#### Request + +`GetTransactionRequest` contains the ID of the transaction that is being queried. + +```proto +message GetTransactionRequest { + bytes id = 1; + bytes block_id = 2; + bytes collection_id = 3; + entities.EventEncodingVersion event_encoding_version = 4; +} +``` + +#### Response + +`TransactionResponse` contains the basic information about a transaction, but does not include post-execution results. + +```proto +message TransactionResponse { + entities.Transaction transaction = 1; + entities.Metadata metadata = 2; +} +``` + +### GetTransactionsByBlockID + +`GetTransactionsByBlockID` gets all the [transactions](#transaction) for a specified block. + +```proto +rpc GetTransactionsByBlockID(GetTransactionsByBlockIDRequest) returns (TransactionsResponse); +``` + +#### Request + +```proto +message GetTransactionsByBlockIDRequest { + bytes block_id = 1; + entities.EventEncodingVersion event_encoding_version = 2; +} +``` + +#### Response + +```proto +message TransactionsResponse { + repeated entities.Transaction transactions = 1; + entities.Metadata metadata = 2; +} +``` + +### GetTransactionResult + +`GetTransactionResult` gets the execution result of a transaction. + +```proto +rpc GetTransactionResult (GetTransactionRequest) returns (TransactionResultResponse) +``` + +#### Request + +```proto +message GetTransactionRequest { + bytes id = 1; + bytes block_id = 2; + bytes collection_id = 3; + entities.EventEncodingVersion event_encoding_version = 4; +} +``` + +#### Response + +```proto +message TransactionResultResponse { + entities.TransactionStatus status = 1; + uint32 status_code = 2; + string error_message = 3; + repeated entities.Event events = 4; + bytes block_id = 5; + bytes transaction_id = 6; + bytes collection_id = 7; + uint64 block_height = 8; + entities.Metadata metadata = 9; + uint64 computation_usage = 10; +} +``` +### GetTransactionResultByIndex + +`GetTransactionResultByIndex` gets a transaction's result at a specified block and index. + +```proto +rpc GetTransactionResultByIndex(GetTransactionByIndexRequest) returns (TransactionResultResponse); +``` + +#### Request + +```proto +message GetTransactionByIndexRequest { + bytes block_id = 1; + uint32 index = 2; + entities.EventEncodingVersion event_encoding_version = 3; +} +``` + +#### Response + +```proto +message TransactionResultResponse { + entities.TransactionStatus status = 1; + uint32 status_code = 2; + string error_message = 3; + repeated entities.Event events = 4; + bytes block_id = 5; + bytes transaction_id = 6; + bytes collection_id = 7; + uint64 block_height = 8; + entities.Metadata metadata = 9; + uint64 computation_usage = 10; +} +``` + +### GetTransactionResultsByBlockID + +`GetTransactionResultsByBlockID` gets all the transaction results for a specified block. + +```proto +rpc GetTransactionResultsByBlockID(GetTransactionsByBlockIDRequest) returns (TransactionResultsResponse); +``` + +#### Request + +```proto +message GetTransactionsByBlockIDRequest { + bytes block_id = 1; + entities.EventEncodingVersion event_encoding_version = 2; +} +``` + +#### Response + +```proto +message TransactionResultsResponse { + repeated TransactionResultResponse transaction_results = 1; + entities.Metadata metadata = 2; +} +``` + +### GetSystemTransaction + +`GetSystemTransaction` gets the system transaction for a block. + +```proto +rpc GetSystemTransaction(GetSystemTransactionRequest) returns (TransactionResponse); +``` + +#### Request + +```proto +message GetSystemTransactionRequest { + bytes block_id = 1; +} +``` + +#### Response + +```proto +message TransactionResponse { + entities.Transaction transaction = 1; + entities.Metadata metadata = 2; +} +``` + +### GetSystemTransactionResult + +`GetSystemTransactionResult` gets the system transaction result for a block. + +```proto +rpc GetSystemTransactionResult(GetSystemTransactionResultRequest) returns (TransactionResultResponse); +``` + +#### Request + +```proto +message GetSystemTransactionResultRequest { + bytes block_id = 1; + entities.EventEncodingVersion event_encoding_version = 2; +} +``` + +#### Response + +```proto +message TransactionResultResponse { + entities.TransactionStatus status = 1; + uint32 status_code = 2; + string error_message = 3; + repeated entities.Event events = 4; + bytes block_id = 5; + bytes transaction_id = 6; + bytes collection_id = 7; + uint64 block_height = 8; + entities.Metadata metadata = 9; + uint64 computation_usage = 10; +} +``` + +--- + +## Accounts + +### GetAccount + +`GetAccount` gets an [account](#account) by address at the latest sealed block. + +⚠️ Warning: this function is deprecated. It behaves identically to `GetAccountAtLatestBlock` and will be removed in a future version. + +```proto +rpc GetAccount(GetAccountRequest) returns (GetAccountResponse) +``` + +#### Request + +```proto +message GetAccountRequest { + bytes address = 1; +} +``` + +#### Response + +```proto +message GetAccountResponse { + entities.Account account = 1; + entities.Metadata metadata = 2; +} +``` + +### GetAccountAtLatestBlock + +`GetAccountAtLatestBlock` gets an [account](#account) by address. + +The access node queries an execution node for the account details, which are stored as part of the sealed execution state. + +```proto +rpc GetAccountAtLatestBlock(GetAccountAtLatestBlockRequest) returns (AccountResponse) +``` + +#### Request + +```proto +message GetAccountAtLatestBlockRequest { + bytes address = 1; +} +``` + +#### Response + +```proto +message AccountResponse { + entities.Account account = 1; + entities.Metadata metadata = 2; +} +``` + +### GetAccountAtBlockHeight + +`GetAccountAtBlockHeight` gets an [account](#accounts) by address at the given block height. + +The access node queries an execution node for the account details, which are stored as part of the execution state. + +```proto +rpc GetAccountAtBlockHeight(GetAccountAtBlockHeightRequest) returns (AccountResponse) +``` + +#### Request + +```proto +message GetAccountAtBlockHeightRequest { + bytes address = 1; + uint64 block_height = 2; +} +``` + +#### Response + +```proto +message AccountResponse { + entities.Account account = 1; + entities.Metadata metadata = 2; +} +``` + +### GetAccountBalanceAtLatestBlock + +`GetAccountBalanceAtLatestBlock` gets an account's balance by address from the latest sealed block. + +```proto +rpc GetAccountBalanceAtLatestBlock(GetAccountBalanceAtLatestBlockRequest) returns (AccountBalanceResponse); +``` + +#### Request + +```proto +message GetAccountBalanceAtLatestBlockRequest { + bytes address = 1 +} +``` + +#### Response + +```proto +message AccountBalanceResponse { + uint64 balance = 1; + entities.Metadata metadata = 2; +} +``` + +### GetAccountBalanceAtBlockHeight + +`GetAccountBalanceAtBlockHeight` gets an account's balance by address at the given block height. + +```proto +rpc GetAccountBalanceAtBlockHeight(GetAccountBalanceAtBlockHeightRequest) returns (AccountBalanceResponse); +``` + +#### Request + +```proto +message GetAccountBalanceAtBlockHeightRequest { + bytes address = 1; + uint64 block_height = 2; +} +``` + +#### Response + +```proto +message AccountBalanceResponse { + uint64 balance = 1; + entities.Metadata metadata = 2; +} +``` + +### GetAccountKeyAtLatestBlock + +`GetAccountKeyAtLatestBlock` gets an account's public key by address and key index from the latest sealed block. + +```proto +rpc GetAccountKeyAtLatestBlock(GetAccountKeyAtLatestBlockRequest) returns (AccountKeyResponse); +``` + +#### Request + +```proto +message GetAccountKeyAtLatestBlockRequest { + // address of account + bytes address = 1; + // index of key to return + uint32 index = 2; +} +``` + +#### Response + +```proto +message AccountKeyResponse { + entities.AccountKey account_key = 1; + entities.Metadata metadata = 2; +} +``` + +### GetAccountKeyAtBlockHeight + +`GetAccountKeyAtBlockHeight` gets an account's public key by address and key index at the given block height. + +```proto +rpc GetAccountKeyAtBlockHeight(GetAccountKeyAtBlockHeightRequest) returns (AccountKeyResponse); +``` + +#### Request + +```proto +message GetAccountKeyAtBlockHeightRequest { + // address of account + bytes address = 1; + // height of the block + uint64 block_height = 2; + // index of key to return + uint32 index = 3; +} +``` + +#### Response + +```proto +message AccountKeyResponse { + entities.AccountKey account_key = 1; + entities.Metadata metadata = 2; +} +``` + +### GetAccountKeysAtLatestBlock + +`GetAccountKeysAtLatestBlock` gets an account's public keys by address from the latest sealed block. + +```proto +rpc GetAccountKeysAtLatestBlock(GetAccountKeysAtLatestBlockRequest) returns (AccountKeysResponse); +``` + +#### Request + +```proto +message GetAccountKeysAtLatestBlockRequest { + // address of account + bytes address = 1; +} +``` + +#### Response + +```proto +message AccountKeysResponse { + repeated entities.AccountKey account_keys = 1; + entities.Metadata metadata = 2; +} +``` + +### GetAccountKeysAtBlockHeight + +`GetAccountKeysAtBlockHeight` gets an account's public keys by address at the given block height. + +```proto +rpc GetAccountKeysAtBlockHeight(GetAccountKeysAtBlockHeightRequest) returns (AccountKeysResponse); +``` + +#### Request + +```proto +message GetAccountKeysAtBlockHeightRequest { + // address of account + bytes address = 1; + uint64 block_height = 2; +} +``` + +#### Response + +```proto +message AccountKeysResponse { + repeated entities.AccountKey account_keys = 1; + entities.Metadata metadata = 2; +} +``` + +## + +## Scripts + +### ExecuteScriptAtLatestBlock + +`ExecuteScriptAtLatestBlock` executes a read-only Cadence script against the latest sealed execution state. + +This method can be used to read execution state from the blockchain. The script is executed on an execution node and the return value is encoded using the [JSON-Cadence data interchange format](https://cadencelang.dev/docs/1.0/json-cadence-spec). + +```proto +rpc ExecuteScriptAtLatestBlock (ExecuteScriptAtLatestBlockRequest) returns (ExecuteScriptResponse) +``` + +This method is a shortcut for the following: + +``` +header = GetLatestBlockHeader() +value = ExecuteScriptAtBlockID(header.ID, script) +``` + +#### Request + +```proto +message ExecuteScriptAtLatestBlockRequest { + bytes script = 1; + repeated bytes arguments = 2; +} +``` + +#### Response + +```proto +message ExecuteScriptResponse { + bytes value = 1; + entities.Metadata metadata = 2; + uint64 computation_usage = 3; +} +``` + +### ExecuteScriptAtBlockID + +`ExecuteScriptAtBlockID` executes a ready-only Cadence script against the execution state at the block with the given ID. + +This method can be used to read account state from the blockchain. The script is executed on an execution node and the return value is encoded using the [JSON-Cadence data interchange format](https://cadencelang.dev/docs/1.0/json-cadence-spec). + +```proto +rpc ExecuteScriptAtBlockID (ExecuteScriptAtBlockIDRequest) returns (ExecuteScriptResponse) +``` + +#### Request + +```proto +message ExecuteScriptAtBlockIDRequest { + bytes block_id = 1; + bytes script = 2; + repeated bytes arguments = 3; +} +``` + +#### Response + +```proto +message ExecuteScriptResponse { + bytes value = 1; + entities.Metadata metadata = 2; + uint64 computation_usage = 3; +} +``` + +### ExecuteScriptAtBlockHeight + +`ExecuteScriptAtBlockHeight` executes a ready-only Cadence script against the execution state at the given block height. + +This method can be used to read account state from the blockchain. The script is executed on an execution node and the return value is encoded using the [JSON-Cadence data interchange format](https://cadencelang.dev/docs/1.0/json-cadence-spec). + +```proto +rpc ExecuteScriptAtBlockHeight (ExecuteScriptAtBlockHeightRequest) returns (ExecuteScriptResponse) +``` + +#### Request + +```proto +message ExecuteScriptAtBlockHeightRequest { + uint64 block_height = 1; + bytes script = 2; + repeated bytes arguments = 3; +} +``` + +#### Response + +```proto +message ExecuteScriptResponse { + bytes value = 1; + entities.Metadata metadata = 2; + uint64 computation_usage = 3; +} +``` + +--- + +## Events + +The following methods can be used to query for on-chain [events](#event). + +### GetEventsForHeightRange + +`GetEventsForHeightRange` retrieves [events](#event) emitted within the specified block range. + +```proto +rpc GetEventsForHeightRange(GetEventsForHeightRangeRequest) returns (GetEventsForHeightRangeResponse) +``` + +Events can be requested for a specific sealed block range via the `start_height` and `end_height` (inclusive) fields and further filtered by event type via the `type` field. + +If `start_height` is greater than the current sealed chain height, then this method will return an error. + +If `end_height` is greater than the current sealed chain height, then this method will return events up to and including the latest sealed block. + +The event results are grouped by block, with each group specifying a block ID, height and block timestamp. + +Event types are name-spaced with the address of the account and contract in which they are declared. + +#### Request + +```proto +message GetEventsForHeightRangeRequest { + string type + uint64 start_height = 2; + uint64 end_height = 3; + entities.EventEncodingVersion event_encoding_version = 4; +} +``` + +#### Response + +```proto +message EventsResponse { + message Result { + bytes block_id = 1; + uint64 block_height = 2; + repeated entities.Event events = 3; + google.protobuf.Timestamp block_timestamp = 4; + } + repeated Result results = 1; + entities.Metadata metadata = 2; +} +``` + +### GetEventsForBlockIDs + +`GetEventsForBlockIDs` retrieves [events](#event) for the specified block IDs and event type. + +```proto +rpc GetEventsForBlockIDs(GetEventsForBlockIDsRequest) returns (GetEventsForBlockIDsResponse) +``` + +Events can be requested for a list of block IDs via the `block_ids` field and further filtered by event type via the `type` field. + +The event results are grouped by block, with each group specifying a block ID, height and block timestamp. + +#### Request + +```proto +message GetEventsForBlockIDsRequest { + string type = 1; + repeated bytes block_ids = 2; + entities.EventEncodingVersion event_encoding_version = 3; +} +``` + +#### Response + +```proto +message EventsResponse { + message Result { + bytes block_id = 1; + uint64 block_height = 2; + repeated entities.Event events = 3; + google.protobuf.Timestamp block_timestamp = 4; + } + repeated Result results = 1; + entities.Metadata metadata = 2; +} +``` + +--- + +## Network Parameters + +Network parameters provide information about the Flow network. Currently, it only includes the chain ID. +The following method can be used to query for network parameters. + +### GetNetworkParameters + +`GetNetworkParameters` retrieves the network parameters. + +```proto +rpc GetNetworkParameters (GetNetworkParametersRequest) returns (GetNetworkParametersResponse) +``` + +#### Request + +```proto +message GetNetworkParametersRequest {} +``` + +#### Response + +```proto +message GetNetworkParametersResponse { + string chain_id = 1; +} +``` + +| Field | Description | +| -------- | ------------------------------------------------------------------------------------------------------------ | +| chain_id | Chain ID helps identify the Flow network. It can be one of `flow-mainnet`, `flow-testnet` or `flow-emulator` | + +--- + +### GetNodeVersionInfo + +`GetNodeVersionInfo` gets information about a node's current versions. + +```proto +rpc GetNodeVersionInfo (GetNodeVersionInfoRequest) returns (GetNodeVersionInfoResponse); +``` + +#### Request + +```proto +message GetNodeVersionInfoRequest {} +``` + +#### Response + +```proto +message GetNodeVersionInfoResponse { + entities.NodeVersionInfo info = 1; +} +``` + +--- + +## Protocol state snapshot + +The following method can be used to query the latest protocol state [snapshot](https://github.com/onflow/flow-go/blob/master/state/protocol/snapshot.go). + +### GetLatestProtocolStateSnapshot + +`GetLatestProtocolStateSnapshot` retrieves the latest Protocol state snapshot serialized as a byte array. +It is used by Flow nodes joining the network to bootstrap a space-efficient local state. + +```proto +rpc GetLatestProtocolStateSnapshot (GetLatestProtocolStateSnapshotRequest) returns (ProtocolStateSnapshotResponse); +``` + +#### Request + +```proto +message GetLatestProtocolStateSnapshotRequest {} +``` + +#### Response + +```proto +message ProtocolStateSnapshotResponse { + bytes serializedSnapshot = 1; + entities.Metadata metadata = 2; +} +``` + +### GetProtocolStateSnapshotByBlockID + +`GetProtocolStateSnapshotByBlockID` retrieves the latest sealed protocol state snapshot by block ID. +Used by Flow nodes joining the network to bootstrap a space-efficient local state. + +```proto +rpc GetProtocolStateSnapshotByBlockID(GetProtocolStateSnapshotByBlockIDRequest) returns (ProtocolStateSnapshotResponse); +``` + +#### Request + +```proto +message GetProtocolStateSnapshotByBlockIDRequest { + bytes block_id = 1; +} +``` + +#### Response + +```proto +message ProtocolStateSnapshotResponse { + bytes serializedSnapshot = 1; + entities.Metadata metadata = 2; +} +``` + +### GetProtocolStateSnapshotByHeight + +`GetProtocolStateSnapshotByHeight` retrieves the latest sealed protocol state snapshot by block height. +Used by Flow nodes joining the network to bootstrap a space-efficient local state. + +```proto +rpc GetProtocolStateSnapshotByHeight(GetProtocolStateSnapshotByHeightRequest) returns (ProtocolStateSnapshotResponse); +``` + +#### Request + +```proto +message GetProtocolStateSnapshotByHeightRequest { + uint64 block_height = 1; +} +``` + +#### Response + +```proto +message ProtocolStateSnapshotResponse { + bytes serializedSnapshot = 1; + entities.Metadata metadata = 2; +} +``` + +## Execution results + +The following method can be used to query the for [execution results](https://github.com/onflow/flow-go/blob/master/model/flow/execution_result.go) for a given block. + +### GetExecutionResultForBlockID + +`GetExecutionResultForBlockID` retrieves execution result for given block. It is different from Transaction Results, +and contain data about chunks/collection level execution results rather than particular transactions. +Particularly, it contains `EventsCollection` hash for every chunk which can be used to verify the events for a block. + +```proto +rpc GetExecutionResultForBlockID(GetExecutionResultForBlockIDRequest) returns (ExecutionResultForBlockIDResponse); +``` + +#### Request + +```proto +message GetExecutionResultForBlockIDRequest { + bytes block_id = 1; +} +``` + +#### Response + +```proto +message ExecutionResultForBlockIDResponse { + flow.ExecutionResult execution_result = 1; + entities.Metadata metadata = 2; +} +``` + +### GetExecutionResultByID + +`GetExecutionResultByID` returns Execution Result by its ID. It is different from Transaction Results, +and contain data about chunks/collection level execution results rather than particular transactions. +Particularly, it contains `EventsCollection` hash for every chunk which can be used to verify the events for a block. + +```proto +rpc GetExecutionResultByID(GetExecutionResultByIDRequest) returns (ExecutionResultByIDResponse); +``` + +#### Request + +```proto +message GetExecutionResultByIDRequest { + bytes id = 1; +} +``` + +#### Response + +```proto +message ExecutionResultByIDResponse { + flow.ExecutionResult execution_result = 1; + entities.Metadata metadata = 2; +} +``` + + +## Entities + +Below are in-depth descriptions of each of the data entities returned or accepted by the Access API. + +### Block + +```proto +message Block { + bytes id = 1; + bytes parent_id = 2; + uint64 height = 3; + google.protobuf.Timestamp timestamp = 4; + repeated CollectionGuarantee collection_guarantees = 5; + repeated BlockSeal block_seals = 6; + repeated bytes signatures = 7; + repeated ExecutionReceiptMeta execution_receipt_metaList = 8; + repeated ExecutionResult execution_result_list = 9; + BlockHeader block_header = 10; + bytes protocol_state_id = 11; +} +``` + +| Field | Description | +|----------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| id | SHA3-256 hash of the entire block payload | +| height | Height of the block in the chain | +| parent_id | ID of the previous block in the chain | +| timestamp | Timestamp of when the proposer claims it constructed the block.
    **NOTE**: It is included by the proposer, there are no guarantees on how much the time stamp can deviate from the true time the block was published.
    Consider observing blocks' status changes yourself to get a more reliable value | +| collection_guarantees | List of [collection guarantees](#collection-guarantee) | +| block_seals | List of [block seals](#block-seal) | +| signatures | BLS signatures of consensus nodes | +| execution_receipt_metaList | List of [execution-receipt-meta](#execution-receipt-meta) | +| execution_result_list | List of [execution results](#execution-result) | +| block_header | A summary of a [block](#block-header) | +| protocol_state_id | The root hash of protocol state. | + +The detailed semantics of block formation are covered in the [block formation guide](../../build/basics/blocks.md). + +### Block Header + +A block header is a summary of a [block](#block) and contains only the block ID, height, and parent block ID. + +```proto +message BlockHeader { + bytes id = 1; + bytes parent_id = 2; + uint64 height = 3; + google.protobuf.Timestamp timestamp = 4; + bytes payload_hash = 5; + uint64 view = 6; + repeated bytes parent_voter_ids = 7; + bytes parent_voter_sig_data = 8; + bytes proposer_id = 9; + bytes proposer_sig_data = 10; + string chain_id = 11; + bytes parent_voter_indices = 12; + TimeoutCertificate last_view_tc = 13; + uint64 parent_view = 14; +} +``` + +| Field | Description | +|-----------------------|-------------------------------------------------------------------------------------------------------------------| +| id | SHA3-256 hash of the entire block payload | +| parent_id | ID of the previous block in the chain | +| height | Height of the block in the chain | +| timestamp | The time at which this block was proposed | +| payload_hash | A hash of the payload of this block | +| view | View number during which this block was proposed. | +| parent_voter_ids | An array that represents all the voters ids for the parent block | +| parent_voter_sig_data | An aggregated signature over the parent block | +| chain_id | Chain ID helps identify the Flow network. It can be one of `flow-mainnet`, `flow-testnet` or `flow-emulator` | +| parent_voter_indices | A bitvector that represents all the voters for the parent block | +| last_view_tc | A timeout certificate for previous view, it can be nil. It has to be present if previous round ended with timeout | +| parent_view | A number at which parent block was proposed | + +### Block Seal + +A block seal is an attestation that the execution result of a specific [block](#block) has been verified and approved by a quorum of verification nodes. + +```proto +message BlockSeal { + bytes block_id = 1; + bytes execution_receipt_id = 2; + repeated bytes execution_receipt_signatures = 3; + repeated bytes result_approval_signatures = 4; +} +``` + +| Field | Description | +| ---------------------------- | ---------------------------------------------------------------------- | +| block_id | ID of the block being sealed | +| execution_receipt_id | ID execution receipt being sealed | +| execution_receipt_signatures | BLS signatures of verification nodes on the execution receipt contents | +| result_approval_signatures | BLS signatures of verification nodes on the result approval contents | + +### Block Status + +```proto +enum BlockStatus { + UNKNOWN = 0; + FINALIZED = 1; + SEALED = 2; +} +``` + +| Value | Description | +|------------|------------------------------------------------| +| UNKNOWN | The block status is not known | +| FINALIZED | The consensus nodes have finalized the block | +| SEALED | The verification nodes have verified the block | + +### Collection + +A collection is a batch of [transactions](#transaction) that have been included in a block. Collections are used to improve consensus throughput by increasing the number of transactions per block. + +```proto +message Collection { + bytes id = 1; + repeated bytes transaction_ids = 2; +} +``` + +| Field | Description | +|------------------|---------------------------------------------------| +| id | SHA3-256 hash of the collection contents | +| transaction_ids | Ordered list of transaction IDs in the collection | + +### Collection Guarantee + +A collection guarantee is a signed attestation that specifies the collection nodes that have guaranteed to store and respond to queries about a collection. + +```proto +message CollectionGuarantee { + bytes collection_id = 1; + repeated bytes signatures = 2; + bytes reference_block_id = 3; + bytes signature = 4; + repeated bytes signer_ids = 5; // deprecated!! value will be empty. replaced by signer_indices + bytes signer_indices = 6; +} +``` + +| Field | Description | +|---------------------|--------------------------------------------------------------------| +| collection_id | SHA3-256 hash of the collection contents | +| signatures | BLS signatures of the collection nodes guaranteeing the collection | +| reference_block_id | Defines expiry of the collection | +| signature | Guarantor signatures | +| signer_ids | An array that represents all the signer ids | +| signer_indices | Encoded indices of the signers | + +### Transaction + +A transaction represents a unit of computation that is submitted to the Flow network. + +```proto +message Transaction { + bytes script = 1; + repeated bytes arguments = 2; + bytes reference_block_id = 3; + uint64 gas_limit = 4; + ProposalKey proposal_key = 5; + bytes payer = 6; + repeated bytes authorizers = 7; + repeated Signature payload_signatures = 8; + repeated Signature envelope_signatures = 9; +} + +message TransactionProposalKey { + bytes address = 1; + uint32 key_id = 2; + uint64 sequence_number = 3; +} + +message TransactionSignature { + bytes address = 1; + uint32 key_id = 2; + bytes signature = 3; +} +``` + +| Field | Description | +| ----------------------------- | --------------------------------------------------------------------------------------------------------------------------- | +| script | Raw source code for a Cadence script, encoded as UTF-8 bytes | +| arguments | Arguments passed to the Cadence script, encoded as [JSON-Cadence](https://cadencelang.dev/docs/1.0/json-cadence-spec) bytes | +| reference_block_id | Block ID used to determine transaction expiry | +| [proposal_key](#proposal-key) | Account key used to propose the transaction | +| payer | Address of the payer account | +| authorizers | Addresses of the transaction authorizers | +| signatures | [Signatures](#transaction-signature) from all signer accounts | + +The detailed semantics of transaction creation, signing and submission are covered in the [transaction submission guide](../../build/basics/transactions.md#signing-a-transaction). + +#### Proposal Key + +The proposal key is used to specify a sequence number for the transaction. Sequence numbers are covered in more detail [here](../../build/basics/transactions.md#sequence-numbers). + +| Field | Description | +| --------------- | ------------------------------------------------------------------------------------------- | +| address | Address of proposer account | +| key_id | ID of proposal key on the proposal account | +| sequence_number | [Sequence number](../../build/basics/transactions.md#sequence-numbers) for the proposal key | + +#### Transaction Signature + +| Field | Description | +| --------- | ----------------------------------------- | +| address | Address of the account for this signature | +| key_id | ID of the account key | +| signature | Raw signature byte data | + +#### Transaction Status + +```proto +enum TransactionStatus { + UNKNOWN = 0; + PENDING = 1; + FINALIZED = 2; + EXECUTED = 3; + SEALED = 4; + EXPIRED = 5; +} +``` + +| Value | Description | +| --------- | ----------------------------------------------------------------------------------------------------------------------------------------- | +| UNKNOWN | The transaction status is not known. | +| PENDING | The transaction has been received by a collector but not yet finalized in a block. | +| FINALIZED | The consensus nodes have finalized the block that the transaction is included in | +| EXECUTED | The execution nodes have produced a result for the transaction | +| SEALED | The verification nodes have verified the transaction (the block in which the transaction is) and the seal is included in the latest block | +| EXPIRED | The transaction was submitted past its expiration block height. | + +### Account + +An account is a user's identity on Flow. It contains a unique address, a balance, a list of public keys and the code that has been deployed to the account. + +```proto +message Account { + bytes address = 1; + uint64 balance = 2; + bytes code = 3; + repeated AccountKey keys = 4; + map contracts = 5; +} +``` + +| Field | Description | +| --------- | --------------------------------------------------------------------------- | +| address | A unique account identifier | +| balance | The account balance | +| code | The code deployed to this account (**deprecated**, use `contracts` instead) | +| keys | A list of keys configured on this account | +| contracts | A map of contracts or contract interfaces deployed on this account | + +The `code` and `contracts` fields contain the raw Cadence source code, encoded as UTF-8 bytes. + +More information on accounts can be found [here](../../build/basics/accounts.md). + +#### Account Key + +An account key is a reference to a public key associated with a Flow account. Accounts can be configured with zero or more public keys, each of which can be used for signature verification when authorizing a transaction. + +```proto +message AccountKey { + uint32 index = 1; + bytes public_key = 2; + uint32 sign_algo = 3; + uint32 hash_algo = 4; + uint32 weight = 5; + uint32 sequence_number = 6; + bool revoked = 7; +} +``` + +| Field | Description | +| --------------- |---------------------------------------------------------------------------| +| id | Index of the key within the account, used as a unique identifier | +| public_key | Public key encoded as bytes | +| sign_algo | [Signature algorithm](../../build/basics/accounts.md#signature-and-hash-algorithms) | +| hash_algo | [Hash algorithm](../../build/basics/accounts.md#signature-and-hash-algorithms) | +| weight | [Weight assigned to the key](../../build/basics/accounts.md#account-keys) | +| sequence_number | [Sequence number for the key](../../build/basics/transactions.md#sequence-numbers) | +| revoked | Flag indicating whether or not the key has been revoked | + +More information on account keys, key weights and sequence numbers can be found [here](../../build/basics/accounts.md). + +### Event + +An event is emitted as the result of a [transaction](#transaction) execution. Events are either user-defined events originating from a Cadence smart contract, or built-in Flow system events. + +```proto +message Event { + string type = 1; + bytes transaction_id = 2; + uint32 transaction_index = 3; + uint32 event_index = 4; + bytes payload = 5; +} +``` + +| Field | Description | +| ----------------- | ------------------------------------------------------------------------------------------------- | +| type | Fully-qualified unique type identifier for the event | +| transaction_id | ID of the transaction the event was emitted from | +| transaction_index | Zero-based index of the transaction within the block | +| event_index | Zero-based index of the event within the transaction | +| payload | Event fields encoded as [JSON-Cadence values](https://cadencelang.dev/docs/1.0/json-cadence-spec) | + +### Execution Result + +Execution result for a particular block. + +```proto +message ExecutionResult { + bytes previous_result_id = 1; + bytes block_id = 2; + repeated Chunk chunks = 3; + repeated ServiceEvent service_events = 4; +} +``` + +| Field | Description | +| ------------------ | ---------------------------------------------------- | +| previous_result_id | Identifier of parent block execution result | +| block_id | ID of the block this execution result corresponds to | +| chunks | Zero or more chunks | +| service_events | Zero or more service events | + +### Execution Receipt Meta + +ExecutionReceiptMeta contains the fields from the Execution Receipts that vary from one executor to another + +```proto +message ExecutionReceiptMeta { + bytes executor_id = 1; + bytes result_id = 2; + repeated bytes spocks = 3; + bytes executor_signature = 4; +} +``` + +| Field | Description | +|----------------------|--------------------------------------| +| executor_id | Identifier of the executor node | +| result_id | Identifier of block execution result | +| spocks | SPoCK | +| executor_signature | Signature of the executor | + +#### Chunk + +Chunk described execution information for given collection in a block + +```proto +message Chunk { + uint32 CollectionIndex = 1; + bytes start_state = 2; + bytes event_collection = 3; + bytes block_id = 4; + uint64 total_computation_used = 5; + uint32 number_of_transactions = 6; + uint64 index = 7; + bytes end_state = 8; + bytes execution_data_id = 9; + bytes state_delta_commitment = 10; +} +``` + +| Field | Description | +|-------------------------|------------------------------------------------------| +| CollectionIndex | Identifier of a collection | +| start_state | State commitment at start of the chunk | +| event_collection | Hash of events emitted by transactions in this chunk | +| block_id | Identifier of a block | +| total_computation_used | Total computation used by transactions in this chunk | +| number_of_transactions | Number of transactions in a chunk | +| index | Index of chunk inside a block (zero-based) | +| end_state | State commitment after executing chunk | +| execution_data_id | Identifier of a execution data | +| state_delta_commitment | A commitment over sorted list of register changes | + +#### Service Event + +Special type of events emitted in system chunk used for controlling Flow system. + +```proto +message ServiceEvent { + string type = 1; + bytes payload = 2; +} +``` + +| Field | Description | +| ------- | ----------------------------------- | +| type | Type of an event | +| payload | JSON-serialized content of an event | + +## Subscriptions + +### SubscribeEvents + +`SubscribeEvents` streams events for all blocks starting at the requested start block, up until the latest available block. Once the latest is +reached, the stream will remain open and responses are sent for each new block as it becomes available. + +Events within each block are filtered by the provided [EventFilter](#eventfilter), and only those events that match the filter are returned. If no filter is provided, +all events are returned. + +Responses are returned for each block containing at least one event that matches the filter. Additionally, heatbeat responses (SubscribeEventsResponse +with no events) are returned periodically to allow clients to track which blocks were searched. Clients can use this information to determine +which block to start from when reconnecting. + +```proto +rpc SubscribeEvents(SubscribeEventsRequest) returns (stream SubscribeEventsResponse) +``` + +#### Request + +```proto +message SubscribeEventsRequest { + bytes start_block_id = 1; + uint64 start_block_height = 2; + EventFilter filter = 3; + uint64 heartbeat_interval = 4; + entities.EventEncodingVersion event_encoding_version = 5; +} +``` + +| Field | Description | +| ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| start_block_id | The first block to search for events. Only one of start_block_id and start_block_height may be provided, otherwise an InvalidArgument error is returned. If neither are provided, the latest sealed block is used | +| start_block_height | Block height of the first block to search for events. Only one of start_block_id and start_block_height may be provided, otherwise an InvalidArgument error is returned. If neither are provided, the latest sealed block is used | +| filter | Filter to apply to events for each block searched. If no filter is provided, all events are returned | +| heartbeat_interval | Interval in block heights at which the server should return a heartbeat message to the client | +| event_encoding_version | Preferred event encoding version of the block events payload. Possible variants: CCF, JSON-CDC | + +#### Response + +```proto +message SubscribeEventsResponse { + bytes block_id = 1; + uint64 block_height = 2; + repeated entities.Event events = 3; + google.protobuf.Timestamp block_timestamp = 4; + uint64 message_index = 5; +} +``` + +### SubscribeExecutionData + +`SubscribeExecutionData` streams execution data for all blocks starting at the requested start block, up until the latest available block. Once the latest is reached, the stream will remain open and responses are sent for each new execution data as it becomes available. + +```proto +rpc SubscribeExecutionData(SubscribeExecutionDataRequest) returns (stream SubscribeExecutionDataResponse) +``` + +#### Request + +```proto +message SubscribeExecutionDataRequest { + bytes start_block_id = 1; + uint64 start_block_height = 2; + entities.EventEncodingVersion event_encoding_version = 3; +} +``` + +| Field | Description | +| ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| start_block_id | The first block to get execution data for. Only one of start_block_id and start_block_height may be provided, otherwise an InvalidArgument error is returned. If neither are provided, the latest sealed block is used | +| start_block_height | Block height of the first block to get execution data for. Only one of start_block_id and start_block_height may be provided, otherwise an InvalidArgument error is returned. If neither are provided, the latest sealed block is used | +| event_encoding_version | Preferred event encoding version of the block events payload. Possible variants: CCF, JSON-CDC | + +#### Response + +```proto +message SubscribeExecutionDataResponse { + uint64 block_height = 1; + entities.BlockExecutionData block_execution_data = 2; + google.protobuf.Timestamp block_timestamp = 3; +} +``` + +## Execution data + +### EventFilter + +`EventFilter` defines the filter to apply to block events. Filters are applied as an OR operation, i.e. any event matching any of the filters is returned. +If no filters are provided, all events are returned. If there are any invalid filters, the API will return an InvalidArgument error. + +```proto +message EventFilter { + repeated string event_type = 1; + repeated string contract = 2; + repeated string address = 3; +} +``` + +| Field | Description | +| ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| event_type | A list of full event types to include.
    Event types have 2 formats:
    _ Protocol events: `flow.[event name]`
    _ Smart contract events: `A.[contract address].[contract name].[event name]` | +| contract | A list of contracts who's events should be included. Contracts have the following name formats:
    _ Protocol events: `flow`
    _ Smart contract events: `A.[contract address].[contract name]`
    This filter matches on the full contract including its address, not just the contract's name | +| address | A list of addresses who's events should be included. Addresses must be Flow account addresses in hex format and valid for the network the node is connected to. i.e. only a mainnet address is valid for a mainnet node. Addresses may optionally include the `0x` prefix | + + +## Execution data streaming API + +### Execution Data API + +The `ExecutionDataAPI` provides access to block execution data over gRPC, including transactions, events, and register data (account state). It’s an optional API, which makes use of the Execution Sync protocol to trustlessly download data from peers on the network. + +[execution data protobuf file](https://github.com/onflow/flow/blob/master/protobuf/flow/executiondata/executiondata.proto) + + +> The API is disabled by default. To enable it, specify a listener address with the cli flag `--state-stream-addr`. + + + + +Below is a list of the available CLI flags to control the behavior of the API + +| Flag | Type | Description | +|----------------------------------|----------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| state-stream-addr | string | Listener address for API. e.g. 0.0.0.0:9003. If no value is provided, the API is disabled. Default is disabled. | +| execution-data-cache-size | uint32 | Number of block execution data objects to store in the cache. Default is 100. | +| state-stream-global-max-streams | uint32 | Global maximum number of concurrent streams. Default is 1000. | +| state-stream-max-message-size | uint | Maximum size for a gRPC response message containing block execution data. Default is 20*1024*1024 (20MB). | +| state-stream-event-filter-limits | string | Event filter limits for ExecutionData SubscribeEvents API. These define the max number of filters for each type. e.g. EventTypes=100,Addresses=20,Contracts=50. Default is 1000 for each. | +| state-stream-send-timeout | duration | Maximum wait before timing out while sending a response to a streaming client. Default is 30s. | +| state-stream-send-buffer-size | uint | Maximum number of unsent responses to buffer for a stream. Default is 10. | +| state-stream-response-limit | float64 | Max number of responses per second to send over streaming endpoints. This effectively applies a rate limit to responses to help manage resources consumed by each client. This is mostly used when clients are querying data past data. e.g. 3 or 0.5. Default is 0 which means no limit. | + + + +=== networks/access-onchain-data/access-http-api.md === +--- +redirect: /http-api +title: Access HTTP API ↗️ +sidebar_position: 2 +--- + +# Access HTTP API + +Go to [HTTP API](/http-api) + + + + +=== networks/access-onchain-data/websockets-stream-api/unsubscribe-message.md === +--- +title: Unsubscribe request message format +sidebar_label: Unsubscribing from topic +sidebar_position: 3 +--- + +# Unsubscribe message format + +Unsubscribe requests must be sent as JSON in text frames, one request per frame. + +### Example of unsubscribe request + +```json +{ + "subscription_id": "some-id-1", + "action": "unsubscribe" +} +``` + +### Example of successful response + +```json +{ + "subscription_id": "some-id-1", + "action": "unsubscribe" +} +``` + +### Example of error response + +```json +{ + "error": { + "code": 404, + "message": "subscription not found" + } +} +``` + +### Request fields + +| Name | Type | Required | Description | +|-------------------|--------|----------|-----------------------------------------------------------------------| +| `subscription_id` | STRING | YES | Unique identifier of the subscription | +| `action` | STRING | YES | Action to perform. Must be `unsubscribe` to initiate a unsubscription | + + +=== networks/access-onchain-data/websockets-stream-api/subscribe-message.md === +--- +title: Subscribe request message format +sidebar_label: Subscribing to topic +sidebar_position: 2 +--- + +# Subscribe request format + +Subscribe requests must be sent as JSON in text frames, one request per frame. + + +### Example of subscribe request + +```json +{ + "subscription_id": "some-id-1", + "action": "subscribe", + "topic": "block_digests", + "arguments": { + "block_status": "finalized", + "start_block_height": "99416580" + } +} +``` + +### Example of successful response + +```json +{ + "subscription_id": "some-id-1", + "action": "subscribe" +} +``` + +### Example of failed response + +```json +{ + "subscription_id": "some-id-1", + "error": { + "code": 400, + "message": "invalid message" + } +} +``` + +### Example of messages provided by subscription (if successful) + +```json +{ + "subscription_id": "some-id-1", + "topic": "block_digests", + "payload": { + "id": "0x1234...", + "height:": "123456789", + "timestamp": "2025-01-02T10:00:00Z" + } +} +``` + +### Example of messages provided by subscription (if error) + +```json +{ + "subscription_id": "some-id-1", + "error": { + "code": 500, + "message": "internal error" + } +} +``` + +### Request fields: + +| Name | Type | Required | Description | +| ----------------- | ------ | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | +| `subscription_id` | STRING | NO | Optional unique identifier for the subscription. Max length of ID generated by client is 20 characters. Server will generate a unique ID if omitted | +| `action` | STRING | YES | Action to perform. Must be `subscribe` to initiate a subscription | +| `topic` | STRING | YES | The topic to subscribe to, such as `blocks`, `block_digests`, etc. See more details on [Supported Topics](supported-topics/index.md) page. | +| `arguments` | STRING | NO | Additional topic specific parameters for the subscription, such as `start_block_id`, `start_block_height` or other. | + +You can use `subscription_id` as a client-generated identifier to track responses asynchronously. +If you don't provide `subscription_id`, the server will generate one and include it in the response. + + +=== networks/access-onchain-data/websockets-stream-api/postman-example.md === +--- +title: Connecting to WebSockets via Postman UI +sidebar_label: Connecting to WebSockets via Postman UI +sidebar_position: 6 +--- + +This tutorial will guide you through connecting to a WebSocket using Postman and sending a subscription message. + +## Step 1: Open Postman + +Ensure you have Postman installed and opened on your system. If you don’t have it yet, download it from [Postman’s official website](https://www.postman.com/downloads/). + +## Step 2: Create a New WebSocket Request + +1. In Postman, click on **File** > **New...** > **WebSocket**. +![pe_1]() +2. Enter the WebSocket URL in **Enter URL** field : `wss://rest-mainnet.onflow.org/v1/ws` or `wss://rest-testnet.onflow.org/v1/ws` +3. Click **Connect** button to establish the WebSocket connection. +![pe_2]() + +## Step 3: Send a Subscription Message + +1. Once connected, go to the **Messages** tab. +2. Enter the JSON message into the text box. In this example the [digests block subscription](./supported-topics/block_digests_topic.md) will be established. For other available topics check [Supported topics page](./supported-topics/index.md). +3. Click **Send** to subscribe to the WebSocket topic. +![pe_3]() + +## Step 4: View Responses + +- After sending the message, you should start receiving responses in the **Response** bottom tab. +- Each message received from the server will be displayed in real-time. + +![pe_4]() + +## Step 5: Disconnect + +- When you are done, click **Disconnect** to close the WebSocket connection. + +## Troubleshooting + +- Ensure WebSocket URL is correct and active. +- In case of an error validate your JSON message for any syntax errors before sending and check correctness of all arguments on [Supported topics page](./supported-topics/index.md). + +Congratulations! You have successfully connected to a WebSocket server using Postman and sent a subscription message. + + + + + + + + + +=== networks/access-onchain-data/websockets-stream-api/list-subscriptions-message.md === +--- +title: List subscriptions request message format +sidebar_label: Listing subscriptions +sidebar_position: 5 +--- + +# List subscriptions message format + +List subscriptions requests must be sent as JSON in text frames, one request per frame. +This message is different from others as it doesn't require you to provide subscription ID. +Thus, the response for this message is different too. + +### Example of request + +```json +{ + "action": "list_subscriptions" +} +``` + +### Example of response + +```json +{ + "subscriptions": [ + { + "subscription_id": "some-id-1", + "topic": "blocks", + "arguments": { + "block_status": "finalized", + "start_block_height": "123456789" + } + }, + { + "subscription_id": "some-id-2", + "topic": "events", + "arguments": {} + } + ] +} +``` + +If there are no active subscriptions, `subscriptions` array will be empty. + +### Request fields + +| Name | Type | Required | Description | +|----------|--------|----------|-----------------------------------------------------------------------------------------| +| `action` | STRING | YES | Action to perform. Must be `list_subscriptions` to initiate a list subscription request | + + +=== networks/access-onchain-data/websockets-stream-api/index.md === +--- +title: Overview +sidebar_label: Overview +sidebar_position: 1 +--- + +# Websockets Stream API + +## Overview + +The Stream API allows clients to receive real-time updates from the Flow blockchain via WebSocket connections. It +supports subscribing to various topics, such as blocks, events, and transactions, enabling low-latency access to live +data. + +### Important Information + +- **Endpoint**: The WebSocket server is available at: + - Mainnet: `wss://rest-mainnet.onflow.org/v1/ws` + - Testnet: `wss://rest-testnet.onflow.org/v1/ws` +- **Limits**: + - Each connection supports up to 20 concurrent subscriptions. Exceeding this limit will result in an error. + - Each subscription may provide up to 20 responses per second. + - After 1 minute of inactivity (no data sent or received) the connection is closed. + +- **Supported Topics**: See more details on [Supported Topics](supported-topics/index.md) page. + - [`block_digests`](supported-topics/block_digests_topic.md) + - [`block_headers`](supported-topics/block_headers_topic.md) + - [`blocks`](supported-topics/blocks_topic.md) + - [`events`](supported-topics/events_topic.md) + - [`account_statuses`](supported-topics/account_statuses_topic.md) + - [`transaction_statuses`](supported-topics/transaction_statuses_topic.md) + - [`send_and_get_transaction_statuses`](supported-topics/send_and_get_transaction_statuses_topic.md) + +- **Notes**: Always handle errors gracefully and close unused subscriptions to maintain efficient connections. + +--- + +## Setting Up a WebSocket Connection + +Use any WebSocket client library to connect to the endpoint. Below is an example using JavaScript: + +```javascript +const ws = new WebSocket('wss://rest-mainnet.onflow.org/ws'); + +ws.onopen = () => { + console.log('Connected to WebSocket server'); +}; + +ws.onclose = () => { + console.log('Disconnected from WebSocket server'); +}; + +ws.onerror = (error) => { + console.error('WebSocket error:', error); +}; +``` + +--- + +## Subscribing to Topics + +To receive data from a specific topic, send a subscription request in JSON format over the WebSocket connection. + +### Request Format + +```json +{ + "subscription_id": "some-id-42", + "action": "subscribe", + "topic": "blocks", + "arguments": { + "block_status": "sealed", + "start_block_height": "123456789" + } +} +``` + +- **`subscription_id`**(optional): A unique identifier for the subscription (a string with maximum length constraint of 20 characters). If omitted, the server generates one. +- **`action`**: The action to perform. Supported actions include: `subscribe`, `unsubscribe`, `list_subscriptions`. +- **`topic`**: The topic to subscribe to. See the supported topics in the Overview. +- **`arguments`**: Additional topic specific arguments for subscriptions, such as `start_block_height`, `start_block_id`, and others. See more details about arguments for each topic on [Supported Topics](supported-topics/index.md) page. + +### Successful Response Format + +```json +{ + "subscription_id": "some-id-42", + "action": "subscribe" +} +``` + +--- + +## Unsubscribing from Topics + +To stop receiving data from a specific topic, send an unsubscribe request. + +### Request Format + +```json +{ + "subscription_id": "some-id-42", + "action": "unsubscribe" +} +``` + +### Successful Response Format + +```json +{ + "subscription_id": "some-id-42", + "action": "unsubscribe" +} +``` + +--- + +## Listing Active Subscriptions + +You can retrieve a list of all active subscriptions for the current WebSocket connection. + +### Request Format + +```json +{ + "action": "list_subscriptions" +} +``` + +### Successful Response Format + +```json +{ + "subscriptions": [ + { + "subscription_id": "some-id-1", + "topic": "blocks", + "arguments": { + "block_status": "sealed", + "start_block_height": "123456789" + } + }, + { + "subscription_id": "some-id-2", + "topic": "events", + "arguments": {} + } + ] +} +``` + +--- + +## Errors Example + +If a request is invalid or cannot be processed, the server responds with an error message. + +### OK Response + +```json +{ + "subscription_id": "some-id-42", + "topic": "block_digests", + "payload": { + "id": "0x1234...", + "height:": "123456789", + "timestamp": "2025-01-02T10:00:00Z" + } +} +``` + +### Error Response + +```json +{ + "subscription_id": "some-id-42", + "error": { + "code": 500, + "message": "Access Node failed" + } +} +``` + +### Common Error Codes + +- **400**: Invalid message format or arguments +- **404**: Subscription not found +- **500**: Internal server error + +### Asynchronous environments + +If you're working in an asynchronous environment, the Streaming API ensures **first-in first-out** message processing, +so responses will be returned in the same order the requests were received over the connection. +You can leverage this feature to simplify your code and maintain consistency. + +Additionally, you can specify a custom `subscription_id` in the subscribe request to easily identify the correct response. It must not be an empty string and must follow a maximum length constraint of 20 characters. + +=== networks/access-onchain-data/websockets-stream-api/common-errors.md === +--- +title: Common errors +sidebar_label: Common errors +sidebar_position: 7 +--- + +This document outlines the possible errors returned from the WebSocket API. Understanding these errors will help properly handle error cases in client implementation. + +## Error Structure + +All errors returned by the WebSocket API follow this structure: + +```json +{ + "subscriptionID": "string", + "error": { + "code": number, + "message": "string" + }, + "action": "string" +} +``` + +Where: +- `subscriptionID`: The ID of the subscription related to the error (if applicable) +- `error.code`: HTTP status code indicating the error type +- `error.message`: Human-readable description of the error +- `action`: The action that was being performed when the error occurred (`subscribe`, `unsubscribe`, or `list_subscription`) + + +### Message Format Errors + +**Status Code:** 400 Bad Request + +These errors occur when the server cannot parse or validate your incoming message. + +| Error Message | Description | When to Expect | +|---------------|-------------|---------------| +| *"error reading message: ..."* | The raw message could not be read from the WebSocket connection | When sending malformed JSON or when the connection is disrupted | +| *"error parsing message: ..."* | The message was read but could not be processed | When the message structure doesn't match the expected format | +| *"error unmarshalling base message: ..."* | The message JSON could not be processed into the expected format | When required fields are missing or of incorrect type | +| *"error unmarshalling subscribe message: ..."* | The message JSON could not be processed into a subscribe request | When sending a malformed subscribe request | +| *"error unmarshalling unsubscribe message: ..."* | The message JSON could not be processed into an unsubscribe request | When sending a malformed unsubscribe request | +| *"error unmarshalling list subscriptions message: ..."* | The message JSON could not be processed into a list subscriptions request | When sending a malformed list subscriptions request | +| *"unknown action type: ..."* | The action specified in the message is not recognized | When specifying an action other than `subscribe`, `unsubscribe`, or `list_subscription` | + +## Subscription-Related Errors + +### Subscribe Action Errors + +**Action:** `subscribe` + +| Error Message | Status Code | Description | When to Expect | +|---------------|-------------|-------------|---------------| +| *"error creating new subscription: maximum number of subscriptions reached"* | 429 Too Many Requests | The maximum number of active subscriptions per connection has been reached | When trying to create more subscriptions than allowed by the server | +| *"error parsing subscription id: ..."* | 400 Bad Request | The provided subscription ID is invalid | When providing a malformed subscription ID | +| *"subscription ID is already in use: ..."* | 400 Bad Request | The provided subscription ID is already being used | When trying to reuse an existing subscription ID | +| *"error creating data provider: ..."* | 400 Bad Request | The subscription could not be created | When providing an invalid topic or arguments for your subscription | + +### Unsubscribe Action Errors + +**Action:** "unsubscribe" + +| Error Message | Status Code | Description | When to Expect | +|---------------|-------------|-------------|---------------| +| *"error parsing subscription id: ..."* | 400 Bad Request | The provided subscription ID is invalid | When providing a malformed subscription ID | +| *"subscription not found"* | 404 Not Found | The specified subscription does not exist | When trying to unsubscribe from a non-existent subscription | + +### Subscription Runtime Errors + +**Action:** "subscribe" + +| Error Message | Status Code | Description | When to Expect | +|---------------|-------------|-------------|---------------| +| *"internal error: ..."* | 500 Internal Server Error | An error occurred while processing your subscription | When there's an issue with the subscription after it was successfully created | + +## Error Handling Best Practices + +1. **Always check for errors in responses**: Every response from the WebSocket API should be checked for the presence of an error object. + +2. **Handle subscription limits**: Be prepared to handle the case where the maximum number of subscriptions has been reached. + +3. **Log detailed error information**: Log the complete error object for debugging purposes. + +4. **Validate messages before sending**: Ensure your messages conform to the expected format to avoid parsing errors. + +=== networks/access-onchain-data/websockets-stream-api/supported-topics/transaction_statuses_topic.md === +--- +title: Transaction statuses +sidebar_label: Transaction statuses +sidebar_position: 7 +--- + +Provides updates on transaction status changes for already sent transactions. + +## Example Request + +```json +{ + "subscription_id": "some-id", + "action": "subscribe", + "topic": "transaction_statuses", + "arguments": { + "tx_id": "fe3784095bc194dca02e4b14e7e6a1e0519d10b7bc907453e5b5dc276259a106" + } +} +``` + +### Request Arguments + +| Name | Type | Required | Description | +| ------- | ------ | -------- | -------------------------------------------------------- | +| `tx_id` | STRING | YES | The ID of the transaction to monitor for status changes. | + + +## Example Response + +```json +{ + "subscription_id": "some-id", + "topic": "transaction_statuses", + "payload": { + "transaction_result": { + "block_id": "b668e472c404e471cba8bab5246ca98f90d8492e80c81aae4cccbfae6e734aad", + "collection_id": "efdcbf3b2b02b20cdfa7f2669034da05e44232ea68e41d3ed14756472081f9b9", + "execution": "Success", + "status": "Sealed", + "status_code": 0, + "error_message": "", + "computation_used": "0", + "events": [ + { + "type": "A.0b2a3299cc857e29.TopShot.Withdraw", + "transaction_id": "fe3784095bc194dca02e4b14e7e6a1e0519d10b7bc907453e5b5dc276259a106", + "transaction_index": "4", + "event_index": "0", + "payload": "eyJ2YWx1ZSI6eyJpZCI6IkEuMGIyYTMyOTljYzg1N2UyOS5Ub3BTaG90LldpdGhkcmF3IiwiZmllbGRzIjpbeyJ2YWx1ZSI6eyJ2YWx1ZSI6IjQwOTQ3MzE4IiwidHlwZSI6IlVJbnQ2NCJ9LCJuYW1lIjoiaWQifSx7InZhbHVlIjp7InZhbHVlIjp7InZhbHVlIjoiMHg2N2Q5OTk5MWMxMzRlODQ4IiwidHlwZSI6IkFkZHJlc3MifSwidHlwZSI6Ik9wdGlvbmFsIn0sIm5hbWUiOiJmcm9tIn1dfSwidHlwZSI6IkV2ZW50In0K" + }, + // Full response is cut down due to its large size; see `_links` for the full response. ... + { + "type": "A.f919ee77447b7497.FlowFees.FeesDeducted", + "transaction_id": "fe3784095bc194dca02e4b14e7e6a1e0519d10b7bc907453e5b5dc276259a106", + "transaction_index": "4", + "event_index": "22", + "payload": "eyJ2YWx1ZSI6eyJpZCI6IkEuZjkxOWVlNzc0NDdiNzQ5Ny5GbG93RmVlcy5GZWVzRGVkdWN0ZWQiLCJmaWVsZHMiOlt7InZhbHVlIjp7InZhbHVlIjoiMC4wMDAwNDc5OCIsInR5cGUiOiJVRml4NjQifSwibmFtZSI6ImFtb3VudCJ9LHsidmFsdWUiOnsidmFsdWUiOiIxLjAwMDAwMDAwIiwidHlwZSI6IlVGaXg2NCJ9LCJuYW1lIjoiaW5jbHVzaW9uRWZmb3J0In0seyJ2YWx1ZSI6eyJ2YWx1ZSI6IjAuMDAwMDAxODgiLCJ0eXBlIjoiVUZpeDY0In0sIm5hbWUiOiJleGVjdXRpb25FZmZvcnQifV19LCJ0eXBlIjoiRXZlbnQifQo=" + } + ], + "_links": { + "_self": "/v1/transaction_results/fe3784095bc194dca02e4b14e7e6a1e0519d10b7bc907453e5b5dc276259a106" + } + }, + "message_index": 3 + } +} +``` + + + +=== networks/access-onchain-data/websockets-stream-api/supported-topics/send_and_get_transaction_statuses_topic.md === +--- +title: Send and get transaction statuses +sidebar_label: Send and get transaction statuses +sidebar_position: 8 +--- + +Sends a transaction and provides updates on its status changes. + +## Example Request + +```json +{ + "subscription_id": "some-id-7", + "action": "subscribe", + "topic": "send_and_get_transaction_statuses" + "arguments": { + "arguments": [], + "authorizers": ["dba05362251g43g4"], + "envelope_signatures": [ + { + "address": "dba05362251g43g4", + "key_index": "0", + "signature": "PJPVEOCtPKubTEpPqd4zrrSXo1RhpABAMDuzIchgBje8gyh04XuWY4f/tu+c0llDhOU/5sQBokeOTdygaS6eTQ==" + } + ], + "gas_limit": "1000", + "payer": "dba05362251g43g4", + "proposal_key": { + "address": "dba05362251g43g4", + "key_index": "0", + "sequence_number": "0" + }, + "reference_block_id": "817d7c1d2c13a4bd37c182747a4116b45cd175c0ba4878071c33f0f278b37dd7", + "script": "CgkJCXRyYW5zYWN0aW9uIHsKCQkJCXByZXBhcmUoYWNjOiAmQWNjb3VudCkge30KCQkJCWV4ZWN1dGUgewoJCQkJCWxvZygidGVzdCIpCgkJCQl9CgkJCX0KCQk=" + } +} +``` + +| Name | Type | REQUIRED | Description | +| --------------------- | ------ | -------- | ------------------------------------------------------------------------- | +| `script` | STRING | YES | Base64-encoded content of the Cadence script. | +| `arguments` | LIST | YES | A list of arguments, each encoded as Base64. | +| `reference_block_id` | STRING | YES | BlockID for the transaction's reference block | +| `gas_limit` | STRING | YES | The limit on the amount of computation a transaction can perform. | +| `payer` | STRING | YES | The 8-byte address of an account. | +| `proposal_key` | OBJECT | YES | A required object representing the proposal key. | +| `authorizers` | LIST | YES | A list of authorizers, each represented as a hexadecimal-encoded address. | +| `payload_signatures` | LIST | NO | A list of Base64-encoded signatures. | +| `envelope_signatures` | LIST | YES | A list of Base64-encoded signatures. | + +## Example Response + +```json +{ + "subscription_id": "some-id", + "topic": "send_and_get_transaction_statuses", + "payload": { + "transaction_result": { + "block_id": "7ad167602487665db095f7cb0b95139e5dcaf3ad2479ee4d14cade35b7d4bbdc", + "collection_id": "d0855ed45c16be2831ab9892ec8a9ddfd10a0e01e683466971cfd87c759bf7d1", + "execution": "Failure", + "status": "Sealed", + "status_code": 1, + "error_message": "[Error Code: 1009] error caused by: 1 error occurred:\n\t* transaction verification failed: [Error Code: 1006] invalid proposal key: public key 0 on account dba05362251g43g4 does not have a valid signature: [Error Code: 1009] invalid envelope key: public key 0 on account dba05362251g43g4 does not have a valid signature: signature is not valid\n\n", + "computation_used": "0", + "events": [], + "_links": { + "_self": "/v1/transaction_results/92014de98466a6304ecd821c95ee2612e248c22419d243e6e3ff4d138dffde04" + } + }, + "message_index": 3 + } +} +``` + +=== networks/access-onchain-data/websockets-stream-api/supported-topics/index.md === +--- +title: Supported topics +sidebar_label: Supported topics +sidebar_position: 1 +--- + +# Supported Topics + +In this section, there is a list of topics that client can subscribe to in order to receive updates on different states of the Flow blockchain. + +It is possible to subscribe to each topic multiple times with different configurations based on input arguments. + +The responses for all topics are aligned with the [Flow REST API](/http-api) responses. + +=== networks/access-onchain-data/websockets-stream-api/supported-topics/events_topic.md === +--- +title: Events +sidebar_label: Events +sidebar_position: 5 +--- + +Provides blockchain events. The response can be configured using additional arguments to filter and retrieve only filtered events instead of all events. + +## Example Request + +Started from latest block for event types `flow.AccountKeyAdded` and `flow.AccountKeyRemoved`: + +```json +{ + "subscription_id": "some-id", + "action": "subscribe", + "topic": "events", + "arguments": { + "event_types": [ + "flow.AccountKeyAdded", + "flow.AccountKeyRemoved" + ] + } +} +``` + +Started from block height `106197172` for contracts `A.f919ee77447b7497.FlowFees` and `A.1654653399040a61.FlowToken` with heartbeat interval equal 10 blocks: + +```json +{ + "subscription_id": "some-id", + "action": "subscribe", + "topic": "events", + "arguments": { + "start_block_height": "106197172", + "heartbeat_interval": "10", + "contracts": [ + "A.f919ee77447b7497.FlowFees", + "A.1654653399040a61.FlowToken" + ] + } +} +``` + +Started from block id `44774d980c75d9380caaf4c65a2ee6c4bde9a1e6da6aa858fe2dc5e4a7aff773` for account addresses `0xe544175ee0461c4b` and `2d4c3caffbeab845` with heartbeat interval equal 5 blocks: + +```json +{ + "subscription_id": "some-id", + "action": "subscribe", + "topic": "events", + "arguments": { + "start_block_id": "44774d980c75d9380caaf4c65a2ee6c4bde9a1e6da6aa858fe2dc5e4a7aff773", + "heartbeat_interval": "5", + "addresses": [ + "0xe544175ee0461c4b", + "2d4c3caffbeab845" + ] + } +} +``` + +### Request Arguments + +| Name | Type | Required | Description | +| -------------------- | ------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------ | +| `start_block_id` | STRING | NO | The ID of the block from which the subscription starts. If this argument is set, it is **not** possible to set `start_block_height`. | | +| `start_block_height` | STRING | NO | The height of the block from which the subscription starts. If this argument is set, it is **not** possible to set `start_block_id` | +| `heartbeat_interval` | STRING | NO | Maximum number of blocks between messages after which a response with no events is returned. This helps the client track progress for sparse event filters. | +| `event_types` | LIST | NO | A comma-separated list of event types to include. | +| `addresses` | LIST | NO | A comma-separated list of addresses who's events should be included. The format could be `"0xe544175ee0461c4b"` or `"e544175ee0461c4b"`. | +| `contracts` | LIST | NO | A comma-separated list of contracts who's events should be included. The format is `"A.f919ee77447b7497.FlowFees"` | + +If neither `start_block_id` nor `start_block_height` is set, the subscription will start from the latest block based on its status. + +## Example Response + +```json +{ + "subscription_id": "some-id", + "topic": "events", + "payload": { + "block_id": "660ce05ff19193a08c24730cdc0d747da76dfcc39fbab523d970270f2d5c9a3c", + "block_height": "106197288", + "block_timestamp": "2025-03-11T12:46:03.588742664Z", + "events": [ + { + "type": "flow.AccountKeyAdded", + "transaction_id": "7d9290e54437b4b9a5de416c04af6d597fcf5bf1cefcf618232ad86e5f71322b", + "transaction_index": "1", + "event_index": "14", + "payload": "2IGChNigg0BpUHVibGljS2V5goJpcHVibGljS2V52IvYiQyCcnNpZ25hdHVyZUFsZ29yaXRobdiIQQLYpINBAW1IYXNoQWxnb3JpdGhtgYJocmF3VmFsdWXYiQzYpINBAnJTaWduYXR1cmVBbGdvcml0aG2BgmhyYXdWYWx1ZdiJDNiig0EDdGZsb3cuQWNjb3VudEtleUFkZGVkhYJnYWRkcmVzc9iJA4JpcHVibGljS2V52IhAgmZ3ZWlnaHTYiReCbWhhc2hBbGdvcml0aG3YiEEBgmhrZXlJbmRleNiJBILYiEEDhUhbvtriVP1Dy4KYQBUYNhhKGHoYZhicGHwYwxgYGKcYqxhqGIcYZxiCGKMXGDgYRRjnGGQYjBieGIIYxhiUGIgY+BjjGM0YlxhBGL0Y2hiyGHUY8hjoGBwYMhiUGC4YIxjtGNkYJhgoGPMYNxgmGF0YqhgjGP0YlRh2GMoYTxihGOIYsBizGEsYVIECGwAAABdCgQcAgQPCQA==" + }, + { + "type": "flow.AccountKeyAdded", + "transaction_id": "7d9290e54437b4b9a5de416c04af6d597fcf5bf1cefcf618232ad86e5f71322b", + "transaction_index": "1", + "event_index": "15", + "payload": "2IGChNigg0BpUHVibGljS2V5goJpcHVibGljS2V52IvYiQyCcnNpZ25hdHVyZUFsZ29yaXRobdiIQQLYpINBAW1IYXNoQWxnb3JpdGhtgYJocmF3VmFsdWXYiQzYpINBAnJTaWduYXR1cmVBbGdvcml0aG2BgmhyYXdWYWx1ZdiJDNiig0EDdGZsb3cuQWNjb3VudEtleUFkZGVkhYJnYWRkcmVzc9iJA4JpcHVibGljS2V52IhAgmZ3ZWlnaHTYiReCbWhhc2hBbGdvcml0aG3YiEEBgmhrZXlJbmRleNiJBILYiEEDhUhbvtriVP1Dy4KYQBg2GMoY4QYYUhiTGNkYjBinGFsYuhiPGEQYcBjrGKoYdRhsGCkYVRivGMIYRxj6GCUYpRj1GJ4YeRipDgoYPBiLGKAYdgkY8RhVGC4YKxhHGDYYVRiqGOcIGGsYOhhwGIgEGKwYyhj4AxgxGLwYpxhuGMQYtxjsGKeBAhsAAAAXSHboAIEDwkEB" + }, + { + "type": "flow.AccountKeyAdded", + "transaction_id": "7d9290e54437b4b9a5de416c04af6d597fcf5bf1cefcf618232ad86e5f71322b", + "transaction_index": "1", + "event_index": "16", + "payload": "2IGChNigg0BpUHVibGljS2V5goJpcHVibGljS2V52IvYiQyCcnNpZ25hdHVyZUFsZ29yaXRobdiIQQLYpINBAW1IYXNoQWxnb3JpdGhtgYJocmF3VmFsdWXYiQzYpINBAnJTaWduYXR1cmVBbGdvcml0aG2BgmhyYXdWYWx1ZdiJDNiig0EDdGZsb3cuQWNjb3VudEtleUFkZGVkhYJnYWRkcmVzc9iJA4JpcHVibGljS2V52IhAgmZ3ZWlnaHTYiReCbWhhc2hBbGdvcml0aG3YiEEBgmhrZXlJbmRleNiJBILYiEEDhUhbvtriVP1Dy4KYQBjTABhfGC8YmBiZGLoYwBjEGI0YwBjJGJwYVRhxGJ0YxRjKCRj6AxhaEBiEGI0YfBj3GM0YPhiDGFIYrBg/GMgYnBh0GFQYNBhAGFEYZxi/GNMIGB8YeRhEGKQYbRhHGHAYShjyGEYYnhjrGCEYZBjBGLYYYxg5GBwYkoECGgX14QCBA8JBAg==" + } + ], + "message_index": 11 + } +} +``` + + +=== networks/access-onchain-data/websockets-stream-api/supported-topics/blocks_topic.md === +--- +title: Blocks +sidebar_label: Blocks +sidebar_position: 4 +--- + +Provides full block information each time a new block appears on the blockchain. + +## Example Request + +Started from latest block: + +```json +{ + "subscription_id": "some-id", + "action": "subscribe", + "topic": "blocks", + "arguments": { + "block_status": "sealed" + } +} +``` + +Started from block height `106192109`: + +```json +{ + "subscription_id": "some-id", + "action": "subscribe", + "topic": "blocks", + "arguments": { + "block_status": "sealed", + "start_block_height": "106192109" + } +} +``` + +Started from block id `83a8229cbe552f9b10160163394986dc7d99790ad3fedf7db4153d7d7863a3fa`: + +```json +{ + "subscription_id": "some-id", + "action": "subscribe", + "topic": "blocks", + "arguments": { + "block_status": "sealed", + "start_block_id": "83a8229cbe552f9b10160163394986dc7d99790ad3fedf7db4153d7d7863a3fa" + } +} +``` + +### Request Arguments + +| Name | Type | Required | Description | +| -------------------- | ------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------ | +| `block_status` | STRING | YES | The status of blocks to subscribe to. Supported values are: `sealed`, `finalized`. | +| `start_block_id` | STRING | NO | The ID of the block from which the subscription starts. If this argument is set, it is **not** possible to set `start_block_height`. | | +| `start_block_height` | STRING | NO | The height of the block from which the subscription starts. If this argument is set, it is **not** possible to set `start_block_id` | + +If neither `start_block_id` nor `start_block_height` is set, the subscription will start from the latest block based on its status. + +## Example Response + +```json +{ + "subscription_id": "some-id", + "topic": "blocks", + "payload": { + "header": { + "id": "7a7bc4dc574f67f0dc01a6c96cfbabe73ead23f76ac8130e620996779a500925", + "parent_id": "70b7f0a8c14e9f374eaf2f37da4dee7815c8639b3f9e67c301e84cf7fb51070c", + "height": "106195712", + "timestamp": "2025-03-11T12:25:00.450424315Z", + "parent_voter_signature": "+GyIAAAAAAAAAACwobZq2GxrWxPUuNJwo5T1pFWvwcAF4/ue8e7j7eFTcRhtReHV+dWnneyGtJdpuaIagLCEfjHvfItzt3J/kXsbdEFeycVBeznP4LIHs0XWWkeRn+yds4NAM8jltmGGBnvgJ68=" + }, + "payload": { + "collection_guarantees": [ + { + "collection_id": "74d146368179f95a49531072cda799d1c0905523fd5a35c224eefbd92fab6a90", + "signer_indices": "71d9de679d7ff457a0", + "signature": "" + }, + { + "collection_id": "b4b40fa4bd5a98cc5f61924aa63a98c588f56447cec5bcdad538e0a855f1a0f3", + "signer_indices": "710746ee7fd5f7a540", + "signature": "" + } + ], + "block_seals": [ + { + "block_id": "71418383aefda2df4da5fabb03d5ff0e8778f83783c5566c1110ba4a4d6e8de3", + "result_id": "35f480934324280f6eebd6016b143bc28cecb8f71fcd8262153320ad93b16c61", + "final_state": "\"0cc68829215fb9d69641537a317787b4ff805fe07d2f9ce12534b87d7d0f1335\"", + "aggregated_approval_signatures": [ + { + "verifier_signatures": [ + "rF6XjkIxY8lYD1vZvUycBtT+9DNY4d0U+p1q6WxiA8siYuFawrThkEIkLA3lYPjz" + ], + "signer_ids": [ + "80a0eaa9eb5fd541b2abbd1b5ffa79f0ae9a36973322556ebd4bdd3e1d9fe4cd" + ] + }, + { + "verifier_signatures": [ + "j2Y94dVrZZT1qNuK1ZbTOxj5HfNZxmV5zVBA3uwTKrQ4FFQ6gN0na1nXhZDJN1po" + ], + "signer_ids": [ + "e7e46cd698170b1f86bc9116dded0ac7df6ea0d86c41788c599fa77072059ea1" + ] + }, + { + "verifier_signatures": [ + "jp1/x2dr+LVS6Wl3ScaabsxD8745sb1kec3FUrj0SVXGEFnS7AUvG5RTKfsdF6m3" + ], + "signer_ids": [ + "49c9f946170d5fb40c2af953b1534fae771905865b142ab6ac9685b8ba5b51c1" + ] + }, + { + "verifier_signatures": [ + "rogMdMXwEKJvMUxdHcFqseW9VGVmNzya51kI8yoc8M0kPfuRfENqfgY1NuQBVn3N" + ], + "signer_ids": [ + "a1e6a5d9385d549f546803566747463e616e1d02ade2fcadba1b49c492ec8f29" + ] + }, + { + "verifier_signatures": [ + "seNSZjDBI7P4730jLcMWp1cq5XjSoSao9KLmrevSz2voQ+92Fcf7HqcSIpiF5CLi" + ], + "signer_ids": [ + "8f8d77ba98d1606b19fce8f6d35908bfc29ea171c02879162f6755c05e0ca1ee" + ] + } + ] + }, + { + "block_id": "9735518c51b170372fc3d04a6e360fef8b7f987fdb5f1e0f84d9a065d21a550c", + "result_id": "328efa584043b0042b32b5e53c4d3c56988387440d94e9507d0a8d24a0f31e82", + "final_state": "\"e1fb1b23de61b1cd83f22ffbcdd14a1844332d2e730e01df519c43ea3565bc3a\"", + "aggregated_approval_signatures": [ + { + "verifier_signatures": [ + "tchbJMwDd92Ui2UXnGPL20rEsTrkHQIYsYPZDAgR7O/9lRZh/u/5Y/7JN9+AiMwP" + ], + "signer_ids": [ + "0a29d8eb288d9bb0a0a4f2f9ff180ec83617659998ce363814048ec1683083e0" + ] + }, + { + "verifier_signatures": [ + "q07CVWjMP1ocBmShFFZ9K5SYIwBitF8g5gajVkOJ0t+O8twzbtW7SjWPY8NIWKyp" + ], + "signer_ids": [ + "446ae6d5ebdf6bc45aee29ed3b8da8dcf155afff87296401a3c0a28206121bcc" + ] + } + ] + } + ] + }, + "_expandable": {}, + "_links": { + "_self": "/v1/blocks/7a7bc4dc574f67f0dc01a6c96cfbabe73ead23f76ac8130e620996779a500925" + }, + "block_status": "BLOCK_SEALED" + } +} +``` + + +=== networks/access-onchain-data/websockets-stream-api/supported-topics/block_headers_topic.md === +--- +title: Block headers +sidebar_label: Block headers +sidebar_position: 3 +--- + +Provides block headers without the payload, each time a new block appears on the blockchain. + +## Example Request + +Started from latest block: + +```json +{ + "subscription_id": "some-id", + "action": "subscribe", + "topic": "block_headers", + "arguments": { + "block_status": "finalized" + } +} +``` + +Started from block height `106195326`: + +```json +{ + "subscription_id": "some-id", + "action": "subscribe", + "topic": "block_headers", + "arguments": { + "block_status": "finalized", + "start_block_height": "106195326" + } +} +``` + +Started from block id `cb27b014fa105a1e0e64d56cfbe2d7e140f4adf32938e38c3459592d01a72e91`: + +```json +{ + "subscription_id": "some-id", + "action": "subscribe", + "topic": "block_headers", + "arguments": { + "block_status": "finalized", + "start_block_id": "cb27b014fa105a1e0e64d56cfbe2d7e140f4adf32938e38c3459592d01a72e91" + } +} +``` + +### Request Arguments + +| Name | Type | Required | Description | +| -------------------- | ------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------ | +| `block_status` | STRING | YES | The status of blocks to subscribe to. Supported values are: `sealed`, `finalized`. | +| `start_block_id` | STRING | NO | The ID of the block from which the subscription starts. If this argument is set, it is **not** possible to set `start_block_height`. | | +| `start_block_height` | STRING | NO | The height of the block from which the subscription starts. If this argument is set, it is **not** possible to set `start_block_id` | + +If neither `start_block_id` nor `start_block_height` is set, the subscription will start from the latest block based on its status. + +## Example Response + +```json +{ + "subscription_id": "some-id", + "topic": "block_headers", + "payload": { + "id": "5cd0b1d0a0f0017c25647a6e2454a59aafa90682f2329449a610e19673ba07de", + "parent_id": "72ecd7cf6b18488b3597e677c5fa620d2dfad981fdd81b5cdb1851490b0cff56", + "height": "106195236", + "timestamp": "2025-03-11T12:18:39.702990376Z", + "parent_voter_signature": "+GyIAAAAAAAAAACwsabEiORFcP/ru95TABxwxXsxnUtJNoUbGB1xKKNtpR/LNUqDL5TyIQjL3xBl5KtKgLCFde8F5DHtUSGYSQUzaGhv+IoQgh1wgbXlY/soY5T30/HwmrucwD925EKOJAQUj7s=" + } +} +``` + + +=== networks/access-onchain-data/websockets-stream-api/supported-topics/block_digests_topic.md === +--- +title: Block digests +sidebar_label: Block digests +sidebar_position: 2 +--- + +Provides a summarized version of block information, including only the block ID, height, and timestamp, each time a new block appears on the blockchain. + +## Example Request + +Started from latest block: + +```json +{ + "subscription_id": "some-id", + "action": "subscribe", + "topic": "block_digests", + "arguments": { + "block_status": "sealed" + } +} +``` + +Started from block height `106192109`: + +```json +{ + "subscription_id": "some-id", + "action": "subscribe", + "topic": "block_digests", + "arguments": { + "block_status": "sealed", + "start_block_height": "106192109" + } +} +``` + +Started from block id `37193c008576c5f9e3fb9738d4cc53c9ca021ca593e437eb79107c13ec5a1758`: + +```json +{ + "subscription_id": "some-id", + "action": "subscribe", + "topic": "block_digests", + "arguments": { + "block_status": "sealed", + "start_block_id": "37193c008576c5f9e3fb9738d4cc53c9ca021ca593e437eb79107c13ec5a1758" + } +} +``` + +### Request Arguments + +| Name | Type | Required | Description | +| -------------------- | ------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------ | +| `block_status` | STRING | YES | The status of blocks to subscribe to. Supported values are: `sealed`, `finalized`. | +| `start_block_id` | STRING | NO | The ID of the block from which the subscription starts. If this argument is set, `start_block_height` MUST be empty. | | +| `start_block_height` | STRING | NO | The height of the block from which the subscription starts. If this argument is set, `start_block_id` MUST be empty. | + +If neither `start_block_id` nor `start_block_height` is set, the subscription will start from the latest block based on its status. + +## Example Response + +```json +{ + "subscription_id": "some-id", + "topic": "block_digests", + "payload": { + "block_id": "311ca4b8530fad041356ace3ba27cd6ca8bed53d166b4cefdde4c3ae414940d5", + "height": "106190012", + "timestamp": "2025-03-11T11:08:58.504803374Z" + } +} +``` + +=== networks/access-onchain-data/websockets-stream-api/supported-topics/account_statuses_topic.md === +--- +title: Account statuses +sidebar_label: Account statuses +sidebar_position: 6 +--- + +Provides accounts statuses updates. The response can be configured using additional arguments to filter and retrieve only filtered account statuses instead of all core account events. + +## Example Request + +Started from latest block for event types `flow.AccountKeyAdded` and `flow.AccountKeyRemoved`: + +```json +{ + "subscription_id": "some-id", + "action": "subscribe", + "topic": "account_statuses", + "arguments": { + "event_types": [ + "flow.AccountKeyAdded", + "flow.AccountKeyRemoved" + ] + } +} +``` + +Started from block height `106219488` for all accounts events with heartbeat interval equal 10 blocks: + +```json +{ + "subscription_id": "some-id", + "action": "subscribe", + "topic": "account_statuses", + "arguments": { + "start_block_height": "106219488", + "heartbeat_interval": "10" + } +} +``` + +Started from block id `f1ba2fb02daf02c7a213b6b0f75774aaf54180ae67fb62bdf22ae37295fe1120` for account addresses `0xe544175ee0461c4b` and `2d4c3caffbeab845` with heartbeat interval equal 5 blocks: + +```json +{ + "subscription_id": "some-id", + "action": "subscribe", + "topic": "account_statuses", + "arguments": { + "start_block_id": "f1ba2fb02daf02c7a213b6b0f75774aaf54180ae67fb62bdf22ae37295fe1120", + "heartbeat_interval": "5", + "account_addresses": [ + "0xe544175ee0461c4b", + "2d4c3caffbeab845" + ] + } +} +``` + +### Request Arguments + +| Name | Type | Required | Description | +| -------------------- | ------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------ | +| `start_block_id` | STRING | NO | The ID of the block from which the subscription starts. If this argument is set, it is **not** possible to set `start_block_height`. | | +| `start_block_height` | STRING | NO | The height of the block from which the subscription starts. If this argument is set, it is **not** possible to set `start_block_id` | +| `heartbeat_interval` | STRING | NO | Maximum number of blocks between messages after which a response with no events is returned. This helps the client track progress for sparse event filters. | +| `event_types` | LIST | NO | A comma-separated list of event types to include. See the list of possible event types value [below](#the-list-of-possible-core-event-types). | +| `account_addresses` | LIST | NO | A comma-separated list of addresses who's events should be included. The format could be `"0xe544175ee0461c4b"` or `"e544175ee0461c4b"`. | + +If neither `start_block_id` nor `start_block_height` is set, the subscription will start from the latest block based on its status. + +#### The list of possible core event types + +- `flow.AccountCreated` emitted when a new account gets created. +- `flow.AccountKeyAdded` emitted when a key gets added to an account. +- `flow.AccountKeyRemoved` emitted when a key gets removed from an account. +- `flow.AccountContractAdded` emitted when a contract gets deployed to an account. +- `flow.AccountContractUpdated` emitted when a contract gets updated on an account. +- `flow.AccountContractRemoved` emitted when a contract gets removed from an account. +- `flow.InboxValuePublished` emitted when a Capability is published from an account. +- `flow.InboxValueUnpublished` emitted when a Capability is unpublished from an account. +- `flow.InboxValueClaimed` emitted when a Capability is claimed by an account. + +## Example Response + +```json +{ + "subscription_id": "some-id", + "topic": "account_statuses", + "payload": { + "block_id": "ab20d1a3574177e69636eea73e7db4e74cffb2754cb14ca0bf18c2b96e8b68b9", + "height": "106219247", + "account_events": { + "0x37d2b958f6970c48": [ + { + "type": "flow.AccountKeyAdded", + "transaction_id": "19af79cf2fe081491f1e7b0bf490869c8baece742c6606b4a51383515131b5f0", + "transaction_index": "1", + "event_index": "14", + "payload": "2IGChNigg0BpUHVibGljS2V5goJpcHVibGljS2V52IvYiQyCcnNpZ25hdHVyZUFsZ29yaXRobdiIQQLYpINBAW1IYXNoQWxnb3JpdGhtgYJocmF3VmFsdWXYiQzYpINBAnJTaWduYXR1cmVBbGdvcml0aG2BgmhyYXdWYWx1ZdiJDNiig0EDdGZsb3cuQWNjb3VudEtleUFkZGVkhYJnYWRkcmVzc9iJA4JpcHVibGljS2V52IhAgmZ3ZWlnaHTYiReCbWhhc2hBbGdvcml0aG3YiEEBgmhrZXlJbmRleNiJBILYiEEDhUg30rlY9pcMSIKYQBjBGFoYKhg8GLoAGEIHGHAYYREYoBirGKsYiRhrGDAY3xiTGLkUGJYYdRixGOwYjxjNGCkAExhRGCoY/xgfEBh/GJ0YtxjBGH8YLxiqGD4JGKIY6xgmDhiUGDEYqRhvGCYY8hitGMEWGKwY6RiEGF4YQRhBGKGBAhsAAAAXSHboAIEBwkA=" + } + ] + }, + "message_index": 4 + } +} +``` + + +=== growth/index.md === +--- +sidebar_position: 1 +title: Growth +description: Get advice, support, and resources for each stage of development for your project. +--- + +At each stage of your project, you can get advice, support, and resources from the Flow ecosystem. Here's a breakdown of _what you are doing_ and _what support we offer_ at each stage: + +## Product Idea + +You've got an **idea** for an app, game, or project that you want to build on Flow. + +### What you are doing + +* Developing the idea in a written format, such as a pitch deck, whitepaper, design doc, or business plan +* Writing software +* Joining a hackathon or buildathon + +### What support we offer + +* Technical support +* Product support +* Marketing support for your launch +* DevRel + +## MVP/Demo/Hackathon Project Complete + +You've got something that works in a place others can use it and experience key features of your product. + +### What you are doing + +* Writing software +* Integrating with service providers +* Getting user feedback and improving your product + +### What support we offer + +* Direct contact with Flow Foundation through a DevRel Lead. +* Feedback and Guidence from the Flow Foundation team + +## Live product on mainnet + +Real people are using your app regularly and doing the types of things that you are or will eventually generate revenue from (even if it's still a small number of users). + +### What you are doing + +* Acquiring users +* Tracking metrics +* Improving your product +* Raising funds +* Micro grants + +### What support we offer + +* BizDev Support (intros, etc) +* Dedicated slack or tg channel +* DevRel + +## Product market fit + +You've got an app and are meeting the needs of regular customers. Core features are implemented, edge cases are handled, and most of your asterisks are resolved. + +### What you are doing + +* Acquiring users +* Tracking metrics +* Improving your product + +### What support we offer + +* Fundraising support (intros to investor network) +* Grants tied to bigger ecosystem milestones +* DevRel + + +=== evm/using.mdx === +--- +title: Using Flow EVM +sidebar_label: Using Flow EVM +sidebar_position: 4 +--- + +import BrowserOnly from '@docusaurus/BrowserOnly'; +import { AddNetworkButton } from '@site/src/components/addNetworkButton'; + +# Using Flow + +## EVM Wallets + +Applications deployed to Flow EVM will work with popular EVM-compatible wallets such as [MetaMask](https://chromewebstore.google.com/detail/metamask/nkbihfbeogaeaoehlefnkodbefgpgknn), all you need to do is add the correct [RPC endpoint](./networks) as a custom network. + +### [MetaMask](https://metamask.io) + + + {() => { + // ******* If Chain Id changes, update the Chain ID in the AddNetworkButton component ******* + return ; + }} + +Manual method: Add Flow EVM as a custom network to MetaMask: + +1. Open the MetaMask browser extension +2. Open the network selection dropdown menu by clicking the dropdown button at the top of the extension +3. Click the **`Add network`** button +4. Click **`Add a network manually`** +5. In the **`Add a network manually`** dialog that appears, enter the following information: + +| Name | Value | +| --------------- | ------------------------------------ | +| Network Name | Flow EVM | +| Description | The public RPC url for Flow Mainnet | +| RPC Endpoint | https://mainnet.evm.nodes.onflow.org | +| Chain ID | 747 | +| Currency Symbol | FLOW | +| Block Explorer | https://evm.flowscan.io/ | + +6. Tap the Save button to save Flow EVM as a network. + +You should now be able to connect to the Flow EVM by selecting it from the network selection dropdown menu. + +To additionally add the Flow EVM Testnet to MetaMask, follow the same steps as above, but use the following information: + +| Name | Value | +| --------------- | ------------------------------------ | +| Network Name | Flow EVM Testnet | +| Description | The public RPC url for Flow Testnet | +| RPC Endpoint | https://testnet.evm.nodes.onflow.org | +| Chain ID | 545 | +| Currency Symbol | FLOW | +| Block Explorer | https://evm-testnet.flowscan.io | + +Use the [Flow Testnet Faucet](https://faucet.flow.com/fund-account) to fund your account for testing. + +## Flow Native Wallets + +### [Flow Wallet](https://wallet.flow.com) + +Flow Wallet is available on [Android](https://play.google.com/store/apps/details?id=com.flowfoundation.wallet) and [iOS](https://apps.apple.com/ca/app/flow-wallet-nfts-and-crypto/id6478996750), with desktop support using the Flow Wallet [Chrome extension](https://chromewebstore.google.com/detail/flow-reference-wallet/hpclkefagolihohboafpheddmmgdffjm). In addition to being able to transact in both EVM and Cadence environments, Flow Wallet will also allow you to view and move assets between EVM and Cadence, making it possible to manage all your assets in one place. + +To use the Flow Wallet Chrome extension: + +1. Open the Flow Wallet browser extension and create your account. +2. Connect to an app using Flow Wallet. + +## EVM Specification + +- Flow EVM is a virtual EVM-based blockchain using the latest EVM byte-code interpreter `Geth v1.13` +- Utilizes `FLOW` token for transactions, with balances denominated in `Atto-FLOW` (1 `FLOW` = 10^18 `Atto-FLOW`) +- The [EVM Gateway](https://github.com/onflow/flow-evm-gateway) exposes the standard EVM API (Ethereum JSON-RPC) +- Read more about the implementation in [FLIP 223: EVM integration interface](https://github.com/onflow/flips/blob/main/protocol/20231116-evm-support.md) + +## JSON-RPC Methods + +
    + +| Method | Status | Notes | +| ----------------------------------------- | ------ | ----------- | +| [web3_clientVersion] | ✅ | +| [web3_sha3] | ✅ | +| [net_listening] | ✅ | +| [net_peerCount] | ✅ | +| [net_version] | ✅ | +| [eth_accounts] | 🚧 | Unsupported | +| [eth_blockNumber] | ✅ | +| [eth_call] | ✅ | +| [eth_chainId] | ✅ | +| [eth_coinbase] | ✅ | +| [eth_estimateGas] | ✅ | +| [eth_gasPrice] | ✅ | +| [eth_getBalance] | ✅ | +| [eth_getBlockByHash] | ✅ | +| [eth_getBlockByNumber] | ✅ | +| [eth_getBlockTransactionCountByHash] | ✅ | +| [eth_getBlockTransactionCountByNumber] | ✅ | +| [eth_getBlockReceipts] | ✅ | +| [eth_getCode] | ✅ | +| [eth_getFilterChanges] | ✅ | +| [eth_getFilterLogs] | ✅ | +| [eth_getLogs] | ✅ | +| [eth_getProof] | 🚧 | Unsupported | +| [eth_getStorageAt] | ✅ | +| [eth_getTransactionByBlockHashAndIndex] | ✅ | +| [eth_getTransactionByBlockNumberAndIndex] | ✅ | +| [eth_getTransactionByHash] | ✅ | +| [eth_getTransactionCount] | ✅ | +| [eth_getTransactionReceipt] | ✅ | +| [eth_getUncleByBlockHashAndIndex] | ✅ | +| [eth_getUncleByBlockNumberAndIndex] | ✅ | +| [eth_getUncleCountByBlockHash] | ✅ | +| [eth_getUncleCountByBlockNumber] | ✅ | | +| [eth_newBlockFilter] | ✅ | +| [eth_newFilter] | ✅ | +| [eth_newPendingTransactionFilter] | ✅ | +| [eth_sendRawTransaction] | ✅ | +| [eth_sendTransaction] | 🚧 | Unsupported | +| [eth_sign] | 🚧 | Unsupported | +| [eth_signTransaction] | 🚧 | Unsupported | +| [eth_syncing] | ✅ | +| [eth_uninstallFilter] | ✅ | +| [eth_maxPriorityFeePerGas] | ✅ | +| [eth_feeHistory] | ✅ | +| [debug_traceTransaction] | ✅ | +| [debug_traceBlockByNumber] | ✅ | +| [debug_traceBlockByHash] | ✅ | +| [debug_traceCall] | ✅ | + +**Legend**: ❌ = not supported. 🚧 = work in progress. ✅ = supported. + +Read more about the [EVM Gateway](https://github.com/onflow/flow-evm-gateway) on Flow and how it implements the Ethereum JSON-RPC API. + +[web3_clientVersion]: https://ethereum.org/en/developers/docs/apis/json-rpc/#web3_clientversion +[web3_sha3]: https://ethereum.org/en/developers/docs/apis/json-rpc/#web3_sha3 +[net_listening]: https://ethereum.org/en/developers/docs/apis/json-rpc/#net_listening +[net_peerCount]: https://ethereum.org/en/developers/docs/apis/json-rpc/#net_peercount +[net_version]: https://ethereum.org/en/developers/docs/apis/json-rpc/#net_version +[eth_accounts]: https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_accounts +[eth_blockNumber]: https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_blocknumber +[eth_call]: https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_call +[eth_chainId]: https://eips.ethereum.org/EIPS/eip-695 +[eth_coinbase]: https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_coinbase +[eth_compileLLL]: https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_compilelll +[eth_compileSerpent]: https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_compileserpent +[eth_compileSolidity]: https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_compile_solidity +[eth_estimateGas]: https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_estimategas +[eth_gasPrice]: https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_gasprice +[eth_getBalance]: https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getbalance +[eth_getBlockByHash]: https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getblockbyhash +[eth_getBlockByNumber]: https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getblockbynumber +[eth_getBlockTransactionCountByHash]: https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getblocktransactioncountbyhash +[eth_getBlockTransactionCountByNumber]: https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getblocktransactioncountbynumber +[eth_getCode]: https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getcode +[eth_getCompilers]: https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getcompilers +[eth_getFilterChanges]: https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getfilterchanges +[eth_getFilterLogs]: https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getfilterlogs +[eth_getLogs]: https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getlogs +[eth_getProof]: https://eips.ethereum.org/EIPS/eip-1186 +[eth_getStorageAt]: https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getstorageat +[eth_getTransactionByBlockHashAndIndex]: https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_gettransactionbyblockhashandindex +[eth_getTransactionByBlockNumberAndIndex]: https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_gettransactionbyblocknumberandindex +[eth_getTransactionByHash]: https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_gettransactionbyhash +[eth_getTransactionCount]: https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_gettransactioncount +[eth_getTransactionReceipt]: https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_gettransactionreceipt +[eth_getUncleByBlockHashAndIndex]: https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getunclebyblockhashandindex +[eth_getUncleByBlockNumberAndIndex]: https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getunclebyblocknumberandindex +[eth_getUncleCountByBlockHash]: https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getunclecountbyblockhash +[eth_getUncleCountByBlockNumber]: https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getunclecountbyblocknumber +[eth_getWork]: https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getwork +[eth_hashrate]: https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_hashrate +[eth_mining]: https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_mining +[eth_newBlockFilter]: https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_newblockfilter +[eth_newFilter]: https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_newfilter +[eth_newPendingTransactionFilter]: https://openethereum.github.io/JSONRPC-eth-module.html#eth_newpendingtransactionfilter +[eth_pendingTransactions]: https://github.com/ethereum/wiki/issues/685 +[eth_protocolVersion]: https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_protocolversion +[eth_sendRawTransaction]: https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_sendrawtransaction +[eth_sendTransaction]: https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_sendtransaction +[eth_sign]: https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_sign +[eth_signTransaction]: https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_signtransaction +[eth_signTypedData]: https://eips.ethereum.org/EIPS/eip-712 +[eth_submitHashrate]: https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_submithashrate +[eth_submitWork]: https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_submitwork +[eth_syncing]: https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_syncing +[eth_uninstallFilter]: https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_uninstallfilter +[db_getHex]: https://ethereum.org/en/developers/docs/apis/json-rpc/#db_gethex +[db_getString]: https://ethereum.org/en/developers/docs/apis/json-rpc/#db_getstring +[db_putHex]: https://ethereum.org/en/developers/docs/apis/json-rpc/#db_puthex +[db_putString]: https://ethereum.org/en/developers/docs/apis/json-rpc/#db_putstring +[shh_addToGroup]: https://ethereum.org/en/developers/docs/apis/json-rpc/#shh_addtogroup +[shh_getFilterChanges]: https://ethereum.org/en/developers/docs/apis/json-rpc/#shh_getfilterchanges +[shh_getMessages]: https://ethereum.org/en/developers/docs/apis/json-rpc/#shh_getmessages +[shh_hasIdentity]: https://ethereum.org/en/developers/docs/apis/json-rpc/#shh_hasidentity +[shh_newFilter]: https://ethereum.org/en/developers/docs/apis/json-rpc/#shh_newfilter +[shh_newGroup]: https://ethereum.org/en/developers/docs/apis/json-rpc/#shh_newgroup +[shh_newIdentity]: https://ethereum.org/en/developers/docs/apis/json-rpc/#shh_newidentity +[shh_post]: https://ethereum.org/en/developers/docs/apis/json-rpc/#shh_post +[shh_uninstallFilter]: https://ethereum.org/en/developers/docs/apis/json-rpc/#shh_uninstallfilter +[shh_version]: https://ethereum.org/en/developers/docs/apis/json-rpc/#shh_post +[txpool_content]: https://geth.ethereum.org/docs/rpc/ns-txpool#txpool_content +[txpool_inspect]: https://geth.ethereum.org/docs/rpc/ns-txpool#txpool_inspect +[txpool_status]: https://geth.ethereum.org/docs/rpc/ns-txpool#txpool_status +[parity_pendingTransactions]: https://openethereum.github.io/JSONRPC-parity-module#parity_pendingtransactions +[EIP-1186]: https://eips.ethereum.org/EIPS/eip-1186 + + +=== evm/quickstart.md === +--- +title: EVM Quickstart +description: Deploy your first contract on Flow testnet and connect it to a rainbowkit/wagmi/viem app +sidebar_position: 5 +keywords: + - Flow EVM + - EVM quickstart + - Hardhat + - Flowscan + - Flow Wallet + - smart contracts + - contract deployment + - Flow Faucet + - OpenZeppelin + - ERC-20 +--- + +# EVM Quickstart + +Flow EVM is an EVM-equivalent blockchain that combines the advantages of Flow, including security, low-cost gas, and native VRF with compatibility with exiting blockchain applications tools, and contracts. If it works on another EVM-equivalent blockchain, it should work on Flow EVM! + +This guide is a self-contained quickstart that will walk you through deploying a contract on Flow EVM testnet with [Hardhat] and testing it with [testnet Flowscan]. + +If you prefer, check out our tutorials for [Remix] and [Foundry] for information on how to deploy a contract with those platforms. + +## Objectives + +After completing this guide, you'll be able to: + +- Fund a wallet with testnet tokens from the [Flow Faucet] +- Deploy a contract on Flow EVM Testnet +- Interact with a contract using [Flowscan] +- Utilize automatically sponsored gas with the [Flow Wallet] on testnet **and mainnet** + +## Prerequisites + +### Traditional Cryptocurrency Wallet + +EVM [Accounts] created by the Flow wallet have unique properties that allow for powerful features, but they do **not** have recovery phrases or private keys that can be exported in a way that's compatible with [Hardhat]. As a result, you'll need to use a traditional EOA and [MetaMask], or the wallet of your choice, to deploy your contracts. + +## Deploy Your Contract + +For this exercise, we'll use a [Button Clicker Contract] that's relatively simple, but includes several [OpenZeppelin] contracts. This way, we can walk through the process to configure your project to use these common imports. + +:::info + +If you **really** want to speedrun this tutorial, fork the [Button Clicker Contract] repo, run `npm install`, add a `.env` with your deploy wallet key as `DEPLOY_WALLET_1`, and deploy with `npx hardhat ignition deploy ./ignition/modules/ClickToken.ts --network flowTestnet`. + +Then skip to the frontend section. + +::: + +### Hardhat Setup + +Open a terminal window and navigate either to the folder where you wish to create your project folder, or an empty project folder. Run: + +```bash +npx hardhat init +``` + +![Hardhat Init](hardhat-init.png) + +Select `Create a TypeScript project (with Viem)` + +Enter `.` if you ran the command from an empty folder, or enter a path. + +Choose the defaults for the remaining options, then open the project in your editor. + +### Environment Setup + +Add a `.env` and in it, add an environment variable called `DEPLOY_WALLET_1` with your deployment wallet's [private key]. + +```text +DEPLOY_WALLET_1= +``` + +:::danger + +The [private key] functions the same as the recovery phrase for a wallet. Anyone with the key can drain the wallet at any time! Use separate wallets for development and never commit a key to a repo. + +::: + +### Hardhat Config + +We'll be using [OpenZeppelin Contracts], so install them, then open the project in your editor: + +```bash +npm install --save-dev @openzeppelin/hardhat-upgrades +npm install --save-dev @nomicfoundation/hardhat-ethers ethers # peer dependencies +``` + +Then install the contracts themselves: + +```bash +npm install --save-dev @openzeppelin/contracts +``` + +You'll also need `dotenv` to better protect your wallet key, so go ahead and add that too: + +```bash +npm install dotenv +``` + +Open `hardhat.config`. Below the imports, add the `require` statements for the contracts and `dotenv`: + +```tsx +require('@openzeppelin/hardhat-upgrades'); +require('dotenv').config(); +``` + +The default config is pretty bare. We'll need to add quite a few items. We'll do these one at a time, then provide a complete copy at the end. + +First, add a `networks` property containing the network information for Flow Testnet and Mainnet: + +```tsx +networks: { + flow: { + url: 'https://mainnet.evm.nodes.onflow.org', + accounts: [process.env.DEPLOY_WALLET_1 as string], + }, + flowTestnet: { + url: 'https://testnet.evm.nodes.onflow.org', + accounts: [process.env.DEPLOY_WALLET_1 as string], + }, +}, +``` + +Then, add an entry for `etherscan`: + +```tsx +etherscan: { +} +``` + +In it, add a property for `apiKey` and add keys for Flow Mainnet and Testnet. Note that the Etherscan API requires this to be here, but at the time of writing, API keys aren't actually needed. Any text can be used: + +```tsx +apiKey: { + // Is not required by blockscout. Can be any non-empty string + 'flow': "abc", + 'flowTestnet': "abc" +}, +``` + +Next, add `customChains` and the network information for Flow: + +```tsx +customChains: [ + { + network: 'flow', + chainId: 747, + urls: { + apiURL: 'https://evm.flowscan.io/api', + browserURL: 'https://evm.flowscan.io/', + }, + }, + { + network: 'flowTestnet', + chainId: 545, + urls: { + apiURL: 'https://evm-testnet.flowscan.io/api', + browserURL: 'https://evm-testnet.flowscan.io/', + }, + }, +]; +``` + +You should end up with: + +```tsx +import type { HardhatUserConfig } from 'hardhat/config'; +import '@nomicfoundation/hardhat-toolbox-viem'; + +require('@openzeppelin/hardhat-upgrades'); +require('dotenv').config(); + +const config: HardhatUserConfig = { + solidity: '0.8.28', + networks: { + flow: { + url: 'https://mainnet.evm.nodes.onflow.org', + accounts: [process.env.DEPLOY_WALLET_1 as string], + }, + flowTestnet: { + url: 'https://testnet.evm.nodes.onflow.org', + accounts: [process.env.DEPLOY_WALLET_1 as string], + }, + }, + etherscan: { + apiKey: { + // Is not required by blockscout. Can be any non-empty string + flow: 'abc', + flowTestnet: 'abc', + }, + customChains: [ + { + network: 'flow', + chainId: 747, + urls: { + apiURL: 'https://evm.flowscan.io/api', + browserURL: 'https://evm.flowscan.io/', + }, + }, + { + network: 'flowTestnet', + chainId: 545, + urls: { + apiURL: 'https://evm-testnet.flowscan.io/api', + browserURL: 'https://evm-testnet.flowscan.io/', + }, + }, + ], + }, +}; + +export default config; +``` + +### Contract Setup + +Delete `Lock.sol` and add `ClickToken.sol`. In it add, the [Button Clicker Contract]. + +:::warning + +Hardhat only installs the most current version of Solidity. `^0.8.27` means that this contract requires 0.8.27 or **higher**. You generally **don't** want to include the `^` in your contracts unless you have a specific reason for doing so. + +::: + +We won't go into the details of the contract for this tutorial. It's a relatively simple [ERC-20] implementation that mints one token any time the `mintTo` function is called. Perfect for a Button Clicker game! + +### Deployment Setup + +Delete `Lock.ts` from the `ignition/modules` folder, and add `ClickToken.ts`. In it, add: + +```tsx +// This setup uses Hardhat Ignition to manage smart contract deployments. +// Learn more about it at https://hardhat.org/ignition + +import { buildModule } from '@nomicfoundation/hardhat-ignition/modules'; + +const ClickerModule = buildModule('ClickTokenModule', (m) => { + const clickToken = m.contract('ClickToken'); + + return { clickToken }; +}); + +export default ClickerModule; +``` + +### Obtain Testnet Funds + +Visit the [Flow Faucet] and follow the instructions to add testnet funds. Compared to other networks, the [Flow Faucet] grants a vast amount of tokens - enough gas for millions of transactions. + +### Deploy the Contract + +Deploy the contract with: + +```bash +npx hardhat ignition deploy ./ignition/modules/ClickToken.ts --network flowTestnet +``` + +You should see something similar to: + +```bash +✔ Confirm deploy to network flowTestnet (545)? … yes +Hardhat Ignition 🚀 + +Deploying [ ClickTokenModule ] + +Batch #1 + Executed ClickTokenModule#ClickToken + +[ ClickTokenModule ] successfully deployed 🚀 + +Deployed Addresses + +ClickTokenModule#ClickToken - 0x5Ff8221DfDD1F82fd538391D231502B4b927fbD7 +``` + +### Verify the Contract + +Next, verify the contract with: + +```bash +hardhat ignition verify chain-545 --include-unrelated-contracts +``` + +You'll see something similar to: + +```bash +briandoyle@Mac button-clicker-contract % npx hardhat ignition verify chain-545 --include-unrelated-contracts +Verifying contract "contracts/ClickToken.sol:ClickToken" for network flowTestnet... +Successfully verified contract "contracts/ClickToken.sol:ClickToken" for network flowTestnet: + - https://evm-testnet.flowscan.io//address/0x64366c923d5046F8417Dcd8a0Cb4a789F8722387#code +``` + +## Testing the Contract + +Click the link to open the contract in [testnet Flowscan]. Click the `Connect` button and connect your wallet, then navigate to the `Contract` tab and `Read/Write contract`. + +![read write contract](read-write.png) + +Find the `mintTo` function and expand the UI to mint yourself a few tokens. You can click the `self` button to automatically add your address without needing to copy/paste. + +Once you've "earned" a few tokens, use `balanceOf` to see how many tokens you have. You can also use `getAllScores` to get a list of everyone with the tokens, and how many they have. + +### Testing with Free Gas + +If you don't have it yet, set up the [Flow Wallet], connect, and try minting some more tokens. You'll see that the wallet automatically sponsors your gas: + +![flow-wallet](sponsored-gas.png) + +Even better, the [Flow Wallet] is currently **sponsoring transactions on mainnet** too! + +## Conclusion + +In this tutorial, you learned how to: + +- Fund a wallet with testnet tokens from the [Flow Faucet] +- Deploy a contract on Flow EVM Testnet using Hardhat +- Interact with a contract using [Flowscan] +- Utilize automatically sponsored gas with the [Flow Wallet] on testnet and mainnet + +You've now mastered the basics of deploying and interacting with EVM contracts on Flow. But this is just the beginning! Flow EVM's true power lies in its ability to combine the best of both worlds: EVM compatibility with Flow's native features. + +In our [Cross-VM Apps] tutorial series, you'll learn how to supercharge your EVM applications by integrating them with Flow Cadence. You'll discover how to: + +- Build hybrid applications that seamlessly connect to both Flow EVM and Flow Cadence +- Use Cadence's powerful features to enhance your EVM contracts +- Enable multi-call contract writes with a single signature +- Take advantage of Flow's native features like VRF and sponsored transactions + +Ready to unlock the full potential of Flow EVM? Start with our [Batched Transactions] tutorial to learn how to build your first cross-VM application. + +[Cadence]: https://cadence-lang.org/docs +[Next.js]: https://nextjs.org/docs/app/getting-started/installation +[wagmi]: https://wagmi.sh/ +[viem]: https://viem.sh/ +[rainbowkit]: https://www.rainbowkit.com/ +[Hardhat]: https://hardhat.org/ +[Remix]: ./guides/remix.md +[Foundry]: ./guides/foundry.md +[Flow Faucet]: https://faucet.flow.com/fund-account +[Flowscan]: https://evm-testnet.flowscan.io/ +[Flow Wallet]: https://wallet.flow.com/ +[Button Clicker Contract]: https://github.com/briandoyle81/button-clicker-contract/blob/main/contracts/ClickToken.sol +[OpenZeppelin]: https://www.openzeppelin.com/ +[Ignition]: https://hardhat.org/ignition/docs/getting-started#overview +[Accounts]: ../evm/accounts.md +[MetaMask]: https://metamask.io +[private key]: https://support.metamask.io/configure/accounts/how-to-export-an-accounts-private-key/ +[ERC-20]: https://ethereum.org/en/developers/docs/standards/tokens/erc-20/ +[testnet Flowscan]: https://evm-testnet.flowscan.io/ +[Cross-VM Apps]: ../tutorials/cross-vm-apps/introduction.md +[Batched Transactions]: ../tutorials/cross-vm-apps/introduction.md +[OpenZeppelin Contracts]: https://www.openzeppelin.com/contracts + + +=== evm/networks.md === +--- +title: Network Information +sidebar_label: Network Information +sidebar_position: 5 +--- + +# Network Information + +Flow EVM has the following public RPC nodes available: + +# Mainnet + +| Name | Value | +| --------------- | ------------------------------------ | +| Network Name | Flow EVM | +| Description | The public RPC URL for Flow Mainnet | +| RPC Endpoint | https://mainnet.evm.nodes.onflow.org | +| Chain ID | 747 | +| Currency Symbol | FLOW | +| Block Explorer | https://evm.flowscan.io | + +# Testnet + +| Name | Value | +| --------------- | ------------------------------------ | +| Network Name | Flow EVM Testnet | +| Description | The public RPC URL for Flow Testnet | +| RPC Endpoint | https://testnet.evm.nodes.onflow.org | +| Chain ID | 545 | +| Currency Symbol | FLOW | +| Block Explorer | https://evm-testnet.flowscan.io | + + +=== evm/how-it-works.md === +--- +title: How Flow EVM Works +sidebar_label: How it Works +sidebar_position: 3 +--- + +# How Flow EVM Works + +## Introduction + +The Flow network uses [Cadence](https://cadence-lang.org/) as its main execution environment. Cadence offers a safe, efficient, and developer-friendly experience for building smart contracts and decentralized applications. Cadence can be used to extend EVM apps built in solidity by unlocking gasless experiences, new business models and fine-tuned access control. With Flow offering full EVM support, existing applications and tools already deployed in the EVM ecosystem can simply onboard to the network with [no code changes](https://developers.flow.com/evm/about). + +Flow EVM is designed with these major goals in mind: + +- Supporting EVM equivalency: Ensure that any tools and applications deployed to or run on Ethereum can also be deployed and run on Flow. +- Minimizing breaking changes to the Cadence ecosystem, software and tools +- Maximum composability across environments: Allowing atomic and smooth interaction between EVM and Cadence environments. + +### EVM - A Smart Contract In Cadence + +To satisfy the design goals and thanks to the extensibility properties of the Cadence runtime, Flow EVM is designed as a higher-level environment incorporated as a smart contract deployed to Cadence. This smart contract is not owned by anyone and has its own storage space, allows Cadence to query, and is updated through EVM transactions. EVM transactions can be wrapped inside Cadence transactions and passed to the EVM contract for execution. The artifacts of EVM transaction execution (e.g. receipts and logs) are emitted as special Cadence events (TransactionExecuted, BlockExecuted) and available to the upstream process (Flow transaction) to enable atomic operations. + +The EVM environment has its own concept of blocks, and every Flow block includes at most one EVM Block. The EVM block is formed at the end of Flow Block execution and includes all the transaction executed during the EVM block execution. Note that since EVM blocks are formed on-chain and Flow provides fast finality, as long as the user of these events waits for Flow block finality, it doesn’t have to worry about EVM block forks, uncle chains, and other consensus-related challenges. + +### No Shared Memory Design + +The interaction between two environments is through atomic calls and none of the environments has access to the raw memory of the other. This maintains the security properties of each environment. Cadence can submit transactions to the EVM environment and EVM transactions can make calls to a special precompiled contract called Cadence Arch. You can read more about this in the Precompiled section. + +### No New Native Token + +Flow EVM uses the same native token as Cadence (FLOW token). No new token is minted at the genesis block of EVM and all the tokens have to be bridged over from the Cadence side into the EVM side. To facilitate this a native bridge is provided by the EVM contract. + +### EVM Equivalency + +Under the hood, Flow EVM uses [the standard EVM implementation](https://github.com/ethereum/go-ethereum) and regularly applies updates through Flow’s height-coordinated updates (e.g. Execution layer changes planned for the Ethereum Prague update). This means anything that can run on Ethereum after the Cancun upgrade can run on Flow EVM. This means many useful EIPs such as [EIP-1014](https://eips.ethereum.org/EIPS/eip-1014), [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559), [EIP-4844](https://eips.ethereum.org/EIPS/eip-4844), [EIP-5656](https://eips.ethereum.org/EIPS/eip-5656), [EIP-6780](https://eips.ethereum.org/EIPS/eip-6780), … are supported automatically. + +Yet a small set of differences between Flow EVM and Ethereum might be seen (mostly of the nature of extension) for two reasons: + +- A set of extensions has been added to ensure seamless and easy interaction between the two environments. +- Flow EVM is secured by the Flow network and benefits from its robust network properties, such as fast block production and finalization, making issues like handling uncle chains irrelevant. + +## Gateways + +As mentioned, Flow EVM runs on top of the Flow network and its consensus model. Flow EVM does not leverage `geth` or introduce new node types to the existing architecture. Operators wishing to participate in securing the network stake tokens and run one of the Flow node types. + +To support `web3.js` clients, the [EVM Gateway](https://github.com/onflow/flow-evm-gateway) honors the Ethereum [JSON-RPC specification](https://ethereum.org/en/developers/docs/apis/json-rpc/). The gateway integrates with Flow access nodes and can be run by anyone (unstaked). It serves two purposes: + +### Gateway As A Light Client + +The gateway follows Flow's block production, collecting, verifying and indexing EVM-related events. The gateway provides the necessary endpoints and services all JSON-RPC requests for third-party dapps interacting with Flow EVM. EVM events include all information needed to reconstruct the EVM state since the genesis block (replayability). By re-executing transactions, the gateway can collect traces and maintain a local and archival copy of the EVM state over time. + +### Gateway As a Sequencer + +As mentioned, Flow EVM can be seen as a higher-level environment built on top of Cadence. Thus, all EVM transactions are ultimately handled using a Flow transaction (a wrapped call to the EVM). The gateway accepts EVM transactions, runs an internal mempool of transactions, wraps batches of EVM transactions in Flow transactions, and submits them. + +Note that the safety of transaction execution is not dependent on the gateway; they only relay the transaction. The safety measures of the EVM environment (e.g., Nonce, etc.) ensure that each transaction is executed at most once. Since gateways are submitting Flow transactions, they have to pay the related transaction fees. Part of these fees is associated with the computation fees of the EVM transaction. + +To facilitate the repayment of fees, the `evm.run` function accepts a `coinbase` address, which collects gas fees from the transaction, and pays it to the address provided by the gateway node. Essentially, the transaction wrapper behaves similarly to a miner, receives the gas usage fees on an EVM address, and pays for the transaction fees. The gas price per unit of gas creates a marketplace for these 3rd parties to compete over transactions. + +**Censorship Resistance and MEV Protection** + +Since Flow EVM runs on the Flow network, it benefits from Flow’s protections against censorship and MEV attacks. The Flow network natively provides censorship & MEV resistance which is achieved by designating specific validators for building transaction bundles that are separated from the validators proposing blocks (proposer-builder separation). More details about this are available in Flow’s protocol [white papers](https://flow.com/technical-paper). +For extra protection on the EVM side, the gateway software is designed to be fully configurable and as lightweight as possible. This enables anyone with an account on Flow (e.g., any application) to run their own instances. + +**Fee Market Change (EIP-1559)** + +[EIP-1559](https://eips.ethereum.org/EIPS/eip-1559) is supported by the Flow EVM and Gateway nodes can decide on the inclusion of the transactions based on the tips or gas fees. The parameters for the EIP 1559 are adjustable by the Flow network. Currently, the base fee is set to zero, as EVM transactions are wrapped by the Flow transactions. + +## Block hash calculation difference + +Developers using the GoLang Ethereum client to integrate with Flow will find that the block hash calculated by the Flow EVM RPC endpoints `eth_getBlockByNumber` and `eth_getBlockByHash` differ from the hash calculated locally by `go-ethereum`. This is due to underlying +differences in the `Block` implementation to support EVM on Flow. For more information see https://github.com/onflow/flow-evm-gateway/issues/719. + +## Opcodes + +Flow EVM supports opcodes listed [here](https://www.evm.codes/?fork=cancun), except for the following changes. + +- **COINBASE** (`block.coinbase`) + Similar to Ethereum it returns the address of block’s beneficiary address. In the case of Flow EVM, it returns the address of the current sequencer's fee wallet (see Gateway section for more details). + +- **PREVRANDAO** (`block.prevrandao`) + On Ethereum, this value provides access to beacon chain randomness (see [EIP-4399](https://eips.ethereum.org/EIPS/eip-4399)), Since Flow uses a different approach in consensus and verifiable randomness generation, this value is filled with a random number provided by the Flow protocol. While Flow EVM provides such opcode, it is recommended not to rely on this value for security-sensitive applications, as it is the case on Ethereum. In order to benefit from the full power of secure randomness on Flow, it's recommended to use the [Cadence Arch precompiles](https://github.com/onflow/docs/blob/main/docs/evm/how-it-works.md#precompiled-contracts). + +## Precompiled Contracts + +Besides all the precompiled contracts supported by Ethereum (see here for [the list](https://www.evm.codes/precompiled?fork=cancun)), Flow EVM has augmented this with a unique precompiled contract, the Cadence Arch, that provides access to the Cadence world. + +Cadence Arch is a multi-function smart contract (deployed at `0x0000000000000000000000010000000000000001`) that allows any smart contract on Flow EVM a limited set of interactions with the Cadence environment. + +Functions currently available on the Cadence Arch smart contract are: + +- `FlowBlockHeight() uint64` (signature: `0x53e87d66`) returns the current Flow block height, this could be used instead of Flow EVM block heights to trigger scheduled actions given it's more predictable when a block might be formed. +- `VerifyCOAOwnershipProof(bytes32 _hash, bytes memory _signature)(bool success)` returns true if the proof is valid. An ownership proof verifies that a Flow wallet controls a COA account (see the next section for more details on COA). +- `revertibleRandom() uint64` returns a safe pseudo-random value that is produced by the Flow VRF (using Flow internal randomness beacon). The function invokes Cadence's `revertibleRandom` described [here](https://developers.flow.com/build/advanced-concepts/randomness). Although the random value is safe, a transaction may revert its results in the case of an unfavourable outcome. The function should only be used by trusted calls where there is no issue with reverting the results. `getRandomSource` must be used instead with untrusted calls. +- `getRandomSource(uint64) bytes32` should be used when implementing a [commit-reveal](https://developers.flow.com/build/advanced-concepts/randomness#commit-reveal-scheme) scheme. It returns a secure random source from the Cadence randomness history contract. Learn more about the secure usage of randomness on Flow [here](https://developers.flow.com/build/advanced-concepts/randomness). + +Here is a sample demonstrating how to call the Cadence Arch. + +```solidity + address constant public cadenceArch = 0x0000000000000000000000010000000000000001; + + function flowBlockHeight() public view returns (uint64){ + (bool ok, bytes memory data) = cadenceArch.staticcall(abi.encodeWithSignature("flowBlockHeight()")); + require(ok, "failed to fetch the flow block height through cadence arch"); + uint64 output = abi.decode(data, (uint64)); + return output; + } +``` + +## Special Addresses + +### Native Token Bridge + +Both Cadence and Flow EVM use the same token (FLOW) to run their operations. No new token is minted on the EVM side. Moving FLOW tokens easily across two environments has been supported natively by the EVM smart contract. Because the EVM have limited visibility into Cadence and to make tracking funds easier, every time Flow tokens are withdrawn from the Cadence side and deposited into an EVM address, the balance would be added to a special address `0x0000000000000000000000010000000000000000` (native token bridge) and then transferred to the destination EVM address. The bridge address always maintains a balance of zero. Clearly, this EOA address is a network address and is not controlled by public key. + +### Cadence-Owned Accounts (COAs) + +COA is a natively supported EVM smart contract wallet type that allows a Cadence resource to own and control an EVM address. This native wallet provides the primitives needed to bridge or control assets across Flow EVM and Cadence. From the EVM perspective, COAs are smart contract wallets that accept native token transfers and support several ERCs including [ERC-165](https://eips.ethereum.org/EIPS/eip-165), [ERC-721](https://eips.ethereum.org/EIPS/eip-721), [ERC-777](https://eips.ethereum.org/EIPS/eip-777), [ERC-1155](https://eips.ethereum.org/EIPS/eip-1155), [ERC-1271](https://eips.ethereum.org/EIPS/eip-1271). + +These smart contract wallets are only deployable through the Cadence environment and their address starts with the prefix `0x000000000000000000000002`. The address `0x0000000000000000000000020000000000000000` is reserved for COA factory, an address that deploys contracts for COA accounts. + +A COA is not controlled by a key. Instead, every COA account has a unique resource accessible on the Cadence side, and anyone who owns that resource submits transactions on behalf of this address. These direct transactions have COA’s EVM address as the `tx.origin` and a new EVM transaction type (`TxType = 0xff`) is used to differentiate these transactions from other types of EVM transactions (e.g, DynamicFeeTxType (`0x02`). Currently, to make integration and tracking of these transactions byte EVM ecosystem tools, these types of transactions are encoded as legacy EVM transactions (hash computation is based on legacy tx rlp encoding). +Controlling through a resource makes a COA a powerful smart contract wallet. It makes the transfer of ownership of the EVM address super easy without the need to transfer all the assets that an EVM address owns. It also allows a Cadence smart contract to take ownership of an EVM address and makes fully decentralized exchange and bridges across environments possible. + +To learn more about how to interact with a COA from the Cadence side, [see here](https://developers.flow.com/evm/cadence/interacting-with-coa). + +## Proofs + +**Inclusion proof of execution artifacts (logs and receipts)** + +Similar to other EVM environments, proof can be constructed for artifacts such as receipts. As mentioned earlier, all the EVM execution artifacts are collected as part of a Cadence event. Cadence events are similar to EVM logs, and the root hash of all events (event commitment) of a block is included in Flow's block content. The Cadence event inclusion proof functionality enables constructing proofs for any artifact. For example, if one wants to construct an external proof for the inclusion of a specific EVM log or receipt, here are the steps: + +- Flow block validation: Anyone following the Flow blocks can validate the Flow block headers. + +- EVM block validation: Since each Flow block has the root hash of Cadence events emitted during block execution. It can construct and verify the inclusion of the specific Event. In this case, every time an EVM block is executed an `evm.BlockExecuted` event is emitted that contains the full EVM block information. + +- Receipt inclusion: Each EVM block includes the root hash for the receipts generated during block execution. Similar to other EVM chains, a proof can be constructed to prove inclusion of a log or receipt. + +**Inclusion proof of transactions** + +Each Flow EVM block (TransactionHashRoot) includes the Merkle root hash of all the transaction hashes executed during this block. Despite similar functionality, this root is a bit different than TransactionRoot provided by Ethereum, It is a commitment over the list of transaction hashes instead of transactions, so each leaf node in the Merkle tree has the transaction hash as the value instead of full RLP encoding of transaction. So verifying the proofs requires an extra calling to the hash function. + +**Account proofs** + +Another type of proof that EVM environments provide is proof for the state of accounts. These proofs depend on the trie structure of the execution environment. Flow EVM benefits from the advanced storage and proof system that makes Flow’s multi-role architecture possible. + +Flow’s state system provides ways to construct inclusion and non-inclusion proofs and one can construct proofs for EVM account’s meta data (account balances, nonce, … ). A less common proof type is proof over the storage state of an account (mostly used for smart contracts). The first release of Flow EVM won’t support these type of proofs. + + +=== evm/fees.md === +--- +title: Fees +sidebar_label: Fees +sidebar_position: 6 +--- + +:::info + +Are you a Cadence developer looking for information about Fees on Cadence? If so, check out the Cadence specific documentation [here](../build/basics/fees.md) + +::: + +EVM transactions are ultra low-cost and use the native FLOW token as gas. [Externally Owned Accounts (EOAs)](https://developers.flow.com/evm/build/accounts) function the same on Flow as other EVM networks like Ethereum. + +
    +

    How Transaction Fees are Computed on EVM

    + +With Flow EVM, EVM operations can now be called within Cadence transactions. EVM operations also have an associated effort measured in gas which needs to be factored into the execution effort calculation in addition to the Flow computation for any EVM transaction. + +``` +Transaction fee on EVM = surge x [inclusion fee + (execution effort * unit cost)] +``` + +- `Surge' factor` dynamically accounts for network pressure and market conditions. This is currently constant at 1.0 but subject to change with community approval. +- `Inclusion fee` accounts for the resources required to process a transaction due to its core properties (byte size, signatures). This is currently constant at 1E-6 FLOW, but subject to change with community approval. +- `Execution fee` The fee that accounts for the operational cost of running the transaction script, processing the results, sending results for verification, generating verification receipts, etc. and is calculated as a product of `execution effort units` and the `cost per unit`. + - `Execution Effort (computation)` is based on transaction type and operations that are called during the execution of a transaction. The weights determine how “costly” (time consuming) each operation is. + - `Execution Effort Unit Cost` = `2.49E-07 FLOW` (currently constant, but subject to change with community approval) + +

    Calculation of Execution Effort

    + +``` +Execution Effort (computation) = + 0.00478 * function_or_loop_call + + 0.00246 * GetValue + + 0.00234 * SetValue + + 8.65988 * CreateAccount + + EVMGasUsageCost * EVMGasUsage +``` + +where + +``` +`EVMGasUsage` is reported by EVM as the cost in gas for executing the transaction within the EVM, for instance, 21K gas for a simple send transaction. +``` + +``` +`EVMGasUsageCost` - The ratio that converts EVM gas into Flow computation units (execution effort) is currently set at `1/5000` but subject to revision by community approval +``` + +**Note**: The weights and unit cost mentioned above have been updated recently to accommodate an increased computation limit on Flow, which now supports the deployment of larger EVM contracts. For detailed information, refer to the relevant [FLIP](https://github.com/onflow/flips/blob/main/governance/20240508-computation-limit-hike.md) and join the ongoing discussion on the community [forum post](https://forum.flow.com/t/proposing-transaction-fee-changes-and-flow-evm-gas-charges-for-flow-crescendo-launch/5817). These values may be adjusted in the future based on community feedback and evolving requirements. + +
    + +
    +

    Demonstration of Transaction Fees on EVM

    + +Assume a simple NFT transfer transaction that makes 31 cadence loop calls, reads 5668 bytes from the storage register, and saves 1668 bytes to the storage register. + +- 'function_or_loop_call' = 31 +- 'GetValue' = 5688 +- 'SetValue' = 1668 +- 'CreateAccount' = 0 + +**Scenario 1 - Cadence-only Transaction** + +``` +Execution Effort = 0.00478 * (31) + 0.00246 * (5668) + 0.00234 *(1668) + 8.65988 *(0) + EVMGasUsageCost * EVMGasUsage +``` + +But since `EVMGasUsage` is 0 for a Cadence transaction, + +``` +Execution Effort = 18.04378 +``` + +Thus + +``` +Transaction fee = [1E-6 FLOW + (18.04378 * 2.49E-07 FLOW)] x 1 = 5.5E-06 FLOW +``` + +**Scenario 2 - EVM Transaction** +If the EVMGasUsage can be assumed to be 21,000 gas (typical for a simple transfer), + +``` +Execution Effort = 0.00478 * (31) + 0.00246 * (5668) + 0.00234 *(1668) + 8.65988 *(0) + 1/5000 * 21000 = 22.24378 +``` + +Thus + +``` +Transaction fee = [1E-6 FLOW + (110.97 * 2.49E-07 FLOW)] x 1 = 6.55E-06 FLOW +``` + +**Note**: Please be aware that this example serves solely for illustrative purposes to elucidate the calculations. Actual transaction fees may differ due to various factors, including the byte size of the transaction. + +
    + +## Gasless Transactions + +Fees needed to execute transactions on a Web3 app are often a major challenge for new users and can be a barrier to adoption. Builders can easily extend their apps with Cadence to create ‘gasless’ experiences by specifying their app as the [sponsor](../build/advanced-concepts/account-abstraction.md#sponsored-transactions) instead of the user. + +To learn more about storage fee and transaction fee, visit [Flow Tokenomics page](https://flow.com/flow-tokenomics/technical-overview). + + +=== evm/faucets.mdx === +--- +slug: /evm/faucets +redirect: /ecosystem/faucets +title: Faucets ↙ +sidebar_position: 10 +--- + +# Faucets + +Go to [Faucets](../ecosystem/faucets.md) + +import {Redirect} from '@docusaurus/router'; + +; + + +=== evm/cross-chain-bridges.mdx === +--- +slug: /evm/cross-chain-bridges +redirect: /ecosystem/bridges +title: Cross-chain Bridges ↙ +sidebar_position: 8 +--- + +# Cross-chain Bridges + +Go to [Bridges](../ecosystem/bridges.md) + +import {Redirect} from '@docusaurus/router'; + +; + + +=== evm/block-explorers.mdx === +--- +slug: /evm/block-explorers +redirect: /ecosystem/block-explorers +title: Block Explorers ↙ +sidebar_position: 11 +--- + +# Faucets + +Go to [Block explorers](../ecosystem/block-explorers.md) + +import {Redirect} from '@docusaurus/router'; + +; + + +=== evm/accounts.md === +--- +title: Accounts +sidebar_label: Accounts +sidebar_position: 7 +--- + +:::info + +Are you a Cadence developer looking for information about Accounts on Cadence? If so, check out the Cadence specific documentation [here](../build/basics/accounts.md) + +::: + +# Accounts + +There are three types of accounts used for Flow EVM. + +1. **Externally Owned Accounts (EOA)**: EOAs are controlled by private individuals using cryptographic keys and can initiate transactions directly. They are the primary account type for users to interact with the blockchain, holding and sending cryptocurrency or calling smart contract functions. +2. **Contract Accounts**: These accounts hold smart contract code and are governed by this code's logic. Unlike EOAs, Contract Accounts do not initiate transactions on their own but can execute transactions in response to calls they receive from EOAs or other contracts. +3. **Cadence Owned Accounts (COA)**: This is an account type unique to Flow EVM. These accounts are managed by [Cadence resources](https://cadence-lang.org/docs/language/resources) and can be used to interact with the Flow EVM from within the Cadence environment. + +EOAs and Contract accounts function the same as on other EVM networks. Users may interact with these accounts using the standard EVM JSON-RPC API ([see endpoints here](./using.mdx)). You can read more about EOAs and Contract accounts on the [Ethereum docs](https://ethereum.org/developers/docs/accounts). + +However, in order to leverage all the features of Cadence, developers will need to utilize Cadence Owned Accounts. + +:::danger + +🚨🚨🚨 **ASSET LOSS RISK** 🚨🚨🚨 + +Cadence-Owned Accounts, easily identifiable by the leading zeroes (`0x00000000000000000000000`) **only exist on Flow**. The keys to these addresses are generated in a way that is not compatible with other networks. + +As a result, any assets sent to one of these addresses on another network **will be lost permanently!** + +We're working with major wallet providers to block such transfers, and recommend that all app and wallet developers do the same. + +::: + +## Cadence Owned Accounts + +A Cadence Owned Account (COA) is a natively supported EVM smart contract wallet type that allows a Cadence resource to own and control an EVM address. This native wallet type provides the primitives needed to bridge or control assets across Flow EVM and Cadence facilitating composability between environments. + +![Account-Model](./flow-evm-account-model.png) + +### Why use COAs? + +COAs create powerful new opportunities to improve the UX, functionality and utility of EVM applications by taking advantage of Cadence. Key benefits include: + +- **Enhanced Composability**: Applications written in Solidity can be extended and composed upon within Cadence. This allows developers to build upon existing EVM applications and deliver a more feature-rich user experience. + +- **Atomic Interactions**: Developers are able to execute multiple EVM transactions atomically from a COA. This is particularly useful for applications that require multiple transactions to be executed within a single block, or require all prior transactions' state changes to revert if a single transaction in the batch fails. This is not possible natively using EOAs or with `UserOperations` when using the ERC-4337 standard; in both cases each individual transaction is distinct and cannot be reverted back once state has changed. + +- **Native Account Abstraction**: COAs are controlled by Cadence resources, which are in turn owned by Flow accounts. [Flow accounts](./accounts.md) have built-in support for multi-signature authentication, key rotation, and account recovery. As a Cadence resource, COAs naturally inherit [these features](../build/advanced-concepts/account-abstraction.md). + +- **Fine-Grained Access Control**: As Cadence resources, access to a COA can be governed by more sophisticated policies than those available with basic EVM accounts. By utilizing powerful Cadence access control primitives such as [capabilities and entitlements](https://cadence-lang.org/docs/language/access-control), developers can restrict who is able to interact with a COA and what actions they are permitted to perform. + +### Differences from Traditional EVM Accounts + +COAs are smart contracts that are deployed to, and are fully accessible within, Flow EVM. However, unlike traditional EVM accounts (e.g. EOAs or smart contract accounts), COAs are owned by a Cadence resource. This means that COAs can be created and controlled natively within the Cadence execution environment. + +Unlike EOAs, COAs do not have an associated key, but are assigned a 20-byte EVM address upon creation from Cadence. This address is based on the UUID of the Cadence resource and is prefixed with `0x000000000000000000000002`. This address determines the location of the COA smart contract deployment and is the EVM address that is used to interact with the COA. + +A COA may instantiate transactions itself (where the COA's EVM address acts as `tx.origin`). This behaviour differs from other EVM environments, where only externally owned accounts (EOAs) may instantiate transactions. + +Because COAs are owned by Cadence resources, an EVM transaction is not required to trigger a transaction from a COA (e.g. a transaction to make a call to `execute` or EIP-4337's `validateUserOpMethod`). Instead, call transactions may be triggered directly from the Cadence resource that owns the COA. By invoking the `call` method on this resource, a transaction event will be emitted within the EVM environment. + +### More Information + +To learn how to create and interact with COAs in Cadence, see the guide for [Interacting with COAs from Cadence](../tutorials/cross-vm-apps/interacting-with-coa.md). + +For more information about Cadence Owned Accounts, see the [Flow EVM Support FLIP](https://github.com/onflow/flips/pull/225/files) + + +=== evm/about.md === +--- +title: Why EVM on Flow +sidebar_label: Why EVM on Flow +sidebar_position: 1 +--- + +# Why EVM on Flow + +Flow is an L1 that now supports EVM-equivalency. This means that all of Flow's protocol benefits, such as fast transactions, low costs, and mainstream scalability, are natively available without any additional code changes to solidity contracts. With EVM, solidity devs and builders can now easily tap into Flow's user base and unique IPs without any implementation risk. + +## Seamless Integration for Ethereum Developers + +Flow EVM is designed to work out-of-the-box with the Ethereum toolchain or other clients. Native EVM transactions also continue to be supported when using Metamask and other EVM-compatible clients. +EVM-equivalency on Flow works behind-the-scenes by implementing a minimal transaction script in Cadence, Flow's smart contract language, to integrate Flow features with EVM. This is made possible because EVM transactions are composed and executed within Cadence transactions, enabling novel use-cases and patterns for integration. + + +## Best-In-Class UX + +Flow allows for the creation of app on-boarding experiences that meet every type of user exactly where they are at, from web3 beginners to ecosystem veterans. This is possible through Account Linking, which utilizes the account abstraction model on Flow and enables users to immediately use an app without wallet authentication. On-chain accounts can be created as needed by the application which custodies their use for an anonymous user. At some later point these users may choose to link the custodied account to their self-custodial wallet taking full ownership of the account. EVM apps on Flow can also leverage Account Linking to handle creation of accounts and achieve a similarly smooth onboarding user experience. + +With Flow, builders can choose to expand EVM capabilities and transcend limitations using Cadence, which offers a powerful new account model, programmable resources, and hybrid ownership. + +## Instant Cross-VM Token Transfers + +EVM and Cadence environments both use FLOW as gas for transactions, sharing a singular token supply across both environments. Fungible and non-fungible tokens can also be seamlessly transferred between environments using the native VM token bridge, taking place instantly in a single atomic transaction. + +## Scalability, Performance and Low Gas Fees + +For sustainable user adoption, apps require the network they build on to be secure, efficient, affordable and fast. Gas fees are ultra-low cost on the network, but Flow goes a step further allowing for gasless experiences through sponsored transactions. Scalable performance is ensured with an innovative multi-node distributed consensus, flexible transaction model and horizontally scaled transaction linearization which solves proposer-builder separation, separation of compute, and settlement – all without sharding. + +Flow’s state space is extensible to the petabyte scale making it easy to store application data on-chain. This means contracts can maintain a full working dataset - including metadata - together with contract logic. + +Flow's transaction throughput peaked to 2M daily transactions during 2023 sustaining a similar average transaction volume as Ethereum. Unlike Ethereum, Flow has always operated well under its maximum throughput ceiling which is presently scalable to 5x more transactions with further performance optimizations to come when parallel execution is released. State scalability on Flow sets the foundations for further significant throughput optimization. + + +## MEV Resilience + +The [MEV Resilient](../build/basics/mev-resistance.md) design on Flow offers DeFi builders improved market efficiency, fairness, trust and long-term viability for their apps. Since Flow EVM transactions are composed and executed within a Cadence transaction, block production is handled by Flow’s [multi-role architecture](https://flow.com/post/flow-blockchain-multi-node-architecture-advantages). This heterogeneity between node roles ensures that visibility into block proposal, assembly, asserting block validity and other correctness checks during the block production cycle exposes limited information to each node type on a need to know basis, observing the Principle of Least Privilege. These differences in node and consensus design results in strong economic disincentives for collusion because no individual node has full visibility into the state of block production for the chain. This robust MEV resilience is a significant difference from other EVM-compatible networks and results in reasonably priced, predictable gas fees. The impracticality of frontrunning or other attacks improves the user experience by eliminating failed transactions and invisible fees. + + +## Join the Community + +Are you interested in launching an EVM project on Flow or partnering with us? Visit our weekly Flow [office hours](https://calendar.google.com/calendar/ical/c_47978f5cd9da636cadc6b8473102b5092c1a865dd010558393ecb7f9fd0c9ad0%40group.calendar.google.com/public/basic.ics) for discussions on project development and other opportunities for collaboration. You can also chat with us developers-chat in the Flow [Discord](https://discord.gg/flow). + + +## Further Reading and Discussions + +- [Why EVM on Flow: Beyond Solidity](https://forum.flow.com/t/evm-on-flow-beyond-solidity/5260) +- [Path to EVM Equivalence on Flow](https://forum.flow.com/t/evm-equivalence-on-flow-proposal-and-path-forward/5478) + +## Flow Improvement Proposals (FLIPs) + +Those wishing to understand the technical specifics of how Flow EVM works we recommend reviewing the following improvement proposals. + +- Understanding [EVM Support on Flow](https://github.com/onflow/flips/pull/225) +- Exploring the [Flow VM Bridge](https://github.com/onflow/flips/pull/233/files/d5bc46c4b13f0b9b168a94f994c77a5a689f6b24..122e938b7acae7e774246b1b66aaf5979ca21444) +- Insights into the [Flow EVM Gateway](https://github.com/onflow/flips/pull/235/files) +- Integration of the [Cadence Interface](https://github.com/onflow/flips/blob/f646491ec895442dcccdb24d80080bab1c56188e/protocol/20231116-evm-support.md) + + +=== evm/guides/web3-js.md === +--- +title: Web3.js on Flow Blockchain +sidebar_label: Web3.js +sidebar_position: 9 +--- + +# Web3.js + +[Web3.js](https://web3js.org/) is a Javascript library for building on EVM-compatible networks. + +It allows developers to interact with smart contracts, send transactions, and retrieve data from the network. + +## Prerequisites + +:::info +This guide assumes you have the latest version of [Node.js](https://nodejs.org/en) installed. +::: + +To install `web3` in your project, run the following command: + +```sh +npm install web3 +``` + +## Initializing Web3 with Flow + +To use `web3` in your project, start by importing the module and initializing your `Web3` instance with a Flow RPC endpoint. + +```js +const { Web3 } = require('web3'); +const web3 = new Web3('https://testnet.evm.nodes.onflow.org'); +``` + +**Note:** If you want to connect to the Flow testnet, replace the above URL with `https://mainnet.evm.nodes.onflow.org`. + +## Querying The Blockchain + +`web3` provides a number of methods for querying the blockchain, such as getting the latest block number, querying account balances, and more. + +You can try using some of these methods to verify that your `web3` instance is working correctly. + +```js +// Get the latest block number +const blockNumber = await web3.eth.getBlockNumber(); +console.log(blockNumber); // Latest block number + +// Get the balance of an account +const balance = await web3.eth.getBalance('0x1234'); // Replace with any address +console.log(balance); // Balance in attoFlow + +// Get the chain ID +const chainId = await web3.eth.getChainId(); +console.log(chainId); + +// Get the gas price +const gasPrice = await web3.eth.getGasPrice(); +console.log(gasPrice); // Gas price in attoFlow +``` + +For more information about other queries you can make `web3`, please see the [official documentation](https://docs.web3js.org/). + +## Interacting with Smart Contracts + +The `web3` library allows developers to interact with smart contracts via the `web3.eth.Contract` API. + +For this example we will use the following `Storage` contract. + +We recommend deploying your own contract, which can be done using [Hardhat](../guides/hardhat.md) or [Remix](../guides/remix.md). + +```solidity +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +contract Storage { + uint256 public storedData; + + function store(uint256 x) public { + storedData = x; + } + + function retrieve() public view returns (uint256) { + return storedData; + } +} +``` + +The ABI for this contract can be generated using the [`solc` compiler](https://docs.soliditylang.org/en/latest/installing-solidity.html), or another tool such as [Hardhat](../guides/hardhat.md) or [Remix](../guides/remix.md). + +Now that we have both the ABI and address of the contract, we can create a new `Contract` object for use in our application. + +```js +// Replace with the ABI of the deployed contract +const abi = [ + { + inputs: [], + stateMutability: 'nonpayable', + type: 'constructor', + }, + { + inputs: [ + { + internalType: 'uint256', + name: 'x', + type: 'uint256', + }, + ], + name: 'store', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [], + name: 'retrieve', + outputs: [ + { + internalType: 'uint256', + name: '', + type: 'uint256', + }, + ], + stateMutability: 'view', + type: 'function', + }, +]; + +// Replace with the address of the deployed contract +const contractAddress = '0x4c7784ae96e7cfcf0224a95059573e96f03a4e70'; + +// Create a new contract object with the ABI and address +const contract = new web3.eth.Contract(abi, contractAddress); +``` + +We can now interact with the contract on the network by using the `contract` object. + +### Reading State + +State can be read from the contract by using the `call` function with one of the contract's methods. This will not change the state and will not send a transaction. + +```js +// Retrieve the current value stored in the contract +// (this is using the `retrieve` method from the contract with no arguments) +const result = await contract.methods.retrieve().call(); + +console.log(result); // Current value stored in the contract +``` + +### Changing State + +We can mutate the state of the contract by sending a transaction to the network. + +In order to send a transaction to the network, you will need an account with sufficient funds to pay for the transaction. + +:::info +If you do not have an account yet, you can create one using the following command from your project's root directory: + +```sh +node -e "console.log(require('web3').eth.accounts.create())" +``` + +Note that this is not a secure way to generate an account, and you should use a more secure method in a production environment. + +You can fund your account using the [Flow Faucet](https://faucet.flow.com/fund-account). +::: + +We can use the `privateKeyToAccount` function to create an `Web3Account` object from our account's private key. + +```js +// You must replace this with the private key of the account you wish to use +const account = web3.eth.accounts.privateKeyToAccount('0x1234'); +``` + +Then, we can sign a transaction using the user's account and send it to the network. + +```js +const newValue = 1337; // Replace with any value you want to store + +// Sign a transaction that stores a new value in the contract +// (this is using the `store` method from the contract with the new value as an argument) +let signed = await account.signTransaction({ + from: account.address, + to: contractAddress, + data: contract.methods.store(newValue).encodeABI(), + gas: 10000000n, // Replace with the gas limit you want to use + gasPrice: await web3.eth.getGasPrice(), // Replace with the gas price you want to use +}); + +// Send signed transaction to the network +const result = await web3.eth.sendSignedTransaction(signed.rawTransaction); + +// { status: 1, transactionHash: '0x1234', ... } +// status=1 means the transaction was successful +console.log(result); +``` + +Now that the transaction has been sent, the contract's state should have been updated. We can verify this by querying the contract's state again: + +```js +const result = await contract.methods.retrieve().call(); +console.log(result); // New value stored in the contract +``` + +For more information about using smart contracts in web3.js, see the [official documentation](https://docs.web3js.org/libdocs/Contract). + + +=== evm/guides/wagmi.md === +--- +title: Viem & Wagmi +description: 'Using Wagmi to interact with Solidity contract to Flow EVM.' +sidebar_label: Viem & Wagmi +sidebar_position: 4 +--- + +:::info +Make sure to use `viem` version `2.9.6` or greater. This version contains flow EVM networks +::: + +# Using viem + +Flow networks have been added to viem chain definitions [viem networks](https://github.com/wevm/viem/tree/main/src/chains/definitions). This allows for convenient flow network configuration when using viem and wagmi. + +## Viem Flow Config + +The configuration below uses Flow Testnet. Since this configuration is already in viem various properties are already set, like block explorer and json-rpc endpoint. See how this configuration is used in a nextjs wagmi web application below. + +```javascript +import { http, createConfig } from '@wagmi/core'; +import { flowTestnet } from '@wagmi/core/chains'; +import { injected } from '@wagmi/connectors'; + +export const config = createConfig({ + chains: [flowTestnet], + connectors: [injected()], + transports: { + [flowTestnet.id]: http(), + }, +}); +``` + +# Using Next.js and Wagmi + +This tutorial will guide you through creating a simple web application, connect to an EVM capable wallet and interact with the "HelloWorld" smart contract to get and set greetings. We will not dive into managing transactions. + +## Prerequisites + +- Node.js installed on your machine +- A code editor (e.g., Visual Studio Code) +- Basic knowledge of React and Next.js + +## Step 1: Setting Up the Next.js Project + +This tutorial will be following [Wagmi getting-started manual tutorial](https://wagmi.sh/react/getting-started) +First, let's create a Wagmi project named `flow-evm-wagmi`. We will use npm but you are welcome to use yarn or bun. + +```bash +npm create wagmi@latest + +# project name flow-evm-wagmi +# Select 'React' then 'next' + +``` + +After Wagmi automatic installation procedure. + +```bash +cd flow-evm-wagmi +npm install +``` + +## Step 2: Configuring Wagmi and Connecting the Wallet + +Make sure you have Metamask installed and Flow network configured. [Metamask and Flow blockchain](/evm/using). +Wagmi needs to know what networks to be aware of. Let's configure to use Flow Testnet by updating config.ts file with the following: + +```javascript +import { http, createConfig } from '@wagmi/core'; +import { flowTestnet } from '@wagmi/core/chains'; +import { injected } from '@wagmi/connectors'; + +export const config = createConfig({ + chains: [flowTestnet], + connectors: [injected()], + transports: { + [flowTestnet.id]: http(), + }, +}); +``` + +By default Wagmi configures many wallets, MetaMask, Coinbase Wallet, and WalletConnect as wallet providers. Above we simplify the code to only be interested in the Injected Provider, which we are interested in Metamask. Verify `page.tsx` code looks like the following. + +```javascript +'use client' + +import { useAccount, useConnect, useDisconnect } from 'wagmi' + +function App() { + const account = useAccount() + const { connectors, connect, status, error } = useConnect() + const { disconnect } = useDisconnect() + + return ( + <> +
    +

    Account

    + +
    + status: {account.status} +
    + addresses: {JSON.stringify(account.addresses)} +
    + chainId: {account.chainId} +
    + + {account.status === 'connected' && ( + + )} +
    + +
    +

    Connect

    + {connectors.map((connector) => ( + + ))} +
    {status}
    +
    {error?.message}
    +
    + +} + +export default App + +``` + +![Connect Metamask](./Connect-Metamask.gif) + +This step relies on an already deployed HelloWorld contract. See [Using Remix](./remix.md) to deploy a smart contract on flow evm blockchain. +Create or edit the simple `page.tsx` file in the app directory to have better styles, that's beyond this tutorial. We will modify `page.txs` to add a new `HelloWorld.tsx`. Replace `YOUR_CONTRACT_ADDRESS` with your deployed address. + +## Step 3: Creating the Interface for HelloWorld Contract + +Now, let's create a component to interact with the HelloWorld contract. Assume your contract is already deployed, and you have its address and ABI. + +- Create a new file, HelloWorld.ts, in the components directory. +- Use Wagmi's hooks to read from and write to the smart contract: + +```javascript +import { useState } from 'react'; +import { + useContractRead, + useContractWrite, + useAccount, + useConnect, +} from 'wagmi'; +import contractABI from './HelloWorldABI.json'; // Import your contract's ABI + +const contractAddress = 'YOUR_CONTRACT_ADDRESS'; + +const HelloWorld = () => { + const [newGreeting, setNewGreeting] = useState(''); + const { address, isConnected } = useAccount(); + const { connect } = useConnect(); + + const { data: greeting } = useContractRead({ + addressOrName: contractAddress, + contractInterface: contractABI, + functionName: 'hello', + }); + + const { write: changeGreeting } = useContractWrite({ + addressOrName: contractAddress, + contractInterface: contractABI, + functionName: 'changeGreeting', + args: [newGreeting], + }); + + if (!isConnected) { + return ; + } + + return ( +
    +

    Current Greeting: {greeting}

    + setNewGreeting(e.target.value)} + placeholder="New greeting" + /> + +
    + ); +}; + +export default HelloWorld; +``` + +Reminder: aReplace YOUR_CONTRACT_ADDRESS with the actual address of your deployed HelloWorld contract. + +Also notice you need the HelloWorld contract ABI, save this to a new file called `HelloWorld.json` in the app directory. + +```json +{ + "abi": [ + { + "inputs": [], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "newGreeting", + "type": "string" + } + ], + "name": "changeGreeting", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "greeting", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "hello", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + } + ] +} +``` + +## Step 4: Integrating the HelloWorld Component + +Finally, import and use the HelloWorld component in your `pages.tsx`, throw it at the bottom of the render section. + +```javascript +import HelloWorld from './helloWorld' + + // put at the bottom of the Connect section. +
    +

    Connect

    + {connectors.map((connector) => ( + + ))} +
    {status}
    +
    {error?.message}
    +
    + + // 👇👇👇👇👇👇👇👇👇👇👇 +
    + +
    + +``` + +Now, you have a functional App that can connect to Metamask, display the current greeting from the "HelloWorld" smart contract, and update the greeting. + +Test it by updating the greeting, signing a transaction in your Metamask then wait a minute then refresh the website. Handling transactions are outside of this tutorial. We'll leave that as a future task. [Checkout Wagmi documentation](https://wagmi.sh/react/getting-started) + +![Update HelloWorld Greeting](./Update-HelloWorld-Greeting.gif) + + +=== evm/guides/vrf.md === +--- +title: VRF (Randomness) in Solidity +sidebar_label: VRF (Randomness) in Solidity +sidebar_position: 6 +--- + +## **Introduction** + +Flow provides secure, native on-chain randomness that developers can leverage through Cadence Arch, a precompiled +contract available on the Flow EVM environment. This guide will walk through how Solidity developers can use Cadence +Arch to access Flow’s verifiable randomness using Solidity. + +### **What is Cadence Arch?** + +[Cadence Arch](https://github.com/onflow/flips/blob/main/protocol/20231116-evm-support.md#cadence-arch) is a precompiled +smart contract that allows Solidity developers on Flow EVM to interact with Flow’s randomness and other network features +like block height. This contract can be accessed using its specific address, and Solidity developers can make static +calls to retrieve random values and other information. + +--- + +## **Prerequisites** + +- Basic Solidity knowledge. +- Installed Metamask extension. +- Remix IDE for compilation and deployment. +- Flow EVM Testnet setup in Metamask. + +## **Network Information for Flow EVM** + +| **Parameter** | **Value** | +| ------------------- | ----------------------------------------------------------------------------- | +| **Network Name** | Flow EVM Testnet | +| **RPC Endpoint** | [https://testnet.evm.nodes.onflow.org](https://testnet.evm.nodes.onflow.org/) | +| **Chain ID** | 545 | +| **Currency Symbol** | FLOW | +| **Block Explorer** | [https://evm-testnet.flowscan.io](https://evm-testnet.flowscan.io/) | + +## **Steps to Connect Flow EVM Testnet to Metamask** + +1. Open Metamask and click **Networks** -> **Add Network**. +2. Enter the following details: + - **Network Name**: Flow EVM Testnet + - **RPC URL**: `https://testnet.evm.nodes.onflow.org` + - **Chain ID**: `545` + - **Currency Symbol**: `FLOW` + - **Block Explorer**: `https://evm-testnet.flowscan.io` +3. Click **Save** and switch to the Flow EVM Testnet. + +![image.png](./vrf-1.png) + +## **Obtaining Testnet FLOW** + +You can fund your account with testnet FLOW using the [Flow Faucet](https://testnet-faucet.onflow.org/fund-account). +Enter your Flow-EVM testnet address, and you’ll receive testnet FLOW tokens to interact with smart contracts. + +--- + +## **Solidity Code Example: Retrieving Random Numbers** + +Below is a simple Solidity contract that interacts with the Cadence Arch contract to retrieve a pseudo-random number. + +```solidity +// SPDX-License-Identifier: GPL-3.0 +pragma solidity >=0.7.0 <0.9.0; + +contract CadenceArchCaller { + // Address of the Cadence Arch contract + address constant public cadenceArch = 0x0000000000000000000000010000000000000001; + + // Function to fetch a pseudo-random value + function revertibleRandom() public view returns (uint64) { + // Static call to the Cadence Arch contract's revertibleRandom function + (bool ok, bytes memory data) = cadenceArch.staticcall(abi.encodeWithSignature("revertibleRandom()")); + require(ok, "Failed to fetch a random number through Cadence Arch"); + uint64 output = abi.decode(data, (uint64)); + // Return the random value + return output; + } +} + +``` + +### **Explanation of the Contract** + +1. **Cadence Arch Address**: + + The `cadenceArch` variable stores the address of the Cadence Arch precompiled contract + (`0x0000000000000000000000010000000000000001`), which is constant across Flow EVM. + +2. **Revertible Random**: + + The `revertibleRandom()` function makes a static call to the `revertibleRandom()` function to fetch a pseudo-random + number. If the call is successful, it decodes the result as a `uint64` random value. + +--- + +## **Deploying and Testing the Contract** + +### Compile and Deploy the Contract + +1. Open Remix IDE. +2. Create a new file and paste the Solidity code above. + +![image.png](./vrf-2.png) + +3. Compile the contract by selecting the appropriate Solidity compiler version (0.8.x). + +![image.png](./vrf-3.png) + +4. Connect Remix to your Metamask wallet (with Flow EVM testnet) by selecting **Injected Web3** as the environment. + +![image.png](./vrf-4.png) + +5. Deploy the contract. + +![image.png](./vrf-5.png) + +### Call revertibleRandom + +After deployment, you can interact with the contract to retrieve a random number. + +Call the `revertibleRandom()` function in the left sidebar on the deployed contract. This will fetch a pseudo-random +number generated by Flow’s VRF. + +![image.png](./vrf-6.png) + +The result will be a `uint64` random number generated on Flow EVM. + +--- + +## **Generating Random Numbers in a Range** + +For use-cases like games and lotteries, it’s useful to generate a random number within a specified range, the following +example shows how to get a value between a min and max number. + +```solidity +// SPDX-License-Identifier: GPL-3.0 +pragma solidity >=0.7.0 <0.9.0; + +contract RandomInRange { + address constant public cadenceArch = 0x0000000000000000000000010000000000000001; + + // Generate a random number between min and max + function getRandomInRange(uint64 min, uint64 max) public view returns (uint64) { + // Static call to the Cadence Arch contract's revertibleRandom function + (bool ok, bytes memory data) = cadenceArch.staticcall(abi.encodeWithSignature("revertibleRandom()")); + require(ok, "Failed to fetch a random number through Cadence Arch"); + uint64 randomNumber = abi.decode(data, (uint64)); + + // Return the number in the specified range + return (randomNumber % (max + 1 - min)) + min; + } +} +``` + +:::warning + +The above code is susceptible to the [modulo +bias](https://research.kudelskisecurity.com/2020/07/28/the-definitive-guide-to-modulo-bias-and-how-to-avoid-it/), +particularly if the random number range is not a multiple of your desired range. To avoid this, you can use a more +complex algorithm like rejection sampling, an example for which is provided in [this +repository](https://github.com/onflow/random-coin-toss). + +::: + +## **Secure Randomness with Commit-Reveal Scheme in Solidity** + +The **`revertibleRandom()`** function can be directly used to generate a pseudo-random number. However, in certain +situations, especially involving untrusted callers, this function exposes a vulnerability: the ability of a transaction +to **revert after seeing the random result**. + +**The Issue with Using `revertibleRandom()` Directly:** + +- When an untrusted party calls a contract function that uses `revertibleRandom()`, they receive the random number + **during the transaction execution**. +- **Post-selection** is the ability of the caller to abort the transaction if the random outcome is unfavorable. In this + case, the user could choose to revert the transaction (for example, if they lose a bet) and attempt to call the + function again in hopes of a better outcome. +- This can lead to a form of **transaction reversion attack**, where the randomness can be exploited by repeatedly + attempting transactions until a favorable result is obtained. + +## Read More + +For further details on Flow’s randomness and secure development practices, check out the [Flow Randomness +Documentation](https://developers.flow.com/build/advanced-concepts/randomness). + +You can also view an example in both Solidity and Cadence of a [random coin toss +implentation](https://github.com/onflow/random-coin-toss) using the VRF. + +_This documentation was contributed by [Noah Naizir](https://x.com/noah_overflow), a community developer._ + + +=== evm/guides/remix.md === +--- +title: Flow Remix Guide +description: 'Using Remix to deploy a solidity contract to Flow EVM.' +sidebar_label: Remix +sidebar_position: 3 +--- + +# Using Remix + +Remix is an open-source, web-based development environment tailored for EVM smart contract development. It offers developers a comprehensive suite of tools for writing, deploying, and testing smart contracts in Solidity. For more information, visit [Remix](https://remix.ethereum.org/). + +## Add the Flow Network to MetaMask + +![Add Flow Network](./Remix-adding-metamask-network.gif) + +Navigate to the [Using EVM](../using.mdx) page to find the button to add the Flow network information to your metamask. + +## Fund Your Flow Account + +Navigate to the [Flow Testnet Faucet](https://faucet.flow.com/fund-account) to obtain FLOW tokens necessary for deploying a smart contract. + +## Deploying a Smart Contract Using Remix + +![Deploy Smart Contract](./Remix-deploy-contract-flowevm.gif) + +### HelloWorld Smart Contract + +```solidity +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +contract HelloWorld { + // Declare a public field of type string. + string public greeting; + + // Constructor to initialize the greeting. + // In Solidity, the constructor is defined with the "constructor" keyword. + constructor() { + greeting = "Hello, World!"; + } + + // Public function to change the greeting. + // The "public" keyword makes the function accessible from outside the contract. + function changeGreeting(string memory newGreeting) public { + greeting = newGreeting; + } + + // Public function that returns the greeting. + // In Solidity, explicit return types are declared. + function hello() public view returns (string memory) { + return greeting; + } +} + + +``` + +### Steps to Deploy the HelloWorld Smart Contract + +1. Create a file named `HelloWorld.sol`. +2. Select Solidity Compiler and compile `HelloWorld.sol`. +3. Select Deploy & Run Transactions. +4. Make sure to select `Injected Provider - Metamask` in Environment dropdown. +5. Deploy the `HelloWorld` smart contract. + +## Calling the Deployed Smart Contract + +![Call Smart Contract](./Remix-call-getGreeting.gif) + +### Using Ethers.js to Call the HelloWorld Smart Contract + +1. Create a new `get-greeting.js` file under `scripts`. +2. Paste in the JavaScript code below. +3. Click on green play button to run. +4. Verify the greeting is "Hello World!". + +```javascript +// Import ethers from the ethers.js library +const { ethers } = require('ethers'); + +// Define the contract ABI +const contractABI = ['function hello() public view returns (string memory)']; + +// Define the contract address +const contractAddress = '0x8a120383e6057b1f3aef4fa9b89c2f1b0a695926'; + +// Connect to the Ethereum network +// This example uses the default provider from ethers.js, which connects to the Ethereum mainnet. +// For a testnet or custom RPC, use ethers.getDefaultProvider('networkName') or new ethers.providers.JsonRpcProvider(url) +const provider = new ethers.providers.Web3Provider(window?.ethereum); + +// Create a new contract instance +const contract = new ethers.Contract(contractAddress, contractABI, provider); + +// Call the hello function of the contract +async function getGreeting() { + const greeting = await contract.hello(); + console.log(greeting); +} + +// Execute the function +getGreeting(); +``` + +Follow the steps below to change the greeting and retrieve the new greeting. + +## Updating the Deployed Smart Contract + +![Update Smart Contract](./Remix-update-greeting.gif) + +1. Select the `HelloWorld.sol` file. +2. Select the `Deploy and Run Transaction` page. +3. Make sure to select `Injected Provider - Metamask` in Environment dropdown. +4. Type a new greeting in the text input next to orange `changeGreeting` button. +5. Click on the orange `changeGreeting` button. +6. Sign the Metamask transaction. +7. Verify the greeting has changed by re-running `get-greeting.js` script above. + + +=== evm/guides/rainbowkit.md === +--- +title: Using Rainbowkit with Flow Wallet +description: A step-by-step guide on adding Flow Wallet as a custom Wallet to RainbowKit. +sidebar_position: 4 +sidebar_label: Rainbowkit +--- + +Integrating Flow Wallet with [RainbowKit][1] allows users to seamlessly connect their Flow accounts through one of the most popular wallet connection interfaces. + +This guide walks you through the process of defining Flow Wallet as a custom wallet in RainbowKit and testing the integration. You can follow along by setting up a new RainbowKit project or use the code in this guide to integrate these steps into your existing dApp. + +## Objectives + +After completing this guide, you'll be able to: +- Create a custom Flow Wallet connector compatible with RainbowKit's interface +- Configure your Wagmi setup to support Flow Wallet connections +- Implement a complete wallet connection flow for Flow blockchain users +- Test and verify the Flow Wallet integration in your dApp + +## Prerequisites + +### Next.js and Modern Frontend Development + +The RainbowKit starter is built on Next.js, so familiarity with React, hooks, and modern frontend development will help you follow along. + +## A Flow Wallet + +To use Flow Wallet with RainbowKit, install the Flow Wallet browser extension from the [Chrome Web Store][2]. + +Once installed, set up your wallet by creating or importing an account. For quick access, pin the extension to your browser toolbar. + +## Setting Up Your Environment + +### Initial Setup + +The RainbowKit starter is built on Next.js, following its standard project structure and conventions. Create a new project or ensure your existing one has the necessary dependencies: + +```bash +$ npm init @rainbow-me/rainbowkit@latest +$ cd my-rainbowkit-app +$ npm run dev +``` + +The [RainbowKit](https://www.rainbowkit.com/) components will be available throughout your application via the provided wrapper components. + +### Creating the Flow Wallet Connector +The first major step is defining the Flow Wallet connector. Create a new file called `flowWallet.ts` in `src/flowWallet.ts` to house the wallet configuration: + +```tsx +/* src/flowWallet.ts */ +import { Wallet, getWalletConnectConnector } from '@rainbow-me/rainbowkit'; + +export interface MyWalletOptions { + projectId: string; +} + +export const flowWallet = ({ projectId }: MyWalletOptions): Wallet => ({ + id: 'flow-wallet', + name: 'Flow Wallet', + iconUrl: 'https://lilico.app/logo_mobile.png', + iconBackground: '#41CC5D', + downloadUrls: { + android: 'https://play.google.com/store/apps/details?id=com.flowfoundation.wallet', + ios: 'https://apps.apple.com/ca/app/flow-wallet-nfts-and-crypto/id6478996750', + chrome: 'https://chromewebstore.google.com/detail/flow-wallet/hpclkefagolihohboafpheddmmgdffjm', + qrCode: 'https://link.lilico.app', + }, + mobile: { + getUri: (uri: string) => uri, + }, + qrCode: { + getUri: (uri: string) => uri, + instructions: { + learnMoreUrl: 'https://wallet.flow.com', + steps: [ + { + description: 'We recommend putting Flow Wallet on your home screen for faster access to your wallet.', + step: 'install', + title: 'Open the Flow Wallet app', + }, + { + description: 'You can find the scan button on home page, a connection prompt will appear for you to connect your wallet.', + step: 'scan', + title: 'Tap the scan button', + }, + ], + }, + }, + extension: { + instructions: { + learnMoreUrl: 'https://wallet.flow.com', + steps: [ + { + description: 'We recommend pinning Flow Wallet to your taskbar for quicker access to your wallet.', + step: 'install', + title: 'Install the Flow Wallet extension', + }, + { + description: 'Be sure to back up your wallet using a secure method. Never share your secret phrase with anyone.', + step: 'create', + title: 'Create or Import a Wallet', + }, + { + description: 'Once you set up your wallet, click below to refresh the browser and load up the extension.', + step: 'refresh', + title: 'Refresh your browser', + }, + ], + }, + }, + createConnector: getWalletConnectConnector({ projectId }), +}); +``` + +### Configuring Wagmi Integration + +Next, update your Wagmi configuration to include Flow Wallet support. Modify your `wagmi.ts` file: + +```tsx +/* src/wagmi.ts */ +'use client'; + +import { connectorsForWallets } from '@rainbow-me/rainbowkit'; +import { createConfig, http } from 'wagmi'; +import { mainnet, flowMainnet } from 'viem/chains'; +import { flowWallet } from './flowWallet'; + +/* +We can leave this as is for the tutorial but it should be +replaced with your own project ID for production use. +*/ +const projectId = 'YOUR_PROJECT_ID'; + +const connectors = connectorsForWallets( + [ + { + groupName: 'Recommended', + wallets: [flowWallet] + }, + ], + { + appName: 'RainbowKit App', + projectId, + } +); + +export const config = createConfig({ + connectors, + chains: [flowMainnet, mainnet], + ssr: true, + transports: { + [flowMainnet.id]: http(), + [mainnet.id]: http(), + }, +}); +``` + +:::info + +WalletConnect Project ID + +Every dApp that relies on WalletConnect now needs to obtain a projectId from [WalletConnect Cloud (now rebranded as reown)](https://cloud.reown.com/sign-in). This is absolutely free and only takes a few minutes. + +To get a Project ID, sign up at WalletConnect Cloud, create a new project, and copy the generated ID into the `projectId` variable in the `wagmi.ts` file. + +::: + +## Testing Your Integration + +After implementing the Flow Wallet connector and configuring Wagmi, follow these steps to verify that the integration works correctly in your dApp: + +1. **Click "Connect Wallet"** – Open your application and click the "Connect Wallet" button. +2. **Check for Flow Wallet** – Ensure Flow Wallet appears as an option in the RainbowKit wallet selection modal. + - If you haven't installed the browser extension and set up your wallet yet, you can find install it via the [Chrome Web Store][2]. +3. **Connect the Wallet** – Click on Flow Wallet in the selection modal. If using the browser extension, open it and press "Connect." + +![Rainbowkit dAPP UI](./rainbowkit-1.png) + +4. **Verify Connection** – Confirm that your Flow Wallet is now connected and visible in your dApp's UI. + +![Rainbowkit dAPP UI](./rainbowkit-2.png) + +## Conclusion + +In this tutorial, you learned how to integrate Flow Wallet with [RainbowKit](https://www.rainbowkit.com/), creating a seamless wallet connection experience for your users. You should now be able to: +- Create a custom Flow Wallet connector compatible with RainbowKit's interface +- Configure your Wagmi setup to support Flow Wallet connections +- Implement a complete wallet connection flow for Flow blockchain users +- Test and verify the Flow Wallet integration in your dApp + +Now that you've completed this tutorial, you're ready to enhance your dApp with additional Flow blockchain features such as token transfers, NFT minting, and smart contract interactions. + +[1]: https://www.rainbowkit.com/ +[2]: https://chromewebstore.google.com/detail/flow-wallet/hpclkefagolihohboafpheddmmgdffjm?hl=en + +=== evm/guides/integrating-metamask.mdx === +--- +title: Integrating Metamask +sidebar_position: 1 +--- + +import BrowserOnly from '@docusaurus/BrowserOnly'; +import { AddNetworkButton } from '@site/src/components/addNetworkButton'; + +# Wallets & Configurations + +This document shows how to integrate the Flow Network programmatically with your Dapp via MetaMask. + +If you want to add it to your wallet now, you can click the buttons below, or follow the [manual process]. + + + {() => { + // ******* If Chain Id changes, update the Chain ID in the AddNetworkButton component ******* + return ; + }} + + +## Metamask + +Integrating additional networks into MetaMask can pose challenges for users who lack technical expertise and may lead to errors. Simplifying this process can greatly enhance user onboarding for your application. This guide demonstrates how to create a straightforward button within your frontend application to streamline the addition of the Flow network to MetaMask. + +### EIP-3035 & MetaMask + +[EIP-3035](https://eips.ethereum.org/EIPS/eip-3085) is an Ethereum Improvement Proposal that defines an RPC method for adding Ethereum-compatible chains to wallet applications. Since March 2021 MetaMask has implemented that EIP as part of their MetaMask [Custom Networks API](https://consensys.io/blog/connect-users-to-layer-2-networks-with-the-metamask-custom-networks-api). + +### Flow Network configuration + +To add the Flow Testnet network to Metamask, add the following network configuration: + +```js +export const TESTNET_PARAMS = { + chainId: '0x221', + chainName: 'Flow', + rpcUrls: ['https://testnet.evm.nodes.onflow.org'], + nativeCurrency: { + name: 'Flow', + symbol: 'FLOW', + decimals: 18, + }, + blockExplorerUrls: ['https://evm-testnet.flowscan.io/'] +}; +``` + +### Adding Flow Network + +To add this configuration to MetaMask, call the `wallet_addEthereumChain` method which is exposed by the web3 provider. + +```js +function addFlowTestnet() { + injected.getProvider().then((provider) => { + provider + .request({ + method: 'wallet_addEthereumChain', + params: [TESTNET_PARAMS], + }) + .catch((error: any) => { + console.log(error); + }); + }); +} +``` + +The variable, `injected`, is initialized as a `web3-react/injected-connector` used to interface with MetaMask APIs. Usage for other popular web frameworks is similar. + +The typical usage would be to expose this button if you get errors when attempting to connect to MetaMask (i.e. `Wrong Network` or `Error Connecting`). + +### User Experience + +Users of your app will need to first approve a connection to Metamask. After doing this, if you don't detect a successful Web3 network connection, you may present a dialog asking them to add the Flow network to their wallet. + +![Metamask Network](../metamask-network.png) + +After they approve, your app will be connected to the Flow network. + +By using this approach to add the Flow network to Metamask, you can avoid manual user data entry and ensure that users are ready to interact with your dApp! + +{/* Reference-style links, does not render on page */} + +[manual process]: ../using.mdx + + +=== evm/guides/hardhat.md === +--- +title: Flow Hardhat Guide +description: 'Using Hardhat to deploy a Solidity contract to Flow EVM.' +sidebar_label: Hardhat +sidebar_position: 2 +--- + +# Flow Hardhat Guide + +Hardhat is an Ethereum development tool designed to facilitate the deployment, testing, and debugging of smart contracts. It provides a streamlined experience for developers working with Solidity contracts. + +## Prerequisites + +### Node + +Node v18 or higher, available for [download here](https://nodejs.org/en/download). + +For those new to Hardhat, we recommend exploring the [official documentation](https://hardhat.org/tutorial/creating-a-new-hardhat-project) to get acquainted. The following instructions utilize `npm` to initialize a project and install dependencies: + +### Wallet + +You'll also need a wallet that supports EVM. For this guide, a MetaMask account and its corresponding private key will work. + +```shell +mkdir hardhat-example +cd hardhat-example + +npm init + +npm install --save-dev hardhat + +npx hardhat init +``` + +> When prompted, select TypeScript and to use `@nomicfoundation/hardhat-toolbox` to follow along with this guide. + +### Fund Your Wallet + +To deploy smart contracts, ensure your wallet has **$FLOW**. Obtain funds by navigating to the Flow [Faucet](https://faucet.flow.com/fund-account) and entering your wallet address. + +## Deploying a Smart Contract with Hardhat + +This section guides you through the process of deploying smart contracts on the Flow network using Hardhat. + +### Configuration + +First, incorporate the Testnet network into your `hardhat.config.ts`: + +```javascript +import { HardhatUserConfig } from 'hardhat/config'; +import '@nomicfoundation/hardhat-toolbox'; + +const config: HardhatUserConfig = { + solidity: '0.8.24', + networks: { + testnet: { + url: 'https://testnet.evm.nodes.onflow.org', + accounts: [``], // In practice, this should come from an environment variable and not be commited + gas: 500000, // Example gas limit + }, + }, +}; + +export default config; +``` + +To keep this example straightforward, we've included the account's private key directly in `hardhat.config.ts`. However, it is crucial to avoid committing private keys to your Git repository for security reasons. Instead, opt for using environment variables for safer handling of sensitive information. + +### Deploying HelloWorld Smart Contract + +## HelloWorld Smart Contract + +```solidity +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +contract HelloWorld { + // Declare a public field of type string. + string public greeting; + + // Constructor to initialize the greeting. + // In Solidity, the constructor is defined with the "constructor" keyword. + constructor() { + greeting = "Hello, World!"; + } + + // Public function to change the greeting. + // The "public" keyword makes the function accessible from outside the contract. + function changeGreeting(string memory newGreeting) public { + greeting = newGreeting; + } + + // Public function that returns the greeting. + // In Solidity, explicit return types are declared. + function hello() public view returns (string memory) { + return greeting; + } +} +``` + +Deploying: + +1. Create a file named `HelloWorld.sol` under `contracts` directory. +2. Add above `HelloWorld.sol` contract code to new file. +3. Create a `deploy.ts` file in `scripts` directory. +4. Paste in the following TypeScript code. + +```javascript +import { ethers } from 'hardhat'; + +async function main() { + const [deployer] = await ethers.getSigners(); + + console.log('Deploying contracts with the account:', deployer.address); + + const deployment = await ethers.deployContract('HelloWorld'); + + console.log('HelloWorld address:', await deployment.getAddress()); +} + +main() + .then(() => process.exit(0)) + .catch((error) => { + console.error(error); + process.exit(1); + }); +``` + +5. Run `npx hardhat run scripts/deploy.ts --network testnet` in the project root. +6. Copy the deployed `HelloWorld` address. This address will be used in other scripts. + +Output should look like this (with the exception that your address will be different): + +```shell +❯ npx hardhat run scripts/deploy.ts --network testnet +Deploying contracts with the account: ... +HelloWorld address: 0x3Fe94f43Fb5CdB8268A801f274521a07F7b99dfb +``` + +You can now search for your deployed contract on the [Flowscan block explorer](https://evm-testnet.flowscan.io/)! + +### Get HelloWorld Contract Greeting + +Now, we want to get the greeting from the deployed `HelloWorld` smart contract. + +```javascript +import { ethers } from 'hardhat'; +import HelloWorldABI from '../artifacts/contracts/HelloWorld.sol/HelloWorld.json'; + +async function main() { + // Replace with your contract's address + const contractAddress = '0x3Fe94f43Fb5CdB8268A801f274521a07F7b99dfb'; + // Get hardhat provider + const provider = ethers.provider; + // Create a new contract instance + const helloWorldContract = new ethers.Contract( + contractAddress, + HelloWorldABI.abi, + provider, + ); + // Call the greeting function + const greeting = await helloWorldContract.hello(); + console.log('The greeting is:', greeting); +} + +main().catch((error) => { + console.error(error); + process.exit(1); +}); +``` + +Steps: + +1. Create a `getGreeting.ts` file in the `scripts` directory. +2. Paste contents of script above. Make sure to update the contract address with the one from deployment in earlier step. +3. Call script to get the greeting, `npx hardhat run scripts/getGreeting.ts --network testnet` +4. The output should be as follows: + +```shell +❯ npx hardhat run scripts/getGreeting.ts --network testnet +The greeting is: Hello, World! +``` + +### Update Greeting on HelloWorld Smart Contract + +Next, we'll add a script to update the greeting and log it. + +```javascript +import { ethers } from 'hardhat'; +import HelloWorldABI from '../artifacts/contracts/HelloWorld.sol/HelloWorld.json'; + +async function main() { + const contractAddress = '0x3Fe94f43Fb5CdB8268A801f274521a07F7b99dfb'; + + const newGreeting = process.env.NEW_GREETING; + if (!newGreeting) { + console.error('Please set the NEW_GREETING environment variable.'); + process.exit(1); + } + + // Signer to send the transaction (e.g., the first account from the hardhat node) + const [signer] = await ethers.getSigners(); + + // Contract instance with signer + const helloWorldContract = new ethers.Contract( + contractAddress, + HelloWorldABI.abi, + signer, + ); + + console.log('The greeting is:', await helloWorldContract.hello()); + + // Create and send the transaction + const tx = await helloWorldContract.changeGreeting(newGreeting); + console.log('Transaction hash:', tx.hash); + + // Wait for the transaction to be mined + await tx.wait().catch((error: Error) => {}); + console.log('Greeting updated successfully!'); + console.log('The greeting is:', await helloWorldContract.hello()); +} + +main().catch((error) => { + console.error(error); + process.exit(1); +}); +``` + +Here are the steps to follow: + +1. Create an `updateGreeting.ts` script in the `scripts` directory. +2. Paste in the TypeScript above, make sure to update the contract address with the one from deployment in earlier step. +3. Call the new script, `NEW_GREETING='Howdy!' npx hardhat run ./scripts/updateGreeting.ts --network testnet` +4. The output should be + +```shell +❯ NEW_GREETING='Howdy!' npx hardhat run ./scripts/updateGreeting.ts --network testnet +The greeting is: Hello, World! +Transaction hash: 0x03136298875d405e0814f54308390e73246e4e8b4502022c657f04f3985e0906 +Greeting updated successfully! +The greeting is: Howdy! +``` + + +### Verifying Contract + +To verify your contract on [Flowscan](https://evm-testnet.flowscan.io/), you can update your Hardhat config file as such including the correct chainID, apiURL and browserURL: + +```javascript +import { HardhatUserConfig } from 'hardhat/config'; +import '@nomicfoundation/hardhat-toolbox'; +import "@nomicfoundation/hardhat-verify"; + +const PRIVATE_KEY = vars.get("EVM_PRIVATE_KEY"); + +const config: HardhatUserConfig = { + solidity: '0.8.24', + networks: { + testnet: { + url: 'https://testnet.evm.nodes.onflow.org', + accounts: [PRIVATE_KEY], // In practice, this should come from an environment variable and not be commited + gas: 500000, // Example gas limit + }, + }, + etherscan: { + apiKey: { + // Is not required by blockscout. Can be any non-empty string + 'testnet': "abc" + }, + customChains: [ + { + network: "testnet", + chainId: 545, + urls: { + apiURL: "https://evm-testnet.flowscan.io/api", + browserURL: "https://evm-testnet.flowscan.io/", + } + } + ] + }, + sourcify: { + enabled: false + } +}; + +export default config; +``` + +The [verify](https://docs.blockscout.com/developer-support/verifying-a-smart-contract/hardhat-verification-plugin) plugin requires you to include constructor arguments with the verify task and ensures that they correspond to expected ABI signature. However, Blockscout ignores those arguments, so you may specify any values that correspond to the ABI. Execute the following command to verify the contract: + +```shell +npx hardhat verify --network testnet DEPLOYED_CONTRACT_ADDRESS "Constructor argument 1" +``` + +=== evm/guides/foundry.md === +--- +title: Using Foundry with Flow +description: 'Using Foundry to deploy a Solidity contract to Flow EVM.' +sidebar_label: Foundry +sidebar_position: 5 +--- + +# Using Foundry with Flow + +Foundry is a suite of development tools that simplifies the process of developing and deploying Solidity contracts to EVM networks. This guide will walk you through the process of deploying a Solidity contract to Flow EVM using the Foundry development toolchain. You can check out the official Foundry docs [here](https://book.getfoundry.sh/). + +In this guide, we'll deploy an ERC-20 token contract to Flow EVM using Foundry. We'll cover: + +- Developing and testing a basic ERC-20 contract +- Deploying the contract to Flow EVM using Foundry tools +- Querying Testnet state +- Mutating Testnet state by sending transactions + +## Overview + +To use Flow across all Foundry tools you need to: + +1. Provide the Flow EVM RPC URL to the command you are using: + + ```shell + --rpc-url https://testnet.evm.nodes.onflow.org + ``` + +2. Use the `--legacy` flag to disable [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559) style transactions. Flow will support EIP-1559 soon and this flag won't be needed. + +As an example, we'll show you how to deploy a fungible token contract to Flow EVM using Foundry. You will see how the above flags are used in practice. + +## Example: Deploying an ERC-20 Token Contract to Flow EVM + +ERC-20 tokens are the most common type of tokens on Ethereum. We'll use [OpenZeppelin](https://www.openzeppelin.com/) starter templates with Foundry on Flow Testnet to deploy our own token called `MyToken`. + +### Installation + +The best way to install Foundry, is to use the `foundryup` CLI tool. You can get it using the following command: + +```shell +curl -L https://foundry.paradigm.xyz | bash +``` + +Install the tools: + +```shell +foundryup +``` + +This will install the Foundry tool suite: `forge`, `cast`, `anvil`, and `chisel`. + +You may need to reload your shell after `foundryup` installation. + +Check out the official [Installation](https://book.getfoundry.sh/getting-started/installation) guide for more information about different platforms or installing specific versions. + +### Wallet Setup + +We first need to generate a key pair for our EVM account. We can do this using the `cast` tool: + +```shell +cast wallet new +``` + +`cast` will print the private key and address of the new account. We can then paste the account address into the [Faucet](https://faucet.flow.com/fund-account) to fund it with some Testnet FLOW tokens. + +You can verify the balance of the account after funding. Replace `$YOUR_ADDRESS` with the address of the account you funded: + +```shell +cast balance --ether --rpc-url https://testnet.evm.nodes.onflow.org $YOUR_ADDRESS +``` + +### Project Setup + +First, create a new directory for your project: + +```shell +mkdir mytoken +cd mytoken +``` + +We can use `init` to initialize a new project: + +```shell +forge init +``` + +This will create a contract called `Counter` in the `contracts` directory with associated tests and deployment scripts. We can replace this with our own ERC-20 contract. To verify the initial setup, you can run the tests for `Counter`: + +```shell +forge test +``` + +The tests should pass. + +### Writing the ERC-20 Token Contract + +We'll use the OpenZeppelin ERC-20 contract template. We can start by adding OpenZeppelin to our project: + +```shell +forge install OpenZeppelin/openzeppelin-contracts +``` + +Rename `src/Counter.sol` to `src/MyToken.sol` and replace the contents with the following: + +```solidity +pragma solidity ^0.8.20; + +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; + +contract MyToken is ERC20 { + constructor(uint256 initialMint_) ERC20("MyToken", "MyT") { + _mint(msg.sender, initialMint_); + } +} +``` + +The above is a basic ERC-20 token with the name `MyToken` and symbol `MyT`. It also mints the specified amount of tokens to the contract deployer. The amount is passed as a constructor argument during deployment. + +Before compiling, we also need to update the test file. + +### Testing + +Rename `test/Counter.t.sol` to `test/MyToken.t.sol` and replace the contents with the following: + +```solidity +pragma solidity ^0.8.20; + +import {Test, console2, stdError} from "forge-std/Test.sol"; +import {MyToken} from "../src/MyToken.sol"; + +contract MyTokenTest is Test { + uint256 initialSupply = 420000; + + MyToken public token; + address ownerAddress = makeAddr("owner"); + address randomUserAddress = makeAddr("user"); + + function setUp() public { + vm.prank(ownerAddress); + token = new MyToken(initialSupply); + } + + /* + Test general ERC-20 token properties + */ + function test_tokenProps() public view { + assertEq(token.name(), "MyToken"); + assertEq(token.symbol(), "MyT"); + assertEq(token.decimals(), 18); + assertEq(token.totalSupply(), initialSupply); + assertEq(token.balanceOf(address(0)), 0); + assertEq(token.balanceOf(ownerAddress), initialSupply); + } + + /* + Test Revert transfer to sender with insufficient balance + */ + function test_transferRevertInsufficientBalance() public { + vm.prank(randomUserAddress); + vm.expectRevert(abi.encodeWithSignature("ERC20InsufficientBalance(address,uint256,uint256)", randomUserAddress, 0, 42)); + token.transfer(ownerAddress, 42); + } + + /* + Test transfer + */ + function test_transfer() public { + vm.prank(ownerAddress); + assertEq(token.transfer(randomUserAddress, 42), true); + assertEq(token.balanceOf(randomUserAddress), 42); + assertEq(token.balanceOf(ownerAddress), initialSupply - 42); + } + + /* + Test transferFrom with approval + */ + function test_transferFrom() public { + vm.prank(ownerAddress); + token.approve(randomUserAddress, 69); + + uint256 initialRandomUserBalance = token.balanceOf(randomUserAddress); + uint256 initialOwnerBalance = token.balanceOf(ownerAddress); + + vm.prank(randomUserAddress); + assertEq(token.transferFrom(ownerAddress, randomUserAddress, 42), true); + assertEq(token.balanceOf(randomUserAddress), initialRandomUserBalance + 42); + assertEq(token.balanceOf(ownerAddress), initialOwnerBalance - 42); + assertEq(token.allowance(ownerAddress, randomUserAddress), 69 - 42); + } +} +``` + +You can now make sure everything is okay by compiling the contracts: + +```shell +forge compile +``` + +Run the tests: + +```shell +forge test +``` + +They should all succeed. + +### Deploying to Flow Testnet + +We can now deploy `MyToken` using the `forge create` command. We need to provide the RPC URL, private key from a funded account using the faucet, and constructor arguments that is the initial mint amount in this case. We need to use the `--legacy` flag to disable EIP-1559 style transactions. Replace `$DEPLOYER_PRIVATE_KEY` with the private key of the account you created earlier: + +```shell +forge create --rpc-url https://testnet.evm.nodes.onflow.org \ + --private-key $DEPLOYER_PRIVATE_KEY \ + --constructor-args 42000000 \ + --legacy \ + src/MyToken.sol:MyToken +``` + +The above will print the deployed contract address. We'll use it in the next section to interact with the contract. + +### Verifying a Smart Contract + +Once deployed, you can verify the contract so that others can see the source code and interact with it from Flow's block explorer. You can use the [`forge verify-contract`](https://book.getfoundry.sh/reference/forge/forge-verify-contract) command: + +```shell +forge verify-contract --rpc-url https://testnet.evm.nodes.onflow.org/ \ + --verifier blockscout \ + --verifier-url https://evm-testnet.flowscan.io/api \ + $DEPLOYED_MYTOKEN_ADDRESS \ + src/MyToken.sol:MyToken +```` + +:::info + +When verifying a Mainnet contract, be sure to use the Mainnet [RPC](../../evm/networks.md) and block explorer URLs. + +::: + +### Querying Testnet State + +Based on the given constructor arguments, the deployer should own `42,000,000 MyT`. We can check the `MyToken` balance of the contract owner. Replace `$DEPLOYED_MYTOKEN_ADDRESS` with the address of the deployed contract and `$DEPLOYER_ADDRESS` with the address of the account you funded earlier: + +```shell +cast balance \ + --rpc-url https://testnet.evm.nodes.onflow.org \ + --erc20 $DEPLOYED_MYTOKEN_ADDRESS \ + $DEPLOYER_ADDRESS +``` + +This should return the amount specified during deployment. We can also call the associated function directly in the contract: + +```shell +cast call $DEPLOYED_MYTOKEN_ADDRESS \ + --rpc-url https://testnet.evm.nodes.onflow.org \ + "balanceOf(address)(uint256)" \ + $DEPLOYER_ADDRESS +``` + +We can query other data like the token symbol: + +```shell +cast call $DEPLOYED_MYTOKEN_ADDRESS \ + --rpc-url https://testnet.evm.nodes.onflow.org \ + "symbol()(string)" +``` + +### Sending Transactions + +Let's create a second account and move some tokens using a transaction. You can use `cast wallet new` to create a new test account. You don't need to fund it to receive tokens. Replace `$NEW_ADDRESS` with the address of the new account: + +```shell +cast send $DEPLOYED_MYTOKEN_ADDRESS \ + --rpc-url https://testnet.evm.nodes.onflow.org \ + --private-key $DEPLOYER_PRIVATE_KEY \ + --legacy \ + "transfer(address,uint256)(bool)" \ + $NEW_ADDRESS 42 +``` + +We can check the balance of the new account: + +```shell +cast balance \ + --rpc-url https://testnet.evm.nodes.onflow.org \ + --erc20 $DEPLOYED_MYTOKEN_ADDRESS \ + $NEW_ADDRESS +``` + +The deployer should also own less tokens now: + +```shell +cast balance \ + --rpc-url https://testnet.evm.nodes.onflow.org \ + --erc20 $DEPLOYED_MYTOKEN_ADDRESS \ + $DEPLOYER_ADDRESS +``` + + +=== evm/guides/ethers.md === +--- +title: Ethers.js on Flow Blockchain +sidebar_label: Ethers +sidebar_position: 8 +--- + +# Ethers.js + +[ethers.js](https://docs.ethers.org/v5/) is a powerful JavaScript library for interacting with Ethereum and other EVM-compatible blockchain networks. + +In this guide, we'll walk you through how to use ethers.js to interact with smart contracts on the Flow Blockchain. + +--- + +## Installation + +To begin using ethers.js in your project, you'll need to install the package. You can do this by running the following command: + +```bash +bashCopy code +npm install --save ethers + +``` + +## Setup + +After installing ethers.js, the next step is to import it into your project. + +You can do this by adding the following line of code at the beginning of your JavaScript file: + +```jsx +const ethers = require('ethers'); +``` + +## Connecting to Flow + +To connect to the Flow Blockchain using ethers.js, you need to create a new `JsonRpcProvider` instance with the appropriate RPC URL for Flow: + +```jsx +const ethers = require('ethers'); + +const url = 'https://testnet.evm.nodes.onflow.org/'; +const provider = new ethers.providers.JsonRpcProvider(url); +``` + +**Note:** If you want to connect to the Flow testnet, replace the above URL with `https://mainnet.evm.nodes.onflow.org`. + +## Reading Data from the Blockchain + +Once your provider is set up, you can start reading data from the Flow Blockchain. For instance, to retrieve the latest block number, you can use the `getBlockNumber` method: + +```jsx +async function getLatestBlock() { + const latestBlock = await provider.getBlockNumber(); + console.log(latestBlock); +} +``` + +## Writing Data to the Blockchain + +To send transactions or write data to the Flow Blockchain, you need to create a `Signer`. This can be done by initializing a new `Wallet` object with your private key and the previously created `Provider`: + +```jsx +const privateKey = 'YOUR_PRIVATE_KEY'; +const signer = new ethers.Wallet(privateKey, provider); +``` + +**Note:** Replace `'YOUR_PRIVATE_KEY'` with the actual private key of the wallet you want to use. + +## Interacting with Smart Contracts + +ethers.js also enables interaction with smart contracts on the Flow Blockchain. To do this, create a `Contract` object using the ABI (Application Binary Interface) and the address of the deployed contract: + +```jsx +const abi = [ + // ABI of deployed contract +]; + +const contractAddress = 'CONTRACT_ADDRESS'; + +// read-only contract instance +const contract = new ethers.Contract(contractAddress, abi, provider); +``` + +For contracts that require writing, you'll need to provide a `Signer` object instead of a `Provider`: + +```jsx +// write-enabled contract instance +const contract = new ethers.Contract(contractAddress, abi, signer); +``` + +**Note:** Replace `'CONTRACT_ADDRESS'` with the actual address of your deployed contract. + +After setting up your `Contract` object, you can call methods on the smart contract as needed: + +```jsx +async function setValue(value) { + const tx = await contract.set(value); + console.log(tx.hash); +} + +async function getValue() { + const value = await contract.get(); + console.log(value.toString()); +} +``` + + +=== ecosystem/wallets.md === +--- +sidebar_position: 2 +description: Store, manage, and interact securely with tokens and digital assets on Flow. Discover a range of wallets that offer convenient ways to handle and safeguard your cryptocurrency holdings, ensuring easy access and enhanced security for your transactions and assets. +sidebar_custom_props: + icon: 🔑 +--- + +# Wallets + +Store, manage, and interact securely with tokens and digital assets on Flow. Discover a range of wallets that offer convenient ways to handle and safeguard your cryptocurrency holdings, ensuring easy access and enhanced security for your transactions and assets. + +
    + +## Flow Wallet + +[Flow Wallet](https://wallet.flow.com/) is the most popular Flow-native wallet, it sponsors all gas fees for users and interacts seamlessly with both Cadence and EVM dApps in the ecosystem. + +## Metamask Wallet + +[Metamask](https://metamask.io/) is a secure and user-friendly crypto wallet for NFTs and digital tokens. Presently only supports Flow EVM and cannot access Cadence accounts. + +## Dapper Wallet + +[Dapper Wallet](https://www.meetdapper.com/) is a wallet exceptionally friendly for first time crypto collectors to buy and manage digital assets. + +## Ledger + +[Ledger](https://www.ledger.com/) is a hardware wallet to secure, buy, exchange, and grow your crypto assets. + +## Finoa + +[Finoa](https://www.finoa.io/) is a platform for institutional investors to safely store and stake their FLOW tokens. + +## Blocto + +[Blocto](https://www.blocto.io/) is a cross-chain mobile wallet for IOS and Android devices. + +
    + +## For Developers + +
    + +## Flow Dev Wallet + +[The Flow Dev Wallet](../tools/flow-dev-wallet/index.md) simulates the protocols used by [FCL](../tools/clients/fcl-js/index.md) to interact with the Flow blockchain on behalf of simulated user accounts. + +## Magic.link + +[Magic](https://magic.link/) is a developer SDK that integrates with your application to enable passwordless Web3 onboarding (no seed phrases) and authentication using magic links (similar to Slack and Medium). + +
    + + +=== ecosystem/vcs-and-funds.md === +--- +title: VCs & Funds +description: Connect with venture capital firms and investment funds supporting Flow projects +sidebar_position: 8 +sidebar_custom_props: + icon: 💼 +--- + +# VCs & Funds + +Building a successful Web3 project requires more than just great technology - having the right investors and partners can make all the difference. The Flow ecosystem is supported by some of the world's leading venture capital firms and crypto-native funds. + +Research shows that warm introductions can increase your chances of securing funding by up to 500% more liley compared to cold outreach. The Flow Foundation can help facilitate introductions to our network of trusted investors who have a deep understanding of the Flow ecosystem and web3. Reach out to your local dev-rel in [office hours](https://calendar.google.com/calendar/u/0/embed?src=c_47978f5cd9da636cadc6b8473102b5092c1a865dd010558393ecb7f9fd0c9ad0@group.calendar.google.com) or [discord](https://discord.gg/flow) to get a warm introduction. + +
    + + +## Understanding the `Counter` Contract + +To fully grasp how the script works, it's important to understand the structure of the `Counter` contract. Below is the source code for the contract: + +```cadence +access(all) contract Counter { + + access(all) var count: Int + + // Event to be emitted when the counter is incremented + access(all) event CounterIncremented(newCount: Int) + + // Event to be emitted when the counter is decremented + access(all) event CounterDecremented(newCount: Int) + + init() { + self.count = 0 + } + + // Public function to increment the counter + access(all) fun increment() { + self.count = self.count + 1 + emit CounterIncremented(newCount: self.count) + } + + // Public function to decrement the counter + access(all) fun decrement() { + self.count = self.count - 1 + emit CounterDecremented(newCount: self.count) + } + + // Public function to get the current count + view access(all) fun getCount(): Int { + return self.count + } +} +``` + +### Breakdown of the Contract + +- **Contract Declaration**: `access(all) contract Counter` declares a new contract named `Counter` that is accessible to everyone. +- **State Variable**: `access(all) var count: Int` declares a public variable `count` of type `Int`. The `access(all)` modifier means that this variable can be read by anyone. +- **Events**: Two events are declared: + - `CounterIncremented(newCount: Int)`: Emitted when the counter is incremented. + - `CounterDecremented(newCount: Int)`: Emitted when the counter is decremented. +- **Initializer**: The `init()` function initializes the `count` variable to `0` when the contract is deployed. +- **Public Functions**: + - `increment()`: Increases the `count` by `1` and emits the `CounterIncremented` event. + - `decrement()`: Decreases the `count` by `1` and emits the `CounterDecremented` event. + - `getCount()`: Returns the current value of `count`. The `view` modifier indicates that this function does not modify the contract's state. + +### Key Points + +- **Public Access**: The `count` variable and the functions `increment()`, `decrement()`, and `getCount()` are all public, allowing anyone to interact with them. +- **State Modification**: The `increment()` and `decrement()` functions modify the state of the contract by changing the value of `count` and emitting events. +- **Read Costs**: Reading data from the blockchain is free on Flow. Executing scripts like the one you ran does not incur any costs. However, transactions that modify state, such as calling `increment()` or `decrement()`, will incur costs and require proper authorization. + +### What's Next? + +In the upcoming tutorials, you'll learn how to: + +- **Modify the Counter**: Invoke the `increment()` and `decrement()` functions to update the `count` value. +- **Deploy Contracts**: Use the Flow CLI to deploy your own smart contracts. +- **Interact with Contracts Locally**: Use the Flow Emulator to test contracts in a local development environment. +- **Build Frontend Applications**: Display data from smart contracts in a React application using the Flow Client Library. + +By understanding the `Counter` contract and how to interact with it, you're building a solid foundation for developing more complex applications on the Flow blockchain. + +Proceed to the next tutorial to learn how to create your own contracts and deploy them live using the Flow CLI. + + + +[Cadence]: https://cadence-lang.org/ +[EVM]: https://flow.com/upgrade/crescendo/evm + +=== build/differences-vs-evm/index.md === +--- +sidebar_position: 2 +title: Differences vs. EVM +sidebar_custom_props: + icon: ↔️ +description: Understand the key differences between Flow and EVM-based blockchains. Learn about Flow's unique account model, Cadence programming language, and transaction structure compared to Ethereum. +keywords: + - Flow vs EVM + - Cadence vs Solidity + - blockchain differences + - account model + - smart contracts + - transactions + - Flow nodes + - development tools + - Flow architecture + - blockchain comparison + - Flow capabilities + - resource orientation + - Flow security model + - blockchain SDK + - developer tools +--- + +Flow [Cadence] is designed with many improvements over prior blockchain networks. As a result, you'll notice many differences between Flow vs. other blockchains, especially Ethereum. This document will be most useful to developers who are already familiar with building on the EVM, but contains details useful to all developers. Check out [Why Flow] for a more general overview of the Flow blockchain. + +:::tip + +Remember, Flow also supports full [EVM] equivalence! You can start by moving over your existing contracts, then start building new features that take advantage of the power of Cadence. + +::: + +## The Flow Cadence Account Model + +Key pairs establish ownership on blockchains. In other blockchains (e.g. Bitcoin and Ethereum), the user's address is also calculated based on their public key, making a unique one-to-one relationship between accounts (addresses) and public keys. This also means there is no concrete "account creation" process other than generating a valid key pair. + +With the advent of smart contracts, Ethereum introduced a new account type for deploying contracts that can use storage space (i.e., to store contract bytecode). You can learn more about the distinction between EOA and Contract [accounts on Ethereum]. + +The [Flow account model] combines the concepts of EOAs and Contract Accounts into a single account model and decouples accounts and public keys. Flow accounts are associated with one or more public keys of varying weights that specify interested parties that need to produce valid cryptographic signatures for each transaction authorized by that account. + +![Screenshot 2023-08-16 at 16.43.07.png](../basics/_accounts_images/Screenshot_2023-08-16_at_16.43.07.png) + +This natively enables interesting use cases, like key revocation, rotation, and multi-signature transactions. All Flow accounts can use network storage (e.g., for deploying contracts and storing resources like NFTs) based on the number of FLOW tokens they hold. + +:::warning + +You must run an explicit account creation transaction on Flow to create a new account. [Flow CLI] can create an account on any network with a given public key. Doing so requires a [very small fee] to be paid in FLOW. + +::: + +Another key difference is that [storage] for data and assets related to an account are stored in the account, **not** in the contract as with the EVM. + +Check out the [Accounts] concept document to learn more about Flow accounts. + +## Smart Contracts + +On Flow, smart contracts can be written in [Cadence], or Solidity. Cadence syntax is user-friendly and inspired by modern languages like Swift. Notable features of Cadence that make it unique and the key power of the Flow blockchain are: + +- **Resource-oriented**: Cadence introduces a new type called Resources. Resources enable onchain representation of digital assets natively and securely. Resources can only exist in one location at a time and are strictly controlled by the execution environment to avoid common mishandling mistakes. Each resource has a unique `uuid` associated with it on the blockchain. Examples of usage are fungible tokens, NFTs, or any custom data structure representing a real-world asset. Check out [Resources] to learn more. +- **Capability-based**: Cadence offers a [Capability-based Security] model. This also enables the use of Resources as structures to build access control. Capabilities and [Entitlements] can provide fine-grained access to the underlying objects for better security. For example, when users list an NFT on a Flow marketplace, they create a new Capability to the stored NFT in their account so the buyer can withdraw the asset when they provide the tokens. Check out [Capability-based Access Control] to learn more about Capabilities on Cadence. + +:::warning + +Cadence is not compiled. All contracts are public and unobfuscated on Flow. This isn't that different from the EVM, where it's trivial to decompile a contract back into Solidity. + +::: + +Check out the [Cadence] website to learn the details of the Cadence programming language. + +If you are a Solidity developer, we recommend you start with Cadence's [Guide for Solidity Developers] to dive deeper into the differences between the two languages. + +Here are some additional resources that can help you get started with Cadence: + +- [The Cadence tutorial] +- ERC-20 equivalent on Flow is the Flow Fungible Token Standard + - [Repository](https://github.com/onflow/flow-ft) + - [Tutorial](https://cadence-lang.org/docs/tutorial/fungible-tokens) +- ERC-721 equivalent on Flow is the Flow Non-Fungible Token Standard + - [Repository](https://github.com/onflow/flow-nft) + - [Tutorial](https://cadence-lang.org/docs/tutorial/non-fungible-tokens-1) +- Asset marketplaces with Cadence + - [Tutorial](https://cadence-lang.org/docs/tutorial/marketplace-setup) + - [NFT Storefront](https://github.com/onflow/nft-storefront/) is an example marketplace standard + +## Transactions and Scripts + +You can interact with the state on most other blockchains by cryptographically authorizing smart contract function calls. On Flow, transactions offer rich functionality through Cadence code. This allows you to seamlessly combine multiple contracts and function calls into a single transaction that updates the blockchain state - all executing together as one unified operation. + +Here is a sample transaction that mints an NFT from `ExampleNFT` contract on Testnet: + +```cadence +import NonFungibleToken from 0x631e88ae7f1d7c20 +import ExampleNFT from 0x2bd9d8989a3352a1 + +/// Mints a new ExampleNFT into recipient's account + +transaction(recipient: Address) { + + /// Reference to the receiver's collection + let recipientCollectionRef: &{NonFungibleToken.Collection} + + /// Previous NFT ID before the transaction executes + let mintingIDBefore: UInt64 + + prepare(signer: &Account) { + + self.mintingIDBefore = ExampleNFT.totalSupply + + // Borrow the recipient's public NFT collection reference + self.recipientCollectionRef = getAccount(recipient) + .capabilities.get<&{NonFungibleToken.Collection}>(ExampleNFT.CollectionPublicPath) + .borrow() + ?? panic("The recipient does not have a NonFungibleToken Receiver at " + .concat(ExampleNFT.CollectionPublicPath.toString()) + .concat(" that is capable of receiving an NFT.") + .concat("The recipient must initialize their account with this collection and receiver first!")) + + } + + execute { + + let currentIDString = self.mintingIDBefore.toString() + + // Mint the NFT and deposit it to the recipient's collection + ExampleNFT.mintNFT( + recipient: self.recipientCollectionRef, + name: "Example NFT #".concat(currentIDString), + description: "Example description for #".concat(currentIDString), + thumbnail: "https://robohash.org/".concat(currentIDString), + royalties: [] + ) + } + + post { + self.recipientCollectionRef.getIDs().contains(self.mintingIDBefore): "The next NFT ID should have been minted and delivered" + ExampleNFT.totalSupply == self.mintingIDBefore + 1: "The total supply should have been increased by 1" + } +} +``` + +### Authorizing Transactions + +The process to authorize a transaction on Flow Cadence is more complex, but also much more powerful than an EVM transaction: + +- [Accounts] can have multiple keys with varying weights +- Multiple accounts can sign a single transaction (`prepare` takes any number of arguments) +- Transaction computation fees can be paid by a different account, called the `Payer` account. +- The [transaction nonce] is provided by the `Proposer` account. This enables rate control and order to be dictated by a different party if needed. +- All of the above roles can be the same account. + +The same powerful concept also exists for querying the blockchain state using Scripts. Here is a sample script that fetches the `ExampleNFT` IDs owned by a given account on Testnet: + +```cadence +/// Script to get NFT IDs in an account's collection + +import NonFungibleToken from 0x631e88ae7f1d7c20 +import ExampleNFT from 0x2bd9d8989a3352a1 + +access(all) fun main(address: Address, collectionPublicPath: PublicPath): [UInt64] { + + let account = getAccount(address) + + let collectionRef = account + .capabilities.get<&{NonFungibleToken.Collection}>(collectionPublicPath) + .borrow() + ?? panic("The account with address " + .concat(address.toString()) + .concat("does not have a NonFungibleToken Collection at " + .concat(ExampleNFT.CollectionPublicPath.toString()) + .concat(". The account must initialize their account with this collection first!"))) + + return collectionRef.getIDs() + +} +``` + +Check out [Transactions] and [Scripts] to learn more about the concepts. You can also read the Cadence language reference on [Transactions] to dive deeper. + +## Flow Nodes + +Developers need a blockchain node to send transactions and fetch state. Flow is based on a multi-node architecture that separates tasks like consensus and computation into separate nodes. You can learn more about the Flow architecture in the [Flow Primer]. + +Access Nodes are the node type that are most useful for developers, as they provide access to the Flow network [via an API]. + +## SDKs and Tools + +If you're already familiar with blockchain development, here's a comparison between popular software packages and Flow's tooling: + +- [hardhat](https://hardhat.org/) / [Truffle](https://trufflesuite.com/) / [Foundry](https://github.com/foundry-rs/foundry) + - [Flow CLI](https://github.com/onflow/flow-cli/) provides local development tools and the [Flow Emulator](https://github.com/onflow/flow-emulator) +- [OpenZeppelin](https://www.openzeppelin.com/) + - [Emerald OZ](https://oz.ecdao.org/overview) +- [go-ethereum](https://geth.ethereum.org/) + - [Flow Go SDK](https://github.com/onflow/flow-go-sdk/) + - [FCL](https://github.com/onflow/fcl-js/) also provides Backend API for Flow in JS +- [web3.js](https://github.com/web3/web3.js) + - [FCL](https://github.com/onflow/fcl-js/) + - [flow-cadut](https://github.com/onflow/flow-cadut) provides more utilities for using Flow on Web +- [Remix](https://remix.ethereum.org/) + - [Flow Playground](https://play.flow.com/) provides basic experimentation on the web + - [Cadence VSCode Extension](https://marketplace.visualstudio.com/items?itemName=onflow.cadence) is strongly suggested to install for local development +- [Testing Smart Contracts](https://ethereum.org/en/developers/docs/smart-contracts/testing/) + - [Cadence testing framework](https://cadence-lang.org/docs/testing-framework) enables native tests in Cadence. + - [overflow](https://github.com/bjartek/overflow) for testing in Go. + + + +[Why Flow]: ../flow.md +[EVM]: ../../evm/about.md +[accounts on Ethereum]: https://ethereum.org/en/developers/docs/accounts +[Flow CLI]: ../../tools/flow-cli/accounts/create-accounts.md +[very small fee]: ../basics/fees.md#fee-structure +[Flow account model]: ../basics/accounts.md +[Accounts]: ../basics/accounts.md +[storage]: ../basics/accounts.md#storage +[Cadence]: https://cadence-lang.org/ +[Resources]: https://cadence-lang.org/docs/language/resources +[Capability-based Security]: https://en.wikipedia.org/wiki/Capability-based_security +[Entitlements]: https://cadence-lang.org/docs/language/access-control#entitlements +[Capability-based Access Control]: https://cadence-lang.org/docs/language/capabilities +[Guide for Solidity Developers]: https://cadence-lang.org/docs/solidity-to-cadence +[The Cadence tutorial]: https://cadence-lang.org/docs/tutorial/first-steps +[transaction nonce]: https://ethereum.org/en/developers/docs/accounts/#an-account-examined +[Transactions]: ../basics/transactions.md +[Scripts]: ../basics/scripts.md +[Transactions]: https://cadence-lang.org/docs/language/transactions +[Flow Primer]: https://flow.com/primer#primer-how-flow-works +[via an API]: ../../networks/flow-networks/index.md + + +=== build/core-contracts/index.md === +--- +title: Flow Core Contracts +description: The smart contracts that power the Flow protocol +sidebar_label: Core Smart Contracts +sidebar_position: 9 +sidebar_custom_props: + icon: 📝 + description: Explore the foundational contracts driving the Flow blockchain and learn how to utilize these vital building blocks for your own smart contract development. +keywords: + - core contracts + - Flow protocol + - smart contracts + - FungibleToken + - FlowToken + - ServiceAccount + - FlowFees + - FlowIDTableStaking + - NonFungibleToken + - MetadataViews + - StakingCollection + - NFTStorefront + - AccountLinking + - EVM + - protocol contracts + - Flow standards + - blockchain infrastructure + - contract standards +--- + +Flow relies on a set of core contracts that define key portions of the +Flow protocol. + +These contracts control the following: + +- Standard fungible token behavior. ([FungibleToken, FungibleTokenMetadataViews, FungibleTokenSwitchboard, Burner](./02-fungible-token.md)) +- Flow Protocol Token. ([FlowToken](./03-flow-token.md)) +- Flow Service Account. ([ServiceAccount, NodeVersionBeacon, RandomBeaconHistory](./04-service-account.md)) +- Account, transaction and storage fee payments. ([FlowFees and FlowStorageFees](./05-flow-fees.md)) +- Staking and delegation ([FlowIDTableStaking](./06-staking-contract-reference.md)) +- Epochs ([FlowEpoch, FlowClusterQC, FlowDKG](./07-epoch-contract-reference.md)) + +There are other important contracts that aren't part of the core protocol +but are nevertheless important to developers on Flow: + +- Standard Non-Fungible Token Behavior. ([NonFungibleToken](./08-non-fungible-token.md)) +- NFT Metadata Standard. ([MetadataViews, ViewResolver](./09-nft-metadata.md)) +- Staking Collection. ([StakingCollection](./11-staking-collection.md)) +- NFT Storefronts. ([NFTStorefront](./10-nft-storefront.md)) +- Account linking and Hybrid Custody. ([AccountLinking](./12-hybrid-custody.md)) +- EVM interfacing contract. ([EVM](./13-evm.md)) + + +=== build/core-contracts/15-bridge.md === +--- +title: VM Bridge Contracts +sidebar_position: 15 +sidebar_label: VM Bridge +description: Learn about Flow's bridge contracts that manage bridging tokens between the Cadence and EVM environments. +keywords: + - core contracts + - transaction fees + - EVM + - bridge + - fungible tokens + - non fungible tokens + - nft +--- + +The Flow VM bridge is the account and series of smart contracts that manage how +assets are safely bridged between the Cadence and EVM Flow Environments. + +| Network | Contract Address | +| ------------------------- | -------------------- | +| Emulator | `0xf8d6e0586b0a20c7` | +| Cadence Testing Framework | `0x0000000000000001` | +| Testnet | `0xdfc20aee650fcbdf` | +| Mainnet | `0x1e4aa0b87d10b141` | + +# Contracts + +There are many important contracts deployed to the bridge account. +You should refer to [the bridge repo](https://github.com/onflow/flow-evm-bridge) +and [the bridge guides](../../tutorials/cross-vm-apps/vm-bridge.md) +for more detailed information about the bridge and tutorials for how to use the bridge properly. + +Here is a list of each Cadence contract used for the bridge: + +| Contract | Purpose | +| ------------------------------------- | --------------------------------------------------------------------------------------------------------- | +| `CrossVMNFT` | Contract defining cross-VM NFT-related interfaces | +| `CrossVMToken` | Contract defining cross-VM Fungible Token Vault interface | +| `FlowEVMBridgeHandlerInterfaces` | Defines interface for custom bridged token handlers | +| `IBridgePermissions` | Defines an interface to prevent bridging for a specific token | +| `ICrossVM` | Defines an interface to get EVM contract addresses | +| `ICrossVMAsset` | Defines an interface to represent a Cadence bridged version of an EVM asset | +| `IEVMBridgeNFTMinter` | Defines an interface that allows the bridge to mint NFTs | +| `IEVMBridgeTokenMinter` | Defines an interface that allows the bridge to mint FTs | +| `IFlowEVMNFTBridge` | Defines core methods for bridging NFTs | +| `IFlowEVMTokenBridge` | Defines core methods for bridging FTs | +| `FlowEVMBridge` | The main entrypoint for briding tokens across Flow VMs | +| `FlowEVMBridgeAccessor` | Defines methods to route bridge requests from the EVM contract to the Flow-EVM bridge contract | +| `FlowEVMBridgeConfig` | Used to store configuration options for the VM Bridge | +| `FlowEVMBridgeCustomAssociations` | Stores configuration information about custom bridged asset configurations | +| `FlowEVMBridgeCustomAssociationTypes` | Defines interfaces used to specify custom bridged asset associations | +| `FlowEVMBridgeHandlers` | Defines mechanisms for handling assets with custom associations (Deprecated) | +| `FlowEVMBridgeNFTEscrow` | Handles locking of NFTs that are bridged from Flow to EVM and back | +| `FlowEVMBridgeResolver` | Defines methods to resolve Metadata Views for bridged assets | +| `FlowEVMBridgeTemplates` | Serves Cadence code from chunked templates for bridge-deployed assets | +| `FlowEVMBridgeTokenEscrow` | Handles locking of FTs that are bridged from Flow to EVM and back | +| `FlowEVMBridgeUtils` | Defines many different utility methods that are used by bridge contracts | +| `ArrayUtils` | Provides useful utility functions for manipulating arrays | +| `ScopedFTProviders` | Provides utilities for creating provider capabilities for tokens that are restricted to a specific amount | +| `Serialize` | Provides utilities for serializing common types to json-compatible strings | +| `SerializeMetadata` | Provides methods for serializing NFT metadata as a JSON compatible string | +| `StringUtils` | Provides useful utility functions for manipulating strings | + +# EVM Bridge Solidity Contracts + +There are also Solidity contracts that are deployed in Flow EVM that are needed for the bridge. +Here are their addresses: + +| Contracts | Testnet | Mainnet | +| ------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- | +| `FlowEVMBridgeFactory.sol` | [`0xf8146b4aef631853f0eb98dbe28706d029e52c52`](https://evm-testnet.flowscan.io/address/0xF8146B4aEF631853F0eB98DBE28706d029e52c52) | [`0x1c6dea788ee774cf15bcd3d7a07ede892ef0be40`](https://evm.flowscan.io/address/0x1C6dEa788Ee774CF15bCd3d7A07ede892ef0bE40) | +| `FlowEVMBridgeDeploymentRegistry.sol` | [`0x8781d15904d7e161f421400571dea24cc0db6938`](https://evm-testnet.flowscan.io/address/0x8781d15904d7e161f421400571dea24cc0db6938) | [`0x8fdec2058535a2cb25c2f8cec65e8e0d0691f7b0`](https://evm.flowscan.io/address/0x8FDEc2058535A2Cb25C2f8ceC65e8e0D0691f7B0) | +| `FlowEVMBridgedERC20Deployer.sol` | [`0x4d45CaD104A71D19991DE3489ddC5C7B284cf263`](https://evm-testnet.flowscan.io/address/0x4d45CaD104A71D19991DE3489ddC5C7B284cf263) | [`0x49631Eac7e67c417D036a4d114AD9359c93491e7`](https://evm.flowscan.io/address/0x49631Eac7e67c417D036a4d114AD9359c93491e7) | +| `FlowEVMBridgedERC721Deployer.sol` | [`0x1B852d242F9c4C4E9Bb91115276f659D1D1f7c56`](https://evm-testnet.flowscan.io/address/0x1B852d242F9c4C4E9Bb91115276f659D1D1f7c56) | [`0xe7c2B80a9de81340AE375B3a53940E9aeEAd79Df`](https://evm.flowscan.io/address/0xe7c2B80a9de81340AE375B3a53940E9aeEAd79Df) | + +And below are the bridge escrow's EVM addresses. These addresses are [`CadenceOwnedAccount`s (COA)](https://developers.flow.com/tutorials/cross-vm-apps/interacting-with-coa#coa-interface) and they are stored stored in the same Flow account as you'll find the Cadence contracts (see above). + +| Network | Address | +| ------- | ---------------------------------------------------------------------------------------------------------------------------------- | +| Testnet | [`0x0000000000000000000000023f946ffbc8829bfd`](https://evm-testnet.flowscan.io/address/0x0000000000000000000000023f946FFbc8829BFD) | +| Mainnet | [`0x00000000000000000000000249250a5c27ecab3b`](https://evm.flowscan.io/address/0x00000000000000000000000249250a5C27Ecab3B) | + + +=== build/core-contracts/14-burner.md === +--- +title: Flow Burner Contract Address +sidebar_position: 14 +sidebar_label: Burner +description: Learn about Flow's Burner contract that enables custom destruction logic for resources. Understand how to implement the Burnable interface and safely destroy resources with custom callbacks. +keywords: + - resource burning + - Burner contract + - resource destruction + - burn callback + - Burnable interface + - resource management + - Flow resources + - custom destruction + - safe burning + - resource cleanup + - Flow protocol + - contract safety + - resource lifecycle + - destruction logic + - burn operations +--- + +# Contract + +The [Burner](https://github.com/onflow/flow-ft/blob/master/contracts/utility/Burner.cdc) contract provides a way for resources to define +custom logic that is executed when the resource is destroyed. +Resources that want to utilize this functionality should implement +the `Burner.Burnable` interface which requires that they include +a `burnCallback()` function that includes the custom logic. + +It is recommended that regardless of the resource, all users and developers +should use `Burner.burn()` when destroying a resource instead of `destroy`. + +| Network | Contract Address | +| ------- | ------------------------------------------------------------------------------ | +| Cadence Testing Framework | `0x0000000000000001` | +| Emulator | `0xee82856bf20e2aa6` | +| Testnet | [`0x294e44e1ec6993c6`](https://contractbrowser.com/account/0x294e44e1ec6993c6) | +| Mainnet | [`0xd8a7e05a7ac670c0`](https://contractbrowser.com/account/0xd8a7e05a7ac670c0) | + +=== build/core-contracts/13-evm.md === +--- +title: Flow EVM +sidebar_position: 13 +sidebar_label: EVM +description: Learn about Flow's EVM contract that enables Ethereum Virtual Machine compatibility on Flow. Understand how to interact with EVM from Cadence and access Flow's EVM equivalence features. +keywords: + - Flow EVM + - EVM compatibility + - Ethereum Virtual Machine + - EVM tooling + - Cadence EVM + - EVM contract + - EVM integration + - blockchain interop + - smart contracts + - EVM equivalence + - contract deployment + - Flow protocol + - cross-chain + - EVM support + - FLIP 223 +--- + +# Contract + +The `EVM` contract is the entrypoint from Cadence to Flow EVM. While many developers may choose to interact with EVM +via [EVM-equivalent tooling paths](../../evm/using.mdx), all access to Flow EVM ultimately interfaces via Cadence at +some level. + +If you would like to interact with EVM directly from Cadence, you can use the `EVM` contract and it's constructs. Read +more about the EVM contract and its role in Flow's EVM equivalence in [FLIP +#223](https://github.com/onflow/flips/blob/main/protocol/20231116-evm-support.md). + +Mainnet/Testnet Source: [`EVM.cdc`](https://github.com/onflow/flow-go/blob/master/fvm/evm/stdlib/contract.cdc) + +| Network | Contract Address | +| ------------------------- | -------------------------------------------------------------------------- | +| Emulator | `0xf8d6e0586b0a20c7` | +| Cadence Testing Framework | `0x0000000000000001` | +| Testnet | [`0x8c5303eaa26202d6`](https://contractbrowser.com/A.8c5303eaa26202d6.EVM) | +| Mainnet | [`0xe467b9dd11fa00df`](https://contractbrowser.com/A.e467b9dd11fa00df.EVM) | + + +=== build/core-contracts/12-hybrid-custody.md === +--- +title: Flow Account Linking Contract Address +sidebar_position: 12 +sidebar_label: Account Linking +description: Learn about Flow's Account Linking contracts that enable hybrid custody solutions. Understand how to manage child accounts and share specific resources between parent and child accounts securely. +keywords: + - account linking + - hybrid custody + - child accounts + - parent accounts + - account management + - resource sharing + - custody solution + - account security + - wallet integration + - Flow accounts + - contract browser + - account permissions + - resource access + - account control + - custody model +--- + +# Contract + +The Account Linking contracts manage ChildAccounts to permit hybrid custody in scenarios where apps only want to share a subset of resources on their accounts with various parents. In many cases, this will be a user's primary wallet outside of the application a child account came from. + +You can see the docs for account linking [here](https://developers.flow.com/build/advanced-concepts/account-linking) + +| Network | Contract Address | +| ------- | ------------------------------------------------------------------------------ | +| Testnet | [`0x294e44e1ec6993c6`](https://contractbrowser.com/account/0x294e44e1ec6993c6) | +| Mainnet | [`0xd8a7e05a7ac670c0`](https://contractbrowser.com/account/0xd8a7e05a7ac670c0) | + + +=== build/core-contracts/11-staking-collection.md === +--- +title: Flow Staking Collection Contract Reference +sidebar_position: 11 +sidebar_label: Staking Collection +description: Learn about Flow's Staking Collection contract that manages user stake and delegation resources. Understand how to interact with nodes, delegators, and locked tokens through the collection interface. +keywords: + - staking collection + - Flow staking + - node management + - delegation + - locked tokens + - machine accounts + - staking operations + - node registration + - delegator registration + - stake management + - token delegation + - staking interface + - Flow protocol + - staking transactions + - collection events +--- + +# Contract + +The `FlowStakingCollection` contract is a contract that manages a resource containing a user's stake and delegation objects. + +The `FlowStakingCollection` allows a user to manage multiple active nodes or delegators +and interact with node or delegator objects stored in either their optional locked account +or in the StakingCollection itself (stored in the main account). +If a user has locked tokens, StakingCollection allows a user to interact with their locked tokens +to perform staking actions for any of their nodes or delegators. + +The staking collection also manages creating a node's machine accounts if they have any collector or consensus nodes. +It also allows them to deposit and withdraw tokens from any of their machine accounts through the staking collection. + +See the [Staking Collection Docs](../../networks/staking/14-staking-collection.md) for more information on the design of the staking collection contract. + +Source: [FlowStakingCollection.cdc](https://github.com/onflow/flow-core-contracts/blob/master/contracts/FlowStakingCollection.cdc) + +| Network | Contract Address | +| ------------------------- | -------------------- | +| Emulator | `0xf8d6e0586b0a20c7` | +| Cadence Testing Framework | `0x0000000000000001` | +| Testnet | `0x95e019a17d0e23d7` | +| Mainnet | `0x8d0e87b65159ae63` | + +## Transactions + +Use the following transactions to interact with the StakingCollection. + +\_Note: The StakingCollection differentiates between stake and delegation requests through +passing an optional DelegatorID argument. For example, if you wish to Stake New Tokens for an active node, +pass `nil` as the optional DelegatorID argument to the Stake New Tokens transaction. +The same applies for all the other staking operation transactions. + +| ID | Name | Source | +| ------------ | ----------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **`SCO.01`** | Setup Staking Collection | [stakingCollection/setup_staking_collection.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/stakingCollection/setup_staking_collection.cdc) | +| **`SCO.02`** | Register Delegator | [stakingCollection/register_delegator.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/stakingCollection/register_delegator.cdc) | +| **`SCO.03`** | Register Node | [stakingCollection/register_node.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/stakingCollection/register_node.cdc) | +| **`SCO.04`** | Create Machine Account | [stakingCollection/create_machine_account.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/stakingCollection/create_machine_account.cdc) | +| **`SCO.05`** | Request Unstaking | [stakingCollection/request_unstaking.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/stakingCollection/request_unstaking.cdc) | +| **`SCO.06`** | Stake New Tokens | [stakingCollection/stake_new_tokens.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/stakingCollection/stake_new_tokens.cdc) | +| **`SCO.07`** | Stake Rewarded Tokens | [stakingCollection/stake_rewarded_tokens.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/stakingCollection/stake_rewarded_tokens.cdc) | +| **`SCO.08`** | Stake Unstaked Tokens | [stakingCollection/stake_unstaked_tokens.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/stakingCollection/stake_unstaked_tokens.cdc) | +| **`SCO.09`** | Unstake All | [stakingCollection/unstake_all.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/stakingCollection/unstake_all.cdc) | +| **`SCO.10`** | Withdraw Rewarded Tokens | [stakingCollection/withdraw_rewarded_tokens.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/stakingCollection/withdraw_rewarded_tokens.cdc) | +| **`SCO.11`** | Withdraw Unstaked Tokens | [stakingCollection/withdraw_unstaked_tokens.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/stakingCollection/withdraw_unstaked_tokens.cdc) | +| **`SCO.12`** | Close Stake | [stakingCollection/close_stake.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/stakingCollection/close_stake.cdc) | +| **`SCO.13`** | Transfer Node | [stakingCollection/transfer_node.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/stakingCollection/transfer_node.cdc) | +| **`SCO.14`** | Transfer Delegator | [stakingCollection/transfer_delegator.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/stakingCollection/transfer_delegator.cdc) | +| **`SCO.15`** | Withdraw From Machine Account | [stakingCollection/withdraw_from_machine_account.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/stakingCollection/withdraw_from_machine_account.cdc) | +| **`SCO.22`** | Update Networking Address | [stakingCollection/update_networking_address.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/stakingCollection/update_networking_address.cdc) | + +## Scripts + +| ID | Name | Source | +| ------------ | ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **`SCO.16`** | Get All Delegator Info | [stakingCollection/scripts/get_all_delegator_info.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/stakingCollection/scripts/get_all_delegator_info.cdc) | +| **`SCO.15`** | Get All Node Info | [stakingCollection/scripts/get_all_node_info.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/stakingCollection/scripts/get_all_node_info.cdc) | +| **`SCO.22`** | Get Delegator Ids | [stakingCollection/scripts/get_delegator_ids.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/stakingCollection/scripts/get_delegator_ids.cdc) | +| **`SCO.17`** | Get Node Ids | [stakingCollection/scripts/get_node_ids.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/stakingCollection/scripts/get_node_ids.cdc) | +| **`SCO.18`** | Get Does Stake Exist | [stakingCollection/scripts/get_does_stake_exist.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/stakingCollection/scripts/get_does_stake_exist.cdc) | +| **`SCO.19`** | Get Locked Tokens Used | [stakingCollection/scripts/get_locked_tokens_used.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/stakingCollection/scripts/get_locked_tokens_used.cdc) | +| **`SCO.20`** | Get Unlocked Tokens Used | [stakingCollection/scripts/get_unlocked_tokens_used.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/stakingCollection/scripts/get_unlocked_tokens_used.cdc) | +| **`SCO.21`** | Get Machine Accounts | [stakingCollection/scripts/get_machine_accounts.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/stakingCollection/scripts/get_machine_accounts.cdc) | + +## Setup Transaction + +To setup the Staking Collection for an account, use the `SC.01` transaction. + +The setup process finds any node or delegator records already stored in the main account's storage, +as well as any in the associated locked account if an associated locked account exists. +It connects these node and delegator records with the new Staking Collection, allowing them +to be interacted with using the Staking Collection API. + +## Events + +The `StakingCollection` contract emits an event whenever an important action occurs. + +```cadence + access(all) event NodeAddedToStakingCollection(nodeID: String, role: UInt8, amountCommitted: UFix64, address: Address?) + access(all) event DelegatorAddedToStakingCollection(nodeID: String, delegatorID: UInt32, amountCommitted: UFix64, address: Address?) + + access(all) event NodeRemovedFromStakingCollection(nodeID: String, role: UInt8, address: Address?) + access(all) event DelegatorRemovedFromStakingCollection(nodeID: String, delegatorID: UInt32, address: Address?) + + access(all) event MachineAccountCreated(nodeID: String, role: UInt8, address: Address) +``` + + +=== build/core-contracts/10-nft-storefront.md === +--- +title: NFT Storefront Smart Contract +sidebar_position: 10 +sidebar_label: NFT Storefront +description: Learn about Flow's NFT Storefront contracts that enable non-custodial NFT marketplaces. Understand how to list NFTs for sale, handle purchases, manage commissions, and implement creator royalties. +keywords: + - NFT marketplace + - NFT storefront + - NFT listings + - NFT sales + - creator royalties + - marketplace commission + - non-custodial + - NFT trading + - NFT commerce + - listing management + - sale cuts + - NFT purchases + - marketplace integration + - NFT transactions + - Flow marketplace +--- + +The `NFTStorefront` contracts implement a standard way to list NFTs for sale +and buy them from listings. `NFTStorefrontV2` is the more powerful and full-featured +version, so developers and users are encouraged to use it instead of `NFTStorefront` +or their own implementation. + +Source: [NFTStorefrontV2.cdc] + +| Network | Contract Address | +| ------- | -------------------- | +| Testnet | `0x2d55b98eb200daef` | +| Mainnet | `0x4eb8a10cb9f87357` | + +Source: [NFTStorefront.cdc] + +| Network | Contract Address | +| ------- | -------------------- | +| Testnet | `0x94b06cfca1d8a476` | +| Mainnet | `0x4eb8a10cb9f87357` | + +## Primer + +The `NFTStorefrontV2` contract lets you create a _non-custodial Resource (NFT) marketplace_ on the FLOW blockchain. + +`NFTStorefrontV2` makes it simple for Sellers to list NFTs in dApp specific marketplaces. DApp developers leverage the APIs provided by the contract to manage listings being offered for sale and to transact NFT trades. + +![dapps_1](https://user-images.githubusercontent.com/14581509/191749748-714f9d8f-cb41-4be4-a3d2-ec84cb8b5ffb.png) + +Developers should use the `NFTStorefrontV2` to create their marketplace and to enable p2p purchases. The diagram below shows how dApps can facilitate the creation of NFT listings for different marketplaces and how marketplaces can filter their listings. + +Listings made through a specific dApp storefront can be simultaneously listed on 3rd party marketplaces beyond that dApp. Well known 3rd party marketplaces listen for compatible NFT listing events enabling the automation of listings into their marketplace dashboards. + +![dapps_2](https://user-images.githubusercontent.com/14581509/191753605-e1c48a57-0c3c-4509-808b-8fee4e7d32e8.png) + +Using the `NFTStorefrontV2`, marketplaces can instantly and easily tap into the vibrant FLOW NFT ecosystem and allow NFT holders to list their NFTs and enables creator royalties. + +Marketplaces then process an NFT trade by interacting directly with seller storefronts. Flow's account based model ensures that NFTs listed for sale always reside in the Seller account until traded, regardless of how many listings are posted across any number of marketplaces, for the same NFT. + +![marketplace_1](https://user-images.githubusercontent.com/14581509/191755699-fe0570cb-80a3-408c-8eef-4051e3209481.png) + +## Functional Overview + +A general purpose sale support contract for NFTs implementing the Flow [`NonFungibleToken`] standard. +Each account that wants to list NFTs for sale creates a `Storefront` resource to store in their account and lists individual sales within that Storefront as Listings. There is usually one Storefront per account held at the `/storage/NFTStorefrontV2`. + +Each listing can define one or more sale cuts taken out of the sale price to go to one or more addresses. Listing fees, royalties, or other considerations can be paid using sale cuts. Also, the listing can include a commission as one of these sale cuts is paid to whoever facilitates the purchase. + +Listings can have an optional list of marketplace [receiver capabilities] used to receive the commission for fulfilling the listing. An NFT may be listed in one or more Listings, and the validity of each listing can easily be checked. + +Interested parties can globally track Listing events on-chain and filter by NFT types, IDs and other characteristics to determine which to make available for purchase within their own marketplace UIs." + +## Selling NFTs + +`NFTStorefrontV2` offers a generic process for creating the listing for an NFT. It provides all the essential APIs to manage those listings independently. + +Many marketplaces create a single storefront resource to manage different individual listings. We recommend creating the listing under the user-owned storefront resource to make it trustless and platform-independent. Users should possess the `Storefront` resource under their account to create the listing using the storefront contract. + +## Creating a successful listing using the NFTStorefrontV2 contract. + +As recommended above, the first step is to create and store the [Storefront resource] in the user account using the [setup_account] transaction. + +The next step is to create a listing under the newly created storefront resource. If the user (repetitive) already holds the storefront resource, then use the existing resource. The seller can come with multiple requirements for listing their NFTs, and We try our best to cover most of them below. + +### **Scenario 1:** Selling NFTs corresponds to more than one cryptocurrency, i.e. FLOW, USDC etc. + +The `NFTStorefrontV2` contract doesn't support selling an NFT for multiple different currencies with a single listing. However, this can be achieved by creating multiple listings for the same NFT for each different currency. + +**Example -** Alice wants to sell a kitty and is open to receiving FLOW and USDC + +![scenario_1](./scenario_1.png) + +Putting an NFT on sell called listing, seller can create a listing using [sell_item] transaction by providing some required details to list an NFT, i.e. Receiving currency type, [Capability] from where NFT will be deducted etc. If interested look [`createListing`] for more details. + +To receive a different currency seller has to provide a different **Receiver currency type** , i.e. `salePaymentVaultType` As depicted in the above diagram, There are two listing formations with almost the same inputs. The only differentiator is the `salePaymentVaultType` parameter that needs to be different when creating duplicate NFT listings with different sale currency types. + +### **Scenario 2:** Peer-to-Peer (p2p) listing of NFT: A listing anyone can fulfil. + +Dapps can leverage the **NFTStorefrontV2** to facilitate the creation of a listing for the seller independent of any marketplace. Dapps or marketplaces can list those listings on their platforms, or seller can settle it p2p. + +The seller can use [sell_item] transaction to create a p2p listing, providing the `marketplacesAddress` with an empty array. The seller has a choice of providing [commission] to the facilitator of sale, which can also act as a discount if the facilitator and the purchaser are the same. + +### **Scenario 3:** The seller wants to list its NFT in different marketplaces. + +`NFTStorefrontV2` offers two different ways of doing it. + +- The seller can create a listing and provide the `marketplacesAddress` that it wants to have a listing on using [sell_item] transaction. + + Marketplaces can listen to `ListingAvailable` events and check whether their address is included in the `commissionReceivers` list; If yes, the marketplace would be rewarded during the successful fulfilment of the listing. + + Example - Bob wants to list on marketplace 0xA, 0xB & 0xC and is willing to offer 10% commission on the sale price of the listing to the marketplaces. + + ![scenario_3](https://user-images.githubusercontent.com/14581509/190966834-8eda4ec4-e9bf-49ef-9dec-3c47a236d281.png) + +- Another way to accomplish this is to create separate listings for each marketplace on which a user wants their listing using [sell_item_with_marketplace_cut] transaction. In this case, the marketplace would be incentivized by earning one of the parts of the [`saleCut`] by appending marketplace saleCut in `saleCuts` array during the creation of the listing. + +### Considerations + +1. **Ghost listings -** _Ghost listings are listings which don't have an underlying NFT in the seller's account. However, the listing is still available for buyers to attempt to purchase_. StorefrontV2 is not immune to ghost listings. Usually, ghost listings will cause a purchaser's transaction to fail, which is annoying but isn't a significant problem. Ghost listings become a problem for the seller when the listed NFT comes back to the seller's account after its original sale. The ghost listing will no longer be invalid when it comes back, and anyone can purchase it even if the seller doesn't want to sell it at that price anymore. + + **Note -** _We recommend that marketplaces and p2p dApps create an off-chain notification service that tells their users (i.e., sellers) to remove the listings if they don't hold the NFT anymore in the same account._ + +2. **Expired listings -** `NFTStorefrontV2` introduces a safety measure to specify that a listing will expire after a certain period that can be set during the creation so no one can purchase the listing anymore. It is not a fool-proof safety measure, but it does give some safe ground to the sellers for the ghost listings & stale listings. + + **Note -** _We recommended for marketplaces and p2p dApps not to show the expired listings on their dashboards._ + +## Purchasing NFTs + +Purchasing NFTs through the `NFTStorefrontV2` is simple. The buyer has to provide the payment vault and the `commissionRecipient` , if applicable, during the purchase. p2p dApps don't need any intermediaries to facilitate the purchase of listings. [`purchase`] API offered by the `Listing` resource gets used to facilitate the purchase of NFT. + +During the listing purchase all saleCuts are paid automatically. This also includes distributing royalties for that NFT, if applicable. If the vault provided by the buyer lacks sufficient funds then the transaction will fail. + +### Considerations + +1. **Auto cleanup -** `NFTStorefrontV2` offers a unique ability to do auto cleanup of duplicate listings during a purchase. It comes with a drawback if one NFT has thousands of duplicate listings. It will become the bottleneck during purchasing one of the listings as it will likely trigger an out-of-gas error. + + **Note -** _We recommended NOT to have more than 50 (TBD) duplicate listings of any given NFT._ + +2. **Unsupported receiver capability** - A common pitfall during the purchase of an NFT that some saleCut receivers don't have a supported receiver capability because that entitled sale cut would transfer to first valid sale cut receiver. However, it can be partially solved by providing the generic receiver using the [`FungibleTokenSwitchboard`] contract and adding all the currency capabilities the beneficiary wants to receive. More on the `FungibleTokenSwitchboard` can be read in [Fungible Token Switchboard] + +## Enabling creator royalties for NFTs + +The `NFTStorefrontV2` contract optionally supports paying royalties to the minter account for secondary resales of that NFT after the original sale. Marketplaces decide for themselves whether to support creator royalties when validating listings for sale eligibility. We encourage all marketplaces to support creator royalties and support community creators in the **FLOW** ecosystem. + +Providing that a seller's NFT supports the [Royalty Metadata View] standard, then marketplaces can honor royalties payments at time of purchase. `NFTStorefrontV2` dynamically calculates the royalties owed at the time of listing creation and applies it as a saleCut of the listing at the time of purchase. + +```cadence +// Check whether the NFT implements the MetadataResolver or not. +if nft.getViews().contains(Type()) { + // Resolve the royalty view + let royaltiesRef = nft.resolveView(Type()) + ?? panic("Unable to retrieve the royalties view for the NFT with type " + .concat(nft.getType().identifier).concat(" and ID ") + .concat(nft.id.toString()).concat(".") + // Fetch the royalties. + let royalties = (royaltiesRef as! MetadataViews.Royalties).getRoyalties() + + // Append the royalties as the salecut + for royalty in royalties { + self.saleCuts.append(NFTStorefrontV2.SaleCut(receiver: royalty.receiver, amount: royalty.cut * effectiveSaleItemPrice)) + totalRoyaltyCut = totalRoyaltyCut + royalty.cut * effectiveSaleItemPrice + } +} +``` + +Complete transaction can be viewed in [sell_item]. + +saleCut only supports a single token receiver type and therefore beneficiaries of a `saleCut` can also only receive the token type used for the purchase. To support different token types for saleCuts we recommend using the [`FungibleTokenSwitchboard`] contract. The contract defines a generic receiver for fungible tokens which itself handles routing of tokens to the respective vault for that token type. Learn more about this in [Fungible Token Switchboard]. + +## Enabling marketplace commissions for NFT sales + +`NFTStorefrontV2` enables optional commissions on trades for marketplaces which require it as a condition to list a NFT for sale. Commission & commission receivers are set by the seller during initial listing creation. At time of purchase the commission amount is paid once only to the commission receiver matching the marketplace receiver address which facilitated the sale. + +For NFT listings in marketplaces which don't require commission, commission receivers can be set as nil. Setting the buyer of the NFT and `commissionRecipient` to the same has the effect of applying a discount for the buyer. + +![scenario_2](https://user-images.githubusercontent.com/14581509/190966499-c176203f-b6a6-4422-860f-1bf6f2bcdbb6.png). + +## APIs & Events offered by NFTStorefrontV2 + +## Resource Interface `ListingPublic` + +```cadence +resource interface ListingPublic { + access(all) fun borrowNFT(): &NonFungibleToken.NFT? + access(all) fun purchase( + payment: @FungibleToken.Vault, + commissionRecipient: Capability<&{FungibleToken.Receiver}>?, + ): @NonFungibleToken.NFT + access(all) fun getDetails(): ListingDetail + access(all) fun getAllowedCommissionReceivers(): [Capability<&{FungibleToken.Receiver}>]? +} +``` + +An interface providing a useful public interface to a Listing. + +### Functions + +#### **fun `borrowNFT()`** + +```cadence +fun borrowNFT(): &NonFungibleToken.NFT? +``` + +This will assert in the same way as the NFT standard borrowNFT() +if the NFT is absent, for example if it has been sold via another listing. + +--- + +#### **fun `purchase()`** + +```cadence +fun purchase(payment FungibleToken.Vault, commissionRecipient Capability<&{FungibleToken.Receiver}>?): NonFungibleToken.NFT +``` + +Facilitates the purchase of the listing by providing the payment vault +and the commission recipient capability if there is a non-zero commission for the given listing. +Respective saleCuts are transferred to beneficiaries and funtion return underlying or listed NFT. + +--- + +#### **fun `getDetails()`** + +```cadence +fun getDetails(): ListingDetails +``` + +Fetches the details of the listings + +--- + +#### **fun `getAllowedCommissionReceivers()`** + +```cadence +fun getAllowedCommissionReceivers(): [Capability<&{FungibleToken.Receiver}>]? +``` + +Fetches the allowed marketplaces capabilities or commission receivers for the underlying listing. +If it returns `nil` then commission is up to grab by anyone. + +--- + +## Resource `Storefront` + +```cadence +resource Storefront { + access(all) fun createListing( + nftProviderCapability: Capability<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic}>, + nftType: Type, + nftID: UInt64, + salePaymentVaultType: Type, + saleCuts: [SaleCut], + marketplacesCapability: [Capability<&{FungibleToken.Receiver}>]?, + customID: String?, + commissionAmount: UFix64, + expiry: UInt64 + ): UInt64 + access(all) fun removeListing(listingResourceID: UInt64) + access(all) fun getListingIDs(): [UInt64] + access(all) fun getDuplicateListingIDs(nftType: Type, nftID: UInt64, listingID: UInt64): [UInt64] + access(all) fun cleanupExpiredListings(fromIndex: UInt64, toIndex: UInt64) + access(all) fun borrowListing(listingResourceID: UInt64): &Listing{ListingPublic}? +} +``` + +A resource that allows its owner to manage a list of Listings, and anyone to interact with them +in order to query their details and purchase the NFTs that they represent. + +Implemented Interfaces: + +- `StorefrontManager` +- `StorefrontPublic` + +### Initializer + +```cadence +fun init() +``` + +### Functions + +#### **fun `createListing()`** + +```cadence +fun createListing(nftProviderCapability Capability<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic}>, nftType Type, nftID UInt64, salePaymentVaultType Type, saleCuts [SaleCut], marketplacesCapability [Capability<&{FungibleToken.Receiver}>]?, customID String?, commissionAmount UFix64, expiry UInt64): UInt64 +``` + +insert +Create and publish a Listing for an NFT. + +--- + +#### **fun `removeListing()`** + +```cadence +fun removeListing(listingResourceID UInt64) +``` + +removeListing +Remove a Listing that has not yet been purchased from the collection and destroy it. + +--- + +#### **fun `getListingIDs()`** + +```cadence +fun getListingIDs(): [UInt64] +``` + +getListingIDs +Returns an array of the Listing resource IDs that are in the collection + +--- + +#### **fun `getDuplicateListingIDs()`** + +```cadence +fun getDuplicateListingIDs(nftType Type, nftID UInt64, listingID UInt64): [UInt64] +``` + +getDuplicateListingIDs +Returns an array of listing IDs that are duplicates of the given `nftType` and `nftID`. + +--- + +#### **fun `cleanupExpiredListings()`** + +```cadence +fun cleanupExpiredListings(fromIndex UInt64, toIndex UInt64) +``` + +cleanupExpiredListings +Cleanup the expired listing by iterating over the provided range of indexes. + +--- + +#### **fun `borrowListing()`** + +```cadence +fun borrowListing(listingResourceID: UInt64): &{ListingPublic}? +``` + +borrowListing +Returns a read-only view of the listing for the given listingID if it is contained by this collection. + +--- + +## Resource Interface `StorefrontPublic` + +```cadence +resource interface StorefrontPublic { + access(all) fun getListingIDs(): [UInt64] + access(all) fun getDuplicateListingIDs(nftType: Type, nftID: UInt64, listingID: UInt64): [UInt64] + access(all) fun cleanupExpiredListings(fromIndex: UInt64, toIndex: UInt64) + access(all) fun borrowListing(listingResourceID: UInt64): &Listing{ListingPublic}? + access(all) fun cleanupPurchasedListings(listingResourceID: UInt64) + access(all) fun getExistingListingIDs(nftType: Type, nftID: UInt64): [UInt64] +} +``` + +StorefrontPublic +An interface to allow listing and borrowing Listings, and purchasing items via Listings +in a Storefront. + +### Functions + +#### **fun `getListingIDs()`** + +```cadence +fun getListingIDs(): [UInt64] +``` + +getListingIDs Returns an array of the Listing resource IDs that are in the collection + +--- + +#### **fun `getDuplicateListingIDs()`** + +```cadence +fun getDuplicateListingIDs(nftType Type, nftID UInt64, listingID UInt64): [UInt64] +``` + +getDuplicateListingIDs Returns an array of listing IDs that are duplicates of the given nftType and nftID. + +--- + +#### **fun `borrowListing()`** + +```cadence +fun borrowListing(listingResourceID UInt64): &Listing{ListingPublic}? +``` + +borrowListing Returns a read-only view of the listing for the given listingID if it is contained by this collection. + +--- + +#### **fun `cleanupExpiredListings()`** + +```cadence +fun cleanupExpiredListings(fromIndex UInt64, toIndex UInt64) +``` + +cleanupExpiredListings Cleanup the expired listing by iterating over the provided range of indexes. + +--- + +#### **fun `cleanupPurchasedListings()`** + +```cadence +fun cleanupPurchasedListings(listingResourceID: UInt64) +``` + +cleanupPurchasedListings +Allows anyone to remove already purchased listings. + +--- + +#### **fun `getExistingListingIDs()`** + +```cadence +fun getExistingListingIDs(nftType Type, nftID UInt64): [UInt64] +``` + +getExistingListingIDs +Returns an array of listing IDs of the given `nftType` and `nftID`. + +--- + +## Events + +**event `StorefrontInitialized`** + +```cadence +event StorefrontInitialized(storefrontResourceID: UInt64) +``` + +A Storefront resource has been created. Consumers can now expect events from this Storefront. Note that we do not specify an address: we cannot and should not. Created resources do not have an owner address, and may be moved +after creation in ways we cannot check. `ListingAvailable` events can be used to determine the address +of the owner of the Storefront at the time of the listing but only at that precise moment in that precise transaction. If the seller moves the Storefront while the listing is valid, that is on them. + +--- + +**event `StorefrontDestroyed`** + +```cadence +event StorefrontDestroyed(storefrontResourceID: UInt64) +``` + +A Storefront has been destroyed. Event consumers can now stop processing events from this Storefront. +Note - we do not specify an address. + +--- + +**event `ListingAvailable`** + +```cadence +event ListingAvailable(storefrontAddress: Address, listingResourceID: UInt64, nftType: Type, nftUUID: UInt64, nftID: UInt64, salePaymentVaultType: Type, salePrice: UFix64, customID: String?, commissionAmount: UFix64, commissionReceivers: [Address]?, expiry: UInt64) +``` + +Above event gets emitted when a listing has been created and added to a Storefront resource. The Address values here are valid when the event is emitted, but the state of the accounts they refer to may change outside of the +`NFTStorefrontV2` workflow, so be careful to check when using them. + +--- + +**event `ListingCompleted`** + +```cadence +event ListingCompleted(listingResourceID: UInt64, storefrontResourceID: UInt64, purchased: Bool, nftType: Type, nftUUID: UInt64, nftID: UInt64, salePaymentVaultType: Type, salePrice: UFix64, customID: String?, commissionAmount: UFix64, commissionReceiver: Address?, expiry: UInt64) +``` + +The listing has been resolved. It has either been purchased, removed or destroyed. + +--- + +**event `UnpaidReceiver`** + +```cadence +event UnpaidReceiver(receiver: Address, entitledSaleCut: UFix64) +``` + +A entitled receiver has not been paid during the sale of the NFT. + +--- + +**Holistic process flow diagram of NFTStorefrontV2 -** + +![NFT Storefront Process flow](https://user-images.githubusercontent.com/14581509/191960793-ff153e5d-2934-410c-b724-5c5dffd2c20f.png) + + + +[NFTStorefrontV2.cdc]: https://github.com/onflow/nft-storefront/blob/main/contracts/NFTStorefrontV2.cdc +[NFTStorefront.cdc]: https://github.com/onflow/nft-storefront/blob/main/contracts/NFTStorefront.cdc +[`NonFungibleToken`]: https://github.com/onflow/flow-nft/blob/master/contracts/NonFungibleToken.cdc +[receiver capabilities]: https://cadence-lang.org/docs/language/capabilities +[Storefront resource]: #resource-storefront +[setup_account]: https://github.com/onflow/nft-storefront/blob/main/transactions/setup_account.cdc +[sell_item]: https://github.com/onflow/nft-storefront/blob/main/transactions/sell_item.cdc +[Capability]: https://cadence-lang.org/docs/language/capabilities +[`createListing`]: #fun-createlisting +[Fungible Token Switchboard]: https://github.com/onflow/flow-ft#fungible-token-switchboard +[commission]: #enabling-marketplace-commissions-for-nft-sales +[sell_item_with_marketplace_cut]: https://github.com/onflow/nft-storefront/blob/main/transactions/sell_item_with_marketplace_cut.cdc +[`saleCut`]: https://github.com/onflow/nft-storefront/blob/160e97aa802405ad26a3164bcaff0fde7ee52ad2/contracts/NFTStorefrontV2.cdc#L104 +[`purchase`]: #fun-purchase +[`FungibleTokenSwitchboard`]: https://github.com/onflow/flow-ft/blob/master/contracts/FungibleTokenSwitchboard.cdc +[Royalty Metadata View]: https://github.com/onflow/flow-nft/blob/21c254438910c8a4b5843beda3df20e4e2559625/contracts/MetadataViews.cdc#L335 + +=== build/core-contracts/09-nft-metadata.md === +--- +title: NFT Metadata Contract +sidebar_position: 9 +sidebar_label: NFT Metadata +description: Learn about Flow's NFT metadata standards implemented through ViewResolver and MetadataViews contracts. Understand how to attach and manage on-chain metadata for NFTs and integrate with the Flow NFT Catalog. +keywords: + - NFT metadata + - ViewResolver + - MetadataViews + - metadata standard + - NFT catalog + - on-chain metadata + - NFT interoperability + - metadata views + - FLIP-0636 + - NFT discovery + - metadata implementation + - Flow NFT + - NFT standards + - metadata integration + - NFT optimization +--- + +The `ViewResolver` and `MetadataViews` contracts implement a standard to attach on-chain metadata +to NFTs. This standard was originally proposed in [FLIP-0636](https://github.com/onflow/flips/blob/main/application/20210916-nft-metadata.md). + +It is deployed at the same address as the `NonFungibleToken` contract interface. + +Source: [ViewResolver.cdc](https://github.com/onflow/flow-nft/blob/master/contracts/ViewResolver.cdc) + +Source: [MetadataViews.cdc](https://github.com/onflow/flow-nft/blob/master/contracts/MetadataViews.cdc) + +| Network | Contract Address | +| ------------------------- | -------------------- | +| Emulator | `0xf8d6e0586b0a20c7` | +| Cadence Testing Framework | `0x0000000000000001` | +| Testnet | `0x631e88ae7f1d7c20` | +| Mainnet | `0x1d7e57aa55817448` | + +There exists a tool, [Flow NFT Catalog](https://flow-nft-catalog.com), which enables dapp developers the ability to unlock interoperability of your NFT collection across the Flow ecosystem. This will help make your NFT collection's metadata more discoverable and interoperable. + +To optimize your NFT collections for this catalog, you'll need to: + +1. Update your NFT contract to support `ViewResolver` and `MetadataViews` with implementation of the [core NFT views](../advanced-concepts/metadata-views.md). +2. Deploy the updated contract to both testnet and mainnet. +3. Afterwards, onboard your NFT to the Flow NFT catalog at [https://flow-nft-catalog.com](https://flow-nft-catalog.com). + + +=== build/core-contracts/08-non-fungible-token.md === +--- +title: Non-Fungible Token Contract +sidebar_position: 8 +sidebar_label: Non-Fungible Token +description: Learn about Flow's Non-Fungible Token (NFT) standard contract interface, its implementation, events system, and how to build NFT contracts on Flow. Understand the core NFT functionality and event handling. +keywords: + - NFT + - non-fungible token + - NFT standard + - token contract + - NFT events + - NFT transactions + - token interface + - Flow NFT + - NFT implementation + - token collection + - NFT deposits + - NFT withdrawals + - token updates + - NFT metadata + - digital assets +--- + +The `NonFungibleToken` contract interface implements the Fungible Token Standard. +All NFT contracts are encouraged to import and implement this standard. + +- [Basic Non-Fungible Token Tutorial](https://cadence-lang.org/docs/tutorial/non-fungible-tokens-1) +- [Non Fungible Token Guide](../guides/nft.md) +- [Non Fungible Token Standard Repo](https://github.com/onflow/flow-nft) + +Source: [NonFungibleToken.cdc](https://github.com/onflow/flow-nft/blob/master/contracts/NonFungibleToken.cdc) + +| Network | Contract Address | +| ------------------------- | -------------------- | +| Emulator | `0xf8d6e0586b0a20c7` | +| Cadence Testing Framework | `0x0000000000000001` | +| Testnet | `0x631e88ae7f1d7c20` | +| Mainnet | `0x1d7e57aa55817448` | + +# Transactions + +All `NonFungibleToken` projects are encouraged to use +the generic token transactions and scripts in the `flow-nft` [repo](https://github.com/onflow/flow-nft/tree/master/transactions). +They can be used for any token that implements the non-fungible token standard properly +without changing any code besides import addresses on different networks. + +# Events + +Events emitted from all contracts follow a standard format: + +``` +A.{contract address}.{contract name}.{event name} +``` + +The components of the format are: + +- `contract address` - the address of the account the contract has been deployed to +- `contract name` - the name of the contract in the source code +- `event name` - the name of the event as declared in the source code + +## NonFungibleToken Events + +Contracts that implement the Non-Fungible Token standard get access +to standard events that are emitted every time a relevant action occurs, +like depositing and withdrawing tokens. + +This means that projects do not have to implement their own custom events +unless the standard events do not satisfy requirements they have for events. + +The `NonFungibleToken` events will have the following format: + +``` +A.{contract address}.NonFungibleToken.Deposited +A.{contract address}.NonFungibleToken.Withdrawn +``` + +Where the `contract address` is the `NonFungibleToken` address on the network being queried. +The addresses on the various networks are shown above. + +### NonFungibleToken.Deposited + +```cadence +access(all) event Deposited ( + type: String, + id: UInt64, + uuid: UInt64, + to: Address?, + collectionUUID: UInt64 +) +``` + +Whenever `deposit()` is called on a resource type that implements +`NonFungibleToken.Collection`, the `NonFungibleToken.Deposited` event is emitted +with the following arguments: + +- `type: String`: The type identifier of the token being deposited. + - Example: `A.4445e7ad11568276.TopShot.NFT` +- `id: UInt64`: The ID of the token that was deposited. Note: This may or may not be the UUID. + - Example: `173838` +- `uuid: UInt64`: The UUID of the token that was deposited. + - Example: `177021372071991` +- `to: Address?`: The address of the account that owns the Collection that received + the token. If the collection is not stored in an account, `to` will be `nil`. + - Example: `0x4445e7ad11568276` +- `collectionUUID: UInt64`: The UUID of the Collection that received the token. + - Example: `177021372071991` + +### NonFungibleToken.Withdrawn + +```cadence +access(all) event Withdrawn ( + type: String, + id: UInt64, + uuid: UInt64, + from: Address?, + providerUUID: UInt64 +) +``` + +Whenever `withdraw()` is called on a resource type that implements +`NonFungibleToken.Collection`, the `NonFungibleToken.Withdrawn` event is emitted +with the following arguments: + +- `type: String`: The type identifier of the token being withdrawn. + - Example: `A.4445e7ad11568276.TopShot.NFT` +- `id: UInt64`: The id of the token that was withdrawn. Note: May or may not be the UUID. + - Example: `113838` +- `uuid: UInt64`: The UUID of the token that was withdrawn. + - Example: `177021372071991` +- `from: Address?`: The address of the account that owns the Collection that + the token was withdrawn from. If the collection is not stored in an account, `to` will be `nil`. + - Example: `0x4445e7ad11568276` +- `providerUUID: UInt64`: The UUID of the Collection that the token was withdrawn from. + - Example: `177021372071991` + +### NonFungibleToken.Updated + +```cadence +access(all) event Updated( + type: String, + id: UInt64, + uuid: UInt64, + owner: Address? +) +``` + +Whenever a non-fungible token is updated for whatever reason, +projects should call the `NonFungibleToken.emitNFTUpdated()` function +to emit this event. It indicates to event listeners that they should query +the NFT to update any stored information they have about the NFT in their database. + +- `type: String`: The type identifier of the token that was updated. + - Example: `A.4445e7ad11568276.TopShot.NFT` +- `id: UInt64`: The ID of the token that was updated. Note: This may or may not be the UUID. + - Example: `173838` +- `uuid: UInt64`: The UUID of the token that was updated. + - Example: `177021372071991` +- `owner: Address?`: The address of the account that owns the Collection that owns + the token. If the collection is not stored in an account, `to` will be `nil`. + - Example: `0x4445e7ad11568276` + + +=== build/core-contracts/07-epoch-contract-reference.md === +--- +title: Flow Epoch Contracts Reference +sidebar_position: 7 +sidebar_label: Epoch Contracts +description: Learn about Flow's epoch-related contracts that manage network phases, quorum certificates, and distributed key generation. Understand how FlowEpoch, FlowClusterQC, and FlowDKG contracts work together. +keywords: + - epoch contracts + - FlowEpoch + - FlowClusterQC + - FlowDKG + - epoch phases + - quorum certificates + - distributed key generation + - epoch metadata + - epoch counter + - epoch scripts + - QC voting + - DKG participants + - network phases + - Flow protocol + - epoch management +--- + +# Contract + +The `FlowEpoch` contract is the state machine that manages Epoch phases and emits service events. +The `FlowClusterQC` and `FlowDKG` contracts manage the processes that happen during the Epoch Setup phase. + +These contracts are all deployed to the same account as the `FlowIDTableStaking` contract. + +Sources: + +- [FlowEpoch.cdc](https://github.com/onflow/flow-core-contracts/blob/master/contracts/epochs/FlowEpoch.cdc) +- [FlowClusterQC.cdc](https://github.com/onflow/flow-core-contracts/blob/master/contracts/epochs/FlowClusterQC.cdc) +- [FlowDKG.cdc](https://github.com/onflow/flow-core-contracts/blob/master/contracts/epochs/FlowDKG.cdc) + +| Network | Contract Address | +| ------------------------- | -------------------- | +| Emulator | `0xf8d6e0586b0a20c7` | +| Cadence Testing Framework | `0x0000000000000001` | +| Testnet | `0x9eca2b38b18b5dfe` | +| Mainnet | `0x8624b52f9ddcd04a` | + +# Transactions + +## Getting Epoch Info + +These scripts are read-only and get info about the current state of the epoch contract. + +| ID | Name | Source | +| ----------- | ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- | +| **`EP.01`** | Get Epoch Metadata | [epoch/get_epoch_metadata.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/epoch/scripts/get_epoch_metadata.cdc) | +| **`EP.02`** | Get Configurable Metadata | [epoch/get_config_metadata.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/epoch/scripts/get_config_metadata.cdc) | +| **`EP.03`** | Get Epoch Counter | [epoch/get_epoch_counter.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/epoch/scripts/get_epoch_counter.cdc) | +| **`EP.04`** | Get Epoch Phase | [epoch/get_epoch_phase.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/epoch/scripts/get_epoch_phase.cdc) | + +## Quorum Certificate Transactions and Scripts + +| ID | Name | Source | +| ----------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **`QC.01`** | Create QC Voter | [quorumCertificate/get_epoch_metadata.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/quorumCertificate/create_voter.cdc) | +| **`QC.02`** | Submit QC Vote | [quorumCertificate/get_config_metadata.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/quorumCertificate/submit_vote.cdc) | +| **`QC.03`** | Get Collector Cluster | [quorumCertificate/scripts/get_cluster.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/quorumCertificate/scripts/get_cluster.cdc) | +| **`QC.04`** | Get QC Enabled | [quorumCertificate/scripts/get_qc_enabled.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/quorumCertificate/scripts/get_qc_enabled.cdc) | +| **`QC.05`** | Get Node Has Voted | [quorumCertificate/scripts/get_node_has_voted.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/quorumCertificate/scripts/get_node_has_voted.cdc) | +| **`QC.06`** | Get QC Voting Complete | [quorumCertificate/scripts/get_voting_completed.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/quorumCertificate/scripts/get_voting_completed.cdc) | + +## DKG Transactions and Scripts + +| ID | Name | Source | +| ------------ | ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **`DKG.01`** | Create DKG Participant | [dkg/create_participant.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/dkg/create_participant.cdc) | +| **`DKG.02`** | Get Configurable Metadata | [dkg/send_whiteboard_message.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/dkg/send_whiteboard_message.cdc) | +| **`DKG.03`** | Send Final Submission | [dkg/send_final_submission.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/dkg/send_final_submission.cdc) | +| **`DKG.04`** | Get DKG Enabled | [dkg/scripts/get_dkg_enabled.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/dkg/scripts/get_dkg_enabled.cdc) | +| **`DKG.05`** | Get DKG Completed | [dkg/scripts/get_dkg_completed.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/dkg/scripts/get_dkg_completed.cdc) | +| **`DKG.06`** | Get Whiteboard Messages | [dkg/scripts/get_whiteboard_messages.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/dkg/scripts/get_whiteboard_messages.cdc) | +| **`DKG.07`** | Get Final Submissions | [dkg/scripts/get_final_submissions.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/dkg/scripts/get_final_submissions.cdc) | +| **`DKG.08`** | Get Node Has Submitted | [dkg/scripts/get_node_has_submitted.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/dkg/scripts/get_node_has_submitted.cdc) | + +# Events + +See the [epoch documentation](../../networks/staking/05-epoch-scripts-events.md) +for a list and documentation for important `FlowEpoch` events. + + +=== build/core-contracts/06-staking-contract-reference.md === +--- +title: Flow Staking Contract Reference +sidebar_position: 6 +sidebar_label: Staking Table +description: Learn about Flow's staking contract (FlowIDTableStaking) that manages staked nodes, delegation, and rewards. Understand how to interact with staking functionality through transactions and scripts. +keywords: + - staking contract + - Flow staking + - node staking + - delegation + - staking rewards + - FlowIDTableStaking + - staking scripts + - staking events + - node management + - token delegation + - staking table + - epoch events + - staking transactions + - Flow protocol + - staking requirements +--- + +## Contract + +The `FlowIDTableStaking` contract is the central table that manages staked nodes, delegation and rewards. + +Source: [FlowIDTableStaking.cdc](https://github.com/onflow/flow-core-contracts/blob/master/contracts/FlowIDTableStaking.cdc) + +| Network | Contract Address | +| ------------------------- | -------------------- | +| Emulator | `0xf8d6e0586b0a20c7` | +| Cadence Testing Framework | `0x0000000000000001` | +| Testnet | `0x9eca2b38b18b5dfe` | +| Mainnet | `0x8624b52f9ddcd04a` | + +## Transactions and Scripts + +Transactions for the staking contract are in the `flow-core-contracts` repo. +Developers and users are advised to use [the staking collection transactions](../../networks/staking/14-staking-collection.md) +to stake tokens instead of the basic transactions that are used for tests. + +### Getting Staking Info with Scripts + +These scripts are read-only and get info about the current state of the staking contract. + +| ID | Name | Source | +| ----------- | ------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **`SC.01`** | Get Delegation Cut Percentage | [idTableStaking/get_cut_percentage.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/idTableStaking/scripts/get_cut_percentage.cdc) | +| **`SC.02`** | Get Minimum Stake Requirements | [idTableStaking/get_stake_requirements.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/idTableStaking/scripts/get_stake_requirements.cdc) | +| **`SC.03`** | Get Total Weekly Reward Payout | [idTableStaking/get_weekly_payout.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/idTableStaking/scripts/get_weekly_payout.cdc) | +| **`SC.04`** | Get Current Staked Node Table | [idTableStaking/get_current_table.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/idTableStaking/scripts/get_current_table.cdc) | +| **`SC.05`** | Get Proposed Staked Node Table | [idTableStaking/get_proposed_table.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/idTableStaking/scripts/get_proposed_table.cdc) | +| **`SC.06`** | Get Total Flow Staked | [idTableStaking/get_total_staked.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/idTableStaking/scripts/get_total_staked.cdc) | +| **`SC.07`** | Get Total Flow Staked by Node Type | [idTableStaking/get_total_staked_by_type.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/idTableStaking/scripts/get_total_staked_by_type.cdc) | +| **`SC.08`** | Get All Info about a single NodeID | [idTableStaking/get_node_info.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/idTableStaking/scripts/get_node_info.cdc) | +| **`SC.09`** | Get a node's total Commitment (delegators) | [idTableStaking/get_node_total_commitment.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/idTableStaking/scripts/get_node_total_commitment.cdc) | +| **`SC.10`** | Get All Info about a single Delegator | [idTableStaking/delegation/get_delegator_info.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/idTableStaking/delegation/get_delegator_info.cdc) | +| **`SC.11`** | Get a node's total Commitment | [idTableStaking/get_node_total_commitment_without_delegators.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/idTableStaking/scripts/get_node_total_commitment_without_delegators.cdc) | + +### Delegator Transactions + +Documentation for delegating with tokens is described in the staking documentation +for [the staking collection](../../networks/staking/14-staking-collection.md) + +## Events + +The `FlowIDTableStaking` contract emits an event whenever an important action occurs. +See the [staking events Documentation](../../networks/staking/07-staking-scripts-events.md) for more information about each event. + +```cadence + /// Epoch + access(all) event NewEpoch( + totalStaked: UFix64, + totalRewardPayout: UFix64, + newEpochCounter: UInt64 + ) + access(all) event EpochTotalRewardsPaid( + total: UFix64, + fromFees: UFix64, + minted: UFix64, + feesBurned: UFix64, + epochCounterForRewards: UInt64 + ) + + /// Node + access(all) event NewNodeCreated(nodeID: String, role: UInt8, amountCommitted: UFix64) + access(all) event TokensCommitted(nodeID: String, amount: UFix64) + access(all) event TokensStaked(nodeID: String, amount: UFix64) + access(all) event NodeTokensRequestedToUnstake(nodeID: String, amount: UFix64) + access(all) event TokensUnstaking(nodeID: String, amount: UFix64) + access(all) event TokensUnstaked(nodeID: String, amount: UFix64) + access(all) event NodeRemovedAndRefunded(nodeID: String, amount: UFix64) + access(all) event RewardsPaid(nodeID: String, amount: UFix64, epochCounter: UInt64) + access(all) event UnstakedTokensWithdrawn(nodeID: String, amount: UFix64) + access(all) event RewardTokensWithdrawn(nodeID: String, amount: UFix64) + access(all) event NetworkingAddressUpdated(nodeID: String, newAddress: String) + access(all) event NodeWeightChanged(nodeID: String, newWeight: UInt64) + + /// Delegator + access(all) event NewDelegatorCreated(nodeID: String, delegatorID: UInt32) + access(all) event DelegatorTokensCommitted(nodeID: String, delegatorID: UInt32, amount: UFix64) + access(all) event DelegatorTokensStaked(nodeID: String, delegatorID: UInt32, amount: UFix64) + access(all) event DelegatorTokensRequestedToUnstake(nodeID: String, delegatorID: UInt32, amount: UFix64) + access(all) event DelegatorTokensUnstaking(nodeID: String, delegatorID: UInt32, amount: UFix64) + access(all) event DelegatorTokensUnstaked(nodeID: String, delegatorID: UInt32, amount: UFix64) + access(all) event DelegatorRewardsPaid(nodeID: String, delegatorID: UInt32, amount: UFix64, epochCounter: UInt64) + access(all) event DelegatorUnstakedTokensWithdrawn(nodeID: String, delegatorID: UInt32, amount: UFix64) + access(all) event DelegatorRewardTokensWithdrawn(nodeID: String, delegatorID: UInt32, amount: UFix64) + + /// Contract Fields + access(all) event NewDelegatorCutPercentage(newCutPercentage: UFix64) + access(all) event NewWeeklyPayout(newPayout: UFix64) + access(all) event NewStakingMinimums(newMinimums: {UInt8: UFix64}) + access(all) event NewDelegatorStakingMinimum(newMinimum: UFix64) +``` + + +=== build/core-contracts/05-flow-fees.md === +--- +title: Flow Fees Contract +sidebar_position: 5 +sidebar_label: Flow Fees +description: Learn about Flow's fees contracts that handle transaction and storage fees, including fee collection, parameters, and storage capacity management. Understand how fees are processed and managed on the Flow blockchain. +keywords: + - Flow fees + - transaction fees + - storage fees + - fee collection + - fee parameters + - FlowFees + - FlowStorageFees + - fee events + - surge factor + - execution fees + - storage capacity + - fee management + - Flow protocol + - core contracts + - blockchain fees +--- + +## FlowFees + +The `FlowFees` contract is where all the collected flow fees are gathered. + +Source: [FlowFees.cdc](https://github.com/onflow/flow-core-contracts/blob/master/contracts/FlowFees.cdc) + +| Network | Contract Address | +| ------------------------- | -------------------- | +| Emulator | `0xe5a8b7f23e8b548f` | +| Cadence Testing Framework | `0x0000000000000004` | +| Testnet | `0x912d5440f7e3769e` | +| Mainnet | `0xf919ee77447b7497` | + +### Events + +Important events for `FlowFees` are: + +```cadence +// Event that is emitted when tokens are deposited to the fee vault +access(all) event TokensDeposited(amount: UFix64) + +// Event that is emitted when tokens are withdrawn from the fee vault +access(all) event TokensWithdrawn(amount: UFix64) + +// Event that is emitted when fees are deducted +access(all) event FeesDeducted(amount: UFix64, inclusionEffort: UFix64, executionEffort: UFix64) + +// Event that is emitted when fee parameters change +access(all) event FeeParametersChanged(surgeFactor: UFix64, inclusionEffortCost: UFix64, executionEffortCost: UFix64) +``` + +## FlowStorageFees + +The `FlowStorageFees` contract defines the parameters and utility methods for storage fees. + +Source: [FlowStorageFees.cdc](https://github.com/onflow/flow-core-contracts/blob/master/contracts/FlowStorageFees.cdc) + +| Network | Contract Address | +| ------------------------- | -------------------- | +| Emulator | `0xf8d6e0586b0a20c7` | +| Cadence Testing Framework | `0x0000000000000001` | +| Testnet | `0x8c5303eaa26202d6` | +| Mainnet | `0xe467b9dd11fa00df` | + +### Events + +Important events for `FlowStorageFees` are: + +```cadence +// Emitted when the amount of storage capacity an account has per reserved Flow token changes +access(all) event StorageMegaBytesPerReservedFLOWChanged(_ storageMegaBytesPerReservedFLOW: UFix64) + +// Emitted when the minimum amount of Flow tokens that an account needs to have reserved for storage capacity changes. +access(all) event MinimumStorageReservationChanged(_ minimumStorageReservation: UFix64) +``` + + +=== build/core-contracts/04-service-account.md === +--- +title: Service Account Contracts +sidebar_position: 4 +sidebar_label: Service Account +description: Learn about Flow's service account contracts that manage core protocol requirements, including transaction fees, deployment permissions, random beacon history, and node versioning. +keywords: + - service account + - core contracts + - FlowServiceAccount + - transaction fees + - deployment permissions + - RandomBeaconHistory + - NodeVersionBeacon + - protocol versions + - Flow protocol + - core protocol + - contract addresses + - protocol management + - Flow governance + - network configuration +--- + +The service account is the account that manages the core protocol requirements of Flow. + +| Network | Contract Address | +| ------------------------- | -------------------- | +| Emulator | `0xf8d6e0586b0a20c7` | +| Cadence Testing Framework | `0x0000000000000001` | +| Testnet | `0x8c5303eaa26202d6` | +| Mainnet | `0xe467b9dd11fa00df` | + +Here are three important contracts deployed to the service account: + +# FlowServiceAccount + +`FlowServiceAccount` tracks transaction fees, deployment permissions, and provides +some convenience methods for Flow Token operations. + +Source: [FlowServiceAccount.cdc](https://github.com/onflow/flow-core-contracts/blob/master/contracts/FlowServiceAccount.cdc) + +## Events + +Important events from `FlowServiceAccount` are: + +```cadence +access(all) event TransactionFeeUpdated(newFee: UFix64) +access(all) event AccountCreationFeeUpdated(newFee: UFix64) +``` + +# RandomBeaconHistory + +- `RandomBeaconHistory` stores the history of random sources generated by + the Flow network. The defined Heartbeat resource is + updated by the Flow Service Account at the end of every block + with that block's source of randomness. + +Source: [RandomBeaconHistory.cdc](https://github.com/onflow/flow-core-contracts/blob/master/contracts/RandomBeaconHistory.cdc) + +## Events + +Important events from `RandomBeaconHistory` are: + +```cadence +// Event emitted when missing SoRs from past heartbeats are detected and will be backfilled: +// - `blockHeight` is the height where the gap is detected +// - `gapStartHeight` is the height of the first missing entry detected +access(all) event RandomHistoryMissing(blockHeight: UInt64, gapStartHeight: UInt64) + +// Event emitted when missing SoRs are backfilled on the current heartbeat: +// - `blockHeight` is the height where the backfill happened, it also defines the SoR used to backfill +// - `gapStartHeight` is the height of the first backfilled entry +// - `count` is the number of backfilled entries +// Note that in very rare cases, the backfilled gap may not be contiguous. This event does not +// fully define the backfilled entries in this case. +access(all) event RandomHistoryBackfilled(blockHeight: UInt64, gapStartHeight: UInt64, count: UInt64) +``` + +# NodeVersionBeacon + +- `NodeVersionBeacon` holds the past + and future protocol versions that should be used + to execute/handle blocks at a given block height. + +Source: [NodeVersionBeacon.cdc](https://github.com/onflow/flow-core-contracts/blob/master/contracts/NodeVersionBeacon.cdc) + +## Events + +Important events from `NodeVersionBeacon` are: + +```cadence +/// Event emitted when the version table is updated. +/// It contains the current version and all the upcoming versions +/// sorted by block height. +/// The sequence increases by one each time an event is emitted. +/// It can be used to verify no events were missed. +access(all) event VersionBeacon( + versionBoundaries: [VersionBoundary], + sequence: UInt64 +) + +/// Event emitted any time the version boundary freeze period is updated. +/// freeze period is measured in blocks (from the current block). +access(all) event NodeVersionBoundaryFreezePeriodChanged(freezePeriod: UInt64) +``` + + +=== build/core-contracts/03-flow-token.md === +--- +title: Flow Token Contract +sidebar_position: 3 +sidebar_label: Flow Token +description: Learn about the FLOW token smart contract, its implementation, events system, and deployment addresses across different networks. Understand how to interact with the native token of the Flow blockchain. +keywords: + - FLOW token + - Flow contract + - token events + - token transactions + - token minting + - token burning + - core contracts + - native token + - Flow protocol + - token implementation + - token deployment + - contract addresses + - token initialization + - Flow mainnet + - Flow testnet +--- + +The `FlowToken` contract defines the FLOW network token. + +Source: [FlowToken.cdc](https://github.com/onflow/flow-core-contracts/blob/master/contracts/FlowToken.cdc) + +| Network | Contract Address | +| ------------------------- | -------------------- | +| Emulator | `0x0ae53cb6e3f42a79` | +| Cadence Testing Framework | `0x0000000000000003` | +| Testnet | `0x7e60df042a9c0868` | +| Mainnet | `0x1654653399040a61` | + +# Transactions + +Transactions and scripts for `FlowToken` are in the `flow-core-contracts` [repo](https://github.com/onflow/flow-core-contracts/tree/master/transactions/flowToken). + +As mentioned in the `FungibleToken` page, developers are encouraged to use +the generic token transactions in the `flow-ft` [repo](https://github.com/onflow/flow-ft/tree/master/transactions) instead. + +# Events + +Flow relies on a set of core contracts that define key portions of the Flow protocol. Those contracts are core contracts +and are made to emit the events documented below. You can read about the [core contracts here](./index.md) +and view their source code and event definitions. + +Events emitted from core contracts follow a standard format: + +``` +A.{contract address}.{contract name}.{event name} +``` + +The components of the format are: + +- `contract address` - the address of the account the contract has been deployed to +- `contract name` - the name of the contract in the source code +- `event name` - the name of the event as declared in the source code + +### Flow Token Contract + +Description of events emitted from the [FLOW Token contract](./03-flow-token.md). +The contract defines the fungible FLOW token. Please note that events for the fungible token contracts are the same +if deployed to a different account but the `contract address` is +changed to the address of the account the contract has been deployed to. + +### Tokens Initialized + +Event that is emitted when the contract gets created. + +- Event name: `TokensInitialized` +- Mainnet event: `A.1654653399040a61.FlowToken.TokensInitialized` +- Testnet event: `A.7e60df042a9c0868.FlowToken.TokensInitialized` + +```cadence +access(all) event TokensInitialized(initialSupply: UFix64) +``` + +| Field | Type | Description | +| ------------- | ------ | -------------------------------- | +| initialSupply | UFix64 | The initial supply of the tokens | + +### Tokens Withdrawn + +Event that is emitted when tokens get withdrawn from a Vault. + +- Event name: `TokensWithdrawn` +- Mainnet event: `A.1654653399040a61.FlowToken.TokensWithdrawn` +- Testnet event: `A.7e60df042a9c0868.FlowToken.TokensWithdrawn` + +```cadence +access(all) event TokensWithdrawn(amount: UFix64, from: Address?) +``` + +| Field | Type | Description | +| ------ | -------- | --------------------------------------------------------------------------------------------------------------------------------------- | +| amount | UFix64 | The amount of tokens withdrawn | +| from | Address? | Optional address of the account that owns the vault where tokens were withdrawn from. `nil` if the vault is not in an account's storage | + +### Tokens Deposited + +Event that is emitted when tokens get deposited to a Vault. + +- Event name: `TokensDeposited` +- Mainnet event: `A.1654653399040a61.FlowToken.TokensDeposited` +- Testnet event: `A.7e60df042a9c0868.FlowToken.TokensDeposited` + +```cadence +access(all) event TokensDeposited(amount: UFix64, to: Address?) +``` + +| Field | Type | Description | +| ------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------- | +| amount | UFix64 | The amount of tokens withdrawn | +| to | Address? | Optional address of the account that owns the vault where tokens were deposited to. `nil` if the vault is not in an account's storage | + +### Tokens Minted + +Event that is emitted when new tokens gets minted. + +- Event name: `TokensMinted` +- Mainnet event: `A.1654653399040a61.FlowToken.TokensMinted` +- Testnet event: `A.7e60df042a9c0868.FlowToken.TokensMinted` + +```cadence +access(all) event TokensMinted(amount: UFix64) +``` + +| Field | Type | Description | +| ------ | ------ | ---------------------------- | +| amount | UFix64 | The amount of tokens to mint | + +### Tokens Burned + +Event that is emitted when tokens get destroyed. + +- Event name: `TokensBurned` +- Mainnet event: `A.1654653399040a61.FlowToken.TokensBurned` +- Testnet event: `A.7e60df042a9c0868.FlowToken.TokensBurned` + +```cadence +access(all) event TokensBurned(amount: UFix64) +``` + +| Field | Type | Description | +| ------ | ------ | ---------------------------- | +| amount | UFix64 | The amount of tokens to burn | + +### Minter Created + +Event that is emitted when a new minter resource gets created. + +- Event name: `MinterCreated` +- Mainnet event: `A.1654653399040a61.FlowToken.MinterCreated` +- Testnet event: `A.7e60df042a9c0868.FlowToken.MinterCreated` + +```cadence +access(all) event MinterCreated(allowedAmount: UFix64) +``` + +| Field | Type | Description | +| ------------- | ------ | ------------------------------------------------------- | +| allowedAmount | UFix64 | The amount of tokens that the minter is allowed to mint | + +### Burner Created + +Event that is emitted when a new burner Resource gets created. + +- Event name: `BurnerCreated` +- Mainnet event: `A.1654653399040a61.FlowToken.BurnerCreated` +- Testnet event: `A.7e60df042a9c0868.FlowToken.BurnerCreated` + +```cadence +access(all) event BurnerCreated() +``` + +### Staking Events + +To learn more about staking events, read [staking/events/](../../networks/staking/07-staking-scripts-events.md) + + +=== build/core-contracts/02-fungible-token.md === +--- +title: Fungible Token Contract +sidebar_position: 2 +sidebar_label: Fungible Token +description: Learn about Flow's Fungible Token standard contract, its implementation, events, and how to interact with fungible tokens on the Flow blockchain. +keywords: + - fungible token + - FT standard + - token contract + - Flow tokens + - token events + - token transactions + - token metadata + - token standard + - Flow FT + - token implementation + - token interface + - token deployment + - token addresses + - token events + - token specification +--- + +The `FungibleToken` contract implements the Fungible Token Standard. It is the second contract ever deployed on Flow. + +- [Basic Fungible Token Tutorial](https://cadence-lang.org/docs/tutorial/fungible-tokens) +- [Fungible Token Guide](../guides/fungible-token.md) +- [Fungible Token Standard Repo](https://github.com/onflow/flow-ft) + +The `FungibleTokenMetadataViews` and `FungibleTokenSwitchboard` contracts +are also deployed to the same account as `FungibleToken`. + +Source: [FungibleToken.cdc](https://github.com/onflow/flow-ft/blob/master/contracts/FungibleToken.cdc) + +| Network | Contract Address | +| ------------------------- | -------------------- | +| Emulator | `0xee82856bf20e2aa6` | +| Cadence Testing Framework | `0x0000000000000002` | +| Testnet | `0x9a0766d93b6608b7` | +| Mainnet | `0xf233dcee88fe0abe` | + +# Transactions + +All `FungibleToken` projects are encouraged to use +the generic token transactions and scripts in the `flow-ft` [repo](https://github.com/onflow/flow-ft/tree/master/transactions). +They can be used for any token that implements the fungible token standard properly +without changing any code besides import addresses on different networks. + +# Events + +Events emitted from all contracts follow a standard format: + +``` +A.{contract address}.{contract name}.{event name} +``` + +The components of the format are: + +- `contract address` - the address of the account the contract has been deployed to +- `contract name` - the name of the contract in the source code +- `event name` - the name of the event as declared in the source code + +## FungibleToken Events + +Contracts that implement the Fungible Token standard get access +to standard events that are emitted every time a relevant action occurs, +like depositing and withdrawing tokens. + +This means that projects do not have to implement their own custom events +unless the standard events do not satisfy requirements they have for events. + +The `FungibleToken` events will have the following format: + +``` +A.{contract address}.FungibleToken.Deposited +A.{contract address}.FungibleToken.Withdrawn +``` + +Where the `contract address` is the `FungibleToken` address on the network being queried. +The addresses on the various networks are shown above. + +### FungibleToken.Deposited + +```cadence +access(all) event Deposited ( + type: String, + amount: UFix64, + to: Address?, + toUUID: UInt64, + depositedUUID: UInt64, + balanceAfter: UFix64 +) +``` + +Whenever `deposit()` is called on a resource type that implements +`FungibleToken.Vault`, the `FungibleToken.Deposited` event is emitted +with the following arguments: + +- `type: String`: The type identifier of the token being deposited. + - Example: `A.4445e7ad11568276.FlowToken.Vault` +- `amount: UFix64`: The amount of tokens that were deposited. + - Example: `0.00017485` +- `to: Address?`: The address of the account that owns the Vault that received + the tokens. If the vault is not stored in an account, `to` will be `nil`. + - Example: `0x4445e7ad11568276` +- `toUUID: UInt64`: The UUID of the Vault that received the tokens. + - Example: `177021372071991` +- `depositedUUID`: The UUID of the Vault that was deposited (and therefore destroyed). + - Example: `177021372071991` +- `balanceAfter: UFix64`: The balance of the Vault that received the tokens after the deposit happened. + - Example: `1.00047545` + +### FungibleToken.Withdrawn + +```cadence +access(all) event Withdrawn ( + type: String, + amount: UFix64, + from: Address?, + fromUUID: UInt64, + withdrawnUUID: UInt64, + balanceAfter: UFix64 +) +``` + +Whenever `withdraw()` is called on a resource type that implements +`FungibleToken.Vault`, the `FungibleToken.Withdrawn` event is emitted +with the following arguments: + +- `type: String`: The type identifier of the token being withdrawn. + - Example: `A.4445e7ad11568276.FlowToken.Vault` +- `amount: UFix64`: The amount of tokens that were withdrawn. + - Example: `0.00017485` +- `from: Address?`: The address of the account that owns the Vault that the tokens + were withdrawn from. If the vault is not stored in an account, `to` will be `nil`. + - Example: `0x4445e7ad11568276` +- `fromUUID: UInt64`: The UUID of the Vault that the tokens were withdrawn from. + - Example: `177021372071991` +- `withdrawnUUID`: The UUID of the Vault that was withdrawn. + - Example: `177021372071991` +- `balanceAfter: UFix64`: The balance of the Vault that the tokens + were withdrawn from after the withdrawal. + - Example: `1.00047545` + +### FungibleToken.Burned + +```cadence +access(all) event Burned ( + type: String, + amount: UFix64, + fromUUID: UInt64 +) +``` + +Whenever a fungible token that implements `FungibleToken.Vault` is burned +via the `Burner.burn()` method, this event is emitted with the following arguments: + +- `type: String`: The type identifier of the token that was burnt. + - Example: `A.4445e7ad11568276.FlowToken.Vault` +- `amount: UFix64`: The amount of tokens that were burnt. + - Example: `0.00017485` +- `fromUUID: UInt64`: The UUID of the Vault that was burnt. + - Example: `177021372071991` + + +=== build/basics/transactions.md === +--- +sidebar_position: 3 +title: Transactions +description: Learn about Flow blockchain transactions, their structure, lifecycle, and signing process. Understand transaction roles, statuses, finality, and how to optimize transaction execution. +keywords: + - Flow transactions + - transaction speed + - transaction time + - transaction signing + - transaction roles + - transaction status + - transaction finality + - blockchain transactions + - multi-sig + - transaction fees + - sequence numbers + - proposal key + - authorizers + - transaction payload + - transaction lifecycle + - transaction submission +--- + +# Transactions + +Transactions are cryptographically signed data messages that contain a set of instructions that update the Flow state. They are a basic unit of computation that gets executed by execution nodes. In order for a transaction to be included in the Flow blockchain a fee is required from the payer. + +![Screenshot 2023-08-17 at 13.57.36.png](_transactions_images/Screenshot_2023-08-17_at_13.57.36.png) + +:::tip + +Transactions on Flow are fundamentally different from those on Ethereum. The main purpose of a transaction is not to send funds but to contain code that gets executed. This makes transactions very flexible and powerful. In addition to being able to access the authorizing accounts private assets, transactions can also read and call functions in public contracts, and access public domains in other users' accounts Transactions on Flow also feature different roles, such as defining third-party payer accounts, proposer accounts, and authorizers, which we will talk about in detail soon. + +::: + +In order for a transaction to be valid and executed it must contain signatures from accounts involved as well as some other information, let's take a look at all the required fields. + +![Screenshot 2023-08-17 at 14.52.56.png](_transactions_images/Screenshot_2023-08-17_at_14.52.56.png) + +### Script + +The script section contains instructions for transaction execution. This is a Cadence program in source code form (human-readable), and encoded as UTF-8. The transaction program must contain a `transaction` declaration. + +A transaction includes multiple optional phases `prepare`, `pre`, `execute`, and `post` phase. You can read more about it in the [Cadence reference document on transactions](https://cadence-lang.org/docs/language/transactions). Each phase has a purpose, the two most important phases are `prepare` and `execute`. + +In the `prepare` phase, we have access to `&Account` objects, which gives us the power to interact with those accounts. The accounts are called authorizers of transactions, so each account we want to interact with in the `prepare` phase must sign the transaction as an authorizer. +The `execute` phase does exactly what it says, it executes the main logic of the transaction. This phase is optional, but it is a best practice to add your main transaction logic in the section, so it is explicit. + +Again make sure to read Cadence [documentation on transactions](https://cadence-lang.org/docs/language/transactions) + +This is an example of a transaction script: + +```cadence +transaction(greeting: String) { + execute { + log(greeting.concat(", World!")) + } +} +``` + +### Arguments + +Transactions may declare parameters it needs during execution, these must be provided as input arguments when sending a transaction. You can think of them as function arguments. Currently, we provide [arguments in the JSON-Cadence Data Interchange Format](https://cadencelang.dev/docs/1.0/json-cadence-spec). Which is a human-readable JSON format. The sample script from above accepts a single `String` argument. + +### Reference Block + +A reference to a recent block used for expiry. A transaction is considered expired if it is submitted to Flow after reference block height + N, where N is a constant defined by the network. On mainnet current setting for N is 600 which amounts to approximately 10 minutes for expiry (please note this is subject to change). + +### Gas Limit + +When a transaction is executed each operation consumes a predefined amount of computational units (we define more about that in the Fees documentation). This defines the maximum amount of computation that is allowed to be done during this transaction. If a transaction completes execution using fewer computational units than the limit, it remains unaffected. However, if it hits this limit during execution, the transaction will fail, its changes will be reverted, but fees will still be applied. The maximum computational limit for Flow mainnet is currently at 9999, but this might change. The maximum network limit is defined to protect the network from transactions that would run forever. + +### Proposal Key + +Each transaction must declare a proposal key, which can be an account key from any Flow account (App, User or Wallet). The account that owns the proposal key is referred to as the *proposer*. + +Proposer is a role in a transaction that defines who is proposing the transaction, the effect of the transaction being submitted on the proposer is that it will increment the sequence number for the provided proposer key. This is done to ensure transactions are not resubmitted (replay attack) and thus sequencing actions. + +A proposal key definition declares the address, key ID, and up-to-date sequence number for the account key. A single proposer can have many transactions executed in parallel only limited by the key they use to propose the transaction. + +![Screenshot 2023-08-17 at 15.10.33.png](_transactions_images/Screenshot_2023-08-17_at_15.10.33.png) + +- Address identifies the account that will act as a proposer of this transaction. +- Key ID is an index number (starting at 0) that identifies the key on the account provided in the address. +- Sequence Number is a number on each key that increments by 1 with each transaction. This ensures that each transaction executes at most once and prevents many unwanted situations, such as [transaction replay attacks](https://en.wikipedia.org/wiki/Replay_attack). Each key in an account has a dedicated sequence number associated with it. Unlike Ethereum, there is no sequence number for the entire account. + +### Authorizers + +Authorizers are accounts that authorize a transaction to read and mutate their state. A transaction can specify zero or more authorizers, depending on how many accounts the transaction needs to access. + +The number of authorizers on the transaction must match the number of &Account parameters declared in the prepare statement of the Cadence script. + +Example transaction with multiple authorizers: + +```cadence +transaction { + prepare(authorizer1: auth(Capabilities) &Account, authorizer2: auth(Storage) &Account) { } +} +``` + +Each account defined as an authorizer must sign the transaction with its own key, +and by doing so it acknowledges the transaction it signed +will have access to that account and may modify it. +How it will modify it is understood from the list of account entitlements +that are granted in the `prepare` argument list and by reading the transaction script. +In an transaction, developers should only give the minimum set of account entitlements +that are required for the transaction to execute properly. +This ensures that users who are signing transactions can understand +what parts of their account a transaction can access. + +### Payer + +A payer is the account that pays the fees for the transaction. A transaction must specify exactly one payer. The payer is only responsible for paying the network and gas fees; the transaction is not authorized to access resources or code stored in the payer account. + +By explicitly specifying a payer a transaction can be paid by third-party services such as wallet providers. + +## Transaction Lifecycle + +Once a transaction has been submitted to the Flow network using the Access node APIs, it will begin its lifecycle and eventually reach a finality. Each submitted transaction can be identified with an ID. + +**Transaction ID** + +A transaction ID is a hash of the encoded transaction payload and can be calculated at any time. We don't submit transaction ID as part of the transaction payload as it can be derived from the data and thus would mean duplication of data. + +### Transaction Status + +The transaction status represents the state of a transaction on the Flow blockchain. Some statuses are mutable and some are immutable, they usually follow a timeline like so: + +![Screenshot 2023-08-17 at 16.08.18.png](_transactions_images/Screenshot_2023-08-17_at_16.08.18.png) + +- Unknown - The transaction has not yet been seen by the section of the network you communicate with. +- Pending - The transaction has been received by a collection node but has not yet been finalized in a block. +- Finalized - The consensus nodes have included the transaction in a block, but it has not been executed by execution nodes. +- Executed - Execution nodes have produced a result for the transaction. +- Sealed - The verification nodes have verified and agreed on the result of the transaction and the consensus node has included the seal in the latest block. +- Expired - The transaction was submitted past its expiration block height. + +:::danger + +It is **important to differentiate the transaction status and transaction result**. Transaction status will only provide you with information about the inclusion of the transaction in the blockchain, not whether the transaction was executed the way you intended. **A transaction can still fail to execute the way you intended and be sealed.** + +::: + +### Transaction Result + +Once a transaction is executed, its result will be available, providing details on its success or any errors encountered during execution. It also includes events the transaction may have emitted. + +![Screenshot 2023-08-17 at 16.29.30.png](_transactions_images/Screenshot_2023-08-17_at_16.29.30.png) + +:::danger + +From a developer perspective, a transaction is only successful if: + +- It is sealed +- It didn't encounter errors + +::: + +## Transaction Time + +Understanding how transaction times work across different blockchains is crucial for developers and users to optimize their operations and expectations. Flow's multi-node architecture allows for some of the fastest transaction times and finality times across chains. Read on for more detail on how it works and what it means for developers and users. + +### Two Key Transaction Questions + +Whenever a transaction is processed, two primary questions come to mind: + +1. **Inclusion**: Will this transaction be included in the final chain? +2. **Result**: What is the outcome of the transaction? + +Different blockchains tackle these questions in varied sequences. For instance, Bitcoin and Ethereum provide answers simultaneously. Layer 2 solutions (L2s) can sometimes address the outcome before confirming inclusion. But there's a catch: you can have an answer to those questions that might be wrong. Flow, on the other hand, prioritizes the inclusion question. + +### Transaction Finality + +Drawing a parallel to traditional finance, a vendor might instantly know if Visa approves a transaction, but the possibility of chargebacks lingers for weeks. This uncertainty introduces the concept of "finality" in blockchain transactions. + +In the dominant Proof-of-Stake (PoS) environment, which includes most chains except for Bitcoin, there are three key finality stages: + +- **Preliminary result**: It's an initial answer to the aforementioned questions. The preliminary result doesn't ensure correctness, and there are no economic penalties (like "slashing") if the informant provides false information. +- **Soft economic finality**: This stage provides an answer backed by cryptographic proof. If the informant is deceptive, they face economic repercussions or "slashing." +- **Hard economic finality**: The provided answer either holds true, or the entire blockchain requires a restart. The latter case sees at least one-third of the nodes facing economic penalties. + +![finality.png](./_transactions_images/finality.png) + +### Chain Comparisons + +Chain | Preliminary | Soft finality | Hard finality +---------|-------------|---------------|--------------- +Solana | 100ms | n/a | ~30s +Ethereum | 15s | n/a | ~15m +Flow | bypass | 4s | ~10s + +#### Flow + +Flow bypasses preliminary results entirely. It reaches soft finality ("Executed") in about 4 seconds and hard finality ("Sealed") in around 10 seconds. If an Access Node on Flow states a transaction has occurred, it's either correct or cryptographic proof exists that can lead to the node's slashing. + +![transaction-time.png](_transactions_images/chain-comparison.png) + + +## Signing a Transaction + +Due to the existence of **weighted keys** and **split signing roles**, Flow transactions sometimes need to be signed multiple times by one or more parties. That is, multiple unique signatures may be needed to authorize a single transaction. + +A transaction can contain two types of signatures: **payload signatures** and **envelope signatures**. + +![Screenshot 2023-08-17 at 14.52.51.png](_transactions_images/Screenshot_2023-08-17_at_14.52.51.png) + +### Signer Roles +- **Proposer**: the account that specifies a proposal key. +- **Payer**: the account paying for the transaction fees. +- **Authorizers**: zero or more accounts authorizing the transaction to mutate their state. + +### Payload + +The transaction payload is the innermost portion of a transaction and contains the data that uniquely identifies the operations applied by the transaction as we have defined them above. In Flow, two transactions with the same payload will never be executed more than once. + +:::warning + +⚠️ The transaction proposer and authorizer are only required to sign the transaction payload. These signatures are the payload signatures. + +::: + +### Authorization Envelope + +The transaction authorization envelope contains both the transaction payload and the payload signatures. + +The transaction payer is required to sign the authorization envelope. These signatures are **envelope signatures**. + +:::danger + +Special case: if an account is both the payer and either a proposer or authorizer, it is required only to sign the envelope. + +::: + +### Payment Envelope + +The outermost portion of the transaction, which contains the payload and envelope signatures, is referred to as the payment envelope. + +:::danger + +Special case: if an account is both the payer and either a proposer or authorizer, it is required only to sign the envelope. + +::: + +### Payer Signs Last + +The payer must sign the portion of the transaction that contains the payload signatures, which means that the payer must always sign last. This ensures the payer that they are signing a valid transaction with all of the required payload signatures. + +:::danger + +Special case: if an account is both the payer and either a proposer or authorizer, it is required only to sign the envelope. + +::: + +### Signature Structure + +A transaction signature is a composite structure containing three fields: + +- Address +- Key ID +- Signature Data + +The *address* and *key ID* fields declare the account key that generated the signature, which is required in order to verify the signature against the correct public key. + +### Sequence Numbers + +Flow uses sequence numbers to ensure that each transaction executes at most once. This prevents many unwanted situations such as [transaction replay attacks](https://en.wikipedia.org/wiki/Replay_attack). + +Sequence numbers work similarly to transaction nonces in Ethereum, but with several key differences: + +- **Each key in an account has a dedicated sequence number** associated with it. Unlike Ethereum, there is no sequence number for the entire account. +- When creating a transaction, only the **proposer must specify a sequence number**. Payers and authorizers are not required to. + +:::tip + +The transaction proposer is only required to specify a sequence number for a single account key, even if it signs with multiple keys. This key is referred to as the proposal key. + +::: + +Each time an account key is used as a proposal key, its sequence number is incremented by 1. The sequence number is updated after execution, even if the transaction fails (reverts) during execution. + +A transaction is failed if its proposal key does not specify a sequence number equal to the sequence number stored on the account *at execution time.* + +## Common Signing Scenarios + +Below are several scenarios in which different signature combinations are required to authorize a transaction. + +### Single party, single signature + +The simplest Flow transaction declares a single account as the proposer, payer and authorizer. In this case, the account can sign the transaction with a single signature. + +This scenario is only possible if the signature is generated by a key with full signing weight. + +| Account | Key ID | Weight | +| ------- | ------ | ------ | +| 0x01 | 1 | 1000 | + +```json +{ + "payload": { + "proposalKey": { + "address": "0x01", + "keyId": 1, + "sequenceNumber": 42 + }, + "payer": "0x01", + "authorizers": [ "0x01" ] + }, + "payloadSignatures": [], // 0x01 is the payer, so only needs to sign envelope + "envelopeSignatures": [ + { + "address": "0x01", + "keyId": 1, + "sig": "0xabc123" + } + ] +} +``` + +### Single party, multiple signatures + +A transaction that declares a single account as the proposer, payer and authorizer may still specify multiple signatures if the account uses weighted keys to achieve multi-sig functionality. + +| Account | Key ID | Weight | +| ------- | ------ | ------ | +| 0x01 | 1 | 500 | +| 0x01 | 2 | 500 | + +```json +{ + "payload": { + "proposalKey": { + "address": "0x01", + "keyId": 1, + "sequenceNumber": 42 + }, + "payer": "0x01", + "authorizers": [ "0x01" ] + }, + "payloadSignatures": [], // 0x01 is the payer, so only needs to sign envelope + "envelopeSignatures": [ + { + "address": "0x01", + "keyId": 1, + "sig": "0xabc123" + }, + { + "address": "0x01", + "keyId": 2, + "sig": "0xdef456" + } + ] +} +``` + +### Multiple parties + +A transaction that declares different accounts for each signing role will require at least one signature from each account. + +| Account | Key ID | Weight | +| --- | --- | --- | +| 0x01 | 1 | 1000 | +| 0x02 | 1 | 1000 | + +```json +{ + "payload": { + "proposalKey": { + "address": "0x01", + "keyId": 1, + "sequenceNumber": 42 + }, + "payer": "0x02", + "authorizers": [ "0x01" ] + }, + "payloadSignatures": [ + { + "address": "0x01", // 0x01 is not payer, so only signs payload + "keyId": 1, + "sig": "0xabc123" + } + ], + "envelopeSignatures": [ + { + "address": "0x02", + "keyId": 1, + "sig": "0xdef456" + }, + ] +} +``` + +### Multiple parties, multiple signatures + +A transaction that declares different accounts for each signing role may require more than one signature per account if those accounts use weighted keys to achieve multi-sig functionality. + +| Account | Key ID | Weight | +| --- | --- | --- | +| 0x01 | 1 | 500 | +| 0x01 | 2 | 500 | +| 0x02 | 1 | 500 | +| 0x02 | 2 | 500 | + +```json +{ + "payload": { + "proposalKey": { + "address": "0x01", + "keyId": 1, + "sequenceNumber": 42 + }, + "payer": "0x02", + "authorizers": [ "0x01" ] + }, + "payloadSignatures": [ + { + "address": "0x01", // 0x01 is not payer, so only signs payload + "keyId": 1, + "sig": "0xabc123" + }, + { + "address": "0x01", // 0x01 is not payer, so only signs payload + "keyId": 2, + "sig": "0x123abc" + } + ], + "envelopeSignatures": [ + { + "address": "0x02", + "keyId": 1, + "sig": "0xdef456" + }, + { + "address": "0x02", + "keyId": 2, + "sig": "0x456def" + }, + ] +} +``` + +## Transaction Submission and Retrieval + +You can use the Flow CLI to get an existing transaction by ID: + +```sh +flow transactions get 1ec90051e3bc74fc36cbd16fc83df08e463dda8f92e8e2193e061f9d41b2ad92 -n mainnet +``` + +Find [more about the command in the CLI docs](../../tools/flow-cli/get-flow-data/get-blocks.md). + +A user can define their own transactions or it can use already defined transactions by the contract authors that can be found by using the FLIX service. + +Transactions can be submitted and obtained from the access node APIs, currently, there are two gRPC and REST APIs. You can find more information about them here: + +[**gRPC Transaction API**](../../networks/access-onchain-data/index.md#transactions) + +[**REST Transaction API**](/http-api#tag/Transactions) + +There are multiple SDKs implementing the above APIs for different languages: + +[**Javascript SDK**](../../tools/clients/fcl-js/index.md) + +[**Go SDK**](../../tools/clients/flow-go-sdk/index.md) + +Find a list of all SDKs [here](../../tools/clients/index.md) + + +=== build/basics/smart-contracts.md === +--- +slug: /build/basics/smart-contracts +redirect: /build/smart-contracts/overview +title: Smart Contracts ↙ +description: Redirect page to comprehensive Flow smart contracts documentation and overview. +keywords: + - smart contracts + - Flow contracts + - Cadence + - contract development + - blockchain development + - Flow programming + - contract deployment + - contract overview +--- + +# Smart Contracts + +Go to [Smart Contracts](../../build/smart-contracts/overview.md) + +import {Redirect} from '@docusaurus/router'; + +; + + +=== build/basics/scripts.md === +--- +sidebar_position: 4 +title: Scripts +description: Learn about Flow scripts - read-only Cadence code that can query blockchain state without fees. Understand how to write, execute, and optimize scripts for accessing Flow network data. +keywords: + - scripts + - Cadence scripts + - blockchain queries + - read operations + - Flow scripts + - script execution + - state queries + - Flow API + - script limitations + - best practices + - historic data + - script arguments + - script returns + - Flow CLI + - computation limits +--- + +# Scripts + +A script provides a light-weight method to query chain data. + +It is executable Cadence code that can query for Flow execution state data but cannot modify it in any way. + +Unlike a Flow transaction, a script is not signed and requires no transaction fees. Also unlike a transaction, a script can return a value back to the caller. +You can think of executing a script as a read-only operation, very similar to the `eth_call` RPC method on Ethereum. + +Scripts are currently executed on either the Access Nodes or the Execution Nodes based on the Access node configuration. + +Scripts are defined by the following the Cadence code: + +```cadence +// The 'main' function is the entry point function and every script needs to have one. +access(all) fun main() { + // Cadence statements to be executed go here +} +``` + +Scripts can return a typed value: + +```cadence +access(all) fun main(): Int { + return 1 + 2 +} +``` + +Scripts can also accept arguments: + +```cadence +access(all) fun main(arg: String): String { + return "Hello ".concat(arg) +} +``` + +Scripts can call contract functions and query the state of a contract. To call a function on another contract, import it from its address and invoke the function: + +```cadence +import World from 0x01 + +access(all) fun main(): String { + return World.hello() +} +``` + +Scripts can also be run against previous blocks, allowing you to query historic data from the Flow network. This is particularly useful for retrieving historical states of contracts or tracking changes over time. + +## When to use a script? + +Scripts can be used for the following: + +1. Validating a transaction before submitting it e.g. checking if the payer has sufficient balance, the receiver account is setup correctly to receive a token or NFT etc. +2. Collecting chain data over time. +3. Continuously verifying accounts through a background job e.g. a Discord bot that verifies users by their Flow account. +4. Querying core contracts e.g. see [staking scripts and events](../../networks/staking/07-staking-scripts-events.md) for querying staking and epoch related information, see the scripts directory under each of the [core contract transactions](https://github.com/onflow/flow-core-contracts/tree/master/transactions) for other core contracts related scripts. + +## Executing Scripts + +### Access API + +A script can be executed by submitting it to the Access API provided by access nodes. Currently, there are three API endpoints that allow a user to execute scripts at the latest sealed block, a previous block height, or a previous block ID. + +[**gRPC Script API**](../../networks/access-onchain-data/index.md#scripts) + +[**REST Script API**](/http-api#tag/Scripts) + +There are multiple SDKs implementing the above APIs for different languages: + +[**Javascript SDK**](../../tools/clients/fcl-js/index.md) + +[**Go SDK**](../../tools/clients/flow-go-sdk/index.md) + +Find a list of all SDKs [here](../../tools/clients/index.md) + +### Flow CLI + +You can also execute a script by using the [Flow CLI](../../tools/flow-cli/scripts/execute-scripts): + +```sh +flow scripts execute ./helloWorld.cdc +``` + +A user can define their own scripts or can use already defined scripts by the contract authors that can be found by using the [FLIX](../../tools/flow-cli/flix) service. + +## Best Practices + +Following are some recommendations on how to write efficient scripts: + +1. **Simpler and shorter scripts**: Scripts, like transactions, are subject to computation limits (see [limitations](#limitations)). It is recommended to run shorter and simpler scripts which have low time complexity for a faster response. If you have a script with several nested loops, long iteration, or that queries many onchain fields, consider simplifying the script logic. + + +2. **Fewer state reads**: A script reads execution state and to get a faster response, it is best to limit the amount of state that is read by the script. + + +3. **Smaller length of array or dictionary type arguments**: If your script requires an array or a dictionary as an argument where each element causes a state lookup, instead of making a single script call passing in a long list, make multiple calls with a smaller subset of the array or dictionary. + + +4. **NFTCatalog**: If your script uses the [NFTCatalog](https://github.com/onflow/nft-catalog) functions, ensure that you use the [latest functions](https://github.com/onflow/nft-catalog?tab=readme-ov-file#using-the-catalog-for-marketplaces-and-other-nft-applications) and do not use any of the deprecated functions such as `getCatalog()`. + + +## Limitations + +1. **Rate limit** - Script execution is subjected to API rate-limits imposed by the Access nodes and the Execution nodes. The rate limits for the Public Access nodes hosted by QuickNode are outlined [here](https://www.quicknode.com/docs/flow#endpoint-rate-limits). + + +2. **Computation limit** - Similar to a transaction, each script is also subjected to a computation limit. The specific value can be configured by individual Access and Execution node operators. Currently, the default compute (gas) limit for a script is 100,000. + + +3. **Historic block data limit** + 1. Script execution on execution nodes is restricted to approximately the last 100 blocks. Any request for script execution on an execution node on a past block (specified by block ID or block height) will fail if that block is more than 100 blocks in the past. + 2. Script execution on an access node can go much beyond the last 100 blocks but is restricted to the height when the [last](https://developers.flow.com/networks/node-ops/node-operation/past-upgrades) network upgrade ([HCU](https://developers.flow.com/networks/node-ops/node-operation/hcu) or spork) occurred. + + + + +=== build/basics/network-architecture.md === +--- +sidebar_position: 0 +title: Network Architecture ↗️ +--- + + + +; + + +=== build/basics/mev-resistance.md === +--- +title: MEV Resistance +description: How Flow’s unique architecture minimizes Maximal Extractable Value (MEV) to ensure fair and equitable access. +sidebar_position: 5 +keywords: + - MEV + - Maximal Extractable Value + - Flow Blockchain + - Equitable Access + - Transaction Ordering + - Blockchain Security +--- + +# How Flow Suppresses MEV to Ensure Equitable Access + +## The Hidden Cost of MEV in Decentralized Systems + +One of the most under-discussed benefits of decentralization is **equitable access**. Ideally, the value and quality-of-service you receive from a decentralized platform should not depend on your identity, computing power, or personal connections. However, **Maximal Extractable Value (MEV)** poses a significant threat to this principle. + +MEV allows block producers to manipulate transaction ordering for profit—often at the direct expense of users. The ability to front-run, back-run, or sandwich transactions can extract value from ordinary users, reinforcing inequalities rather than eliminating them. In most blockchain networks, MEV is not just an unfortunate side effect; it is structurally embedded in how transactions are processed. + +## Why MEV Persists on Most Blockchains + +MEV is difficult to prevent on most blockchains because **each block has a single builder**. This builder must have: + +- A full copy of the blockchain state +- The ability to simulate transactions before they are finalized +- Absolute control over transaction selection and ordering + +In practice, this means that **the entity responsible for adding your transaction to the blockchain can first simulate it to identify profit opportunities**. They can test hundreds or thousands of ways to rearrange transactions, inserting their own to extract MEV—often at **your** expense. + +For example, if a block builder can earn $10 by sandwiching your transaction, it means **you** likely lose $10 in value. This is functionally theft, and the worst part? If your transaction is airtight and offers no MEV opportunities, the block builder has no obligation to include it at all. Pay the toll, or get locked out. + +## How Flow Accomplishes MEV Resilience + +Unlike many blockchains, **Flow was designed from the ground up to minimize MEV** through a unique multi-role architecture. Flow introduces key design choices that break the typical MEV-enabling structure: + +### 1. **Separating Transaction Selection from Execution** +On Flow, **Collection Nodes** select transactions, but they do not have access to the execution state or computing power to simulate them. Meanwhile, **Execution Nodes** run transactions but cannot choose or reorder them. + +This separation significantly reduces the ability of block builders to test transactions before execution. Even if an attacker controls both a Collection Node and an Execution Node, they cannot easily extract MEV. + +### 2. **Separating Transaction Ordering from Execution** +Flow further decentralizes control by introducing **Consensus Nodes** that determine transaction order. These nodes are separate from both Collection Nodes and Execution Nodes. + +For an attacker to perform MEV, they would need to: +- Control a **Collection Node** to insert a transaction +- Control a **Consensus Node** to place it in the desired order +- Have execution state access to predict its effects + +This makes it vastly more difficult to extract MEV compared to traditional blockchains, where a single entity often controls all three functions. + +### 3. **Strict Transaction Execution Rules** +Execution Nodes on Flow have a **simple, enforceable rule**: +They **must** execute transactions exactly as ordered by Consensus Nodes—or they get slashed. + +Unlike traditional blockchains, where the same party both orders and executes transactions, Flow ensures that Execution Nodes cannot manipulate transaction order for profit. + +### 4. **Parallel Processing for Extra MEV Resistance** +Flow’s unique **pipelined execution model** adds another layer of complexity for potential attackers. + +While one block is being executed, the next block is undergoing consensus, and a third block is still collecting transactions. This means that **to front-run or sandwich attack on Flow, an attacker must successfully predict the outcome of at least two unexecuted blocks—one of which hasn’t even been built yet**. + +Even with significant resources, this makes profitable MEV attacks incredibly difficult. + +## The End Result: A Fairer Blockchain + +Flow’s architecture ensures that: +- The nodes selecting transactions **don’t know** their order +- The nodes ordering transactions **don’t know** the blockchain state +- The nodes executing transactions **can’t** modify the order + +By **intentionally separating powers**, Flow eliminates MEV at its root rather than merely mitigating its effects. + +This level of protection against MEV is not an afterthought—it has been a fundamental design goal of Flow since day one. If equitable access matters, **why settle for anything less?** + + +=== build/basics/flow-token.md === +--- +title: FLOW Coin +sidebar_position: 10 +description: Learn about the FLOW coin, its role as the native token of the Flow blockchain, and how to acquire, use, and build with it. Understand staking, delegation, and transaction fee mechanisms. +keywords: + - FLOW coin + - FLOW token + - native token + - fungible token + - staking + - delegation + - transaction fees + - Flow protocol + - Flow rewards + - token utility + - Flow wallet + - token custody + - Flow transactions + - Flow governance + - Flow ecosystem +--- + +## Introduction + +This section contains information about the FLOW Coin for individual backers, wallet providers, custodians and node operators. + +### FLOW as a Native Coin + +FLOW is the default coin for the Flow protocol, meaning it is used for all protocol-level fee payments, +rewards and staking transactions. FLOW implements the standard [Flow Fungible Token interface](https://github.com/onflow/flow-ft), +which all other on-chain fungible tokens also conform to. This interface is defined in Cadence, +Flow's native smart-contract programming language, which makes it easy to write applications that +interact with FLOW. + +## How to Get FLOW + +There are two ways to acquire FLOW Coins as yield: + +1. [Earn FLOW as a Validator or Delegator](../../networks/staking/06-technical-overview.md): Receive newly-minted FLOW as a reward for running a node. +1. [Earn FLOW as a Community Contributor](https://github.com/onflow/developer-grants): Flow offers grants for selected proposals as well as RFPs for teams to submit proposals for funded development + +## How to Use FLOW + +With FLOW, you can: + +- Spend +- Stake +- Delegate +- Hold +- Vote +- Send and share +- Create, develop, and grow your dapp + +### Spending FLOW + +All you need to spend FLOW is an account and a tool for signing transactions +(a wallet, custodian, or other signing service). +The FCL (Flow Client Library) makes it super duper easy to go to any dapp, +login with your account, have a great time, +and then sign with the wallet of your choice only once you decide to make a purchase. + +### Staking FLOW + +[You can use FLOW to operate a staked node.](../../networks/staking/06-technical-overview.md) Node operators receive newly-minted FLOW +as a reward for helping to secure the network. + +### Delegating FLOW + +[You can use FLOW for stake delegation.](../../networks/staking/06-technical-overview.md) Delegators receive newly-minted FLOW +as a reward for helping to secure the network. + +### Holding FLOW + +If you have already purchased FLOW and wish to hold it, you have a couple of options: + +- For relatively small, short term holdings - most people use a wallet. + Wallets are used to help you sign transactions (verify your actions) when using your FLOW tokens. + +- For larger, long term holdings - you may want to use a custody provider to keep your funds safe. + +You can find wallets and custodians supporting Flow in the [Flow Port](https://port.onflow.org/) + +### Voting with FLOW + +Participating in the Flow community is more than just running a node or building a dapp. +It's also about engaging in discussion, debate, and decision making about the protocol, +the content on it, and the people impacted by it. +You can use your Flow account to submit votes to community polls and other governance related activities. + +### Sending and Sharing FLOW + +If you simply want to share the love and bring your friends to Flow, it's easier than an edible arrangement. + +It is possible to use the Flow blockchain without holding any FLOW coins yourself. +Free to play games, trials, community polls, +and other community activities can all take place with only an account +(which may be created on a person's behalf) +and a small fixed fee which may be paid by a user agent. + +The protocol requires some FLOW coins to process these transactions, +but (and this is the cool part!) a product can support users who do not themselves hold FLOW +while still providing that user with all the underlying security guarantees the Flow protocol provides. + +Transferring FLOW, creating accounts, and updating keys are all actions made easy on [Flow Port](https://port.flow.com/) + +### Submitting Transactions and Updating Users + +Transactions are submitted using a Flow SDK via the Access API. + +On Flow, a transaction is identified by its hash - the hash that exists as soon as that transaction is signed and submitted to an Access or Collection node. +Results of transactions can be queried by transaction hash through the Access API. +A user can check the status of a transaction at any time via the [Flow Block Explorer](https://flowscan.io/). + +To expose these results natively in your app, you can use a Flow SDK to fetch transaction results, +[for example using the Flow Go SDK](https://github.com/onflow/flow-go-sdk#querying-transaction-results). + +Using a Flow SDK you can also fetch account state by address from a Flow Access API, +[for example using the Flow Go SDK](https://github.com/onflow/flow-go-sdk#querying-accounts). + +Once the transaction is sealed, an event is emitted and you will be able to read transaction events and update the user. + +The Flow SDKs also allow polling for events using the Flow Access API, +[for example using the Flow Go SDK](https://github.com/onflow/flow-go-sdk#querying-events). + +## How to Build with FLOW + +To get started building on Flow, please see the [Flow App Quickstart](../getting-started/fcl-quickstart.md) + + +=== build/basics/fees.md === +--- +sidebar_position: 5 +title: Fees +description: Learn about Flow blockchain fees, including transaction fees, storage fees, and how they work to protect the network. Understand fee structures, calculation methods, and optimization strategies. +keywords: + - fees + - transaction fees + - storage fees + - execution fees + - inclusion fees + - surge factor + - fee calculation + - storage capacity + - fee optimization + - network protection + - blockchain fees + - gas fees + - Flow token + - fee structure + - cost estimation +--- + +:::info + +Are you an EVM developer looking for information about EVM Accounts on Flow? If so, check out the EVM specific documentation [here](../../evm/fees.md) + +::: + +# Fees + +## Transaction Fees + +A transaction fee is a cost paid in Flow by the payer account and is required for a transaction to be included in the Flow blockchain. Fees are necessary for protecting the network against spam/infinite running transactions and to provide monetary incentives for participants that make up the Flow network. + +A transaction fee is paid regardless of whether a transaction succeeds or fails. If the payer account doesn't have sufficient Flow balance to pay for the transaction fee, the transaction will fail. We can limit the transaction fee to some extent by providing the gas limit value when submitting the transaction. + +### Understanding the need for transaction fees + +Segmented transaction fees are essential to ensure fair pricing based on the impact on the network. For instance, more heavy operations will require more resources to process and propagate transactions. Common operations, however, will stay reasonably priced. + +Fees will improve the overall security of the network by making malicious actions (eg spam) on the network less viable. + +The unique Flow architecture is targeted at high throughput. It makes it easier to have slack in the system, so short spikes can be handled more gracefully. + + +### **Fee Structure** + +Each transaction fee consists of three components: execution fee, inclusion fee, and network surge factor. + +![Screenshot 2023-08-17 at 17.16.32.png](_fees_images/Screenshot_2023-08-17_at_17.16.32.png) + +**Execution Fee** + +The execution effort for a transaction is determined by the code path the transaction takes and the actions it does. The actions that have an associated execution effort cost can be separated into four broad buckets: + +- Normal lines of cadence, loops, or function calls +- Reading data from storage, charged per byte read +- Writing data to storage, charged per byte written +- Account creation + +| Transaction Type | Estimated cost (FLOW) | +| -------------------------------------------------- | --------------------- | +| FT transfer | 0.00000185 | +| Mint a small NFT (heavily depends on the NFT size) | 0.0000019 | +| Empty Transaction | 0.000001 | +| Add key to an account | 0.000001 | +| Create 1 Account | 0.00000315 | +| Create 10 accounts | 0.00002261 | +| Deploying a contract that is ~50kb | 0.00002965 | + +**Inclusion Fee** + +The inclusion effort of a transaction represents the work needed for: + +- Including the transaction in a block +- Transporting the transaction information from node to node +- Verifying transaction signatures + +Right now, the inclusion effort is always 1.0 and the inclusion effort cost is fixed to `0.000001`. + +**Surge Factor** + +In the future, a network surge will be applied when the network is busy due to an increased influx of transactions required to be processed or a decrease in the ability to process transactions. Right now, the network surge is fixed to `1.0`. + +Currently, both the inclusion fee and surge factor don't represent any significant Flow fees. Keep in mind this can change in the future. + +**Estimating transaction costs** + +Cost estimation is a two-step process. First, you need to gather the execution effort with either the emulator, on testnet, or on mainnet. Second, you use the execution effort for a transaction to calculate the final fees using one of the JavaScript or Go FCL SDKs. + +## Storage + +Flow's approach to storage capacity is a bit similar to some banks' pricing models, where maintaining a minimum balance prevents monthly account fees. Here, the amount of data in your account determines your minimum balance. If you fall below the minimum balance, you cannot transact with your account, except for deposits or deleting data. The essence of storage fee model is that it ensures data availability without continuously charging fees for storage, while also preventing abuses that could burden the network's storage resources. This distinction between current state and blockchain history is crucial for understanding storage requirements and limitations. + +Each Flow account has associated storage used. The account's storage used is the byte size of all the data stored in the account's storage. Accounts also have a storage capacity, which is directly tied to the amount of Flow tokens an account has. The account can, without any additional cost, use any amount of storage up to its storage capacity. + +:::warning + +If a transaction puts an account over storage capacity, that transaction fails and is reverted. Likewise, if a transaction would drop an account's balance below 0.001 Flow tokens, which is the minimum an account can have, the transaction would also fail. + +::: + +**Storage Capacity** + +The storage capacity of an account is dictated by the amount of FLOW it has. + +:::danger + +The **minimum amount of FLOW an account can have is 0.001**. This minimum is provided by the account creator at account creation. + +::: + +The minimum account reservation ensures that most accounts won't run out of storage capacity if anyone deposits anything (like an NFT) to the account. + +Currently, the amount required to store 100 MB in account storage is 1 Flow. + +![Screenshot 2023-08-17 at 17.27.50.png](_fees_images/Screenshot_2023-08-17_at_17.27.50.png) + +Please note that storing data in an account on Flow doesn't charge tokens from the account, it just makes sure you will keep the tokens as a reserve. Once the storage is freed up you can transfer the Flow tokens. + +### Storage Capacity of the Payer + +The storage capacity of the Payer of a transaction is generally computed the same way as the capacity of any other account, however, the system needs to account for the transaction fees the payer will incur at the end of the transaction. The final transaction fee amount is not fully known at this step, only when accounts are checked for storage compliance. If their storage used is more than their storage capacity, the transaction will fail. + +Because of this, the payer's balance is conservatively considered to be lower by the maximum possible transaction fees, when checking for storage compliance. The maximum transaction fee of a specific transaction is the transaction fee as if the transaction would have used up all of its execution effort limit. + +### Storage Used + +All data that is in an account's storage counts towards storage used. Even when an account is newly created it is not empty. There are already some items in its storage: + +- Metadata that marks that the account exists. +- An empty FLOW vault, and stored receiver capability. +- Public keys to the account if the account was created with keys. +- Smart contracts deployed on the account if the account was created with contracts. +- The value of the account's storage used as an unsigned integer. + +Adding additional keys, smart contracts, capabilities, resources, etc. to the account counts towards storage used. + +Data stored on the Flow blockchain is stored in a key-value ledger. Each item's key contains the address that owns the item and the path to the item. An account can have many keys, therefore flow considers the account key items are stored with. This means that the storage used by each item is the byte length of the item plus the byte length of the item's key. + +### Maximum available balance + +Due to the storage restrictions, there is a maximum available balance that user can withdraw from the wallet. The core contract [`FlowStorageFees`](../core-contracts/05-flow-fees.md#flowstoragefees) provides a function to retrieve that value: + +```cadence +import "FlowStorageFees" + +access(all) fun main(accountAddress: Address): UFix64 { + return FlowStorageFees.defaultTokenAvailableBalance(accountAddress) +} +``` + +Alternatively developers can use `availableBalance` property of the `Account` + +```cadence +access(all) fun main(address: Address): UFix64 { + let acc = getAccount(address) + let balance = acc.availableBalance + + return balance +} + +``` + +## Practical Understanding of Fees + +**Using Flow Emulator** + +You can start the [emulator using the Flow CLI](../../tools/emulator/index.md#running-the-emulator-with-the-flow-cli). Run your transaction and take a look at the events emitted: + +```shell +0|emulator | time="2022-04-06T17:13:22-07:00" level=info msg="⭐ Transaction executed" computationUsed=3 txID=a782c2210c0c1f2a6637b20604d37353346bd5389005e4bff6ec7bcf507fac06 +``` + +You should see the `computationUsed` field. Take a note of the value, you will use it in the next step. + +**On testnet or mainnet** + +Once a transaction is completed, you can use an explorer like [Flowscan](https://flowscan.io/) to review the transaction details and events emitted. For Flowscan, you can open the transaction in question and look for the event `FeesDeducted` from the [`FlowFees`](https://github.com/onflow/flow-core-contracts/blob/master/contracts/FlowFees.cdc) contract: + +![flowscan-fees](./_fees_images/flowscan-fees.png) + +In the event data on the right side, you will see a set of fields representing [the fees for a specific transaction.](https://github.com/onflow/flow-core-contracts/blob/master/contracts/FlowFees.cdc#L14): + +- Total Fees Paid +- Inclusion Effort +- Execution Effort + +Take a note of the last value in the list - the `executionEffort` value. You will use it in the next step. + +### Calculating final costs + +The cost for transactions can be calculated using the following FCL scripts on mainnet/testnet respectively. + +**On mainnet** + +```cadence +import FlowFees from 0xf919ee77447b7497 +access(all) fun main( + inclusionEffort: UFix64, + executionEffort: UFix64 +): UFix64 { + return FlowFees.computeFees(inclusionEffort: inclusionEffort, executionEffort: executionEffort) +} +``` + +**On testnet** + +```cadence +import FlowFees from 0x912d5440f7e3769e +access(all) fun main( + inclusionEffort: UFix64, + executionEffort: UFix64 +): UFix64 { + return FlowFees.computeFees(inclusionEffort: inclusionEffort, executionEffort: executionEffort) +} +``` + +## Configuring execution limits + +FCL SDKs allow you to set the execution effort limit for each transaction. Based on the execution effort limit determined in the previous step, you should set a reasonable maximum to avoid unexpected behavior and protect your users. The final transaction fee is computed from the actual execution effort used up to this maximum. + +> **Note**: Keep in mind that the limits are not for the final fees that the user will have to pay. The limits are for the execution efforts specifically. + +It is important to set a limit that isn't too high or too low. If it is set too high, the payer needs to have more funds in their account before sending the transaction. If it is too low, the execution could fail and all state changes are dropped. + +**Using FCL JS SDK** + +You need to set the `limit` parameter for the `mutate` function, for example: + +```js +import * as fcl from "@onflow/fcl" + +const transactionId = await fcl.mutate({ + cadence: ` + transaction { + execute { + log("Hello from execute") + } + } + `, + proposer: fcl.currentUser, + payer: fcl.currentUser, + limit: 100 +}) + +const transaction = await fcl.tx(transactionId).onceExecuted(); +console.log(transaction;) +``` + +**Using FCL Go SDK** + +You need to call the `SetComputeLimit` method to set the fee limit, for example: + +```go +import ( + "github.com/onflow/flow-go-sdk" + "github.com/onflow/flow-go-sdk/crypto" +) + +var ( + myAddress flow.Address + myAccountKey flow.AccountKey + myPrivateKey crypto.PrivateKey +) + +tx := flow.NewTransaction(). + SetScript([]byte("transaction { execute { log(\"Hello, World!\") } }")). + SetComputeLimit(100). + SetProposalKey(myAddress, myAccountKey.Index, myAccountKey.SequenceNumber). + SetPayer(myAddress) +``` + +### Maximum transaction fees of a transaction + +The maximum possible fee imposed on the payer for a transaction can be calculated as the **inclusion cost plus the execution cost**. The execution cost is the fee calculated for running the transaction based on the [execution effort limit maximum specified](#configuring-execution-limits). + +The payer will never pay more than this amount for the transaction. + +## Optimizing Cadence code to reduce effort + +Several optimizations can lead to reduced execution time of transactions. Below is a list of some practices. This list is not exhaustive but rather exemplary. + +**Limit functions calls** + +Whenever you make function calls, make sure these are absolutely required. In some cases, you might be able to check prerequisites and avoid additional calls: + +```cadence +for obj in sampleList { + /// check if call is required + if obj.id != nil { + functionCall(obj) + } +} +``` + +**Limit loops and iterations** + +Whenever you want to iterate over a list, make sure it is necessary to iterate through all elements as opposed to a subset. Avoid loops to grow in size too much over time. Limit loops when possible. + +```cadence +// Iterating over long lists can be costly +access(all) fun sum(list: [Int]): Int { + var total = 0 + var i = 0 + // if list grows too large, this might not be possible anymore + while i < list.length { + total = total + list[i] + } + return total +} + +// Consider designing transactions (and scripts) in a way where work can be "chunked" into smaller pieces +access(all) fun partialSum(list: [Int], start: Int, end: Int): Int { + var partialTotal = 0 + var i = start + while i < end { + partialTotal = partialTotal + list[i] + } + return partialTotal +} +``` + +**Understand the impact of function calls** + +Some functions will require more execution efforts than others. You should carefully review what function calls are made and what execution they involve. + +```cadence +// be aware functions that call a lot of other functions +// (or call themselves) might cost a lot +access(all) fun fib(_ x: Int): Int { + if x == 1 || x== 0 { + return x + } + // + 2 function calls each recursion + return fib(x-1) + fib(x-2) +} + +// consider inlining functions with single statements, to reduce costs +access(all) fun add(_ a: Int, _ b: Int): Int { + // single statement; worth inlining + return a + b +} +``` + +**Avoid excessive load and save operations** + +Avoid costly loading and storage operations and [borrow references](https://cadence-lang.org/docs/design-patterns#avoid-excessive-load-and-save-storage-operations-prefer-in-place-mutations) where possible, for example: + +```cadence +transaction { + + prepare(acct: auth(BorrowValue) &Account) { + + // Borrows a reference to the stored vault, much less costly operation that removing the vault from storage + let vault <- acct.storage.borrow<&ExampleToken.Vault>(from: /storage/exampleToken) + + let burnVault <- vault.withdraw(amount: 10) + + destroy burnVault + + // No `save` required because we only used a reference + } +} +``` + +> **Note**: If the requested resource does not exist, no reading costs are charged. + +**Limit accounts created per transaction** + +Creating accounts and adding keys are associated with costs. Try to only create accounts and keys when necessary. + +**Check user's balance before executing transactions** + +You should ensure that the user's balance has enough balance to cover the highest possible fees. For FT transfers, you need to cover the amount to transfer in addition to the highest possible fees. + +## Educating users + +Wallets will handle the presentation of the final transaction costs but you can still facilitate the user experience by educating them within your application. + +If your user is using self-custody wallets, they may have to pay the transaction and want to understand the fees. Here are some suggestions. + +**Explain that costs can vary depending on the network usage** + +Suggested message: "Fees improve the security of the network. They are flexible to ensure fair pricing based on the impact on the network." + +**Explain that waiting for the network surge to pass is an option** + +Inevitably, network surges will cause higher fees. Users who might want to submit a transaction while the network usage is surging should consider sending the transaction at a later time to reduce costs. + +**Explain that the wallet might not allow the transaction due to a lack of funds** + +If dynamic fees increase to the highest possible level, the user's fund might not be enough to execute the transaction. Let the users know that they should either add funds or try when the network is less busy. + +## How to learn more + +There are several places to learn more about transaction fees: + +- [FLIP-660](https://github.com/onflow/flow/pull/660) +- [FLIP-753](https://github.com/onflow/flow/pull/753) +- [Flow Fees Contract](https://github.com/onflow/flow-core-contracts/blob/master/contracts/FlowFees.cdc) + +> **Note**: If you have thoughts on the implementation of transaction fees on Flow, you can [leave feedback on this forum post](https://forum.onflow.org/t/variable-transaction-fees-are-coming-to-flow/2941). + +## FAQs + +**When will the fee update go into effect?** + +The updates were rolled out with the [Spork on April 6, 2022](../../networks/node-ops/node-operation/past-upgrades#mainnet-17), and were enabled on [June 1st](https://forum.onflow.org/t/permissionless-contract-deployment-progress/2981) during the [weekly epoch transition](https://github.com/onflow/service-account/tree/main/transactions/set-execution-effort-weights/2022/jun-1). + +**Why are fees collected even when transactions fail?** + +Broadcasting and verifying a transaction requires execution, so costs are deducted appropriately. + +**What execution costs are considered above average?** + +There is no average for execution costs. Every function will vary significantly based on the logic implemented. You should review the optimization best practices to determine if you could reduce your costs. + +**Do hardware wallets like Ledger support segmented fees?** + +Yes. + +**What is the lowest execution cost?** + +The lowest execution cost is 1. This means your transaction included one function call or loop that didn't read or write any date. + +**Can I determine how much a transaction will cost on mainnet without actually paying?** + +You can estimate the costs in a two-way process: 1) determine execution costs for transactions (emulator or testnet) and 2) use an FCL SDK method to calculate the final transaction fees. + +**How accurate will testnet fees be to mainnet fees?** + +Final fees are determined by the surge factor on the network. The surge factor for the testnet will be different from the factor for the mainnet, so you need to expect a variation between mainnet and testnet estimates. + +**I use Blocto and I haven't paid any fees yet. Why is that?** + +That is because Blocto is acting as the payer for transactions. Self-custody wallets may have the user pay the transaction. Additionally, apps can sponsor the transaction if they choose. + +**Why would the same transaction have different fees when executed for different accounts?** + +Execution costs, among other things, include the cost to read data from account storage and since the data stored varies from account to account, so does the execution costs, and subsequently the transaction fees. + +Additional Details: + +- The most expensive operations in Cadence are reading and writing to storage. This isn't punitive! Every read needs to be sent to all Verification nodes for verification (with Merkel proofs), and every write requires a path of Merkel hashes to be updated. Reading and writing to storage is inherently expensive on any blockchain. +- The way data is stored in accounts is as a tree (the hint is in the name "atree" :wink:). So, the more elements in the account, the more levels of the tree, and therefore the more nodes of that tree that need to be read and updated. So, looking at the byte size of an account is a decent proxy for figuring out how much it's going to cost. +- Because it's a tree, the cost of reads and writes grows with log(n), but does scale. +- atree has an update queued up for [Crescendo](https://flow.com/upgrade/crescendo) that will improve this. The previous version erred on the side of adding new levels to the tree (to keep the code simple), while the new version tries to pack more data at each level. This should result in fewer levels for the same byte size. Additionally, it includes a more compact encoding leading to a reduction in the byte size of most accounts. +- Even with these improvements, this relationship is likely to remain indefinitely. The bigger the account, the more bookkeeping the nodes have to do, which will result in somewhat larger tx fees. + + +=== build/basics/events.md === +--- +sidebar_position: 6 +title: Events +description: Learn about Flow blockchain events, including core events and user-defined events. Understand how events are emitted during transaction execution and how they can be observed by off-chain applications. +keywords: + - events + - blockchain events + - Flow events + - core events + - user-defined events + - event emission + - event payload + - fungible token events + - fee events + - event listeners + - transaction events + - event types + - event naming + - Flow network + - event observation +--- + +# Events + +Flow events are special values that are emitted on the network during the execution of a Cadence program and can be observed by off-chain observers. + +Events are defined as Cadence code and you should [read Cadence documentation](https://cadence-lang.org/docs/language/events) to understand how to define them. + +Since transactions don't have return values you can leverage events to broadcast certain changes the transaction caused. Clients listening on Flow networks (apps) can listen to these events being emitted and react. + +![Screenshot 2023-08-18 at 14.09.33.png](_events_images/Screenshot_2023-08-18_at_14.09.33.png) + +There are two types of events emitted on the Flow network: + +- Core events +- User-defined events + +Events consist of the **event name** and an optional **payload**. + +![Screenshot 2023-08-18 at 13.59.01.png](_events_images/Screenshot_2023-08-18_at_13.59.01.png) + +## Core Events + +Core events are events emitted directly from the FVM (Flow Virtual Machine). The events have the same name on all networks and do not follow the same naming as user-defined events (they have no address). + +A list of events that are emitted by the Flow network is: + +| Event Name | Description | +| ---------------------------- | ------------------------------------------------------------------------| +| flow.AccountCreated | Event that is emitted when a new account gets created. | +| flow.AccountKeyAdded | Event that is emitted when a key gets added to an account. | +| flow.AccountKeyRemoved | Event that is emitted when a key gets removed from an account. | +| flow.AccountContractAdded | Event that is emitted when a contract gets deployed to an account. | +| flow.AccountContractUpdated | Event that is emitted when a contract gets updated on an account. | +| flow.AccountContractRemoved | Event that is emitted when a contract gets removed from an account. | +| flow.InboxValuePublished | Event that is emitted when a Capability is published from an account. | +| flow.InboxValueUnpublished | Event that is emitted when a Capability is unpublished from an account. | +| flow.InboxValueClaimed1 | Event that is emitted when a Capability is claimed by an account. | + +For more details [on the core events, you can read Cadence reference documentation](https://cadence-lang.org/docs/language/core-events). + +## User-defined events + +Events that are defined inside contracts and when emitted follow a common naming schema. The schema consists of 4 parts: + +```cadence +A.{contract address}.{contract name}.{event type} +``` + +An example event would look like: + +![Screenshot 2023-08-18 at 14.30.36.png](_events_images/Screenshot_2023-08-18_at_14.30.36.png) + +The first `A` means the event is originating from a contract, which will always be the case for user-defined events. The contract address as the name implies is the location of a contract deployed on the Flow network. Next, is the name of the contracted event originates from, and last is the event type defined in the contract. + +There is an unlimited amount of events that can be defined on Flow, but you should know about the most common ones. + +### Fungible Token Events + +All fungible token contracts, including [The FLOW Token contract](../../build/core-contracts/03-flow-token.md), +use the [fungible token standard on Flow](../../build/core-contracts/02-fungible-token.md). +As with any contract, the standard emits events when interacted with. +When any fungible token is transferred, standard events are emitted. +You can find a lot of details on the events emitted in the [Fungible Token documentation](../../build/core-contracts/02-fungible-token.md). + +The most common events are when tokens are transferred which is accomplished with two actions: withdrawing tokens from the payer and depositing tokens in the receiver. Each of those actions has a corresponding event: + +**Withdraw Tokens** + +Event name: `FungibleToken.Withdrawn` +```cadence +event Withdrawn(type: String, + amount: UFix64, + from: Address?, + fromUUID: UInt64, + withdrawnUUID: UInt64, + balanceAfter: UFix64) +``` + +Mainnet event: `A.f233dcee88fe0abe.FungibleToken.Withdrawn` + +Testnet event: `A.9a0766d93b6608b7.FungibleToken.Withdrawn` + +**Deposit Tokens** + +```cadence +event Deposited(type: String, + amount: UFix64, + to: Address?, + toUUID: UInt64, + depositedUUID: UInt64, + balanceAfter: UFix64) +``` + +Event name: `FungibleToken.Deposited` + +Mainnet event: `A.f233dcee88fe0abe.FungibleToken.Deposited` + +Testnet event: `A.9a0766d93b6608b7.FungibleToken.Deposited` + +### **Fee Events** + +Since fees are governed by a contract deployed on the Flow network, that contract also emits events when fees are deducted. + +Charging fees consists of a couple of steps: + +- Calculate and deduct fees +- Withdraw Flow tokens from the payer account +- Deposit Flow tokens to the fees contract + +These events are very common since they accommodate all transactions on Flow. Each fee deduction will result in three events: the withdrawal of Flow tokens, the deposit of Flow tokens, and the fee deduction. + +An example of fee events: + +```yml +Events: + - Index: 0 + Type: A.f233dcee88fe0abe.FungibleToken.Withdrawn + Tx ID: 1ec90051e3bc74fc36cbd16fc83df08e463dda8f92e8e2193e061f9d41b2ad92 + Values: + - type (String): "1654653399040a61.FlowToken.Vault" + - amount (UFix64): 0.00000100 + - from (Address?): b30eb2755dca4572 + + - Index: 1 + Type: A.f233dcee88fe0abe.FungibleToken.Deposited + Tx ID: 1ec90051e3bc74fc36cbd16fc83df08e463dda8f92e8e2193e061f9d41b2ad92 + Values: + - type (String): "1654653399040a61.FlowToken.Vault" + - amount (UFix64): 0.00000100 + - to (Address?): f919ee77447b7497 + + - Index: 2 + Type: A.f919ee77447b7497.FlowFees.FeesDeducted + Tx ID: 1ec90051e3bc74fc36cbd16fc83df08e463dda8f92e8e2193e061f9d41b2ad92 + Values: + - amount (UFix64): 0.00000100 + - inclusionEffort (UFix64): 1.00000000 + - executionEffort (UFix64): 0.00000000 +``` + + +=== build/basics/collections.md === +--- +sidebar_position: 1 +title: Collections +description: Learn about Flow blockchain collections, how they optimize data transfer by linking blocks and transactions, and their role in the network architecture. Understand how collection nodes create and manage transaction collections. +keywords: + - collections + - blockchain collections + - transaction collections + - collection nodes + - HotStuff consensus + - transaction hashes + - network optimization + - collection clusters + - transaction payload + - Flow architecture + - consensus nodes + - collection retrieval + - blockchain scaling + - data optimization +--- + +# Collections + +Collections link blocks and transactions together. Collection node clusters make these collections (using the HotStuff consensus algorithm), made up of an ordered list of one or more hashes of [signed transactions](./transactions.md). In order to optimize data, blocks don't contain transactions (as they do on Ethereum). The benefits are transaction data does not get transferred to consensus nodes on the network which optimizes transfer speed and this architecture allows scaling of ingestion speed by adding collection clusters. Consensus nodes need to only agree on the order of transactions to be executed, they don't need to know the transaction payload, thus making blocks and collections lightweight. Collection nodes hold transaction payloads for anyone who requests them (e.g. execution nodes). + +![Screenshot 2023-08-17 at 19.50.39.png](_collection_images/Screenshot_2023-08-17_at_19.50.39.png) + +## Collection Retrieval + +You can use the Flow CLI to get the collection data by running: + +```sh +flow collections get caff1a7f4a85534e69badcda59b73428a6824ef8103f09cb9eaeaa216c7d7d3f -n mainnet +``` + +Find [more about the command in the CLI docs](../../tools/flow-cli/get-flow-data/get-collections.md). + +Collections can be obtained from the access node APIs, currently, there are two gRPC and REST APIs. You can find more information about them here: + +[**gRPC Collection API**](../../networks/access-onchain-data/index.md#collections) + +[**REST Collection API**](/http-api#tag/Collections) + +There are multiple SDKs implementing the above APIs for different languages: + +[**Javascript SDK**](../../tools/clients/fcl-js/index.md) + +[**Go SDK**](../../tools/clients/flow-go-sdk/index.md) + +Find a list of all SDKs [here](../../tools/clients/index.md) + + +=== build/basics/blocks.md === +--- +sidebar_position: 1 +title: Blocks +description: Learn about Flow blockchain blocks, their structure, lifecycle, and how they maintain the blockchain's state. Understand block headers, payloads, and the finalization process. +keywords: + - blocks + - blockchain blocks + - block header + - block payload + - block seals + - block finalization + - block status + - consensus + - collection guarantees + - block retrieval + - block ID + - block height + - Flow blockchain + - blockchain state +--- + +# Blocks + +## Overview + +Blocks are entities that make up the Flow blockchain. Each block contains a list of [transactions](./transactions.md) that were executed and as a result, changed the global blockchain state. Each block is identified by a unique ID which is a cryptographic hash of the block contents. Block also includes a link to the parent block ID creating a linked list of blocks called the Flow blockchain. + +The unique block ID serves as proof of the block contents which can be independently validated by any observer. Interesting cryptographic properties of the hash that make up the block ID guarantee that if any change is made to the block data it would produce a different hash and because blocks are linked, a different hash would break the link as it would no longer be referenced in the next block. + +A very basic representation of blocks is: + +![Screenshot 2023-08-16 at 15.16.38.png](_blocks_images/Screenshot_2023-08-16_at_15.16.38.png) + +Blocks are ordered starting from the genesis block 0 up to the latest block. Each block contains an ordered list of transactions. This is how the Flow blockchain preserves the complete history of all the changes made to the state from the beginning to the current state. + +Each block contains more data which is divided into **block header** and **block payload**. There are many representations of block data within the Flow protocol. APIs, node types, and specific components within the node may view a block from differing perspectives. For the purpose of this documentation, we will talk about block data we expose through APIs to the clients. + +![Screenshot 2023-08-16 at 10.50.53.png](_blocks_images/Screenshot_2023-08-16_at_10.50.53.png) + +### Block Header + +The Block header contains the following fields: + +- **ID** represents the block's unique identifier, which is derived from the hashing block header including the payload hash. The algorithm used on Flow to hash the content and get an identifier is SHA3 256. This ID is a commitment to all the values in the block staying the same. +- **Parent ID** is a link to the previous block ID in the list making up the blockchain. +- **Height** is the block sequence number, where block 0 was the first block produced, and each next block increments the value by 1. +- **Timestamp** is the timestamp at which this block was proposed by the consensus node. Depending on your use case this time might not be accurate enough, [read more about measuring time on the Flow blockchain](https://cadence-lang.org/docs/measuring-time#time-on-the-flow-blockchain). +- **Payload Hash** represents the payload hash that is included when producing the ID of the block. Payload hash is calculated by taking Merkle root hashes of collection guarantees, seals, execution receipts, and execution results and hashing them together. More on each of the values in the block payload section. + +### Block Payload + +The block payload contains the following fields: + +- **Collection Guarantees** is a list of collection IDs with the signatures from the collection nodes that produced the collections. This acts as a guarantee by collection nodes that [transaction data](./transactions.md) in the collection will be available on the collection node if requested by other nodes at a later time. Flow purposely skips including transaction data in a block, making blocks as small as possible, and the production of new blocks by consensus nodes fast, that is because consensus nodes have to sync the proposed block between nodes, and that data should be the smallest possible. The consensus nodes don't really care what will a transaction do as long as it's valid, they only need to define an order of those transactions in a block. +- **Block Seals** is the attestation by verification nodes that the transactions in a previously executed block have been verified. This seals a previous block referenced by the block ID. It also references the result ID and execution root hash. It contains signatures of the verification nodes that produced the seal. + +## Lifecycle and Status + +Block status is not a value stored inside the block itself but it represents the lifecycle of a block. We derive this value based on the block inclusion in the Flow blockchain and present it to the user as it acts as an important indicator of the finality of the changes the block contains. + +Here we'll give an overview of the different phases a block goes through. [More details can be found in the whitepaper](https://flow.com/technical-paper). Also, a lot of the block states are not necessarily important to the developer but only important to the functioning of the Flow blockchain. + +New blocks are constantly being proposed even if no new transactions are submitted to the network. Consensus nodes are in charge of producing blocks. They use a consensus algorithm (an implementation of HotStuff) to agree on what the new block will be. A block contains the ordered list of collections and each collection contains an ordered list of transactions. This is an important fact to reiterate. A block serves as a list of transitions to the Flow state machine. It documents, as an ordered list, all the changes transactions will make to the state. + +A block that is [agreed upon by the consensus nodes using an implementation of HotStuff consensus algorithm](https://arxiv.org/pdf/2002.07403.pdf) to be the next block is **finalized**. This means the block won't change anymore and it will next be executed by the execution node. Please be careful because until a block is **sealed** the changes are not to be trusted. After verification nodes validate and agree on the correctness of execution results, a block is sealed and consensus nodes will include these seals in the new block. + +In summary, a block can be either **finalized** which guarantees transactions included in the block will stay the same and will be executed, and **sealed** which means the block execution was verified. + +![Screenshot 2023-08-16 at 10.48.26.png](_blocks_images/Screenshot_2023-08-16_at_10.48.26.png) + +## Block Retrieval + +You can use the Flow CLI to get the block data by running: + +```sh +flow blocks get latest -network mainnet +``` + +Find [more about the command in the CLI docs](../../tools/flow-cli/get-flow-data/get-blocks.md). + +Blocks can be obtained from the access node APIs, currently, there are two gRPC and REST APIs. You can find more information about them here: + +[**gRPC Block API**](../../networks/access-onchain-data/index.md#blocks) + +[**REST Block API**](/http-api#tag/Blocks) + +There are multiple SDKs implementing the above APIs for different languages: + +[**Javascript SDK**](../../tools/clients/fcl-js/index.md) + +[**Go SDK**](../../tools/clients/flow-go-sdk/index.md) + +Find a list of all SDKs [here](../../tools/clients/index.md) + + +=== build/basics/accounts.md === +--- +sidebar_position: 2 +title: Accounts +description: Learn about Flow blockchain accounts, including their structure, key management, multi-sig capabilities, and creation process. Understand how accounts store contracts, manage storage, and handle transaction signing. +keywords: + - Flow accounts + - blockchain accounts + - account keys + - multi-sig + - public keys + - account storage + - account creation + - keyless accounts + - service accounts + - account address + - account balance + - signature algorithms + - hash algorithms + - account contracts +--- + +:::info + +Are you an EVM developer looking for information about EVM Accounts on Flow? If so, check out the EVM specific documentation [here](../../evm/accounts.md) + +::: + +# Accounts + +An account on Flow is a record in the chain state that holds the following information: +- Address: unique identifier for the account +- Public Keys: public keys authorized on the account +- Code: Cadence contracts deployed to the account +- Storage: area of the account used to store resource assets. + +Accounts and their keys are needed to sign transactions that change the Flow blockchain state. To execute a transaction, a small amount of Flow, called a ["Fee"](./fees.md) must be paid by the account or subsidized by a wallet or service. Flow allocates a fixed amount of storage to each account for saving data structures and Resources. Flow allocates a [fixed amount of storage](./fees.md#storage) to each account for saving data structures and Resources. +An account may also contain contract code which transactions and scripts can interact with to query or mutate the state of the blockchain. + +A simple representation of an account: + +![Screenshot 2023-08-16 at 16.43.07.png](_accounts_images/Screenshot_2023-08-16_at_16.43.07.png) + +## Address + +A Flow address is represented as 16 hex-encoded characters (usually prefixed with `0x` to indicate hex encoding). Unlike Bitcoin and Ethereum, Flow addresses are not derived from cryptographic public keys. Instead, each Flow address is assigned by the Flow protocol using an on-chain deterministic sequence. The sequence uses an error detection code to guarantee that all addresses differ with at least 2 hex characters. This makes typos resulting in accidental loss of assets not possible. + +This decoupling is a unique advantage of Flow, allowing for multiple public keys to be associated with one account, or for a single public key to be used across several accounts. + +## Balance + +Each Flow account created on Mainnet will by default [hold a Flow vault that holds a balance and is part of the FungibleToken standard](./flow-token.md). This balance is used to pay for [transaction fees and storage fees](./fees.md). More on that in the fees document. + +:::warning + +The minimum amount of FLOW an account can have is **0.001**. + +::: + +This minimum storage fee is provided by the account creator and covers the cost of storing up to 100kB of data in perpetuity. This fee is applied only once and can be "topped up" to add additional storage to an account. The minimum account reservation ensures that most accounts won't run out of storage capacity if anyone deposits anything (like an NFT) to the account. + + +### Maximum available balance + +Due to the storage restrictions, there is a maximum available balance that user can withdraw from the wallet. The core contract [`FlowStorageFees`](../core-contracts/05-flow-fees.md#flowstoragefees) provides a function to retrieve that value: + +```cadence +import "FlowStorageFees" + +access(all) fun main(accountAddress: Address): UFix64 { + return FlowStorageFees.defaultTokenAvailableBalance(accountAddress) +} +``` + +Alternatively developers can use `availableBalance` property of the `Account` + +```cadence +access(all) fun main(address: Address): UFix64 { + let acc = getAccount(address) + let balance = acc.availableBalance + + return balance +} + +``` + +## Contracts + +An account can optionally store multiple [Cadence contracts](https://cadence-lang.org/docs/language/contracts). The code is stored as a human-readable UTF-8 encoded string which makes it easy for anyone to inspect the contents. + +## Storage + +Each Flow account has an associated storage and capacity. The account's storage used is the byte size of all the data stored in the account's storage. An account's [storage capacity is directly tied to the balance of Flow tokens](./fees.md#storage) an account has. An account can, without any additional cost, use any amount of storage up to its storage capacity. If a transaction puts an account over storage capacity or drops an account's balance below the minimum 0.001 Flow tokens, that transaction fails and is reverted. + +## Account **Keys** + +Flow accounts can be configured with multiple public keys that are used to control access. Owners of the associated private keys can sign transactions to mutate the account's state. + +During account creation, public keys can be provided which will be used when interacting with the account. Account keys can be added, removed, or revoked by sending a transaction. This is radically different from blockchains like Ethereum where an account is tied to a single public/private key pair. + +Each account key has a weight that determines the signing power it holds. + +:::warning + +A transaction is not authorized to access an account unless it has a total signature weight greater than or equal to **1000**, the weight threshold. + +::: + +For example, an account might contain 3 keys, each with 500 weight: + +![Screenshot 2023-08-16 at 16.28.58.png](_accounts_images/Screenshot_2023-08-16_at_16.28.58.png) + +This represents a 2-of-3 multi-sig quorum, in which a transaction is authorized to access the account if it receives signatures from *at least* 2 out of 3 keys. + +An account key contains the following attributes: + +- **ID** used to identify keys within an account +- **Public Key** raw public key (encoded as bytes) +- **Signature algorithm** (see below) +- **Hash algorithm** (see below) +- **Weight** integer between 0-1000 +- **Revoked** whether the key has been revoked or it's active +- **Sequence Number** is a number that increases with each submitted transaction signed by this key + +### Signature and Hash Algorithms + +The signature and hashing algorithms are used during the transaction signing process and can be set to certain predefined values. + +There are two curves commonly used with the ECDSA algorithm, secp256r1 ([OID 1.2.840.10045.3.1.7](http://oid-info.com/get/1.2.840.10045.3.1.7), also called the "NIST P-256." this curve is common for mobile secure enclave support), and secp256k1 ([OID 1.3.132.0.10](http://oid-info.com/get/1.3.132.0.10), the curve used by "Bitcoin"). Please be sure to double-check which parameters you are using before registering a key, as presenting a key using one of the curves under the code and format of the other will generate an error. + +| Algorithm | Curve | ID | Code | +| --------- | --------- | --------------- | ---- | +| ECDSA | P-256 | ECDSA_P256 | 2 | +| ECDSA | secp256k1 | ECDSA_secp256k1 | 3 | + +*Please note that the codes listed here are for the signature algorithms as used by the node API, and they are different from the ones [defined in Cadence](https://cadence-lang.org/docs/language/crypto#signing-algorithms)* + +| Algorithm | Output Size | ID | Code | +| --------- | ----------- | -------- | ---- | +| SHA-2 | 256 | SHA2_256 | 1 | +| SHA-3 | 256 | SHA3_256 | 3 | + +Both hashing and signature algorithms are compatible with each other, so you can freely choose from the set. + +### **Locked / Keyless Accounts** + +An account on Flow doesn't require keys in order to exist, but this makes the account immutable since no transaction can be signed that can change the account. This can be useful if we want to freeze an account contract code and it elegantly solves the problem of having multiple account types (as that is the case for Ethereum). + +![Screenshot 2023-08-16 at 18.59.10.png](_accounts_images/Screenshot_2023-08-16_at_18.59.10.png) + +You can achieve keyless accounts by either removing an existing public key from an account signing with that same key and repeating that action until an account has no keys left, or you can create a new account that has no keys assigned. With account linking you can also have a child account that has no keys but is controlled by the parent. + +:::danger + +Be careful when removing keys from an existing account, because once an account's total key weights sum to less than 1000, it can no longer be modified. + +::: + +### **Multi-Sig Accounts** + +Creating a multi-signature account is easily done by managing the account keys and their corresponding weight. To repeat, in order to sign a transaction the keys used to sign it must have weights that sum up to at least 1000. Using this information we can easily see how we can achieve the following cases: + +#### 2-of-3 multi-sig quorum + +![Screenshot 2023-08-16 at 19.34.44.png](_accounts_images/Screenshot_2023-08-16_at_19.34.44.png) + +#### 3-of-3 multi-sig quorum + +![Screenshot 2023-08-16 at 19.34.55.png](_accounts_images/Screenshot_2023-08-16_at_19.34.55.png) + +#### 1-of-2 signature + +![Screenshot 2023-08-16 at 19.34.51.png](_accounts_images/Screenshot_2023-08-16_at_19.34.51.png) + +### Key Format + +We are supporting ECDSA with the curves `P-256` and `secp256k1`. For these curves, the public key is encoded into 64 bytes as `X||Y` where `||` is the concatenation operator. + +- `X` is 32 bytes and is the big endian byte encoding of the `x`-coordinate of the public key padded to 32, i.e. `X=x_31||x_30||...||x_0` or `X = x_31*256^31 + ... + x_i*256^i + ... + x_0`. +- `Y` is 32 bytes and is the big endian byte encoding of the `y`-coordinate of the public key padded to 32, i.e. `Y=y_31||y_30||...||y_0` or `Y = y_31*256^31 + ... + y_i*256^i + ... + y_0` + + +## Account Creation + +Accounts are created on the Flow blockchain by calling a special [create account Cadence function](https://cadence-lang.org/docs/language/accounts#account-creation). Once an account is created we can associate a new key with that account. Of course, all that can be done within a single transaction. Keep in mind that there is an account creation fee that needs to be paid. Account creation fees are relatively low, and we expect that wallet providers and exchanges will cover the cost when a user converts fiat to crypto for the first time. + +For development purposes, [you can use Flow CLI to easily create emulator, testnet and mainnet accounts.](../../tools/flow-cli/accounts/create-accounts.md) The account creation fee is paid by a funding wallet so you don't need a pre-existing account to create it. + +### **Key Generation** + +Keys should be generated in a secure manner. Depending on the purpose of the keys different levels of caution need to be taken. + +:::warning + +Anyone obtaining access to a private key can modify the account the key is associated with (assuming it has enough weight). Be very careful how you store the keys. + +::: + +For secure production keys, we suggest using key management services such as [Google key management](https://cloud.google.com/security-key-management) or [Amazon KMS](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Overview.Encryption.Keys.html), which are also supported by our CLI and SDKs. Those services are mostly great when integrated into your application. However, for personal use, you can securely use any [existing wallets](../../ecosystem/wallets.md) as well as a [hardware Ledger wallet](../../ecosystem/wallets.md). + +## Service Accounts + +### Flow Service Account +The Service Account is a special account in Flow that has special permissions to manage system contracts. It is able to mint tokens, set fees, and update network-level contracts. + +### Tokens & Fees +The Service Account has administrator access to the FLOW token smart contract, so it has authorization to mint and burn tokens. It also has access to the transaction fee smart contract and can adjust the fees charged for transactions execution on Flow. + +### Network Management +The Service Account administers other smart contracts that manage various aspects of the Flow network, such as epochs and (in the future) validator staking auctions. + +### Governance +Besides its special permissions, the Service Account is an account like any other in Flow. +The service account is currently controlled by a smart contract governed by the Flow community. +No single entity has the ability to unilaterally execute a transaction +from the service account because it requires four signatures from controlling keys. +The Flow foundation only controls 3 of the keys and the others are controlled +by trusted community members and organizations. + + +## Accounts Retrieval + +You can use the Flow CLI to get account data by running: + +```sh +flow accounts get 0xf919ee77447b7497 -n mainnet +``` + +Find [more about the command in the CLI docs](../../tools/flow-cli/accounts/get-accounts.md). + +Accounts can be obtained from the access node APIs, currently, there are two gRPC and REST APIs. You can find more information about them here: + +**gRPC API** [building-on-flow/nodes/access-api#accounts](../../networks/access-onchain-data/index.md#accounts) + +**REST API** [http-api#tag/Accounts](/http-api#tag/Accounts) + +There are multiple SDKs implementing the above APIs for different languages: + +**Javascript SDK** [tools/clients/fcl-js](../../tools/clients/fcl-js/index.md) + +**Go SDK** [tools/clients/flow-go-sdk](../../tools/clients/flow-go-sdk/index.md) + +Find a list of all SDKs here: [tools/clients](../../tools/clients/index.md) + + +=== build/app-architecture/index.md === +--- +sidebar_position: 5 +title: App Architecture +description: Learn about self-custody and app custody architectural patterns for building applications on Flow blockchain, including their benefits, considerations, and ideal use cases. +keywords: + - app architecture + - self custody + - app custody + - Flow blockchain + - walletless onboarding + - account linking + - dApp architecture + - blockchain architecture + - key management + - user experience + - web3 development +sidebar_custom_props: + icon: 🏗️ +--- + +# App Architecture on Flow Blockchain + +The Flow blockchain, with its focus on scalability and user-centric design, offers a unique environment for app development. Designed from the ground up, Flow prioritizes user experience, aiming to bridge the gap to mainstream adoption without compromising on decentralization or security. + +While the Flow blockchain offers various architectural patterns, the recommended approaches for developers are **Self-Custody** and **App Custody**. These choices align with Flow's ethos of user-centric design and flexibility. + +### Self-Custody Architecture + +In a self-custody architecture, users retain direct control over their private keys and assets. This model emphasizes user sovereignty and decentralization, placing the responsibility of asset management squarely on the user's shoulders. While it offers the highest degree of control, it also demands a certain level of technical knowledge and awareness from the user, which can sometimes lead to a more complex user experience. + +![self-custody.png](self-custody.png) + +**Architectural Elements**: + +- **Wallet**: A wallet where users store their private keys and sign transactions. +- **Frontend**: Interfaces directly with the user and their wallet for signing transactions. +- **Method of Talking to Chain**: Through FCL directly. + +**Benefits**: + +- **Control**: Users maintain full ownership of their assets and transactions. +- **Security**: Direct management of private keys reduces potential points of failure. + +**Considerations**: + +- **User Experience**: The direct control model can lead to a more complex user experience, especially for those unfamiliar with blockchain. Typically, all transactions must be approved by the user, which can be cumbersome. +- **Key Management**: Users are solely responsible for managing, backing up, and ensuring the safe generation and storage of their keys. + +**Ideal Use Cases**: + +- **Decentralized Finance (DeFi)**: Users interacting with financial protocols while maintaining full control. +- **Web3 Native Users**: Those familiar with blockchain technology and key management. + +### App Custody Architecture + +App custody on Flow offers a unique approach to key management and user experience. Unlike traditional app custody solutions on other blockchains, Flow's App Custody architecture introduces features like **[account linking](../guides/account-linking/index.md)** and **[walletless onboarding](../guides/account-linking/child-accounts.md)**. These features ensure that while users enjoy a seamless experience, they still have the option to link their accounts and move their assets freely around the Flow ecosystem, providing a balanced approach to key management. + +![app-custody.png](app-custody.png) + +**Architectural Elements**: + +- **Wallet**: Both user custody and app custody wallets coexist. +- **Frontend**: Interfaces for both wallet types and features for account linking and walletless onboarding. +- **Backend**: Manages app-custody user keys and assets. Also supports direct blockchain interactions. +- **Method of Interacting with the Chain**: Both direct FCL calls and backend-managed interactions. +- **Payment Rails**: Flexible methods, accommodating both direct and managed transactions. + +**Benefits**: + +- **Walletless Onboarding**: Users can start interacting with the app using traditional, familiar web2 mechanics without the initial need for a blockchain wallet. +- **Streamlined Experience**: Transactions can be processed without constant user approval, offering a smoother user journey. +- **Open Ecosystem with Account Linking**: Users can link their accounts, ensuring they can move their assets freely around the Flow ecosystem without being locked into a single application. +- **Flexibility**: Cater to both tech-savvy users and newcomers without compromising on security. +- **Platform Versatility**: The abstraction of the user wallet allows for integration with various platforms, including Unity games, consoles, and mobile applications. + +**Considerations**: + +- **Complexity**: Implementing app custody can be more intricate. +- **Trust**: Users need to trust the dApp with certain aspects of their data and assets. +- **Legal Implications**: Operating with app custody may come with legal considerations, depending on jurisdiction and the nature of the dApp. It's essential to consult with legal professionals to ensure compliance. + +**Ideal Use Cases**: + +- **Gaming**: Seamless gaming without constant transaction approvals. +- **Social Media Platforms**: Earning tokens for content without initial blockchain familiarity. +- **Loyalty Programs**: Earning rewards without deep blockchain setup. + +## Wrapping Up + +Selecting the right architecture is crucial when developing an app on the Flow blockchain. Your choice will influence not only the technical aspects but also the user experience and overall trust in your application. While Flow offers the tools and flexibility to cater to various needs, it's up to developers to harness these capabilities effectively. Whether you opt for a self-custody or app custody approach, ensure that your decision aligns with the core objectives of your app and the expectations of your users. Making informed architectural decisions will lay a strong foundation for your app's success. + + +=== build/advanced-concepts/scaling.md === +--- +title: Scaling Transactions from a Single Account +description: Learn how to scale transactions from a single account on Flow using multiple proposer keys, enabling concurrent transaction processing for system-level operations. +keywords: + - scaling + - transactions + - proposer keys + - sequence numbers + - concurrent transactions + - system transactions + - transaction scaling + - Flow blockchain + - account scaling + - transaction workers + - batch operations +sidebar_label: Scaling Transactions from a Single Account +--- + +# Scaling Transactions from a Single Account + +Flow is designed for consumer-scale internet applications and is one of the fastest blockchains globally. Transaction traffic on deployed contracts can be divided into two main categories: + +1. **User Transactions** + + These are transactions initiated by users, such as: + + * Buying or selling NFTs + * Transferring tokens + * Swapping tokens on decentralized exchanges (DEXs) + * Staking or unstaking tokens + + In this category, each transaction originates from a unique account and is sent to the Flow network from a different machine. Developers don't need to take special measures to scale for this category, beyond ensuring their logic is primarily on-chain and their supporting systems (e.g., frontend, backend) can handle scaling if they become bottlenecks. Flow's protocol inherently manages scaling for user transactions. + +2. **System Transactions** + + These are transactions initiated by an app's backend or various tools, such as: + + * Minting thousands of tokens from a single minter account + * Creating transaction workers for custodians + * Running maintenance jobs and batch operations + + In this category, many transactions originate from the same account and are sent to the Flow network from the same machine, which can make scaling tricky. This guide focuses on strategies for scaling transactions from a single account. + +In the following sections, we'll explore how to execute concurrent transactions from a single account on Flow using multiple proposer keys. + +:::info + +This guide is specific to non-EVM transactions. For EVM-compatible transactions, you can use any EVM-compatible scaling strategy. + +::: + +## Problem + +Blockchains use sequence numbers, also known as nonces, for each transaction to prevent [replay attacks](https://en.wikipedia.org/wiki/Replay_attack) and allow users to specify the order of their transactions. The Flow network requires a specific sequence number for each incoming transaction and will reject any transaction where the sequence number does not exactly match the expected next value. + +This behavior presents a challenge for scaling, as sending multiple transactions does not guarantee that they will be executed in the order they were sent. This is a fundamental aspect of Flow's resistance to MEV (Maximal Extractable Value), as transaction ordering is randomized within each block. + +If a transaction arrives out of order, the network will reject it and return an error message similar to the following: +``` +* checking sequence number failed: [Error Code: 1007] invalid proposal key: public key X on account 123 has sequence number 7, but given 6 +``` +Our objective is to execute multiple concurrent transactions without encountering the sequence number error described above. While designing a solution, we must consider the following key factors: + +- **Reliability** + + Ideally, we want to avoid local sequence number management, as it is error-prone. In a local sequence number implementation, the sender must determine which error types increment the sequence number and which do not. For instance, network issues do not increment the sequence number, but application errors do. Furthermore, if the sender's sequence number becomes unsynchronized with the network, multiple transactions may fail. + + The most reliable approach to managing sequence numbers is to query the network for the latest sequence number before signing and sending each transaction. + +- **Scalability** + + Allowing multiple workers to manage the same sequence number can introduce coupling and synchronization challenges. To address this, we aim to decouple workers so that they can operate independently without interfering with one another. + +- **Capacity Management** + + To ensure reliability, the system must recognize when it has reached capacity. Additional transactions should be queued and executed once there is sufficient throughput. Fire-and-forget strategies are unreliable for handling arbitrary traffic, as they do not account for system capacity. + +## Solution + +Flow's transaction model introduces a unique role called the proposer. Each Flow transaction is signed by three roles: authorizer, proposer, and payer. The proposer key determines the sequence number for the transaction, effectively decoupling sequence number management from the authorizer and enabling independent scaling. You can learn more about this concept [here](https://developers.flow.com/build/basics/transactions#proposal-key). + +We can leverage this model to design an ideal system transaction architecture as follows: + +- **Multiple Proposer Keys** + + Flow accounts can have multiple keys. By assigning a unique proposer key to each worker, each worker can independently manage its own sequence number without interference from others. + +- **Sequence Number Management** + + Each worker ensures it uses the correct sequence number by fetching the latest sequence number from the network. Since workers operate with different proposer keys, there are no conflicts or synchronization issues. + +- **Queue and Processing Workflow** + + * Each worker picks a transaction request from the incoming requests queue, signs it with its assigned proposer key, and submits it to the network. + * The worker remains occupied until the transaction is finalized by the network. + * If all workers are busy, the incoming requests queue holds additional requests until there is enough capacity to process them. + +- **Key Reuse for Optimization** + + To simplify the system further, we can reuse the same cryptographic key multiple times within the same account by adding it as a new key. These additional keys can have a weight of 0 since they do not need to authorize transactions. + +Here's a visual example of how such an [account configuration](https://www.flowscan.io/account/18eb4ee6b3c026d2?tab=keys) might look: + +![Example.Account](scaling-example-account.png "Example Account") + +As shown, the account includes additional weightless keys designated for proposals, each with its own independent sequence number. This setup ensures that multiple workers can operate concurrently without conflicts or synchronization issues. + +In the next section, we'll demonstrate how to implement this architecture using the [Go SDK](https://github.com/onflow/flow-go-sdk). + +## Example Implementation + +An example implementation of this architecture can be found in the [Go SDK Example](https://github.com/onflow/flow-go-sdk/blob/master/examples/transaction_scaling/main.go). + +This example deploys a simple `Counter` contract: + +```cadence +access(all) contract Counter { + + access(self) var count: Int + + init() { + self.count = 0 + } + + access(all) fun increase() { + self.count = self.count + 1 + } + + access(all) view fun getCount(): Int { + return self.count + } +} +``` + +The goal is to invoke the `increase()` function 420 times concurrently from a single account. By adding 420 concurrency keys and using 420 workers, all these transactions can be executed almost simultaneously. + +### Prerequisites + +We're using Testnet to demonstrate real network conditions. To run this example, you need to create a new testnet account. Start by generating a key pair: + +```bash +flow keys generate +``` + +You can use the generated key with the [faucet](https://testnet-faucet.onflow.org/create-account) to create a testnet account. Update the corresponding variables in the `main.go` file: + +```go +const PRIVATE_KEY = "123" +const ACCOUNT_ADDRESS = "0x123" +``` + +### Code Walkthrough + +When the example starts, it will deploy the `Counter` contract to the account and add 420 proposer keys with the following transaction: + +```cadence +transaction(code: String, numKeys: Int) { + + prepare(signer: auth(AddContract, AddKey) &Account) { + // deploy the contract + signer.contracts.add(name: "Counter", code: code.decodeHex()) + + // copy the main key with 0 weight multiple times + // to create the required number of keys + let key = signer.keys.get(keyIndex: 0)! + var count: Int = 0 + while count < numKeys { + signer.keys.add( + publicKey: key.publicKey, + hashAlgorithm: key.hashAlgorithm, + weight: 0.0 + ) + count = count + 1 + } + } +} +``` + +Next, the main loop starts. Each worker will process a transaction request from the queue and execute it. Here's the code for the main loop: + +```go +// populate the job channel with the number of transactions to execute +txChan := make(chan int, numTxs) +for i := 0; i < numTxs; i++ { + txChan <- i +} + +startTime := time.Now() + +var wg sync.WaitGroup +// start the workers +for i := 0; i < numProposalKeys; i++ { + wg.Add(1) + + // worker code + // this will run in parallel for each proposal key + go func(keyIndex int) { + defer wg.Done() + + // consume the job channel + for range txChan { + fmt.Printf("[Worker %d] executing transaction\n", keyIndex) + + // execute the transaction + err := IncreaseCounter(ctx, flowClient, account, signer, keyIndex) + if err != nil { + fmt.Printf("[Worker %d] Error: %v\n", keyIndex, err) + return + } + } + }(i) +} + +close(txChan) + +// wait for all workers to finish +wg.Wait() +``` + +The `IncreaseCounter` function calls the `increase()` function on the `Counter` contract: + +```go +// Increase the counter by 1 by running a transaction using the given proposal key +func IncreaseCounter(ctx context.Context, flowClient *grpc.Client, account *flow.Account, signer crypto.Signer, proposalKeyIndex int) error { + script := []byte(fmt.Sprintf(` + import Counter from 0x%s + + transaction() { + prepare(signer: &Account) { + Counter.increase() + } + } + + `, account.Address.String())) + + tx := flow.NewTransaction(). + SetScript(script). + AddAuthorizer(account.Address) + + // get the latest account state including the sequence number + account, err := flowClient.GetAccount(ctx, flow.HexToAddress(account.Address.String())) + if err != nil { + return err + } + tx.SetProposalKey( + account.Address, + account.Keys[proposalKeyIndex].Index, + account.Keys[proposalKeyIndex].SequenceNumber, + ) + + return RunTransaction(ctx, flowClient, account, signer, tx) +} +``` + +The above code is executed concurrently by each worker. Since each worker operates with a unique proposer key, there are no conflicts or synchronization issues. Each worker independently manages its sequence number, ensuring smooth execution of all transactions. + +Finally, the `RunTransaction` function serves as a helper utility to send transactions to the network and wait for them to be finalized. It is important to note that the proposer key sequence number is set within the `IncreaseCounter` function before calling `RunTransaction`. + +```go +// Run a transaction and wait for it to be sealed. Note that this function does not set the proposal key. +func RunTransaction(ctx context.Context, flowClient *grpc.Client, account *flow.Account, signer crypto.Signer, tx *flow.Transaction) error { + latestBlock, err := flowClient.GetLatestBlock(ctx, true) + if err != nil { + return err + } + tx.SetReferenceBlockID(latestBlock.ID) + tx.SetPayer(account.Address) + + err = SignTransaction(ctx, flowClient, account, signer, tx) + if err != nil { + return err + } + + err = flowClient.SendTransaction(ctx, *tx) + if err != nil { + return err + } + + txRes := examples.WaitForSeal(ctx, flowClient, tx.ID()) + if txRes.Error != nil { + return txRes.Error + } + + return nil +} +``` + +### Running the Example + +Running the example will execute 420 transactions at the same time: + +```bash +→ cd ./examples +→ go run ./transaction_scaling/main.go +. +. +. +Final Counter: 420 +✅ Done! 420 transactions executed in 11.695372059s +``` + +It takes roughly the time of 1 transaction to run all 420 without any errors. + +=== build/advanced-concepts/randomness.md === +--- +title: Flow On-chain Randomness in Cadence +description: Learn how Flow provides native, secure on-chain randomness at the protocol level, enabling developers to build applications with verifiable, unpredictable outcomes without external oracles. +keywords: + - randomness + - VRF + - on-chain randomness + - revertibleRandom + - random beacon + - commit-reveal + - random number generation + - blockchain randomness + - secure randomness + - Flow protocol + - randomness beacon + - PRNG +sidebar_label: VRF (Randomness) in Cadence +--- + +# Randomness on FLOW + +Flow enhances blockchain functionality and eliminates reliance on external oracles by providing native onchain randomness at the protocol level. This secure, decentralized feature empowers developers to build a variety of applications with truly unpredictable, transparent, and fair outcomes, achieved with greater efficiency. + +Flow's onchain randomness delivers immediate random values within smart contracts, bypassing the latency and complexity of oracle integration. Developers can obtain verifiably random results with a single line of Cadence code, streamlining the development process and enhancing the performance of decentralized applications. + +## Use Cases of Onchain Randomness + +- **Gaming:** Integrates fairness and unpredictability into gameplay, enhancing user engagement without delays. +- **NFTs:** Facilitates the creation of uniquely randomized traits in NFTs quickly, adding to their rarity and value. +- **Lotteries & Draws:** Offers instant and verifiably fair random selection for lotteries, solidifying trust in real-time. +- **DeFi Protocols:** Enables rapid and innovative random reward systems within decentralized finance. +- **DAOs:** Assists in unbiased voting and task assignments through immediate randomness. +- **Broad Applications:** Extends to any domain requiring impartial randomization, from asset distribution to security mechanisms, all with the added benefit of on-demand availability. + +## History of the Distributed Randomness Beacon + +Within the Flow protocol, the heart of randomness generation lies in the "Distributed Randomness Beacon". +This module generates randomness that is distributed across the network while adhering to established cryptographic and security standards. +The output from the randomness beacon is a random source for each block that is unpredictable and impartial. + +For over three years, the beacon has ensured protocol security by selecting which consensus node gets to propose the next block and assigning verification nodes to oversee block computations. For those interested in a more detailed exploration of the randomness beacon and its inner workings, you can read [the technical deep dive on the Flow forum](https://forum.flow.com/t/secure-random-number-generator-for-flow-s-smart-contracts/5110). + +### The History and Limitations of `unsafeRandom` (Now Deprecated) + +Cadence has historically provided the `unsafeRandom` function to return a pseudo-random number. The stream of random numbers produced was potentially unsafe in the following two regards: + +1. The sequence of random numbers is potentially predictable by transactions within the same block and by other smart contracts calling into your smart contract. +2. A transaction calling into your smart contract can potentially bias the sequence of random numbers which your smart contract internally generates. Currently, the block hash seeds `unsafeRandom`. Consensus nodes can *easily* bias the block hash and **influence the seed for `unsafeRandom`**. + +:::warning + +⚠️ Note `unsafeRandom` is deprecated since the Cadence 1.0 release. + +::: + +## Guidelines for Safe Usage + +For usage of randomness where result abortion is not an issue, it is recommended to use the Cadence built-in function `revertibleRandom.` `revertibleRandom` returns a pseudo-random number and is based on the Distributed Randomness Beacon. + +```cadence +// Language reference: +// https://cadence-lang.org/docs/language/built-in-functions#revertiblerandom +// Run the snippet here: https://academy.ecdao.org/en/snippets/cadence-random +access(all) fun main(): UInt64 { + // Simple assignment using revertibleRandom - keep reading docs for safe usage! + let rand: UInt64 = revertibleRandom() + return rand +} +``` + +It is notable that the random number generation process is unpredictable (for miners unpredictable at block construction time and for cadence logic unpredictable at time of call), verifiable, uniform, as well as safe from bias by miners and previously-running Cadence code. + +Protocol improvements (documented in [FLIP 120](https://github.com/onflow/flips/blob/main/cadence/20230713-random-function.md)) +expose the randomness beacon to the FVM and Cadence where it can be used to draw safe randoms without latency. + +Although Cadence exposes safe randomness generated by the Flow protocol via `revertibleRandom`, there is an additional safety-relevant aspect that developers need to be mindful about. + +The `revertibleRandom` function can be used safely in some applications where the transaction results are _not_ deliberately reverted after the random number is revealed (i.e. a trusted contract distributing random NFTs to registered users or onchain lucky draw). +However, if applications require a non-trusted party (for instance app users) to submit a transaction calling a randomized (non-deterministic) contract, the developer must explicitly protect the stream of random numbers to not break the security guarantees: + +:::warning + +🚨 A transaction can atomically revert all its action during its runtime and abort. Therefore, it is possible for a transaction calling into your smart contract to post-select favorable results and revert the transaction for unfavorable results. + +::: + +In other words, transactions submitted by a non-trusted party are able to reject their results after the random is revealed. + +:::info + +**Post-selection** - the ability for transactions to reject results they don't like - is inherent to any smart contract platform that allows transactions to roll back atomically. See this very similar [Ethereum example](https://consensys.github.io/smart-contract-best-practices/development-recommendations/general/public-data/). + +::: + +The central aspect that a contract developer needs to think about is the following scenario: + +- Imagine an adversarial user that is sending a transaction that calls your smart contract. +- The transaction includes code that runs after your smart contract returns and inspects the outcome. +- If the outcome is unfavorable (based on some criteria codified in the transaction), the transaction aborts itself. + +As an example, consider a simple coin toss randomized contract where users can bet any amount of tokens against a random binary output. If the coin toss contract outputs `1`, the user doubles their bet. If the coin toss contract outputs `0`, the user loses their bet in favor of the coin toss. + +Although the user (or the honest coin toss contract) cannot predict or bias the outcome, the user transaction can check the randomized result and cancel the transaction if they are losing their bet. This can be done by calling an exception causing the transaction to error. All temporary state changes are cancelled and the user can repeat the process till they double their bet. + +## Commit-Reveal Scheme + +The recommended way to mitigate the problems above is via a commit-reveal scheme. The scheme involves two steps: commit and reveal. During the commit phase, the user transaction commits to accepting the future output of a smart contract where the last remaining input is an unknown random source. The smart contract stores this commitment on the blockchain. At the current level of optimization, the reveal phase can start as early as the next block, when the "future" beacon's source of randomness becomes available. The reveal phase can be executed at any block after that, now that the commitment to a past block is stored on-chain. With a second transaction, the smart contract can be executed to explicitly generate the random outputs. + +There are ideas how to further optimize the developer experience in the future. For example, a transaction could delegate part of its gas to an independent transaction it spawns. Conceptually, also this future solution would be a commit-and-reveal scheme, just immediately happening within the same block. Until we eventually get to this next level, developers may need to implement their own commit-reveal. In Cadence, it is clean and short. + +### FLIP 123 + +On Flow, we have absorbed all security complexity into the platform. + +[FLIP 123: On-chain Random beacon history for commit-reveal schemes](https://github.com/onflow/flips/blob/main/protocol/20230728-commit-reveal.md#flip-123-on-chain-random-beacon-history-for-commit-reveal-schemes) was introduced to provide a safe pattern to use randomness in transactions so that it's not possible to revert unfavorable randomized transaction results. +We recommend this approach as a best-practice example for implementing a commit-reveal scheme in Cadence. The `RandomBeaconHistory` contract provides a convenient archive, where for each past block height (starting Nov 2023) the respective "source of randomness" can be retrieved. The `RandomBeaconHistory` contract is automatically executed by the system at each block to store the next source of randomness value. + +:::info + +While the commit-and-reveal scheme mitigates post-selection of results by adversarial clients, Flow's secure randomness additionally protects against any pre-selection vulnerabilities (like biasing attacks by byzantine miners). + +::: + +A commit-reveal scheme can be implemented as follows. The coin toss example described earlier will be used for illustration: + +- When a user submits a bidding transaction, the bid amount is transferred to the coin toss contract, and the block height where the bid was made is stored. This is a commitment by the user to use the SoR at the current block. Note that the current block's `SoR_A` isn't known to the transaction execution environment, and therefore the transaction has no way to inspect the random outcome and predict the coin toss result. The current block's `SoR_A` is only available once added to the history core-contract, which only happens at the end of the block's execution. The user may also commit to using an SoR of some future block, which is equally unknown at the time the bid is made. +- The coin toss contract may grant the user a limited window of time (i.e a block height range) to send a second transaction for resolving the results and claim any winnings. Failing to do so, the bid amount remains in the coin toss contract. +- Within that reveal transaction, the user calls the coin toss contract, looks us up the block height at which the block was committed and checks that it has already passed. The contract queries that block's `SoR_A` from the core-contract `RandomBeaconHistory` via block height. +- The coin toss contract uses a PRG seeded with the queried `SoR_A` and diversified using a specific information to the use-case (a user ID or resource ID for instance). Diversification does not add new entropy, but it avoids generating the same outcome for different use-cases. If a diversifier (or salt) isn't used, all users that committed a bid on the same block would either win or lose. +- The PRG is used to generate the random result and resolve the bid. Note that the user can make the transaction abort after inspecting a losing result. However, the bid amount would be lost anyway when the allocated window expires. + +The following lines of code illustrate a random coin toss that cannot be gamed or biased. The reveal-and-commit scheme prevent clients from post-selecting favorable outcomes. + +```cadence +// The code below is taken from the example CoinToss contract found in this project repo +// Source: https://github.com/onflow/random-coin-toss + +/// --- Commit --- +/// In this method, the caller commits a bet. The contract takes note of the +/// block height and bet amount, returning a Receipt resource which is used +/// by the better to reveal the coin toss result and determine their winnings. +access(all) fun commitCoinToss(bet: @FungibleToken.Vault): @Receipt { + let receipt <- create Receipt( + betAmount: bet.balance + ) + // commit the bet + // `self.reserve` is a `@FungibleToken.Vault` field defined on the app contract + // and represents a pool of funds + self.reserve.deposit(from: <-bet) + + emit CoinTossBet(betAmount: receipt.betAmount, commitBlock: receipt.commitBlock, receiptID: receipt.uuid) + + return <- receipt +} + +/// --- Reveal --- +/// Here the caller provides the Receipt given to them at commitment. The contract +/// then "flips a coin" with randomCoin(), providing the committed block height +/// and salting with the Receipts unique identifier. +/// If result is 1, user loses, if it's 0 the user doubles their bet. +/// Note that the caller could condition the revealing transaction, but they've +/// already provided their bet amount so there's no loss for the contract if +/// they do +access(all) fun revealCoinToss(receipt: @Receipt): @FungibleToken.Vault { + pre { + receipt.commitBlock <= getCurrentBlock().height: "Cannot reveal before commit block" + } + + let betAmount = receipt.betAmount + let commitBlock = receipt.commitBlock + let receiptID = receipt.uuid + // self.randomCoin() errors if commitBlock <= current block height in call to + // RandomBeaconHistory.sourceOfRandomness() + let coin = self.randomCoin(atBlockHeight: receipt.commitBlock, salt: receipt.uuid) + + destroy receipt + + if coin == 1 { + emit CoinTossReveal(betAmount: betAmount, winningAmount: 0.0, commitBlock: commitBlock, receiptID: receiptID) + return <- FlowToken.createEmptyVault() + } + + let reward <- self.reserve.withdraw(amount: betAmount * 2.0) + + emit CoinTossReveal(betAmount: betAmount, winningAmount: reward.balance, commitBlock: commitBlock, receiptID: receiptID) + + return <- reward +} +``` + +### Which random function should be used: + +While both are backed by Flow's Randomness Beacon it is important for developers to mindfully choose between `revertibleRandom` or +seeding their own PRNG utilizing the `RandomBeaconHistory` smart contract: + +- With `revertibleRandom` a developer is calling the transaction environment, + which has the power to abort and revert if it doesn't like `revertibleRandom`'s outputs. + `revertibleRandom` is only suitable for smart contract functions that exclusively run within the trusted transactions. +- In contrast, the `RandomBeaconHistory` contract is key for effectively implementing a commit-reveal scheme, where the transaction is non-trusted and may revert the random outputs. + During the commit phase, the user commits to proceed with a future source of randomness, + which is only revealed after the commit transaction concluded. + For each block, the `RandomBeaconHistory` automatically stores the generated source of randomness. + At the time of revealing the source, the committed source becomes a past-block source that can be queried through the history contract. + +Adding a safe pattern to reveal randomness without the possibility of conditional transaction reversion unlocks applications relying on randomness. By providing examples of commit-reveal implementations we hope to foster a more secure ecosystem of decentralized applications and encourage developers to build with best practices. + +In simpler terms, the native secure randomness provided by the protocol can now be safely utilized within Cadence smart contracts +and is available to all developers on Flow and the FVM. + +## An Invitation to Build + +Flow's onchain randomness opens new doors for innovation in web3, offering developers the tools to create fair and transparent decentralized applications. With this feature, new possibilities emerge—from enhancing gameplay in decentralized gaming to ensuring the integrity of smart contract-driven lotteries or introducing novel mechanisms in DeFi. + +This is an invitation for builders and creators: leverage Flow's onchain randomness to distinguish your projects and push the boundaries of what's possible. Your imagination and code have the potential to forge new paths in the web3 landscape. So go ahead and build; the community awaits the next big thing that springs from true randomness. + +## Learn More + +If you'd like to dive deeper into Flow's onchain randomness, here's a list of resources: + +- To learn more about how randomness works under the hood, see [the forum post](https://forum.flow.com/t/secure-random-number-generator-for-flow-s-smart-contracts/5110). +- These documents provide a more in-depth technical understanding of the updates and enhancements to the Flow blockchain. + - **[FLIP 120: Update unsafeRandom function](https://github.com/onflow/flips/blob/main/cadence/20230713-random-function.md#flip-120-update-unsaferandom-function)** + - **[FLIP 123: On-chain Random beacon history for commit-reveal schemes](https://github.com/onflow/flips/blob/main/protocol/20230728-commit-reveal.md#flip-123-on-chain-random-beacon-history-for-commit-reveal-schemes)** +- To see working Cadence code, explore the [coin toss example on GitHub](https://github.com/onflow/random-coin-toss). + + +=== build/advanced-concepts/metadata-views.md === +--- +title: NFT Metadata Views +description: Learn about Flow's standardized way to represent and manage NFT metadata through MetadataViews, enabling consistent metadata interpretation across different platforms and marketplaces. +keywords: + - NFT metadata + - MetadataViews + - NFT standards + - metadata views + - Flow NFT + - ViewResolver + - NFT traits + - NFT royalties + - NFT editions + - contract metadata + - NFT display + - metadata implementation +sidebar_label: NFT Metadata Views +--- + +# NFT Metadata Views on Flow + +`MetadataViews` on Flow offer a standardized way to represent onchain metadata +across different NFTs. Through its integration, developers can ensure +that different platforms and marketplaces can interpret the NFT metadata +in a unified manner. This means that when users visit different websites, +wallets, and marketplaces, +the NFT metadata will be presented in a consistent manner, +ensuring a uniform experience across various platforms. + +:::info + +It is important to understand this document so you can make meaningful decisions +about how to manage your project's metadata as support for metadata views does +not happen by default. Each project has unique metadata and therefore will have to +define how they expose it in unique ways. + +::: + +A view is a standard Cadence struct that represents a specific type of metadata, +such as a [Royalty specification](https://github.com/onflow/flow-nft?tab=readme-ov-file#royalty-view): +```cadence +access(all) struct Royalty { + /// Where royalties should be paid to + access(all) let receiver: Capability<&{FungibleToken.Receiver}> + + /// The cut of the sale that should be taken for royalties. + access(all) let cut: UFix64 + + /// Optional description of the royalty + access(all) let description: String +} +``` + +or a [rarity description](https://github.com/onflow/flow-nft/blob/master/contracts/MetadataViews.cdc#L614): +```cadence +access(all) struct Rarity { + /// The score of the rarity as a number + access(all) let score: UFix64? + + /// The maximum value of score + access(all) let max: UFix64? + + /// The description of the rarity as a string. + access(all) let description: String? +} +``` + +This guide acts as a specification for the correct ways to use each metadata view. +Many of the standard metadata views do not have built-in requirements +for how they are meant to be used, so it is important for developers to understand +the content of this document so third party apps can integrate with their +smart contracts as easily and effectively as possible. + +> If you'd like to follow along while we discuss the concepts below, +you can do so by referring to +the [ExampleNFT contract](https://github.com/onflow/flow-nft/blob/master/contracts/ExampleNFT.cdc). +Additionally, here is the source code for the +[`ViewResolver` contract](https://github.com/onflow/flow-nft/blob/master/contracts/ViewResolver.cdc) +and the [`MetadataViews` contract](https://github.com/onflow/flow-nft/blob/master/contracts/MetadataViews.cdc). + +Flowty has also provided [a useful guide](https://docs.flowty.io/developer-docs/) +for how to manage metadata views properly +in order to be compatible with their marketplace. This guide is very useful +because all of their advice is generally good advice for any NFT contract, +regardless of what marketplace it is using. + +## Two Levels of Metadata: An Overview + +Metadata in Cadence is structured at two distinct levels: + +1. **Contract-Level Metadata**: This provides an overarching description +of the entire NFT collection/project. +Any metadata about individual NFTs is not included here. + +2. **NFT-Level Metadata**: Diving deeper, this metadata relates to individual NFTs. +It provides context, describes rarity, and highlights other distinctive attributes +that distinguish one NFT from another within the same collection. + +While these distinct levels describe different aspects of a project, +they both use the same view system for representing the metadata +and the same basic function calls to query the information, +just from different places. + +## Understanding `ViewResolver` and `MetadataViews.Resolver` + +When considering Flow and how it handles metadata for NFTs, +it is crucial to understand two essential interfaces: +`ViewResolver` and `MetadataViews.Resolver`. +[Interfaces](https://cadence-lang.org/docs/language/interfaces) +serve as blueprints for types that specify the required fields and methods +that your contract or [composite type](https://cadence-lang.org/docs/language/composite-types) must adhere to +to be considered a subtype of that interface. +This guarantees that any contract asserting adherence to these interfaces +will possess a consistent set of functionalities +that other applications or contracts can rely on. + +1. **`ViewResolver` for Contract-Level Metadata**: + - This interface ensures that **contracts**, particularly those encapsulating NFT collections, conform to the Metadata Views standard. + - Through the adoption of this interface, contracts can provide dynamic metadata that represents the entirety of the collection. +2. **`MetadataViews.Resolver` (`ViewResolver.Resolver` in Cadence 1.0) for NFT-Level Metadata**: + - Used within **individual NFT resources**, this interface ensures each token adheres to the Metadata standard format. + - It focuses on the distinct attributes of an individual NFT, such as its unique ID, name, description, and other defining characteristics. + +### Core Functions + +Both the `ViewResolver` and `MetadataViews.Resolver` utilize the following core functions: + +### `getViews` Function + +This function provides a list of supported metadata view types, +which can be applied either by the contract (in the case of `ViewResolver`) +or by an individual NFT (in the case of `MetadataViews.Resolver`). + +```cadence +access(all) fun getViews(): [Type] { + return [ + Type(), + Type(), + ... + ] +} +``` + +### `resolveView` Function + +Whether utilized at the contract or NFT level, this function's role +is to deliver the actual metadata associated with a given view type. + +The caller provides the type of the view they want to query as the only argument, +and the view is returned if it exists, and `nil` is returned if it doesn't. + +```cadence +access(all) fun resolveView(_ view: Type): AnyStruct? { + switch view { + case Type(): + ... + ... + } + return nil +} +``` + +As you can see, the return values of `getViews()` can be used as arguments +for `resolveView()` if you want to just iterate through all the views +that an NFT implements. + + +## NFT-Level Metadata Implementation + +NFT-level metadata addresses the unique attributes of individual tokens +within a collection. It provides structured information for each NFT, +including its identifier, descriptive elements, royalties, +and other associated metadata. Incorporating this level of detail +ensures consistency and standardization among individual NFTs, +making them interoperable and recognizable across various platforms and marketplaces. + +### Core Properties + +In the code below, an NFT has properties such as +its unique ID, name, description, and others. +When we add the `NonFungibleToken.NFT` and by extension, +the `MetadataViews.Resolver` to our NFT resource, +we are indicating that these variables will adhere to the specifications +outlined in the MetadataViews contract for each of these properties. +This facilitates interoperability within the Flow ecosystem +and assures that the metadata of our NFT can be consistently accessed +and understood by various platforms and services that interact with NFTs. + +```cadence +access(all) resource NFT: NonFungibleToken.NFT { + access(all) let id: UInt64 + access(all) let name: String + access(all) let description: String + access(all) let thumbnail: String + access(self) let royalties: [MetadataViews.Royalty] + access(self) let metadata: {String: AnyStruct} + ... +} +``` + +To make this possible though, it is **vital** that projects +all use the standard metadata views in the same way, so third-party +applications can consume them in standard ways. + +For example, many metadata views have `String`-typed fields. It is difficult +to enforce that these fields are formatted in the correct way, so it is important +for projects to be dilligent about how they use them. Take `Traits` for example, +a commonly misused metadata view: +```cadence +access(all) struct Trait { + // The name of the trait. Like Background, Eyes, Hair, etc. + access(all) let name: String + ... + ... +} +``` +The name of the trait should be formatted in a way so that it is easy to display +on a user-facing website. Many projects will use something like CamelCase for +the value, so it looks like "HairColor", which is not pretty on a website. +The correct format for this example would be "Hair Color". +This is just one of many common view uses that projects need to be aware of +to maximize the chance of success for their project. + +## Metadata Views for NFTs + +`MetadataViews` types define how the NFT presents its data. +When invoked, the system knows precisely which view to return, +ensuring that the relevant information is presented consistently across various platforms. +In this section of the document, we will explore each metadata view and describe +how projects should properly use them. + +### Display + +This view provides the bare minimum information about the NFT +suitable for listing or display purposes. When the `Display` type is invoked, +it dynamically assembles the visual and descriptive information +that is typically needed for showcasing the NFT in marketplaces or collections. + +```cadence +case Type(): + return MetadataViews.Display( + name: self.name, + description: self.description, + thumbnail: MetadataViews.HTTPFile( + url: self.thumbnail + ) + ) +``` +If the thumbnail is a HTTP resource: +```cadence +thumbnail : MetadataViews.HTTPFile(url: *Please put your url here) +``` + +If the thumbnail is an IPFS resource: +```cadence +// +thumbnail : MetadataViews.IPFSFile( + cid: thumbnail cid, // Type + path: ipfs path // Type specify path if the cid is a folder hash, otherwise use nil here +) +``` + +![MetadataViews.Display](display.png "Display") + +:::info + +Note about SVG files on-chain: SVG field should be sent as `thumbnailURL`, +should be base64 encoded, and should have a dataURI prefix, like so: +``` +data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InJlZCIvPjwvc3ZnPg== +``` + +::: + +### Editions + +The `Editions` view provides intricate details regarding the particular release of an NFT +within a set of NFTs with the same metadata. +This can include information about the number of copies in an edition, +the specific NFT's sequence number within that edition, or its inclusion in a limited series. +When the `Editions` view is queried, it retrieves this data, +providing collectors with the information they need to comprehend +the rarity and exclusivity of the NFT they are interested in. + +An NFT can also be part of multiple editions, which is why the `Editions` view +can hold any number of `Edition` structs in an array. + +For example, if an NFT is number 11 of 30 of an exclusive edition, +the code to return the `Editions` view would look like this: + +```cadence +case Type(): + let editionInfo = MetadataViews.Edition( + name: "Example NFT Edition", + number: 11, + max: 30 + ) + return MetadataViews.Editions([editionInfo]) +``` + +### Serial Number Metadata + +The `Serial` metadata provides the unique serial number of the NFT, +akin to a serial number on a currency note or a VIN on a car. +This serial number is a fundamental attribute that certifies the individuality +of each NFT and is critical for identification and verification processes. +Serial numbers are expected to be unique among other NFTs from the same project. +Many projects are already using the NFT resource's +[globally unique UUID]([resource's globally unique UUID](https://cadence-lang.org/docs/language/resources#resource-identifier)) +as the ID already, so they will typically also use that as the serial number. + +```cadence +case Type(): + return MetadataViews.Serial(self.uuid) +``` + +### Royalties Metadata + +Royalty information is vital for the sustainable economics of the creators in the NFT space. +[The `Royalties` metadata view](https://github.com/onflow/flow-nft/blob/master/contracts/MetadataViews.cdc#L295) +defines the specifics of any royalty agreements in place, +including the percentage of sales revenue that will go to the original creator +or other stakeholders on secondary sales. + +Each royalty view contains a fungible token receiver capability where royalties should be paid: +```cadence +access(all) struct Royalty { + + access(all) let receiver: Capability<&{FungibleToken.Receiver}> + + access(all) let cut: UFix64 +} +``` + +here is an example of how an NFT might return a `Royalties` view: +```cadence +case Type(): + // Assuming each 'Royalty' in the 'royalties' array has 'cut' and 'description' fields + let royalty = + MetadataViews.Royalty( + // The beneficiary of the royalty: in this case, the contract account + receiver: ExampleNFT.account.capabilities.get<&AnyResource{FungibleToken.Receiver}>(/public/GenericFTReceiver), + // The percentage cut of each sale + cut: 0.05, + // A description of the royalty terms + description: "Royalty payment to the original creator" + ) + } + return MetadataViews.Royalties(detailedRoyalties) +``` + +If someone wants to make a listing for their NFT on a marketplace, +the marketplace can check to see if the royalty receiver +accepts the seller's desired fungible token by calling +the `receiver.getSupportedVaultTypes(): {Type: Bool}` +function via the `receiver` reference: +```cadence +let royaltyReceiverRef = royalty.receiver.borrow() + ?? panic("Could not borrow a reference to the receiver") +let supportedTypes = receiverRef.getSupportedVaultTypes() +if supportedTypes[**royalty.getType()**] { + // The type is supported, so you can deposit + recieverRef.deposit(<-royalty) +} else { + // if it is not supported, you can do something else, + // like revert, or send the royalty tokens to the seller instead +} +``` + +If the desired type is not supported, the marketplace has a few options. +They could either get the address of the receiver by using the +`receiver.owner.address` field and check to see if the account +has a receiver for the desired token, they could perform the sale without a royalty cut, +or they could abort the sale since the token type isn't accepted by the royalty beneficiary. + +You can see example implementations of royalties in the `ExampleNFT` contract +and the associated transactions and scripts. +NFTs are often sold for a variety of currencies, so the royalty receiver should ideally +be a [fungible token switchboard](https://github.com/onflow/flow-ft?tab=readme-ov-file#fungible-token-switchboard) receiver that forwards any received tokens +to the correct vault in the receiving account. + +#### Important instructions for royalty receivers + +If you plan to set your account as a receiver of royalties, +you'll likely want to be able to accept as many token types as possible. +This is possible with the `FungibleTokenSwitchboard`. +If you initialize a switchboard in your account, it can accept any generic fungible token +and route it to the correct vault in your account. + +Therefore, if you want to receive royalties, you should set up your account with the +[`setup_royalty_account_by_paths.cdc`](https://github.com/onflow/flow-ft/blob/master/transactions/switchboard/setup_royalty_account_by_paths.cdc) transaction. + +This will link generic public path from `MetadataViews.getRoyaltyReceiverPublicPath()` +to the capability paths and types that you provide as arguments. +Then you can use that public path and capability for your royalty receiver. + +### External URL Metadata + +The ExternalURL view returns to an associated webpage URL, +providing additional content or information about the NFT. +This can be a website, social media page, or anything else related to the project +that uses a URL. + +```cadence +case Type(): + return MetadataViews.ExternalURL("".concat(self.id.toString())) +``` + +### Traits Metadata + +The [`Trait`](https://github.com/onflow/flow-nft/blob/master/contracts/MetadataViews.cdc#L655) view type encapsulates the unique attributes of an NFT, like any visual aspects or category-defining properties. These can be essential for marketplaces that need to sort or filter NFTs based on these characteristics. +By returning trait views as recommended, you can fit the data in the places you want. +```cadence +access(all) struct Trait { + // The name of the trait. Like Background, Eyes, Hair, etc. + access(all) let name: String + + // The underlying value of the trait + access(all) let value: AnyStruct + + // displayType is used to show some context about what this name and value represent + // for instance, you could set value to a unix timestamp, and specify displayType as "Date" to tell + // platforms to consume this trait as a date and not a number + access(all) let displayType: String? + + // Rarity can also be used directly on an attribute. + // This is optional because not all attributes need to contribute to the NFT's rarity. + access(all) let rarity: Rarity? +``` + +The traits view is extremely important to get right, because many third-party apps +and marketplaces are heavily reliant on it to properly display the entirety of your NFTs. +For example, the names and values of the traits are likely going to be displayed +on a user-facing website, so it is important to return them in a presentable form, such as `First Name`, instead of `first_name` or `firstName`. + +Additionally, limit your `value` field to primitive types like `String`, `Int`, or `Bool`. + +Additionally, the `displayType` is important as well, because it tells websites +how to display the trait properly. Developers should not just default +to `String` or `Integer` for all their display types. +When applicable, the display types to accurately reflect the data that needs to be displayed. + +![MetadataViews.Traits](traits_String.png "traits_String") + +#### Note: Always prefer wrappers over single views + +When exposing a view that could have multiple occurrences on a single NFT, +such as `Edition`, `Royalty`, `Media` or `Trait` the wrapper view should always be used +(such as `Editions`, `Royalties`, etc), even if there is only a single occurrence. +The wrapper view is always the plural version of the single view name +and can be found below the main view definition in the `MetadataViews` contract. + +When resolving the view, the wrapper view should be the returned value, +instead of returning the single view or just an array of several occurrences of the view. + +```cadence +access(all) fun resolveView(_ view: Type): AnyStruct? { + switch view { + case Type(): + let editionInfo = MetadataViews.Edition(name: "Example NFT Edition", number: self.id, max: nil) + let editionList: [MetadataViews.Edition] = [editionInfo] + // return the wrapped view + return MetadataViews.Editions( + editionList + ) + } +} +``` + +## Contract-Level Metadata Implementation + +Contract-level metadata provides a holistic view of an NFT collection, +capturing overarching attributes and contextual information about the entire set, +rather than specifics of individual tokens. These views describe attributes +at the collection or series level rather than individual NFTs. +These views should still should be queryable via individual NFTs though. +One can accomplish this by just forwarding the call +from the NFT's `resolveView()` method to the contract's `resolveView()` method, like so: +```cadence +/// this line is in `ExampleNFT.NFT.resolveView()` +case Type(): + return ExampleNFT.getCollectionDisplay(nftType: Type<@ExampleNFT.NFT>()) +``` + +### NFTCollectionData + +This view provides paths and types related to the NFT collection's storage +and access within the smart contract. The information in this view +is critical for understanding how to interact with a collection. + +```cadence +case Type(): + return MetadataViews.NFTCollectionData( + // where should the collection be saved? + storagePath: ExampleNFT.CollectionStoragePath, + // where to borrow public capabilities from? + publicPath: ExampleNFT.CollectionPublicPath, + // Important types for how the collection should be linked + publicCollection: Type<&ExampleNFT.Collection>(), + publicLinkedType: Type<&ExampleNFT.Collection>(), + // function that can be accessed to create an empty collection for the project + createEmptyCollectionFunction: (fun(): @{NonFungibleToken.Collection} { + return <-ExampleNFT.createEmptyCollection(nftType: Type<@ExampleNFT.NFT>()) + }) + ) +``` + +Here, `NFTCollectionData` is specifying several important elements +related to how the collection is stored and accessed on the Flow blockchain. +It provides information on storage paths and access control paths +for both public and private data, as well as linked types +that specify what capabilities are publicly available +(like collection, receiver, or provider interfaces). + +### NFTCollectionDisplay + +This view describes the collection with visual elements and metadata +that are useful for display purposes, such as in a marketplace or gallery. +Many third party apps need this in order to display high-level information +about an NFT project properly. + +```cadence +case Type(): + let media = MetadataViews.Media( + file: MetadataViews.HTTPFile( + url: "" + ), + mediaType: "image/svg+xml" + ) + return MetadataViews.NFTCollectionDisplay( + name: "The Example Collection", + description: "This collection is used as an example to help you develop your next Flow NFT.", + externalURL: MetadataViews.ExternalURL(""), + squareImage: media, + bannerImage: media, + socials: { + "twitter": MetadataViews.ExternalURL("") + } + ) +``` + +In the example above, the `NFTCollectionDisplay` not only offers fundamental metadata +like the collection's name and description but also provides image URLs +for visual representations of the collection (`squareImage` and `bannerImage`) +and external links, including social media profiles. + +![MetadataViews.CollectionDisplay](collectionDisplay.png "CollectionDisplay") + +### Contract-borrowing Metadata + +With the contract borrowing feature, the [ViewResolver](https://github.com/onflow/flow-nft/blob/master/contracts/ViewResolver.cdc) +interface on contracts can be borrowed directly without needing to import the contract first. +Views can be resolved directly from there. +As an example, you might want to allow your contract +to resolve `NFTCollectionData` and `NFTCollectionDisplay` so that platforms +do not need to find an NFT that belongs to your contract +to get information about how to set up or show your collection. + +```cadence +import ViewResolver from 0xf8d6e0586b0a20c7 +import MetadataViews from 0xf8d6e0586b0a20c7 + +access(all) fun main(addr: Address, name: String): StoragePath? { + let t = Type() + let borrowedContract = getAccount(addr).contracts.borrow<&ViewResolver>(name: name) ?? panic("contract could not be borrowed") + + let view = borrowedContract.resolveView(t) + if view == nil { + return nil + } + + let cd = view! as! MetadataViews.NFTCollectionData + return cd.storagePath +} +``` + +Will Return +```cadence +{"domain":"storage","identifier":"exampleNFTCollection"} +``` + +## More + +Understanding `MetadataViews` and the core functions associated with it +is crucial for developers aiming to deploy NFTs on Flow. +With these views and functions, NFTs can maintain a consistent presentation +across various platforms and marketplaces and foster interoperability +between contracts and applications in the Flow ecosystem. +To gain a deeper understanding of implementing the MetadataView standard, +check out our documentation on "How to Create an NFT Project on Flow". +It provides an introduction to integrating these standards into your NFT contracts. + +- See the [API reference for a complete list of Metadata functions](https://developers.flow.com/build/core-contracts/flow-nft/MetdataViews/MetadataViews) +- Check out [an Example NFT project](https://github.com/onflow/flow-nft/blob/master/contracts/ExampleNFT.cdc) implementing `MetadataViews` +- Read [the NFT Guide](../guides/nft.md) for an introduction to implementation + +=== build/advanced-concepts/flix.md === +--- +title: FLIX (Flow Interaction Templates) +description: Learn about Flow Interaction Templates (FLIX), a standard for creating, auditing, and verifying Flow scripts and transactions with improved security and metadata. +keywords: + - FLIX + - Flow Interaction Templates + - templates + - transactions + - scripts + - smart contracts + - FCL + - interaction templates + - template service +sidebar_position: 3 +--- + +# FLIX (Flow Interaction Templates) + +Flow Interaction Templates is a standard for how contract developers, wallets, users, auditors, and applications can create, audit, and verify the intent, security, and metadata of Flow scripts and transactions, with the goal to improve the understandability and security of authorizing transactions and promote patterns for change resilient composability of applications on Flow. + +Interaction Templates provide a way to use and reuse existing scripts and transactions, as well as to provide more metadata such as a human-readable title and description of what the transaction or script will do, which can be used by the developer as well as the user of the application. + +By using FLIX transactions and scripts, developers don't have to write their own for common operations! + +Read more about the design and purpose of FLIX in the [FLIP](https://github.com/onflow/flips/blob/main/application/20220503-interaction-templates.md) + +## Using FLIX + +Flow makes FLIX available through an API available at flix.flow.com. + +You can query a FLIX API to get an Interaction Template. An example query looks like: https://flix.flow.com/v1/templates?name=transfer-flow + +You can read more about how to query a FLIX API in the documentation available here: [https://github.com/onflow/flow-interaction-template-service](https://github.com/onflow/flow-interaction-template-service) + +:::info + +The FLIX working group is currently working on a protocol to publish FLIX templates on-chain. + +::: + +### Example + +How to integrate FLIX across different developer teams? For this example there are two github repositories. + - (smart contracts) [https://github.com/onflow/hello-world-flix](https://github.com/onflow/hello-world-flix) + - (web development) [https://github.com/onflow/hello-world-web](https://github.com/onflow/hello-world-web) + +The Smart contract developer creates FLIX templates and makes them available in github, these can be versioned. Example is `v0.1.0` release, the templates are available for a specific version. In this example the templates are located at: + - https://github.com/onflow/hello-world-flix/blob/v0.1.0/cadence/templates/ReadHelloWorld.template.json + - https://github.com/onflow/hello-world-flix/blob/v0.1.0/cadence/templates/UpdateHelloWorld.template.json + +Developers can use FLIX templates from the smart contract github to interact with their smart contracts. They simply need the FLIX template URLs to create binding files (TypeScript or JavaScript). One major benefit is the web developers don't need to learn Cadence or copy Cadence to their repository in order to integrate with existing smart contracts. + +TypeScript code generated from templates: +- https://github.com/onflow/hello-world-web/blob/main/app/cadence/readHelloWorld.ts +- https://github.com/onflow/hello-world-web/blob/main/app/cadence/updateHelloWorld.ts + +:::warning + +manually added "@ts-ignore" in generated file because of linting error. 'template' property is typed as "object" when it should also allow strings (url to flix template file). There is current a dev effort that will fix this linting issue. + +::: + +See the `hello-world-web` [README](https://github.com/onflow/hello-world-web/tree/main) for more information on how to generate and execute FLIX templates here [flow-cli flix](../../tools/flow-cli/flix.md) commands + + +### Clients + +There are currently two clients that have integrated with FLIX that you can use: + +**Go client** [https://github.com/onflow/flixkit-go](https://github.com/onflow/flixkit-go) + +**FCL client you** read how to get started [tools/clients/fcl-js/interaction-templates](../../tools/clients/fcl-js/interaction-templates.mdx) + +## (Advanced) Running a FLIX API + +Flow provides an implementation of the Flow interaction template service as an open-source project. If you wish to run your own API, you can find the repository here: [https://github.com/onflow/flow-interaction-template-service](https://github.com/onflow/flow-interaction-template-service) + + +=== build/advanced-concepts/account-abstraction.md === +--- +title: Account Abstraction +description: Learn how Flow provides native support for key use cases enabled by Account Abstraction, including multi-sig transactions, sponsored transactions, and more. +keywords: + - account abstraction + - multi-sig + - sponsored transactions + - bundled transactions + - account recovery + - multi-factor authentication +sidebar_position: 2 +--- + +# Account Abstraction + +Flow provides native support for key use cases that are enabled by Account Abstraction, empowering developers to deliver mainstream-ready user experiences. With Cadence, Flow was designed with these use cases in mind through the separation of the contract and transaction layers. This guide demonstrates how Flow supports key use cases that are made possible with Account Abstraction. + +## Multi-sig Transactions + +Since accounts are smart contracts, they can be defined in order to require multiple signatures in order to execute a transaction, which unlocks a range of new users that improve the user experience for Web3 apps. + +| Account Abstraction | Flow | +| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| The move from from Externally-Owned Accounts (EOAs) to smart contract accounts enables developers to build in logic to require multiple signatures to execute transactions. | Flow has native support for multi-sig transactions since all accounts are defined as smart contracts. Flow provides [support for multiple keys](../basics/accounts.md#account-keys) to be added to an account and weights can be applied to denote relative priority. | + +## Sponsored Transactions + +The concept of paying fees to execute transactions in order to use Web3 apps can be a hurdle for newcomers as they begin to explore these experiences. In order to remove this significant point of friction in requiring newcomers to acquire crypto before they can get started with an app, developers can subsidize these costs on behalf of users. + +| Account Abstraction | Flow | +| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| The ERC-4337 standard introduces the concept of [paymasters](https://eips.ethereum.org/EIPS/eip-4337#extension-paymasters), which can enable a developer to pay the fees for a transaction for their users. | Flow has built-in support for [3 different roles](../basics/transactions.md#signer-roles) for transactions which provides native support for sponsored transactions. | + +## Bundled Transactions + +Developers can deliver a more streamlined user experience that reduces the amount of interruptions in the form of transaction approvals by bundling multiple transactions together into a single transaction that executes the set of operations with one signature. + +| Account Abstraction | Flow | +| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| The ERC-4337 standard outlines support for bundled transactions through a new mempool that holds user operations from smart wallets. Bundlers package sets of these user operations into a single transaction on the blockchain and return the result back to each wallet. | Since Cadence has an explicit separation of contracts and transactions, Flow has protocol-level support for bundling transactions across multiple contracts into a single transaction. | + +## Account Recovery + +Account Abstraction enables developers to build more robust account management features for users, addressing the major pain point of losing access to assets forever if the user loses their keys to their account. Apps can enable users to recover access to their accounts and enclosed assets through social recovery or pre-approved accounts. + +| Account Abstraction | Flow | +| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Smart contract accounts can be defined to include account recovery logic that enables users to define custom recovery methods that can rely on specific accounts or other validated sources. | Since all accounts are smart contracts, Flow has native support for account recovery and cycling of keys to help users regain access to accounts in a secure manner. | + +## Multi-factor Authentication + +Multi-factor authentication is a broadly accepted concept in Web2 apps for secure access to accounts and Account Abstraction enables developers to deliver the same benefits to Web3 users. + +| Account Abstraction | Flow | +| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Smart contract accounts can require a secondary factor to confirm transactions which can be delivered in the form of familiar confirmation channels such as email or SMS. | Since all accounts are smart contracts, Flow has native support for multi-factor authentication as developers can implement these security mechanisms for their users. | + +## Seamless Experience + +Account Abstraction brings the potential for dramatic improvements to the user experience of Web3 apps. Developers can introduce conditions under which a user can grant a smart contract account to pre-approve transactions under certain conditions, reducing interruptions for the user to explicitly sign each transaction. + +These improvements are especially notable on mobile, where users are typically met with the jarring experience of switching between apps in approve transactions. + +| Account Abstraction | Flow | +| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Developers can build new features that streamline the user experience of Web3 apps, such as 'session keys' that pre-approve transactions for a period of time or setting custom limits on transaction volume or network fees. | Since all accounts are smart contracts, Flow has support for these new controls that enable apps to sign pre-approved transactions based on user controls and preferences. | diff --git a/static/llms.txt b/static/llms.txt new file mode 100644 index 0000000000..8d096f8cd6 --- /dev/null +++ b/static/llms.txt @@ -0,0 +1,262 @@ +tutorials/index.md +tutorials/token-launch/register-token.md +tutorials/token-launch/index.md +tutorials/native-vrf/index.md +tutorials/native-vrf/deploy-solidity-contract.md +tutorials/native-vrf/commit-reveal-cadence.md +tutorials/flowtobooth/index.md +tutorials/flowtobooth/image-gallery.md +tutorials/cross-vm-apps/vm-bridge.md +tutorials/cross-vm-apps/introduction.md +tutorials/cross-vm-apps/interacting-with-coa.md +tutorials/cross-vm-apps/index.md +tutorials/cross-vm-apps/direct-calls.md +tutorials/cross-vm-apps/batched-evm-transactions.md +tutorials/cross-vm-apps/add-to-wagmi.md +tutorials/ai-plus-flow/index.md +tutorials/ai-plus-flow/flow-data-sources.md +tutorials/ai-plus-flow/agentkit-flow-guide.md +tutorials/ai-plus-flow/eliza/index.md +tutorials/ai-plus-flow/eliza/build-plugin.md +tutorials/ai-plus-flow/cursor/index.md +tutorials/ai-plus-flow/chatgpt/index.md +tools/index.mdx +tools/error-codes.md +tools/wallet-provider-spec/user-signature.md +tools/wallet-provider-spec/provable-authn.md +tools/wallet-provider-spec/index.md +tools/wallet-provider-spec/custodial.md +tools/wallet-provider-spec/authorization-function.md +tools/vscode-extension/index.md +tools/kit/index.md +tools/flow-dev-wallet/index.md +tools/flow-cli/tests.md +tools/flow-cli/super-commands.md +tools/flow-cli/lint.md +tools/flow-cli/install.md +tools/flow-cli/index.md +tools/flow-cli/flix.md +tools/flow-cli/dependency-manager.md +tools/flow-cli/data-collection.md +tools/flow-cli/boilerplate.md +tools/flow-cli/_template.md +tools/flow-cli/utils/tools.md +tools/flow-cli/utils/snapshot-save.md +tools/flow-cli/utils/signature-verify.md +tools/flow-cli/utils/signature-generate.md +tools/flow-cli/transactions/sign-transaction.md +tools/flow-cli/transactions/send-transactions.md +tools/flow-cli/transactions/send-signed-transactions.md +tools/flow-cli/transactions/get-transactions.md +tools/flow-cli/transactions/decode-transactions.md +tools/flow-cli/transactions/complex-transactions.md +tools/flow-cli/transactions/build-transactions.md +tools/flow-cli/scripts/execute-scripts.md +tools/flow-cli/keys/generate-keys.md +tools/flow-cli/keys/derive-keys.md +tools/flow-cli/keys/decode-keys.md +tools/flow-cli/get-flow-data/get-status.md +tools/flow-cli/get-flow-data/get-events.md +tools/flow-cli/get-flow-data/get-collections.md +tools/flow-cli/get-flow-data/get-blocks.md +tools/flow-cli/flow.json/security.md +tools/flow-cli/flow.json/manage-configuration.md +tools/flow-cli/flow.json/initialize-configuration.md +tools/flow-cli/flow.json/configuration.md +tools/flow-cli/deployment/start-emulator.md +tools/flow-cli/deployment/project-contracts.md +tools/flow-cli/deployment/emulator-snapshot.md +tools/flow-cli/deployment/deploy-project-contracts.md +tools/flow-cli/accounts/get-accounts.md +tools/flow-cli/accounts/create-accounts.md +tools/flow-cli/accounts/account-update-contract.md +tools/flow-cli/accounts/account-staking-info.md +tools/flow-cli/accounts/account-remove-contract.md +tools/flow-cli/accounts/account-fund.md +tools/flow-cli/accounts/account-add-contract.md +tools/emulator/index.md +tools/clients/index.md +tools/clients/flow-go-sdk/migration-v0.25.0.md +tools/clients/flow-go-sdk/index.md +tools/clients/fcl-js/wallet-connect.md +tools/clients/fcl-js/user-signatures.md +tools/clients/fcl-js/transactions.md +tools/clients/fcl-js/sdk-guidelines.md +tools/clients/fcl-js/scripts.md +tools/clients/fcl-js/proving-authentication.mdx +tools/clients/fcl-js/interaction-templates.mdx +tools/clients/fcl-js/installation.mdx +tools/clients/fcl-js/index.md +tools/clients/fcl-js/discovery.md +tools/clients/fcl-js/configure-fcl.md +tools/clients/fcl-js/authentication.md +tools/clients/fcl-js/api.md +tools/clients/fcl-js/cross-vm/wagmi-adapter.mdx +tools/clients/fcl-js/cross-vm/rainbowkit-adapter.mdx +tools/clients/fcl-js/cross-vm/index.md +tools/clients/fcl-js/cross-vm/ethereum-provider.mdx +templates/tutorial.md +networks/index.md +networks/governance.md +networks/staking/index.md +networks/staking/15-staking-guide.md +networks/staking/14-staking-collection.md +networks/staking/13-staking-options.md +networks/staking/12-faq.md +networks/staking/11-machine-account.md +networks/staking/10-qc-dkg-scripts-events.md +networks/staking/09-qc-dkg.md +networks/staking/08-staking-rewards.md +networks/staking/07-staking-scripts-events.md +networks/staking/06-technical-overview.md +networks/staking/05-epoch-scripts-events.md +networks/staking/04-stake-slashing.md +networks/staking/04-epoch-preparation.md +networks/staking/03-schedule.md +networks/staking/02-epoch-terminology.md +networks/node-ops/index.md +networks/node-ops/node-operation/upcoming-sporks.md +networks/node-ops/node-operation/spork.md +networks/node-ops/node-operation/slashing.md +networks/node-ops/node-operation/reclaim-disk.md +networks/node-ops/node-operation/protocol-state-bootstrap.md +networks/node-ops/node-operation/past-upgrades.md +networks/node-ops/node-operation/node-setup.md +networks/node-ops/node-operation/node-roles.md +networks/node-ops/node-operation/node-provisioning.md +networks/node-ops/node-operation/node-providers.md +networks/node-ops/node-operation/node-migration.md +networks/node-ops/node-operation/node-economics.md +networks/node-ops/node-operation/node-bootstrap.md +networks/node-ops/node-operation/monitoring-nodes.md +networks/node-ops/node-operation/machine-existing-operator.md +networks/node-ops/node-operation/hcu.md +networks/node-ops/node-operation/faq.md +networks/node-ops/node-operation/db-encryption-existing-operator.md +networks/node-ops/node-operation/byzantine-node-attack-response.md +networks/node-ops/node-operation/guides/starting-nodes.md +networks/node-ops/node-operation/guides/spork-practice.md +networks/node-ops/node-operation/guides/genesis-bootstrap.md +networks/node-ops/light-nodes/observer-node.md +networks/node-ops/evm-gateway/evm-gateway-setup.md +networks/node-ops/access-nodes/access-node-setup.md +networks/node-ops/access-nodes/access-node-configuration-options.md +networks/network-architecture/user-safety.md +networks/network-architecture/sustainability.md +networks/network-architecture/solving-blockchain-trilemma.md +networks/network-architecture/index.md +networks/flow-port/staking-guide.md +networks/flow-port/index.md +networks/flow-networks/index.md +networks/flow-networks/accessing-testnet.md +networks/flow-networks/accessing-mainnet.md +networks/access-onchain-data/index.md +networks/access-onchain-data/access-http-api.md +networks/access-onchain-data/websockets-stream-api/unsubscribe-message.md +networks/access-onchain-data/websockets-stream-api/subscribe-message.md +networks/access-onchain-data/websockets-stream-api/postman-example.md +networks/access-onchain-data/websockets-stream-api/list-subscriptions-message.md +networks/access-onchain-data/websockets-stream-api/index.md +networks/access-onchain-data/websockets-stream-api/common-errors.md +networks/access-onchain-data/websockets-stream-api/supported-topics/transaction_statuses_topic.md +networks/access-onchain-data/websockets-stream-api/supported-topics/send_and_get_transaction_statuses_topic.md +networks/access-onchain-data/websockets-stream-api/supported-topics/index.md +networks/access-onchain-data/websockets-stream-api/supported-topics/events_topic.md +networks/access-onchain-data/websockets-stream-api/supported-topics/blocks_topic.md +networks/access-onchain-data/websockets-stream-api/supported-topics/block_headers_topic.md +networks/access-onchain-data/websockets-stream-api/supported-topics/block_digests_topic.md +networks/access-onchain-data/websockets-stream-api/supported-topics/account_statuses_topic.md +growth/index.md +evm/using.mdx +evm/quickstart.md +evm/networks.md +evm/how-it-works.md +evm/fees.md +evm/faucets.mdx +evm/cross-chain-bridges.mdx +evm/block-explorers.mdx +evm/accounts.md +evm/about.md +evm/guides/web3-js.md +evm/guides/wagmi.md +evm/guides/vrf.md +evm/guides/remix.md +evm/guides/rainbowkit.md +evm/guides/integrating-metamask.mdx +evm/guides/hardhat.md +evm/guides/foundry.md +evm/guides/ethers.md +ecosystem/wallets.md +ecosystem/vcs-and-funds.md +ecosystem/projects.mdx +ecosystem/index.mdx +ecosystem/hackathons.md +ecosystem/grants.md +ecosystem/faucets.md +ecosystem/developer-profile.md +ecosystem/data-indexers.md +ecosystem/builder-perks.md +ecosystem/bridges.md +ecosystem/block-explorers.md +ecosystem/auditors.md +ecosystem/defi-liquidity/index.md +ecosystem/defi-liquidity/faq.md +ecosystem/defi-liquidity/defi-contracts.md +ecosystem/defi-liquidity/cross-chain-swaps.md +ecosystem/defi-liquidity/add-token-to-metamask.md +build/flow.md +build/explore-more.md +build/smart-contracts/testing.md +build/smart-contracts/overview.md +build/smart-contracts/learn-cadence.md +build/smart-contracts/deploying.md +build/smart-contracts/best-practices/security-best-practices.md +build/smart-contracts/best-practices/project-development-tips.md +build/smart-contracts/best-practices/contract-upgrades.md +build/guides/nft.md +build/guides/more-guides.mdx +build/guides/fungible-token.md +build/guides/account-linking-with-dapper.md +build/guides/mobile/walletless-pwa.md +build/guides/mobile/react-native-quickstart.md +build/guides/mobile/overview.md +build/guides/mobile/ios-quickstart.md +build/guides/account-linking/parent-accounts.md +build/guides/account-linking/index.md +build/guides/account-linking/child-accounts.md +build/getting-started/flow-cli.md +build/getting-started/fcl-quickstart.md +build/getting-started/contract-interaction.md +build/differences-vs-evm/index.md +build/core-contracts/index.md +build/core-contracts/15-bridge.md +build/core-contracts/14-burner.md +build/core-contracts/13-evm.md +build/core-contracts/12-hybrid-custody.md +build/core-contracts/11-staking-collection.md +build/core-contracts/10-nft-storefront.md +build/core-contracts/09-nft-metadata.md +build/core-contracts/08-non-fungible-token.md +build/core-contracts/07-epoch-contract-reference.md +build/core-contracts/06-staking-contract-reference.md +build/core-contracts/05-flow-fees.md +build/core-contracts/04-service-account.md +build/core-contracts/03-flow-token.md +build/core-contracts/02-fungible-token.md +build/basics/transactions.md +build/basics/smart-contracts.md +build/basics/scripts.md +build/basics/network-architecture.md +build/basics/mev-resistance.md +build/basics/flow-token.md +build/basics/fees.md +build/basics/events.md +build/basics/collections.md +build/basics/blocks.md +build/basics/accounts.md +build/app-architecture/index.md +build/advanced-concepts/scaling.md +build/advanced-concepts/randomness.md +build/advanced-concepts/metadata-views.md +build/advanced-concepts/flix.md +build/advanced-concepts/account-abstraction.md \ No newline at end of file diff --git a/static/markdown/build/advanced-concepts/account-abstraction.md b/static/markdown/build/advanced-concepts/account-abstraction.md new file mode 100644 index 0000000000..4336616744 --- /dev/null +++ b/static/markdown/build/advanced-concepts/account-abstraction.md @@ -0,0 +1,66 @@ +--- +title: Account Abstraction +description: Learn how Flow provides native support for key use cases enabled by Account Abstraction, including multi-sig transactions, sponsored transactions, and more. +keywords: + - account abstraction + - multi-sig + - sponsored transactions + - bundled transactions + - account recovery + - multi-factor authentication +sidebar_position: 2 +--- + +# Account Abstraction + +Flow provides native support for key use cases that are enabled by Account Abstraction, empowering developers to deliver mainstream-ready user experiences. With Cadence, Flow was designed with these use cases in mind through the separation of the contract and transaction layers. This guide demonstrates how Flow supports key use cases that are made possible with Account Abstraction. + +## Multi-sig Transactions + +Since accounts are smart contracts, they can be defined in order to require multiple signatures in order to execute a transaction, which unlocks a range of new users that improve the user experience for Web3 apps. + +| Account Abstraction | Flow | +| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| The move from from Externally-Owned Accounts (EOAs) to smart contract accounts enables developers to build in logic to require multiple signatures to execute transactions. | Flow has native support for multi-sig transactions since all accounts are defined as smart contracts. Flow provides [support for multiple keys](../basics/accounts.md#account-keys) to be added to an account and weights can be applied to denote relative priority. | + +## Sponsored Transactions + +The concept of paying fees to execute transactions in order to use Web3 apps can be a hurdle for newcomers as they begin to explore these experiences. In order to remove this significant point of friction in requiring newcomers to acquire crypto before they can get started with an app, developers can subsidize these costs on behalf of users. + +| Account Abstraction | Flow | +| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| The ERC-4337 standard introduces the concept of [paymasters](https://eips.ethereum.org/EIPS/eip-4337#extension-paymasters), which can enable a developer to pay the fees for a transaction for their users. | Flow has built-in support for [3 different roles](../basics/transactions.md#signer-roles) for transactions which provides native support for sponsored transactions. | + +## Bundled Transactions + +Developers can deliver a more streamlined user experience that reduces the amount of interruptions in the form of transaction approvals by bundling multiple transactions together into a single transaction that executes the set of operations with one signature. + +| Account Abstraction | Flow | +| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| The ERC-4337 standard outlines support for bundled transactions through a new mempool that holds user operations from smart wallets. Bundlers package sets of these user operations into a single transaction on the blockchain and return the result back to each wallet. | Since Cadence has an explicit separation of contracts and transactions, Flow has protocol-level support for bundling transactions across multiple contracts into a single transaction. | + +## Account Recovery + +Account Abstraction enables developers to build more robust account management features for users, addressing the major pain point of losing access to assets forever if the user loses their keys to their account. Apps can enable users to recover access to their accounts and enclosed assets through social recovery or pre-approved accounts. + +| Account Abstraction | Flow | +| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Smart contract accounts can be defined to include account recovery logic that enables users to define custom recovery methods that can rely on specific accounts or other validated sources. | Since all accounts are smart contracts, Flow has native support for account recovery and cycling of keys to help users regain access to accounts in a secure manner. | + +## Multi-factor Authentication + +Multi-factor authentication is a broadly accepted concept in Web2 apps for secure access to accounts and Account Abstraction enables developers to deliver the same benefits to Web3 users. + +| Account Abstraction | Flow | +| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Smart contract accounts can require a secondary factor to confirm transactions which can be delivered in the form of familiar confirmation channels such as email or SMS. | Since all accounts are smart contracts, Flow has native support for multi-factor authentication as developers can implement these security mechanisms for their users. | + +## Seamless Experience + +Account Abstraction brings the potential for dramatic improvements to the user experience of Web3 apps. Developers can introduce conditions under which a user can grant a smart contract account to pre-approve transactions under certain conditions, reducing interruptions for the user to explicitly sign each transaction. + +These improvements are especially notable on mobile, where users are typically met with the jarring experience of switching between apps in approve transactions. + +| Account Abstraction | Flow | +| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Developers can build new features that streamline the user experience of Web3 apps, such as 'session keys' that pre-approve transactions for a period of time or setting custom limits on transaction volume or network fees. | Since all accounts are smart contracts, Flow has support for these new controls that enable apps to sign pre-approved transactions based on user controls and preferences. | \ No newline at end of file diff --git a/static/markdown/build/advanced-concepts/flix.md b/static/markdown/build/advanced-concepts/flix.md new file mode 100644 index 0000000000..38f1cc06a9 --- /dev/null +++ b/static/markdown/build/advanced-concepts/flix.md @@ -0,0 +1,75 @@ +--- +title: FLIX (Flow Interaction Templates) +description: Learn about Flow Interaction Templates (FLIX), a standard for creating, auditing, and verifying Flow scripts and transactions with improved security and metadata. +keywords: + - FLIX + - Flow Interaction Templates + - templates + - transactions + - scripts + - smart contracts + - FCL + - interaction templates + - template service +sidebar_position: 3 +--- + +# FLIX (Flow Interaction Templates) + +Flow Interaction Templates is a standard for how contract developers, wallets, users, auditors, and applications can create, audit, and verify the intent, security, and metadata of Flow scripts and transactions, with the goal to improve the understandability and security of authorizing transactions and promote patterns for change resilient composability of applications on Flow. + +Interaction Templates provide a way to use and reuse existing scripts and transactions, as well as to provide more metadata such as a human-readable title and description of what the transaction or script will do, which can be used by the developer as well as the user of the application. + +By using FLIX transactions and scripts, developers don't have to write their own for common operations! + +Read more about the design and purpose of FLIX in the [FLIP](https://github.com/onflow/flips/blob/main/application/20220503-interaction-templates.md) + +## Using FLIX + +Flow makes FLIX available through an API available at flix.flow.com. + +You can query a FLIX API to get an Interaction Template. An example query looks like: https://flix.flow.com/v1/templates?name=transfer-flow + +You can read more about how to query a FLIX API in the documentation available here: [https://github.com/onflow/flow-interaction-template-service](https://github.com/onflow/flow-interaction-template-service) + +:::info + +The FLIX working group is currently working on a protocol to publish FLIX templates on-chain. + +::: + +### Example + +How to integrate FLIX across different developer teams? For this example there are two github repositories. + - (smart contracts) [https://github.com/onflow/hello-world-flix](https://github.com/onflow/hello-world-flix) + - (web development) [https://github.com/onflow/hello-world-web](https://github.com/onflow/hello-world-web) + +The Smart contract developer creates FLIX templates and makes them available in github, these can be versioned. Example is `v0.1.0` release, the templates are available for a specific version. In this example the templates are located at: + - https://github.com/onflow/hello-world-flix/blob/v0.1.0/cadence/templates/ReadHelloWorld.template.json + - https://github.com/onflow/hello-world-flix/blob/v0.1.0/cadence/templates/UpdateHelloWorld.template.json + +Developers can use FLIX templates from the smart contract github to interact with their smart contracts. They simply need the FLIX template URLs to create binding files (TypeScript or JavaScript). One major benefit is the web developers don't need to learn Cadence or copy Cadence to their repository in order to integrate with existing smart contracts. + +TypeScript code generated from templates: +- https://github.com/onflow/hello-world-web/blob/main/app/cadence/readHelloWorld.ts +- https://github.com/onflow/hello-world-web/blob/main/app/cadence/updateHelloWorld.ts + +:::warning + +manually added "@ts-ignore" in generated file because of linting error. 'template' property is typed as "object" when it should also allow strings (url to flix template file). There is current a dev effort that will fix this linting issue. + +::: + +See the `hello-world-web` [README](https://github.com/onflow/hello-world-web/tree/main) for more information on how to generate and execute FLIX templates here [flow-cli flix](../../tools/flow-cli/flix.md) commands + +### Clients + +There are currently two clients that have integrated with FLIX that you can use: + +**Go client** [https://github.com/onflow/flixkit-go](https://github.com/onflow/flixkit-go) + +**FCL client you** read how to get started [tools/clients/fcl-js/interaction-templates](../../tools/clients/fcl-js/interaction-templates.mdx) + +## (Advanced) Running a FLIX API + +Flow provides an implementation of the Flow interaction template service as an open-source project. If you wish to run your own API, you can find the repository here: [https://github.com/onflow/flow-interaction-template-service](https://github.com/onflow/flow-interaction-template-service) \ No newline at end of file diff --git a/static/markdown/build/advanced-concepts/metadata-views.md b/static/markdown/build/advanced-concepts/metadata-views.md new file mode 100644 index 0000000000..5796365faf --- /dev/null +++ b/static/markdown/build/advanced-concepts/metadata-views.md @@ -0,0 +1,594 @@ +--- +title: NFT Metadata Views +description: Learn about Flow's standardized way to represent and manage NFT metadata through MetadataViews, enabling consistent metadata interpretation across different platforms and marketplaces. +keywords: + - NFT metadata + - MetadataViews + - NFT standards + - metadata views + - Flow NFT + - ViewResolver + - NFT traits + - NFT royalties + - NFT editions + - contract metadata + - NFT display + - metadata implementation +sidebar_label: NFT Metadata Views +--- + +# NFT Metadata Views on Flow + +`MetadataViews` on Flow offer a standardized way to represent onchain metadata +across different NFTs. Through its integration, developers can ensure +that different platforms and marketplaces can interpret the NFT metadata +in a unified manner. This means that when users visit different websites, +wallets, and marketplaces, +the NFT metadata will be presented in a consistent manner, +ensuring a uniform experience across various platforms. + +:::info + +It is important to understand this document so you can make meaningful decisions +about how to manage your project's metadata as support for metadata views does +not happen by default. Each project has unique metadata and therefore will have to +define how they expose it in unique ways. + +::: + +A view is a standard Cadence struct that represents a specific type of metadata, +such as a [Royalty specification](https://github.com/onflow/flow-nft?tab=readme-ov-file#royalty-view): +```cadence +access(all) struct Royalty { + /// Where royalties should be paid to + access(all) let receiver: Capability<&{FungibleToken.Receiver}> + + /// The cut of the sale that should be taken for royalties. + access(all) let cut: UFix64 + + /// Optional description of the royalty + access(all) let description: String +} +``` + +or a [rarity description](https://github.com/onflow/flow-nft/blob/master/contracts/MetadataViews.cdc#L614): +```cadence +access(all) struct Rarity { + /// The score of the rarity as a number + access(all) let score: UFix64? + + /// The maximum value of score + access(all) let max: UFix64? + + /// The description of the rarity as a string. + access(all) let description: String? +} +``` + +This guide acts as a specification for the correct ways to use each metadata view. +Many of the standard metadata views do not have built-in requirements +for how they are meant to be used, so it is important for developers to understand +the content of this document so third party apps can integrate with their +smart contracts as easily and effectively as possible. + +> If you'd like to follow along while we discuss the concepts below, +you can do so by referring to +the [ExampleNFT contract](https://github.com/onflow/flow-nft/blob/master/contracts/ExampleNFT.cdc). +Additionally, here is the source code for the +[`ViewResolver` contract](https://github.com/onflow/flow-nft/blob/master/contracts/ViewResolver.cdc) +and the [`MetadataViews` contract](https://github.com/onflow/flow-nft/blob/master/contracts/MetadataViews.cdc). + +Flowty has also provided [a useful guide](https://docs.flowty.io/developer-docs/) +for how to manage metadata views properly +in order to be compatible with their marketplace. This guide is very useful +because all of their advice is generally good advice for any NFT contract, +regardless of what marketplace it is using. + +## Two Levels of Metadata: An Overview + +Metadata in Cadence is structured at two distinct levels: + +1. **Contract-Level Metadata**: This provides an overarching description +of the entire NFT collection/project. +Any metadata about individual NFTs is not included here. + +2. **NFT-Level Metadata**: Diving deeper, this metadata relates to individual NFTs. +It provides context, describes rarity, and highlights other distinctive attributes +that distinguish one NFT from another within the same collection. + +While these distinct levels describe different aspects of a project, +they both use the same view system for representing the metadata +and the same basic function calls to query the information, +just from different places. + +## Understanding `ViewResolver` and `MetadataViews.Resolver` + +When considering Flow and how it handles metadata for NFTs, +it is crucial to understand two essential interfaces: +`ViewResolver` and `MetadataViews.Resolver`. +[Interfaces](https://cadence-lang.org/docs/language/interfaces) +serve as blueprints for types that specify the required fields and methods +that your contract or [composite type](https://cadence-lang.org/docs/language/composite-types) must adhere to +to be considered a subtype of that interface. +This guarantees that any contract asserting adherence to these interfaces +will possess a consistent set of functionalities +that other applications or contracts can rely on. + +1. **`ViewResolver` for Contract-Level Metadata**: + - This interface ensures that **contracts**, particularly those encapsulating NFT collections, conform to the Metadata Views standard. + - Through the adoption of this interface, contracts can provide dynamic metadata that represents the entirety of the collection. +2. **`MetadataViews.Resolver` (`ViewResolver.Resolver` in Cadence 1.0) for NFT-Level Metadata**: + - Used within **individual NFT resources**, this interface ensures each token adheres to the Metadata standard format. + - It focuses on the distinct attributes of an individual NFT, such as its unique ID, name, description, and other defining characteristics. + +### Core Functions + +Both the `ViewResolver` and `MetadataViews.Resolver` utilize the following core functions: + +### `getViews` Function + +This function provides a list of supported metadata view types, +which can be applied either by the contract (in the case of `ViewResolver`) +or by an individual NFT (in the case of `MetadataViews.Resolver`). + +```cadence +access(all) fun getViews(): [Type] { + return [ + Type(), + Type(), + ... + ] +} +``` + +### `resolveView` Function + +Whether utilized at the contract or NFT level, this function's role +is to deliver the actual metadata associated with a given view type. + +The caller provides the type of the view they want to query as the only argument, +and the view is returned if it exists, and `nil` is returned if it doesn't. + +```cadence +access(all) fun resolveView(_ view: Type): AnyStruct? { + switch view { + case Type(): + ... + ... + } + return nil +} +``` + +As you can see, the return values of `getViews()` can be used as arguments +for `resolveView()` if you want to just iterate through all the views +that an NFT implements. + +## NFT-Level Metadata Implementation + +NFT-level metadata addresses the unique attributes of individual tokens +within a collection. It provides structured information for each NFT, +including its identifier, descriptive elements, royalties, +and other associated metadata. Incorporating this level of detail +ensures consistency and standardization among individual NFTs, +making them interoperable and recognizable across various platforms and marketplaces. + +### Core Properties + +In the code below, an NFT has properties such as +its unique ID, name, description, and others. +When we add the `NonFungibleToken.NFT` and by extension, +the `MetadataViews.Resolver` to our NFT resource, +we are indicating that these variables will adhere to the specifications +outlined in the MetadataViews contract for each of these properties. +This facilitates interoperability within the Flow ecosystem +and assures that the metadata of our NFT can be consistently accessed +and understood by various platforms and services that interact with NFTs. + +```cadence +access(all) resource NFT: NonFungibleToken.NFT { + access(all) let id: UInt64 + access(all) let name: String + access(all) let description: String + access(all) let thumbnail: String + access(self) let royalties: [MetadataViews.Royalty] + access(self) let metadata: {String: AnyStruct} + ... +} +``` + +To make this possible though, it is **vital** that projects +all use the standard metadata views in the same way, so third-party +applications can consume them in standard ways. + +For example, many metadata views have `String`-typed fields. It is difficult +to enforce that these fields are formatted in the correct way, so it is important +for projects to be dilligent about how they use them. Take `Traits` for example, +a commonly misused metadata view: +```cadence +access(all) struct Trait { + // The name of the trait. Like Background, Eyes, Hair, etc. + access(all) let name: String + ... + ... +} +``` +The name of the trait should be formatted in a way so that it is easy to display +on a user-facing website. Many projects will use something like CamelCase for +the value, so it looks like "HairColor", which is not pretty on a website. +The correct format for this example would be "Hair Color". +This is just one of many common view uses that projects need to be aware of +to maximize the chance of success for their project. + +## Metadata Views for NFTs + +`MetadataViews` types define how the NFT presents its data. +When invoked, the system knows precisely which view to return, +ensuring that the relevant information is presented consistently across various platforms. +In this section of the document, we will explore each metadata view and describe +how projects should properly use them. + +### Display + +This view provides the bare minimum information about the NFT +suitable for listing or display purposes. When the `Display` type is invoked, +it dynamically assembles the visual and descriptive information +that is typically needed for showcasing the NFT in marketplaces or collections. + +```cadence +case Type(): + return MetadataViews.Display( + name: self.name, + description: self.description, + thumbnail: MetadataViews.HTTPFile( + url: self.thumbnail + ) + ) +``` +If the thumbnail is a HTTP resource: +```cadence +thumbnail : MetadataViews.HTTPFile(url: *Please put your url here) +``` + +If the thumbnail is an IPFS resource: +```cadence +// +thumbnail : MetadataViews.IPFSFile( + cid: thumbnail cid, // Type + path: ipfs path // Type specify path if the cid is a folder hash, otherwise use nil here +) +``` + +![MetadataViews.Display](display.png "Display") + +:::info + +Note about SVG files on-chain: SVG field should be sent as `thumbnailURL`, +should be base64 encoded, and should have a dataURI prefix, like so: +``` +data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InJlZCIvPjwvc3ZnPg== +``` + +::: + +### Editions + +The `Editions` view provides intricate details regarding the particular release of an NFT +within a set of NFTs with the same metadata. +This can include information about the number of copies in an edition, +the specific NFT's sequence number within that edition, or its inclusion in a limited series. +When the `Editions` view is queried, it retrieves this data, +providing collectors with the information they need to comprehend +the rarity and exclusivity of the NFT they are interested in. + +An NFT can also be part of multiple editions, which is why the `Editions` view +can hold any number of `Edition` structs in an array. + +For example, if an NFT is number 11 of 30 of an exclusive edition, +the code to return the `Editions` view would look like this: + +```cadence +case Type(): + let editionInfo = MetadataViews.Edition( + name: "Example NFT Edition", + number: 11, + max: 30 + ) + return MetadataViews.Editions([editionInfo]) +``` + +### Serial Number Metadata + +The `Serial` metadata provides the unique serial number of the NFT, +akin to a serial number on a currency note or a VIN on a car. +This serial number is a fundamental attribute that certifies the individuality +of each NFT and is critical for identification and verification processes. +Serial numbers are expected to be unique among other NFTs from the same project. +Many projects are already using the NFT resource's +[globally unique UUID]([resource's globally unique UUID](https://cadence-lang.org/docs/language/resources#resource-identifier)) +as the ID already, so they will typically also use that as the serial number. + +```cadence +case Type(): + return MetadataViews.Serial(self.uuid) +``` + +### Royalties Metadata + +Royalty information is vital for the sustainable economics of the creators in the NFT space. +[The `Royalties` metadata view](https://github.com/onflow/flow-nft/blob/master/contracts/MetadataViews.cdc#L295) +defines the specifics of any royalty agreements in place, +including the percentage of sales revenue that will go to the original creator +or other stakeholders on secondary sales. + +Each royalty view contains a fungible token receiver capability where royalties should be paid: +```cadence +access(all) struct Royalty { + + access(all) let receiver: Capability<&{FungibleToken.Receiver}> + + access(all) let cut: UFix64 +} +``` + +here is an example of how an NFT might return a `Royalties` view: +```cadence +case Type(): + // Assuming each 'Royalty' in the 'royalties' array has 'cut' and 'description' fields + let royalty = + MetadataViews.Royalty( + // The beneficiary of the royalty: in this case, the contract account + receiver: ExampleNFT.account.capabilities.get<&AnyResource{FungibleToken.Receiver}>(/public/GenericFTReceiver), + // The percentage cut of each sale + cut: 0.05, + // A description of the royalty terms + description: "Royalty payment to the original creator" + ) + } + return MetadataViews.Royalties(detailedRoyalties) +``` + +If someone wants to make a listing for their NFT on a marketplace, +the marketplace can check to see if the royalty receiver +accepts the seller's desired fungible token by calling +the `receiver.getSupportedVaultTypes(): {Type: Bool}` +function via the `receiver` reference: +```cadence +let royaltyReceiverRef = royalty.receiver.borrow() + ?? panic("Could not borrow a reference to the receiver") +let supportedTypes = receiverRef.getSupportedVaultTypes() +if supportedTypes[**royalty.getType()**] { + // The type is supported, so you can deposit + recieverRef.deposit(<-royalty) +} else { + // if it is not supported, you can do something else, + // like revert, or send the royalty tokens to the seller instead +} +``` + +If the desired type is not supported, the marketplace has a few options. +They could either get the address of the receiver by using the +`receiver.owner.address` field and check to see if the account +has a receiver for the desired token, they could perform the sale without a royalty cut, +or they could abort the sale since the token type isn't accepted by the royalty beneficiary. + +You can see example implementations of royalties in the `ExampleNFT` contract +and the associated transactions and scripts. +NFTs are often sold for a variety of currencies, so the royalty receiver should ideally +be a [fungible token switchboard](https://github.com/onflow/flow-ft?tab=readme-ov-file#fungible-token-switchboard) receiver that forwards any received tokens +to the correct vault in the receiving account. + +#### Important instructions for royalty receivers + +If you plan to set your account as a receiver of royalties, +you'll likely want to be able to accept as many token types as possible. +This is possible with the `FungibleTokenSwitchboard`. +If you initialize a switchboard in your account, it can accept any generic fungible token +and route it to the correct vault in your account. + +Therefore, if you want to receive royalties, you should set up your account with the +[`setup_royalty_account_by_paths.cdc`](https://github.com/onflow/flow-ft/blob/master/transactions/switchboard/setup_royalty_account_by_paths.cdc) transaction. + +This will link generic public path from `MetadataViews.getRoyaltyReceiverPublicPath()` +to the capability paths and types that you provide as arguments. +Then you can use that public path and capability for your royalty receiver. + +### External URL Metadata + +The ExternalURL view returns to an associated webpage URL, +providing additional content or information about the NFT. +This can be a website, social media page, or anything else related to the project +that uses a URL. + +```cadence +case Type(): + return MetadataViews.ExternalURL("".concat(self.id.toString())) +``` + +### Traits Metadata + +The [`Trait`](https://github.com/onflow/flow-nft/blob/master/contracts/MetadataViews.cdc#L655) view type encapsulates the unique attributes of an NFT, like any visual aspects or category-defining properties. These can be essential for marketplaces that need to sort or filter NFTs based on these characteristics. +By returning trait views as recommended, you can fit the data in the places you want. +```cadence +access(all) struct Trait { + // The name of the trait. Like Background, Eyes, Hair, etc. + access(all) let name: String + + // The underlying value of the trait + access(all) let value: AnyStruct + + // displayType is used to show some context about what this name and value represent + // for instance, you could set value to a unix timestamp, and specify displayType as "Date" to tell + // platforms to consume this trait as a date and not a number + access(all) let displayType: String? + + // Rarity can also be used directly on an attribute. + // This is optional because not all attributes need to contribute to the NFT's rarity. + access(all) let rarity: Rarity? +``` + +The traits view is extremely important to get right, because many third-party apps +and marketplaces are heavily reliant on it to properly display the entirety of your NFTs. +For example, the names and values of the traits are likely going to be displayed +on a user-facing website, so it is important to return them in a presentable form, such as `First Name`, instead of `first_name` or `firstName`. + +Additionally, limit your `value` field to primitive types like `String`, `Int`, or `Bool`. + +Additionally, the `displayType` is important as well, because it tells websites +how to display the trait properly. Developers should not just default +to `String` or `Integer` for all their display types. +When applicable, the display types to accurately reflect the data that needs to be displayed. + +![MetadataViews.Traits](traits_String.png "traits_String") + +#### Note: Always prefer wrappers over single views + +When exposing a view that could have multiple occurrences on a single NFT, +such as `Edition`, `Royalty`, `Media` or `Trait` the wrapper view should always be used +(such as `Editions`, `Royalties`, etc), even if there is only a single occurrence. +The wrapper view is always the plural version of the single view name +and can be found below the main view definition in the `MetadataViews` contract. + +When resolving the view, the wrapper view should be the returned value, +instead of returning the single view or just an array of several occurrences of the view. + +```cadence +access(all) fun resolveView(_ view: Type): AnyStruct? { + switch view { + case Type(): + let editionInfo = MetadataViews.Edition(name: "Example NFT Edition", number: self.id, max: nil) + let editionList: [MetadataViews.Edition] = [editionInfo] + // return the wrapped view + return MetadataViews.Editions( + editionList + ) + } +} +``` + +## Contract-Level Metadata Implementation + +Contract-level metadata provides a holistic view of an NFT collection, +capturing overarching attributes and contextual information about the entire set, +rather than specifics of individual tokens. These views describe attributes +at the collection or series level rather than individual NFTs. +These views should still should be queryable via individual NFTs though. +One can accomplish this by just forwarding the call +from the NFT's `resolveView()` method to the contract's `resolveView()` method, like so: +```cadence +/// this line is in `ExampleNFT.NFT.resolveView()` +case Type(): + return ExampleNFT.getCollectionDisplay(nftType: Type<@ExampleNFT.NFT>()) +``` + +### NFTCollectionData + +This view provides paths and types related to the NFT collection's storage +and access within the smart contract. The information in this view +is critical for understanding how to interact with a collection. + +```cadence +case Type(): + return MetadataViews.NFTCollectionData( + // where should the collection be saved? + storagePath: ExampleNFT.CollectionStoragePath, + // where to borrow public capabilities from? + publicPath: ExampleNFT.CollectionPublicPath, + // Important types for how the collection should be linked + publicCollection: Type<&ExampleNFT.Collection>(), + publicLinkedType: Type<&ExampleNFT.Collection>(), + // function that can be accessed to create an empty collection for the project + createEmptyCollectionFunction: (fun(): @{NonFungibleToken.Collection} { + return <-ExampleNFT.createEmptyCollection(nftType: Type<@ExampleNFT.NFT>()) + }) + ) +``` + +Here, `NFTCollectionData` is specifying several important elements +related to how the collection is stored and accessed on the Flow blockchain. +It provides information on storage paths and access control paths +for both public and private data, as well as linked types +that specify what capabilities are publicly available +(like collection, receiver, or provider interfaces). + +### NFTCollectionDisplay + +This view describes the collection with visual elements and metadata +that are useful for display purposes, such as in a marketplace or gallery. +Many third party apps need this in order to display high-level information +about an NFT project properly. + +```cadence +case Type(): + let media = MetadataViews.Media( + file: MetadataViews.HTTPFile( + url: "" + ), + mediaType: "image/svg+xml" + ) + return MetadataViews.NFTCollectionDisplay( + name: "The Example Collection", + description: "This collection is used as an example to help you develop your next Flow NFT.", + externalURL: MetadataViews.ExternalURL(""), + squareImage: media, + bannerImage: media, + socials: { + "twitter": MetadataViews.ExternalURL("") + } + ) +``` + +In the example above, the `NFTCollectionDisplay` not only offers fundamental metadata +like the collection's name and description but also provides image URLs +for visual representations of the collection (`squareImage` and `bannerImage`) +and external links, including social media profiles. + +![MetadataViews.CollectionDisplay](collectionDisplay.png "CollectionDisplay") + +### Contract-borrowing Metadata + +With the contract borrowing feature, the [ViewResolver](https://github.com/onflow/flow-nft/blob/master/contracts/ViewResolver.cdc) +interface on contracts can be borrowed directly without needing to import the contract first. +Views can be resolved directly from there. +As an example, you might want to allow your contract +to resolve `NFTCollectionData` and `NFTCollectionDisplay` so that platforms +do not need to find an NFT that belongs to your contract +to get information about how to set up or show your collection. + +```cadence +import ViewResolver from 0xf8d6e0586b0a20c7 +import MetadataViews from 0xf8d6e0586b0a20c7 + +access(all) fun main(addr: Address, name: String): StoragePath? { + let t = Type() + let borrowedContract = getAccount(addr).contracts.borrow<&ViewResolver>(name: name) ?? panic("contract could not be borrowed") + + let view = borrowedContract.resolveView(t) + if view == nil { + return nil + } + + let cd = view! as! MetadataViews.NFTCollectionData + return cd.storagePath +} +``` + +Will Return +```cadence +{"domain":"storage","identifier":"exampleNFTCollection"} +``` + +## More + +Understanding `MetadataViews` and the core functions associated with it +is crucial for developers aiming to deploy NFTs on Flow. +With these views and functions, NFTs can maintain a consistent presentation +across various platforms and marketplaces and foster interoperability +between contracts and applications in the Flow ecosystem. +To gain a deeper understanding of implementing the MetadataView standard, +check out our documentation on "How to Create an NFT Project on Flow". +It provides an introduction to integrating these standards into your NFT contracts. + +- See the [API reference for a complete list of Metadata functions](https://developers.flow.com/build/core-contracts/flow-nft/MetdataViews/MetadataViews) +- Check out [an Example NFT project](https://github.com/onflow/flow-nft/blob/master/contracts/ExampleNFT.cdc) implementing `MetadataViews` +- Read [the NFT Guide](../guides/nft.md) for an introduction to implementation \ No newline at end of file diff --git a/static/markdown/build/advanced-concepts/randomness.md b/static/markdown/build/advanced-concepts/randomness.md new file mode 100644 index 0000000000..3a1965adb6 --- /dev/null +++ b/static/markdown/build/advanced-concepts/randomness.md @@ -0,0 +1,224 @@ +--- +title: Flow On-chain Randomness in Cadence +description: Learn how Flow provides native, secure on-chain randomness at the protocol level, enabling developers to build applications with verifiable, unpredictable outcomes without external oracles. +keywords: + - randomness + - VRF + - on-chain randomness + - revertibleRandom + - random beacon + - commit-reveal + - random number generation + - blockchain randomness + - secure randomness + - Flow protocol + - randomness beacon + - PRNG +sidebar_label: VRF (Randomness) in Cadence +--- + +# Randomness on FLOW + +Flow enhances blockchain functionality and eliminates reliance on external oracles by providing native onchain randomness at the protocol level. This secure, decentralized feature empowers developers to build a variety of applications with truly unpredictable, transparent, and fair outcomes, achieved with greater efficiency. + +Flow's onchain randomness delivers immediate random values within smart contracts, bypassing the latency and complexity of oracle integration. Developers can obtain verifiably random results with a single line of Cadence code, streamlining the development process and enhancing the performance of decentralized applications. + +## Use Cases of Onchain Randomness + +- **Gaming:** Integrates fairness and unpredictability into gameplay, enhancing user engagement without delays. +- **NFTs:** Facilitates the creation of uniquely randomized traits in NFTs quickly, adding to their rarity and value. +- **Lotteries & Draws:** Offers instant and verifiably fair random selection for lotteries, solidifying trust in real-time. +- **DeFi Protocols:** Enables rapid and innovative random reward systems within decentralized finance. +- **DAOs:** Assists in unbiased voting and task assignments through immediate randomness. +- **Broad Applications:** Extends to any domain requiring impartial randomization, from asset distribution to security mechanisms, all with the added benefit of on-demand availability. + +## History of the Distributed Randomness Beacon + +Within the Flow protocol, the heart of randomness generation lies in the "Distributed Randomness Beacon". +This module generates randomness that is distributed across the network while adhering to established cryptographic and security standards. +The output from the randomness beacon is a random source for each block that is unpredictable and impartial. + +For over three years, the beacon has ensured protocol security by selecting which consensus node gets to propose the next block and assigning verification nodes to oversee block computations. For those interested in a more detailed exploration of the randomness beacon and its inner workings, you can read [the technical deep dive on the Flow forum](https://forum.flow.com/t/secure-random-number-generator-for-flow-s-smart-contracts/5110). + +### The History and Limitations of `unsafeRandom` (Now Deprecated) + +Cadence has historically provided the `unsafeRandom` function to return a pseudo-random number. The stream of random numbers produced was potentially unsafe in the following two regards: + +1. The sequence of random numbers is potentially predictable by transactions within the same block and by other smart contracts calling into your smart contract. +2. A transaction calling into your smart contract can potentially bias the sequence of random numbers which your smart contract internally generates. Currently, the block hash seeds `unsafeRandom`. Consensus nodes can *easily* bias the block hash and **influence the seed for `unsafeRandom`**. + +:::warning + +⚠️ Note `unsafeRandom` is deprecated since the Cadence 1.0 release. + +::: + +## Guidelines for Safe Usage + +For usage of randomness where result abortion is not an issue, it is recommended to use the Cadence built-in function `revertibleRandom.` `revertibleRandom` returns a pseudo-random number and is based on the Distributed Randomness Beacon. + +```cadence +// Language reference: +// https://cadence-lang.org/docs/language/built-in-functions#revertiblerandom +// Run the snippet here: https://academy.ecdao.org/en/snippets/cadence-random +access(all) fun main(): UInt64 { + // Simple assignment using revertibleRandom - keep reading docs for safe usage! + let rand: UInt64 = revertibleRandom() + return rand +} +``` + +It is notable that the random number generation process is unpredictable (for miners unpredictable at block construction time and for cadence logic unpredictable at time of call), verifiable, uniform, as well as safe from bias by miners and previously-running Cadence code. + +Protocol improvements (documented in [FLIP 120](https://github.com/onflow/flips/blob/main/cadence/20230713-random-function.md)) +expose the randomness beacon to the FVM and Cadence where it can be used to draw safe randoms without latency. + +Although Cadence exposes safe randomness generated by the Flow protocol via `revertibleRandom`, there is an additional safety-relevant aspect that developers need to be mindful about. + +The `revertibleRandom` function can be used safely in some applications where the transaction results are _not_ deliberately reverted after the random number is revealed (i.e. a trusted contract distributing random NFTs to registered users or onchain lucky draw). +However, if applications require a non-trusted party (for instance app users) to submit a transaction calling a randomized (non-deterministic) contract, the developer must explicitly protect the stream of random numbers to not break the security guarantees: + +:::warning + +🚨 A transaction can atomically revert all its action during its runtime and abort. Therefore, it is possible for a transaction calling into your smart contract to post-select favorable results and revert the transaction for unfavorable results. + +::: + +In other words, transactions submitted by a non-trusted party are able to reject their results after the random is revealed. + +:::info + +**Post-selection** - the ability for transactions to reject results they don't like - is inherent to any smart contract platform that allows transactions to roll back atomically. See this very similar [Ethereum example](https://consensys.github.io/smart-contract-best-practices/development-recommendations/general/public-data/). + +::: + +The central aspect that a contract developer needs to think about is the following scenario: + +- Imagine an adversarial user that is sending a transaction that calls your smart contract. +- The transaction includes code that runs after your smart contract returns and inspects the outcome. +- If the outcome is unfavorable (based on some criteria codified in the transaction), the transaction aborts itself. + +As an example, consider a simple coin toss randomized contract where users can bet any amount of tokens against a random binary output. If the coin toss contract outputs `1`, the user doubles their bet. If the coin toss contract outputs `0`, the user loses their bet in favor of the coin toss. + +Although the user (or the honest coin toss contract) cannot predict or bias the outcome, the user transaction can check the randomized result and cancel the transaction if they are losing their bet. This can be done by calling an exception causing the transaction to error. All temporary state changes are cancelled and the user can repeat the process till they double their bet. + +## Commit-Reveal Scheme + +The recommended way to mitigate the problems above is via a commit-reveal scheme. The scheme involves two steps: commit and reveal. During the commit phase, the user transaction commits to accepting the future output of a smart contract where the last remaining input is an unknown random source. The smart contract stores this commitment on the blockchain. At the current level of optimization, the reveal phase can start as early as the next block, when the "future" beacon's source of randomness becomes available. The reveal phase can be executed at any block after that, now that the commitment to a past block is stored on-chain. With a second transaction, the smart contract can be executed to explicitly generate the random outputs. + +There are ideas how to further optimize the developer experience in the future. For example, a transaction could delegate part of its gas to an independent transaction it spawns. Conceptually, also this future solution would be a commit-and-reveal scheme, just immediately happening within the same block. Until we eventually get to this next level, developers may need to implement their own commit-reveal. In Cadence, it is clean and short. + +### FLIP 123 + +On Flow, we have absorbed all security complexity into the platform. + +[FLIP 123: On-chain Random beacon history for commit-reveal schemes](https://github.com/onflow/flips/blob/main/protocol/20230728-commit-reveal.md#flip-123-on-chain-random-beacon-history-for-commit-reveal-schemes) was introduced to provide a safe pattern to use randomness in transactions so that it's not possible to revert unfavorable randomized transaction results. +We recommend this approach as a best-practice example for implementing a commit-reveal scheme in Cadence. The `RandomBeaconHistory` contract provides a convenient archive, where for each past block height (starting Nov 2023) the respective "source of randomness" can be retrieved. The `RandomBeaconHistory` contract is automatically executed by the system at each block to store the next source of randomness value. + +:::info + +While the commit-and-reveal scheme mitigates post-selection of results by adversarial clients, Flow's secure randomness additionally protects against any pre-selection vulnerabilities (like biasing attacks by byzantine miners). + +::: + +A commit-reveal scheme can be implemented as follows. The coin toss example described earlier will be used for illustration: + +- When a user submits a bidding transaction, the bid amount is transferred to the coin toss contract, and the block height where the bid was made is stored. This is a commitment by the user to use the SoR at the current block. Note that the current block's `SoR_A` isn't known to the transaction execution environment, and therefore the transaction has no way to inspect the random outcome and predict the coin toss result. The current block's `SoR_A` is only available once added to the history core-contract, which only happens at the end of the block's execution. The user may also commit to using an SoR of some future block, which is equally unknown at the time the bid is made. +- The coin toss contract may grant the user a limited window of time (i.e a block height range) to send a second transaction for resolving the results and claim any winnings. Failing to do so, the bid amount remains in the coin toss contract. +- Within that reveal transaction, the user calls the coin toss contract, looks us up the block height at which the block was committed and checks that it has already passed. The contract queries that block's `SoR_A` from the core-contract `RandomBeaconHistory` via block height. +- The coin toss contract uses a PRG seeded with the queried `SoR_A` and diversified using a specific information to the use-case (a user ID or resource ID for instance). Diversification does not add new entropy, but it avoids generating the same outcome for different use-cases. If a diversifier (or salt) isn't used, all users that committed a bid on the same block would either win or lose. +- The PRG is used to generate the random result and resolve the bid. Note that the user can make the transaction abort after inspecting a losing result. However, the bid amount would be lost anyway when the allocated window expires. + +The following lines of code illustrate a random coin toss that cannot be gamed or biased. The reveal-and-commit scheme prevent clients from post-selecting favorable outcomes. + +```cadence +// The code below is taken from the example CoinToss contract found in this project repo +// Source: https://github.com/onflow/random-coin-toss + +/// --- Commit --- +/// In this method, the caller commits a bet. The contract takes note of the +/// block height and bet amount, returning a Receipt resource which is used +/// by the better to reveal the coin toss result and determine their winnings. +access(all) fun commitCoinToss(bet: @FungibleToken.Vault): @Receipt { + let receipt <- create Receipt( + betAmount: bet.balance + ) + // commit the bet + // `self.reserve` is a `@FungibleToken.Vault` field defined on the app contract + // and represents a pool of funds + self.reserve.deposit(from: <-bet) + + emit CoinTossBet(betAmount: receipt.betAmount, commitBlock: receipt.commitBlock, receiptID: receipt.uuid) + + return <- receipt +} + +/// --- Reveal --- +/// Here the caller provides the Receipt given to them at commitment. The contract +/// then "flips a coin" with randomCoin(), providing the committed block height +/// and salting with the Receipts unique identifier. +/// If result is 1, user loses, if it's 0 the user doubles their bet. +/// Note that the caller could condition the revealing transaction, but they've +/// already provided their bet amount so there's no loss for the contract if +/// they do +access(all) fun revealCoinToss(receipt: @Receipt): @FungibleToken.Vault { + pre { + receipt.commitBlock <= getCurrentBlock().height: "Cannot reveal before commit block" + } + + let betAmount = receipt.betAmount + let commitBlock = receipt.commitBlock + let receiptID = receipt.uuid + // self.randomCoin() errors if commitBlock <= current block height in call to + // RandomBeaconHistory.sourceOfRandomness() + let coin = self.randomCoin(atBlockHeight: receipt.commitBlock, salt: receipt.uuid) + + destroy receipt + + if coin == 1 { + emit CoinTossReveal(betAmount: betAmount, winningAmount: 0.0, commitBlock: commitBlock, receiptID: receiptID) + return <- FlowToken.createEmptyVault() + } + + let reward <- self.reserve.withdraw(amount: betAmount * 2.0) + + emit CoinTossReveal(betAmount: betAmount, winningAmount: reward.balance, commitBlock: commitBlock, receiptID: receiptID) + + return <- reward +} +``` + +### Which random function should be used: + +While both are backed by Flow's Randomness Beacon it is important for developers to mindfully choose between `revertibleRandom` or +seeding their own PRNG utilizing the `RandomBeaconHistory` smart contract: + +- With `revertibleRandom` a developer is calling the transaction environment, + which has the power to abort and revert if it doesn't like `revertibleRandom`'s outputs. + `revertibleRandom` is only suitable for smart contract functions that exclusively run within the trusted transactions. +- In contrast, the `RandomBeaconHistory` contract is key for effectively implementing a commit-reveal scheme, where the transaction is non-trusted and may revert the random outputs. + During the commit phase, the user commits to proceed with a future source of randomness, + which is only revealed after the commit transaction concluded. + For each block, the `RandomBeaconHistory` automatically stores the generated source of randomness. + At the time of revealing the source, the committed source becomes a past-block source that can be queried through the history contract. + +Adding a safe pattern to reveal randomness without the possibility of conditional transaction reversion unlocks applications relying on randomness. By providing examples of commit-reveal implementations we hope to foster a more secure ecosystem of decentralized applications and encourage developers to build with best practices. + +In simpler terms, the native secure randomness provided by the protocol can now be safely utilized within Cadence smart contracts +and is available to all developers on Flow and the FVM. + +## An Invitation to Build + +Flow's onchain randomness opens new doors for innovation in web3, offering developers the tools to create fair and transparent decentralized applications. With this feature, new possibilities emerge—from enhancing gameplay in decentralized gaming to ensuring the integrity of smart contract-driven lotteries or introducing novel mechanisms in DeFi. + +This is an invitation for builders and creators: leverage Flow's onchain randomness to distinguish your projects and push the boundaries of what's possible. Your imagination and code have the potential to forge new paths in the web3 landscape. So go ahead and build; the community awaits the next big thing that springs from true randomness. + +## Learn More + +If you'd like to dive deeper into Flow's onchain randomness, here's a list of resources: + +- To learn more about how randomness works under the hood, see [the forum post](https://forum.flow.com/t/secure-random-number-generator-for-flow-s-smart-contracts/5110). +- These documents provide a more in-depth technical understanding of the updates and enhancements to the Flow blockchain. + - **[FLIP 120: Update unsafeRandom function](https://github.com/onflow/flips/blob/main/cadence/20230713-random-function.md#flip-120-update-unsaferandom-function)** + - **[FLIP 123: On-chain Random beacon history for commit-reveal schemes](https://github.com/onflow/flips/blob/main/protocol/20230728-commit-reveal.md#flip-123-on-chain-random-beacon-history-for-commit-reveal-schemes)** +- To see working Cadence code, explore the [coin toss example on GitHub](https://github.com/onflow/random-coin-toss). \ No newline at end of file diff --git a/static/markdown/build/advanced-concepts/scaling.md b/static/markdown/build/advanced-concepts/scaling.md new file mode 100644 index 0000000000..e672d7a746 --- /dev/null +++ b/static/markdown/build/advanced-concepts/scaling.md @@ -0,0 +1,302 @@ +--- +title: Scaling Transactions from a Single Account +description: Learn how to scale transactions from a single account on Flow using multiple proposer keys, enabling concurrent transaction processing for system-level operations. +keywords: + - scaling + - transactions + - proposer keys + - sequence numbers + - concurrent transactions + - system transactions + - transaction scaling + - Flow blockchain + - account scaling + - transaction workers + - batch operations +sidebar_label: Scaling Transactions from a Single Account +--- + +# Scaling Transactions from a Single Account + +Flow is designed for consumer-scale internet applications and is one of the fastest blockchains globally. Transaction traffic on deployed contracts can be divided into two main categories: + +1. **User Transactions** + + These are transactions initiated by users, such as: + + * Buying or selling NFTs + * Transferring tokens + * Swapping tokens on decentralized exchanges (DEXs) + * Staking or unstaking tokens + + In this category, each transaction originates from a unique account and is sent to the Flow network from a different machine. Developers don't need to take special measures to scale for this category, beyond ensuring their logic is primarily on-chain and their supporting systems (e.g., frontend, backend) can handle scaling if they become bottlenecks. Flow's protocol inherently manages scaling for user transactions. + +2. **System Transactions** + + These are transactions initiated by an app's backend or various tools, such as: + + * Minting thousands of tokens from a single minter account + * Creating transaction workers for custodians + * Running maintenance jobs and batch operations + + In this category, many transactions originate from the same account and are sent to the Flow network from the same machine, which can make scaling tricky. This guide focuses on strategies for scaling transactions from a single account. + +In the following sections, we'll explore how to execute concurrent transactions from a single account on Flow using multiple proposer keys. + +:::info + +This guide is specific to non-EVM transactions. For EVM-compatible transactions, you can use any EVM-compatible scaling strategy. + +::: + +## Problem + +Blockchains use sequence numbers, also known as nonces, for each transaction to prevent [replay attacks](https://en.wikipedia.org/wiki/Replay_attack) and allow users to specify the order of their transactions. The Flow network requires a specific sequence number for each incoming transaction and will reject any transaction where the sequence number does not exactly match the expected next value. + +This behavior presents a challenge for scaling, as sending multiple transactions does not guarantee that they will be executed in the order they were sent. This is a fundamental aspect of Flow's resistance to MEV (Maximal Extractable Value), as transaction ordering is randomized within each block. + +If a transaction arrives out of order, the network will reject it and return an error message similar to the following: +``` +* checking sequence number failed: [Error Code: 1007] invalid proposal key: public key X on account 123 has sequence number 7, but given 6 +``` +Our objective is to execute multiple concurrent transactions without encountering the sequence number error described above. While designing a solution, we must consider the following key factors: + +- **Reliability** + + Ideally, we want to avoid local sequence number management, as it is error-prone. In a local sequence number implementation, the sender must determine which error types increment the sequence number and which do not. For instance, network issues do not increment the sequence number, but application errors do. Furthermore, if the sender's sequence number becomes unsynchronized with the network, multiple transactions may fail. + + The most reliable approach to managing sequence numbers is to query the network for the latest sequence number before signing and sending each transaction. + +- **Scalability** + + Allowing multiple workers to manage the same sequence number can introduce coupling and synchronization challenges. To address this, we aim to decouple workers so that they can operate independently without interfering with one another. + +- **Capacity Management** + + To ensure reliability, the system must recognize when it has reached capacity. Additional transactions should be queued and executed once there is sufficient throughput. Fire-and-forget strategies are unreliable for handling arbitrary traffic, as they do not account for system capacity. + +## Solution + +Flow's transaction model introduces a unique role called the proposer. Each Flow transaction is signed by three roles: authorizer, proposer, and payer. The proposer key determines the sequence number for the transaction, effectively decoupling sequence number management from the authorizer and enabling independent scaling. You can learn more about this concept [here](https://developers.flow.com/build/basics/transactions#proposal-key). + +We can leverage this model to design an ideal system transaction architecture as follows: + +- **Multiple Proposer Keys** + + Flow accounts can have multiple keys. By assigning a unique proposer key to each worker, each worker can independently manage its own sequence number without interference from others. + +- **Sequence Number Management** + + Each worker ensures it uses the correct sequence number by fetching the latest sequence number from the network. Since workers operate with different proposer keys, there are no conflicts or synchronization issues. + +- **Queue and Processing Workflow** + + * Each worker picks a transaction request from the incoming requests queue, signs it with its assigned proposer key, and submits it to the network. + * The worker remains occupied until the transaction is finalized by the network. + * If all workers are busy, the incoming requests queue holds additional requests until there is enough capacity to process them. + +- **Key Reuse for Optimization** + + To simplify the system further, we can reuse the same cryptographic key multiple times within the same account by adding it as a new key. These additional keys can have a weight of 0 since they do not need to authorize transactions. + +Here's a visual example of how such an [account configuration](https://www.flowscan.io/account/18eb4ee6b3c026d2?tab=keys) might look: + +![Example.Account](scaling-example-account.png "Example Account") + +As shown, the account includes additional weightless keys designated for proposals, each with its own independent sequence number. This setup ensures that multiple workers can operate concurrently without conflicts or synchronization issues. + +In the next section, we'll demonstrate how to implement this architecture using the [Go SDK](https://github.com/onflow/flow-go-sdk). + +## Example Implementation + +An example implementation of this architecture can be found in the [Go SDK Example](https://github.com/onflow/flow-go-sdk/blob/master/examples/transaction_scaling/main.go). + +This example deploys a simple `Counter` contract: + +```cadence +access(all) contract Counter { + + access(self) var count: Int + + init() { + self.count = 0 + } + + access(all) fun increase() { + self.count = self.count + 1 + } + + access(all) view fun getCount(): Int { + return self.count + } +} +``` + +The goal is to invoke the `increase()` function 420 times concurrently from a single account. By adding 420 concurrency keys and using 420 workers, all these transactions can be executed almost simultaneously. + +### Prerequisites + +We're using Testnet to demonstrate real network conditions. To run this example, you need to create a new testnet account. Start by generating a key pair: + +```bash +flow keys generate +``` + +You can use the generated key with the [faucet](https://testnet-faucet.onflow.org/create-account) to create a testnet account. Update the corresponding variables in the `main.go` file: + +```go +const PRIVATE_KEY = "123" +const ACCOUNT_ADDRESS = "0x123" +``` + +### Code Walkthrough + +When the example starts, it will deploy the `Counter` contract to the account and add 420 proposer keys with the following transaction: + +```cadence +transaction(code: String, numKeys: Int) { + + prepare(signer: auth(AddContract, AddKey) &Account) { + // deploy the contract + signer.contracts.add(name: "Counter", code: code.decodeHex()) + + // copy the main key with 0 weight multiple times + // to create the required number of keys + let key = signer.keys.get(keyIndex: 0)! + var count: Int = 0 + while count < numKeys { + signer.keys.add( + publicKey: key.publicKey, + hashAlgorithm: key.hashAlgorithm, + weight: 0.0 + ) + count = count + 1 + } + } +} +``` + +Next, the main loop starts. Each worker will process a transaction request from the queue and execute it. Here's the code for the main loop: + +```go +// populate the job channel with the number of transactions to execute +txChan := make(chan int, numTxs) +for i := 0; i < numTxs; i++ { + txChan <- i +} + +startTime := time.Now() + +var wg sync.WaitGroup +// start the workers +for i := 0; i < numProposalKeys; i++ { + wg.Add(1) + + // worker code + // this will run in parallel for each proposal key + go func(keyIndex int) { + defer wg.Done() + + // consume the job channel + for range txChan { + fmt.Printf("[Worker %d] executing transaction\n", keyIndex) + + // execute the transaction + err := IncreaseCounter(ctx, flowClient, account, signer, keyIndex) + if err != nil { + fmt.Printf("[Worker %d] Error: %v\n", keyIndex, err) + return + } + } + }(i) +} + +close(txChan) + +// wait for all workers to finish +wg.Wait() +``` + +The `IncreaseCounter` function calls the `increase()` function on the `Counter` contract: + +```go +// Increase the counter by 1 by running a transaction using the given proposal key +func IncreaseCounter(ctx context.Context, flowClient *grpc.Client, account *flow.Account, signer crypto.Signer, proposalKeyIndex int) error { + script := []byte(fmt.Sprintf(` + import Counter from 0x%s + + transaction() { + prepare(signer: &Account) { + Counter.increase() + } + } + + `, account.Address.String())) + + tx := flow.NewTransaction(). + SetScript(script). + AddAuthorizer(account.Address) + + // get the latest account state including the sequence number + account, err := flowClient.GetAccount(ctx, flow.HexToAddress(account.Address.String())) + if err != nil { + return err + } + tx.SetProposalKey( + account.Address, + account.Keys[proposalKeyIndex].Index, + account.Keys[proposalKeyIndex].SequenceNumber, + ) + + return RunTransaction(ctx, flowClient, account, signer, tx) +} +``` + +The above code is executed concurrently by each worker. Since each worker operates with a unique proposer key, there are no conflicts or synchronization issues. Each worker independently manages its sequence number, ensuring smooth execution of all transactions. + +Finally, the `RunTransaction` function serves as a helper utility to send transactions to the network and wait for them to be finalized. It is important to note that the proposer key sequence number is set within the `IncreaseCounter` function before calling `RunTransaction`. + +```go +// Run a transaction and wait for it to be sealed. Note that this function does not set the proposal key. +func RunTransaction(ctx context.Context, flowClient *grpc.Client, account *flow.Account, signer crypto.Signer, tx *flow.Transaction) error { + latestBlock, err := flowClient.GetLatestBlock(ctx, true) + if err != nil { + return err + } + tx.SetReferenceBlockID(latestBlock.ID) + tx.SetPayer(account.Address) + + err = SignTransaction(ctx, flowClient, account, signer, tx) + if err != nil { + return err + } + + err = flowClient.SendTransaction(ctx, *tx) + if err != nil { + return err + } + + txRes := examples.WaitForSeal(ctx, flowClient, tx.ID()) + if txRes.Error != nil { + return txRes.Error + } + + return nil +} +``` + +### Running the Example + +Running the example will execute 420 transactions at the same time: + +```bash +→ cd ./examples +→ go run ./transaction_scaling/main.go +. +. +. +Final Counter: 420 +✅ Done! 420 transactions executed in 11.695372059s +``` + +It takes roughly the time of 1 transaction to run all 420 without any errors. \ No newline at end of file diff --git a/static/markdown/build/app-architecture/index.md b/static/markdown/build/app-architecture/index.md new file mode 100644 index 0000000000..5f93535d27 --- /dev/null +++ b/static/markdown/build/app-architecture/index.md @@ -0,0 +1,90 @@ +--- +sidebar_position: 5 +title: App Architecture +description: Learn about self-custody and app custody architectural patterns for building applications on Flow blockchain, including their benefits, considerations, and ideal use cases. +keywords: + - app architecture + - self custody + - app custody + - Flow blockchain + - walletless onboarding + - account linking + - dApp architecture + - blockchain architecture + - key management + - user experience + - web3 development +sidebar_custom_props: + icon: 🏗️ +--- + +# App Architecture on Flow Blockchain + +The Flow blockchain, with its focus on scalability and user-centric design, offers a unique environment for app development. Designed from the ground up, Flow prioritizes user experience, aiming to bridge the gap to mainstream adoption without compromising on decentralization or security. + +While the Flow blockchain offers various architectural patterns, the recommended approaches for developers are **Self-Custody** and **App Custody**. These choices align with Flow's ethos of user-centric design and flexibility. + +### Self-Custody Architecture + +In a self-custody architecture, users retain direct control over their private keys and assets. This model emphasizes user sovereignty and decentralization, placing the responsibility of asset management squarely on the user's shoulders. While it offers the highest degree of control, it also demands a certain level of technical knowledge and awareness from the user, which can sometimes lead to a more complex user experience. + +![self-custody.png](self-custody.png) + +**Architectural Elements**: + +- **Wallet**: A wallet where users store their private keys and sign transactions. +- **Frontend**: Interfaces directly with the user and their wallet for signing transactions. +- **Method of Talking to Chain**: Through FCL directly. + +**Benefits**: + +- **Control**: Users maintain full ownership of their assets and transactions. +- **Security**: Direct management of private keys reduces potential points of failure. + +**Considerations**: + +- **User Experience**: The direct control model can lead to a more complex user experience, especially for those unfamiliar with blockchain. Typically, all transactions must be approved by the user, which can be cumbersome. +- **Key Management**: Users are solely responsible for managing, backing up, and ensuring the safe generation and storage of their keys. + +**Ideal Use Cases**: + +- **Decentralized Finance (DeFi)**: Users interacting with financial protocols while maintaining full control. +- **Web3 Native Users**: Those familiar with blockchain technology and key management. + +### App Custody Architecture + +App custody on Flow offers a unique approach to key management and user experience. Unlike traditional app custody solutions on other blockchains, Flow's App Custody architecture introduces features like **[account linking](../guides/account-linking/index.md)** and **[walletless onboarding](../guides/account-linking/child-accounts.md)**. These features ensure that while users enjoy a seamless experience, they still have the option to link their accounts and move their assets freely around the Flow ecosystem, providing a balanced approach to key management. + +![app-custody.png](app-custody.png) + +**Architectural Elements**: + +- **Wallet**: Both user custody and app custody wallets coexist. +- **Frontend**: Interfaces for both wallet types and features for account linking and walletless onboarding. +- **Backend**: Manages app-custody user keys and assets. Also supports direct blockchain interactions. +- **Method of Interacting with the Chain**: Both direct FCL calls and backend-managed interactions. +- **Payment Rails**: Flexible methods, accommodating both direct and managed transactions. + +**Benefits**: + +- **Walletless Onboarding**: Users can start interacting with the app using traditional, familiar web2 mechanics without the initial need for a blockchain wallet. +- **Streamlined Experience**: Transactions can be processed without constant user approval, offering a smoother user journey. +- **Open Ecosystem with Account Linking**: Users can link their accounts, ensuring they can move their assets freely around the Flow ecosystem without being locked into a single application. +- **Flexibility**: Cater to both tech-savvy users and newcomers without compromising on security. +- **Platform Versatility**: The abstraction of the user wallet allows for integration with various platforms, including Unity games, consoles, and mobile applications. + +**Considerations**: + +- **Complexity**: Implementing app custody can be more intricate. +- **Trust**: Users need to trust the dApp with certain aspects of their data and assets. +- **Legal Implications**: Operating with app custody may come with legal considerations, depending on jurisdiction and the nature of the dApp. It's essential to consult with legal professionals to ensure compliance. + +**Ideal Use Cases**: + +- **Gaming**: Seamless gaming without constant transaction approvals. +- **Social Media Platforms**: Earning tokens for content without initial blockchain familiarity. +- **Loyalty Programs**: Earning rewards without deep blockchain setup. + +## Wrapping Up + +Selecting the right architecture is crucial when developing an app on the Flow blockchain. Your choice will influence not only the technical aspects but also the user experience and overall trust in your application. While Flow offers the tools and flexibility to cater to various needs, it's up to developers to harness these capabilities effectively. Whether you opt for a self-custody or app custody approach, ensure that your decision aligns with the core objectives of your app and the expectations of your users. Making informed architectural decisions will lay a strong foundation for your app's success. \ No newline at end of file diff --git a/static/markdown/build/basics/accounts.md b/static/markdown/build/basics/accounts.md new file mode 100644 index 0000000000..80e30d34d7 --- /dev/null +++ b/static/markdown/build/basics/accounts.md @@ -0,0 +1,239 @@ +--- +sidebar_position: 2 +title: Accounts +description: Learn about Flow blockchain accounts, including their structure, key management, multi-sig capabilities, and creation process. Understand how accounts store contracts, manage storage, and handle transaction signing. +keywords: + - Flow accounts + - blockchain accounts + - account keys + - multi-sig + - public keys + - account storage + - account creation + - keyless accounts + - service accounts + - account address + - account balance + - signature algorithms + - hash algorithms + - account contracts +--- + +:::info + +Are you an EVM developer looking for information about EVM Accounts on Flow? If so, check out the EVM specific documentation [here](../../evm/accounts.md) + +::: + +# Accounts + +An account on Flow is a record in the chain state that holds the following information: +- Address: unique identifier for the account +- Public Keys: public keys authorized on the account +- Code: Cadence contracts deployed to the account +- Storage: area of the account used to store resource assets. + +Accounts and their keys are needed to sign transactions that change the Flow blockchain state. To execute a transaction, a small amount of Flow, called a ["Fee"](./fees.md) must be paid by the account or subsidized by a wallet or service. Flow allocates a fixed amount of storage to each account for saving data structures and Resources. Flow allocates a [fixed amount of storage](./fees.md#storage) to each account for saving data structures and Resources. +An account may also contain contract code which transactions and scripts can interact with to query or mutate the state of the blockchain. + +A simple representation of an account: + +![Screenshot 2023-08-16 at 16.43.07.png](_accounts_images/Screenshot_2023-08-16_at_16.43.07.png) + +## Address + +A Flow address is represented as 16 hex-encoded characters (usually prefixed with `0x` to indicate hex encoding). Unlike Bitcoin and Ethereum, Flow addresses are not derived from cryptographic public keys. Instead, each Flow address is assigned by the Flow protocol using an on-chain deterministic sequence. The sequence uses an error detection code to guarantee that all addresses differ with at least 2 hex characters. This makes typos resulting in accidental loss of assets not possible. + +This decoupling is a unique advantage of Flow, allowing for multiple public keys to be associated with one account, or for a single public key to be used across several accounts. + +## Balance + +Each Flow account created on Mainnet will by default [hold a Flow vault that holds a balance and is part of the FungibleToken standard](./flow-token.md). This balance is used to pay for [transaction fees and storage fees](./fees.md). More on that in the fees document. + +:::warning + +The minimum amount of FLOW an account can have is **0.001**. + +::: + +This minimum storage fee is provided by the account creator and covers the cost of storing up to 100kB of data in perpetuity. This fee is applied only once and can be "topped up" to add additional storage to an account. The minimum account reservation ensures that most accounts won't run out of storage capacity if anyone deposits anything (like an NFT) to the account. + +### Maximum available balance + +Due to the storage restrictions, there is a maximum available balance that user can withdraw from the wallet. The core contract [`FlowStorageFees`](../core-contracts/05-flow-fees.md#flowstoragefees) provides a function to retrieve that value: + +```cadence +import "FlowStorageFees" + +access(all) fun main(accountAddress: Address): UFix64 { + return FlowStorageFees.defaultTokenAvailableBalance(accountAddress) +} +``` + +Alternatively developers can use `availableBalance` property of the `Account` + +```cadence +access(all) fun main(address: Address): UFix64 { + let acc = getAccount(address) + let balance = acc.availableBalance + + return balance +} + +``` + +## Contracts + +An account can optionally store multiple [Cadence contracts](https://cadence-lang.org/docs/language/contracts). The code is stored as a human-readable UTF-8 encoded string which makes it easy for anyone to inspect the contents. + +## Storage + +Each Flow account has an associated storage and capacity. The account's storage used is the byte size of all the data stored in the account's storage. An account's [storage capacity is directly tied to the balance of Flow tokens](./fees.md#storage) an account has. An account can, without any additional cost, use any amount of storage up to its storage capacity. If a transaction puts an account over storage capacity or drops an account's balance below the minimum 0.001 Flow tokens, that transaction fails and is reverted. + +## Account **Keys** + +Flow accounts can be configured with multiple public keys that are used to control access. Owners of the associated private keys can sign transactions to mutate the account's state. + +During account creation, public keys can be provided which will be used when interacting with the account. Account keys can be added, removed, or revoked by sending a transaction. This is radically different from blockchains like Ethereum where an account is tied to a single public/private key pair. + +Each account key has a weight that determines the signing power it holds. + +:::warning + +A transaction is not authorized to access an account unless it has a total signature weight greater than or equal to **1000**, the weight threshold. + +::: + +For example, an account might contain 3 keys, each with 500 weight: + +![Screenshot 2023-08-16 at 16.28.58.png](_accounts_images/Screenshot_2023-08-16_at_16.28.58.png) + +This represents a 2-of-3 multi-sig quorum, in which a transaction is authorized to access the account if it receives signatures from *at least* 2 out of 3 keys. + +An account key contains the following attributes: + +- **ID** used to identify keys within an account +- **Public Key** raw public key (encoded as bytes) +- **Signature algorithm** (see below) +- **Hash algorithm** (see below) +- **Weight** integer between 0-1000 +- **Revoked** whether the key has been revoked or it's active +- **Sequence Number** is a number that increases with each submitted transaction signed by this key + +### Signature and Hash Algorithms + +The signature and hashing algorithms are used during the transaction signing process and can be set to certain predefined values. + +There are two curves commonly used with the ECDSA algorithm, secp256r1 ([OID 1.2.840.10045.3.1.7](http://oid-info.com/get/1.2.840.10045.3.1.7), also called the "NIST P-256." this curve is common for mobile secure enclave support), and secp256k1 ([OID 1.3.132.0.10](http://oid-info.com/get/1.3.132.0.10), the curve used by "Bitcoin"). Please be sure to double-check which parameters you are using before registering a key, as presenting a key using one of the curves under the code and format of the other will generate an error. + +| Algorithm | Curve | ID | Code | +| --------- | --------- | --------------- | ---- | +| ECDSA | P-256 | ECDSA_P256 | 2 | +| ECDSA | secp256k1 | ECDSA_secp256k1 | 3 | + +*Please note that the codes listed here are for the signature algorithms as used by the node API, and they are different from the ones [defined in Cadence](https://cadence-lang.org/docs/language/crypto#signing-algorithms)* + +| Algorithm | Output Size | ID | Code | +| --------- | ----------- | -------- | ---- | +| SHA-2 | 256 | SHA2_256 | 1 | +| SHA-3 | 256 | SHA3_256 | 3 | + +Both hashing and signature algorithms are compatible with each other, so you can freely choose from the set. + +### **Locked / Keyless Accounts** + +An account on Flow doesn't require keys in order to exist, but this makes the account immutable since no transaction can be signed that can change the account. This can be useful if we want to freeze an account contract code and it elegantly solves the problem of having multiple account types (as that is the case for Ethereum). + +![Screenshot 2023-08-16 at 18.59.10.png](_accounts_images/Screenshot_2023-08-16_at_18.59.10.png) + +You can achieve keyless accounts by either removing an existing public key from an account signing with that same key and repeating that action until an account has no keys left, or you can create a new account that has no keys assigned. With account linking you can also have a child account that has no keys but is controlled by the parent. + +:::danger + +Be careful when removing keys from an existing account, because once an account's total key weights sum to less than 1000, it can no longer be modified. + +::: + +### **Multi-Sig Accounts** + +Creating a multi-signature account is easily done by managing the account keys and their corresponding weight. To repeat, in order to sign a transaction the keys used to sign it must have weights that sum up to at least 1000. Using this information we can easily see how we can achieve the following cases: + +#### 2-of-3 multi-sig quorum + +![Screenshot 2023-08-16 at 19.34.44.png](_accounts_images/Screenshot_2023-08-16_at_19.34.44.png) + +#### 3-of-3 multi-sig quorum + +![Screenshot 2023-08-16 at 19.34.55.png](_accounts_images/Screenshot_2023-08-16_at_19.34.55.png) + +#### 1-of-2 signature + +![Screenshot 2023-08-16 at 19.34.51.png](_accounts_images/Screenshot_2023-08-16_at_19.34.51.png) + +### Key Format + +We are supporting ECDSA with the curves `P-256` and `secp256k1`. For these curves, the public key is encoded into 64 bytes as `X||Y` where `||` is the concatenation operator. + +- `X` is 32 bytes and is the big endian byte encoding of the `x`-coordinate of the public key padded to 32, i.e. `X=x_31||x_30||...||x_0` or `X = x_31*256^31 + ... + x_i*256^i + ... + x_0`. +- `Y` is 32 bytes and is the big endian byte encoding of the `y`-coordinate of the public key padded to 32, i.e. `Y=y_31||y_30||...||y_0` or `Y = y_31*256^31 + ... + y_i*256^i + ... + y_0` + +## Account Creation + +Accounts are created on the Flow blockchain by calling a special [create account Cadence function](https://cadence-lang.org/docs/language/accounts#account-creation). Once an account is created we can associate a new key with that account. Of course, all that can be done within a single transaction. Keep in mind that there is an account creation fee that needs to be paid. Account creation fees are relatively low, and we expect that wallet providers and exchanges will cover the cost when a user converts fiat to crypto for the first time. + +For development purposes, [you can use Flow CLI to easily create emulator, testnet and mainnet accounts.](../../tools/flow-cli/accounts/create-accounts.md) The account creation fee is paid by a funding wallet so you don't need a pre-existing account to create it. + +### **Key Generation** + +Keys should be generated in a secure manner. Depending on the purpose of the keys different levels of caution need to be taken. + +:::warning + +Anyone obtaining access to a private key can modify the account the key is associated with (assuming it has enough weight). Be very careful how you store the keys. + +::: + +For secure production keys, we suggest using key management services such as [Google key management](https://cloud.google.com/security-key-management) or [Amazon KMS](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Overview.Encryption.Keys.html), which are also supported by our CLI and SDKs. Those services are mostly great when integrated into your application. However, for personal use, you can securely use any [existing wallets](../../ecosystem/wallets.md) as well as a [hardware Ledger wallet](../../ecosystem/wallets.md). + +## Service Accounts + +### Flow Service Account +The Service Account is a special account in Flow that has special permissions to manage system contracts. It is able to mint tokens, set fees, and update network-level contracts. + +### Tokens & Fees +The Service Account has administrator access to the FLOW token smart contract, so it has authorization to mint and burn tokens. It also has access to the transaction fee smart contract and can adjust the fees charged for transactions execution on Flow. + +### Network Management +The Service Account administers other smart contracts that manage various aspects of the Flow network, such as epochs and (in the future) validator staking auctions. + +### Governance +Besides its special permissions, the Service Account is an account like any other in Flow. +The service account is currently controlled by a smart contract governed by the Flow community. +No single entity has the ability to unilaterally execute a transaction +from the service account because it requires four signatures from controlling keys. +The Flow foundation only controls 3 of the keys and the others are controlled +by trusted community members and organizations. + +## Accounts Retrieval + +You can use the Flow CLI to get account data by running: + +```sh +flow accounts get 0xf919ee77447b7497 -n mainnet +``` + +Find [more about the command in the CLI docs](../../tools/flow-cli/accounts/get-accounts.md). + +Accounts can be obtained from the access node APIs, currently, there are two gRPC and REST APIs. You can find more information about them here: + +**gRPC API** [building-on-flow/nodes/access-api#accounts](../../networks/access-onchain-data/index.md#accounts) + +**REST API** [http-api#tag/Accounts](/http-api#tag/Accounts) + +There are multiple SDKs implementing the above APIs for different languages: + +**Javascript SDK** [tools/clients/fcl-js](../../tools/clients/fcl-js/index.md) + +**Go SDK** [tools/clients/flow-go-sdk](../../tools/clients/flow-go-sdk/index.md) + +Find a list of all SDKs here: [tools/clients](../../tools/clients/index.md) \ No newline at end of file diff --git a/static/markdown/build/basics/blocks.md b/static/markdown/build/basics/blocks.md new file mode 100644 index 0000000000..b416e11475 --- /dev/null +++ b/static/markdown/build/basics/blocks.md @@ -0,0 +1,93 @@ +--- +sidebar_position: 1 +title: Blocks +description: Learn about Flow blockchain blocks, their structure, lifecycle, and how they maintain the blockchain's state. Understand block headers, payloads, and the finalization process. +keywords: + - blocks + - blockchain blocks + - block header + - block payload + - block seals + - block finalization + - block status + - consensus + - collection guarantees + - block retrieval + - block ID + - block height + - Flow blockchain + - blockchain state +--- + +# Blocks + +## Overview + +Blocks are entities that make up the Flow blockchain. Each block contains a list of [transactions](./transactions.md) that were executed and as a result, changed the global blockchain state. Each block is identified by a unique ID which is a cryptographic hash of the block contents. Block also includes a link to the parent block ID creating a linked list of blocks called the Flow blockchain. + +The unique block ID serves as proof of the block contents which can be independently validated by any observer. Interesting cryptographic properties of the hash that make up the block ID guarantee that if any change is made to the block data it would produce a different hash and because blocks are linked, a different hash would break the link as it would no longer be referenced in the next block. + +A very basic representation of blocks is: + +![Screenshot 2023-08-16 at 15.16.38.png](_blocks_images/Screenshot_2023-08-16_at_15.16.38.png) + +Blocks are ordered starting from the genesis block 0 up to the latest block. Each block contains an ordered list of transactions. This is how the Flow blockchain preserves the complete history of all the changes made to the state from the beginning to the current state. + +Each block contains more data which is divided into **block header** and **block payload**. There are many representations of block data within the Flow protocol. APIs, node types, and specific components within the node may view a block from differing perspectives. For the purpose of this documentation, we will talk about block data we expose through APIs to the clients. + +![Screenshot 2023-08-16 at 10.50.53.png](_blocks_images/Screenshot_2023-08-16_at_10.50.53.png) + +### Block Header + +The Block header contains the following fields: + +- **ID** represents the block's unique identifier, which is derived from the hashing block header including the payload hash. The algorithm used on Flow to hash the content and get an identifier is SHA3 256. This ID is a commitment to all the values in the block staying the same. +- **Parent ID** is a link to the previous block ID in the list making up the blockchain. +- **Height** is the block sequence number, where block 0 was the first block produced, and each next block increments the value by 1. +- **Timestamp** is the timestamp at which this block was proposed by the consensus node. Depending on your use case this time might not be accurate enough, [read more about measuring time on the Flow blockchain](https://cadence-lang.org/docs/measuring-time#time-on-the-flow-blockchain). +- **Payload Hash** represents the payload hash that is included when producing the ID of the block. Payload hash is calculated by taking Merkle root hashes of collection guarantees, seals, execution receipts, and execution results and hashing them together. More on each of the values in the block payload section. + +### Block Payload + +The block payload contains the following fields: + +- **Collection Guarantees** is a list of collection IDs with the signatures from the collection nodes that produced the collections. This acts as a guarantee by collection nodes that [transaction data](./transactions.md) in the collection will be available on the collection node if requested by other nodes at a later time. Flow purposely skips including transaction data in a block, making blocks as small as possible, and the production of new blocks by consensus nodes fast, that is because consensus nodes have to sync the proposed block between nodes, and that data should be the smallest possible. The consensus nodes don't really care what will a transaction do as long as it's valid, they only need to define an order of those transactions in a block. +- **Block Seals** is the attestation by verification nodes that the transactions in a previously executed block have been verified. This seals a previous block referenced by the block ID. It also references the result ID and execution root hash. It contains signatures of the verification nodes that produced the seal. + +## Lifecycle and Status + +Block status is not a value stored inside the block itself but it represents the lifecycle of a block. We derive this value based on the block inclusion in the Flow blockchain and present it to the user as it acts as an important indicator of the finality of the changes the block contains. + +Here we'll give an overview of the different phases a block goes through. [More details can be found in the whitepaper](https://flow.com/technical-paper). Also, a lot of the block states are not necessarily important to the developer but only important to the functioning of the Flow blockchain. + +New blocks are constantly being proposed even if no new transactions are submitted to the network. Consensus nodes are in charge of producing blocks. They use a consensus algorithm (an implementation of HotStuff) to agree on what the new block will be. A block contains the ordered list of collections and each collection contains an ordered list of transactions. This is an important fact to reiterate. A block serves as a list of transitions to the Flow state machine. It documents, as an ordered list, all the changes transactions will make to the state. + +A block that is [agreed upon by the consensus nodes using an implementation of HotStuff consensus algorithm](https://arxiv.org/pdf/2002.07403.pdf) to be the next block is **finalized**. This means the block won't change anymore and it will next be executed by the execution node. Please be careful because until a block is **sealed** the changes are not to be trusted. After verification nodes validate and agree on the correctness of execution results, a block is sealed and consensus nodes will include these seals in the new block. + +In summary, a block can be either **finalized** which guarantees transactions included in the block will stay the same and will be executed, and **sealed** which means the block execution was verified. + +![Screenshot 2023-08-16 at 10.48.26.png](_blocks_images/Screenshot_2023-08-16_at_10.48.26.png) + +## Block Retrieval + +You can use the Flow CLI to get the block data by running: + +```sh +flow blocks get latest -network mainnet +``` + +Find [more about the command in the CLI docs](../../tools/flow-cli/get-flow-data/get-blocks.md). + +Blocks can be obtained from the access node APIs, currently, there are two gRPC and REST APIs. You can find more information about them here: + +[**gRPC Block API**](../../networks/access-onchain-data/index.md#blocks) + +[**REST Block API**](/http-api#tag/Blocks) + +There are multiple SDKs implementing the above APIs for different languages: + +[**Javascript SDK**](../../tools/clients/fcl-js/index.md) + +[**Go SDK**](../../tools/clients/flow-go-sdk/index.md) + +Find a list of all SDKs [here](../../tools/clients/index.md) \ No newline at end of file diff --git a/static/markdown/build/basics/collections.md b/static/markdown/build/basics/collections.md new file mode 100644 index 0000000000..f7ec6e8728 --- /dev/null +++ b/static/markdown/build/basics/collections.md @@ -0,0 +1,50 @@ +--- +sidebar_position: 1 +title: Collections +description: Learn about Flow blockchain collections, how they optimize data transfer by linking blocks and transactions, and their role in the network architecture. Understand how collection nodes create and manage transaction collections. +keywords: + - collections + - blockchain collections + - transaction collections + - collection nodes + - HotStuff consensus + - transaction hashes + - network optimization + - collection clusters + - transaction payload + - Flow architecture + - consensus nodes + - collection retrieval + - blockchain scaling + - data optimization +--- + +# Collections + +Collections link blocks and transactions together. Collection node clusters make these collections (using the HotStuff consensus algorithm), made up of an ordered list of one or more hashes of [signed transactions](./transactions.md). In order to optimize data, blocks don't contain transactions (as they do on Ethereum). The benefits are transaction data does not get transferred to consensus nodes on the network which optimizes transfer speed and this architecture allows scaling of ingestion speed by adding collection clusters. Consensus nodes need to only agree on the order of transactions to be executed, they don't need to know the transaction payload, thus making blocks and collections lightweight. Collection nodes hold transaction payloads for anyone who requests them (e.g. execution nodes). + +![Screenshot 2023-08-17 at 19.50.39.png](_collection_images/Screenshot_2023-08-17_at_19.50.39.png) + +## Collection Retrieval + +You can use the Flow CLI to get the collection data by running: + +```sh +flow collections get caff1a7f4a85534e69badcda59b73428a6824ef8103f09cb9eaeaa216c7d7d3f -n mainnet +``` + +Find [more about the command in the CLI docs](../../tools/flow-cli/get-flow-data/get-collections.md). + +Collections can be obtained from the access node APIs, currently, there are two gRPC and REST APIs. You can find more information about them here: + +[**gRPC Collection API**](../../networks/access-onchain-data/index.md#collections) + +[**REST Collection API**](/http-api#tag/Collections) + +There are multiple SDKs implementing the above APIs for different languages: + +[**Javascript SDK**](../../tools/clients/fcl-js/index.md) + +[**Go SDK**](../../tools/clients/flow-go-sdk/index.md) + +Find a list of all SDKs [here](../../tools/clients/index.md) \ No newline at end of file diff --git a/static/markdown/build/basics/events.md b/static/markdown/build/basics/events.md new file mode 100644 index 0000000000..371be599ee --- /dev/null +++ b/static/markdown/build/basics/events.md @@ -0,0 +1,160 @@ +--- +sidebar_position: 6 +title: Events +description: Learn about Flow blockchain events, including core events and user-defined events. Understand how events are emitted during transaction execution and how they can be observed by off-chain applications. +keywords: + - events + - blockchain events + - Flow events + - core events + - user-defined events + - event emission + - event payload + - fungible token events + - fee events + - event listeners + - transaction events + - event types + - event naming + - Flow network + - event observation +--- + +# Events + +Flow events are special values that are emitted on the network during the execution of a Cadence program and can be observed by off-chain observers. + +Events are defined as Cadence code and you should [read Cadence documentation](https://cadence-lang.org/docs/language/events) to understand how to define them. + +Since transactions don't have return values you can leverage events to broadcast certain changes the transaction caused. Clients listening on Flow networks (apps) can listen to these events being emitted and react. + +![Screenshot 2023-08-18 at 14.09.33.png](_events_images/Screenshot_2023-08-18_at_14.09.33.png) + +There are two types of events emitted on the Flow network: + +- Core events +- User-defined events + +Events consist of the **event name** and an optional **payload**. + +![Screenshot 2023-08-18 at 13.59.01.png](_events_images/Screenshot_2023-08-18_at_13.59.01.png) + +## Core Events + +Core events are events emitted directly from the FVM (Flow Virtual Machine). The events have the same name on all networks and do not follow the same naming as user-defined events (they have no address). + +A list of events that are emitted by the Flow network is: + +| Event Name | Description | +| ---------------------------- | ------------------------------------------------------------------------| +| flow.AccountCreated | Event that is emitted when a new account gets created. | +| flow.AccountKeyAdded | Event that is emitted when a key gets added to an account. | +| flow.AccountKeyRemoved | Event that is emitted when a key gets removed from an account. | +| flow.AccountContractAdded | Event that is emitted when a contract gets deployed to an account. | +| flow.AccountContractUpdated | Event that is emitted when a contract gets updated on an account. | +| flow.AccountContractRemoved | Event that is emitted when a contract gets removed from an account. | +| flow.InboxValuePublished | Event that is emitted when a Capability is published from an account. | +| flow.InboxValueUnpublished | Event that is emitted when a Capability is unpublished from an account. | +| flow.InboxValueClaimed1 | Event that is emitted when a Capability is claimed by an account. | + +For more details [on the core events, you can read Cadence reference documentation](https://cadence-lang.org/docs/language/core-events). + +## User-defined events + +Events that are defined inside contracts and when emitted follow a common naming schema. The schema consists of 4 parts: + +```cadence +A.{contract address}.{contract name}.{event type} +``` + +An example event would look like: + +![Screenshot 2023-08-18 at 14.30.36.png](_events_images/Screenshot_2023-08-18_at_14.30.36.png) + +The first `A` means the event is originating from a contract, which will always be the case for user-defined events. The contract address as the name implies is the location of a contract deployed on the Flow network. Next, is the name of the contracted event originates from, and last is the event type defined in the contract. + +There is an unlimited amount of events that can be defined on Flow, but you should know about the most common ones. + +### Fungible Token Events + +All fungible token contracts, including [The FLOW Token contract](../../build/core-contracts/03-flow-token.md), +use the [fungible token standard on Flow](../../build/core-contracts/02-fungible-token.md). +As with any contract, the standard emits events when interacted with. +When any fungible token is transferred, standard events are emitted. +You can find a lot of details on the events emitted in the [Fungible Token documentation](../../build/core-contracts/02-fungible-token.md). + +The most common events are when tokens are transferred which is accomplished with two actions: withdrawing tokens from the payer and depositing tokens in the receiver. Each of those actions has a corresponding event: + +**Withdraw Tokens** + +Event name: `FungibleToken.Withdrawn` +```cadence +event Withdrawn(type: String, + amount: UFix64, + from: Address?, + fromUUID: UInt64, + withdrawnUUID: UInt64, + balanceAfter: UFix64) +``` + +Mainnet event: `A.f233dcee88fe0abe.FungibleToken.Withdrawn` + +Testnet event: `A.9a0766d93b6608b7.FungibleToken.Withdrawn` + +**Deposit Tokens** + +```cadence +event Deposited(type: String, + amount: UFix64, + to: Address?, + toUUID: UInt64, + depositedUUID: UInt64, + balanceAfter: UFix64) +``` + +Event name: `FungibleToken.Deposited` + +Mainnet event: `A.f233dcee88fe0abe.FungibleToken.Deposited` + +Testnet event: `A.9a0766d93b6608b7.FungibleToken.Deposited` + +### **Fee Events** + +Since fees are governed by a contract deployed on the Flow network, that contract also emits events when fees are deducted. + +Charging fees consists of a couple of steps: + +- Calculate and deduct fees +- Withdraw Flow tokens from the payer account +- Deposit Flow tokens to the fees contract + +These events are very common since they accommodate all transactions on Flow. Each fee deduction will result in three events: the withdrawal of Flow tokens, the deposit of Flow tokens, and the fee deduction. + +An example of fee events: + +```yml +Events: + - Index: 0 + Type: A.f233dcee88fe0abe.FungibleToken.Withdrawn + Tx ID: 1ec90051e3bc74fc36cbd16fc83df08e463dda8f92e8e2193e061f9d41b2ad92 + Values: + - type (String): "1654653399040a61.FlowToken.Vault" + - amount (UFix64): 0.00000100 + - from (Address?): b30eb2755dca4572 + + - Index: 1 + Type: A.f233dcee88fe0abe.FungibleToken.Deposited + Tx ID: 1ec90051e3bc74fc36cbd16fc83df08e463dda8f92e8e2193e061f9d41b2ad92 + Values: + - type (String): "1654653399040a61.FlowToken.Vault" + - amount (UFix64): 0.00000100 + - to (Address?): f919ee77447b7497 + + - Index: 2 + Type: A.f919ee77447b7497.FlowFees.FeesDeducted + Tx ID: 1ec90051e3bc74fc36cbd16fc83df08e463dda8f92e8e2193e061f9d41b2ad92 + Values: + - amount (UFix64): 0.00000100 + - inclusionEffort (UFix64): 1.00000000 + - executionEffort (UFix64): 0.00000000 +``` \ No newline at end of file diff --git a/static/markdown/build/basics/fees.md b/static/markdown/build/basics/fees.md new file mode 100644 index 0000000000..bbd5eef407 --- /dev/null +++ b/static/markdown/build/basics/fees.md @@ -0,0 +1,448 @@ +--- +sidebar_position: 5 +title: Fees +description: Learn about Flow blockchain fees, including transaction fees, storage fees, and how they work to protect the network. Understand fee structures, calculation methods, and optimization strategies. +keywords: + - fees + - transaction fees + - storage fees + - execution fees + - inclusion fees + - surge factor + - fee calculation + - storage capacity + - fee optimization + - network protection + - blockchain fees + - gas fees + - Flow token + - fee structure + - cost estimation +--- + +:::info + +Are you an EVM developer looking for information about EVM Accounts on Flow? If so, check out the EVM specific documentation [here](../../evm/fees.md) + +::: + +# Fees + +## Transaction Fees + +A transaction fee is a cost paid in Flow by the payer account and is required for a transaction to be included in the Flow blockchain. Fees are necessary for protecting the network against spam/infinite running transactions and to provide monetary incentives for participants that make up the Flow network. + +A transaction fee is paid regardless of whether a transaction succeeds or fails. If the payer account doesn't have sufficient Flow balance to pay for the transaction fee, the transaction will fail. We can limit the transaction fee to some extent by providing the gas limit value when submitting the transaction. + +### Understanding the need for transaction fees + +Segmented transaction fees are essential to ensure fair pricing based on the impact on the network. For instance, more heavy operations will require more resources to process and propagate transactions. Common operations, however, will stay reasonably priced. + +Fees will improve the overall security of the network by making malicious actions (eg spam) on the network less viable. + +The unique Flow architecture is targeted at high throughput. It makes it easier to have slack in the system, so short spikes can be handled more gracefully. + +### **Fee Structure** + +Each transaction fee consists of three components: execution fee, inclusion fee, and network surge factor. + +![Screenshot 2023-08-17 at 17.16.32.png](_fees_images/Screenshot_2023-08-17_at_17.16.32.png) + +**Execution Fee** + +The execution effort for a transaction is determined by the code path the transaction takes and the actions it does. The actions that have an associated execution effort cost can be separated into four broad buckets: + +- Normal lines of cadence, loops, or function calls +- Reading data from storage, charged per byte read +- Writing data to storage, charged per byte written +- Account creation + +| Transaction Type | Estimated cost (FLOW) | +| -------------------------------------------------- | --------------------- | +| FT transfer | 0.00000185 | +| Mint a small NFT (heavily depends on the NFT size) | 0.0000019 | +| Empty Transaction | 0.000001 | +| Add key to an account | 0.000001 | +| Create 1 Account | 0.00000315 | +| Create 10 accounts | 0.00002261 | +| Deploying a contract that is ~50kb | 0.00002965 | + +**Inclusion Fee** + +The inclusion effort of a transaction represents the work needed for: + +- Including the transaction in a block +- Transporting the transaction information from node to node +- Verifying transaction signatures + +Right now, the inclusion effort is always 1.0 and the inclusion effort cost is fixed to `0.000001`. + +**Surge Factor** + +In the future, a network surge will be applied when the network is busy due to an increased influx of transactions required to be processed or a decrease in the ability to process transactions. Right now, the network surge is fixed to `1.0`. + +Currently, both the inclusion fee and surge factor don't represent any significant Flow fees. Keep in mind this can change in the future. + +**Estimating transaction costs** + +Cost estimation is a two-step process. First, you need to gather the execution effort with either the emulator, on testnet, or on mainnet. Second, you use the execution effort for a transaction to calculate the final fees using one of the JavaScript or Go FCL SDKs. + +## Storage + +Flow's approach to storage capacity is a bit similar to some banks' pricing models, where maintaining a minimum balance prevents monthly account fees. Here, the amount of data in your account determines your minimum balance. If you fall below the minimum balance, you cannot transact with your account, except for deposits or deleting data. The essence of storage fee model is that it ensures data availability without continuously charging fees for storage, while also preventing abuses that could burden the network's storage resources. This distinction between current state and blockchain history is crucial for understanding storage requirements and limitations. + +Each Flow account has associated storage used. The account's storage used is the byte size of all the data stored in the account's storage. Accounts also have a storage capacity, which is directly tied to the amount of Flow tokens an account has. The account can, without any additional cost, use any amount of storage up to its storage capacity. + +:::warning + +If a transaction puts an account over storage capacity, that transaction fails and is reverted. Likewise, if a transaction would drop an account's balance below 0.001 Flow tokens, which is the minimum an account can have, the transaction would also fail. + +::: + +**Storage Capacity** + +The storage capacity of an account is dictated by the amount of FLOW it has. + +:::danger + +The **minimum amount of FLOW an account can have is 0.001**. This minimum is provided by the account creator at account creation. + +::: + +The minimum account reservation ensures that most accounts won't run out of storage capacity if anyone deposits anything (like an NFT) to the account. + +Currently, the amount required to store 100 MB in account storage is 1 Flow. + +![Screenshot 2023-08-17 at 17.27.50.png](_fees_images/Screenshot_2023-08-17_at_17.27.50.png) + +Please note that storing data in an account on Flow doesn't charge tokens from the account, it just makes sure you will keep the tokens as a reserve. Once the storage is freed up you can transfer the Flow tokens. + +### Storage Capacity of the Payer + +The storage capacity of the Payer of a transaction is generally computed the same way as the capacity of any other account, however, the system needs to account for the transaction fees the payer will incur at the end of the transaction. The final transaction fee amount is not fully known at this step, only when accounts are checked for storage compliance. If their storage used is more than their storage capacity, the transaction will fail. + +Because of this, the payer's balance is conservatively considered to be lower by the maximum possible transaction fees, when checking for storage compliance. The maximum transaction fee of a specific transaction is the transaction fee as if the transaction would have used up all of its execution effort limit. + +### Storage Used + +All data that is in an account's storage counts towards storage used. Even when an account is newly created it is not empty. There are already some items in its storage: + +- Metadata that marks that the account exists. +- An empty FLOW vault, and stored receiver capability. +- Public keys to the account if the account was created with keys. +- Smart contracts deployed on the account if the account was created with contracts. +- The value of the account's storage used as an unsigned integer. + +Adding additional keys, smart contracts, capabilities, resources, etc. to the account counts towards storage used. + +Data stored on the Flow blockchain is stored in a key-value ledger. Each item's key contains the address that owns the item and the path to the item. An account can have many keys, therefore flow considers the account key items are stored with. This means that the storage used by each item is the byte length of the item plus the byte length of the item's key. + +### Maximum available balance + +Due to the storage restrictions, there is a maximum available balance that user can withdraw from the wallet. The core contract [`FlowStorageFees`](../core-contracts/05-flow-fees.md#flowstoragefees) provides a function to retrieve that value: + +```cadence +import "FlowStorageFees" + +access(all) fun main(accountAddress: Address): UFix64 { + return FlowStorageFees.defaultTokenAvailableBalance(accountAddress) +} +``` + +Alternatively developers can use `availableBalance` property of the `Account` + +```cadence +access(all) fun main(address: Address): UFix64 { + let acc = getAccount(address) + let balance = acc.availableBalance + + return balance +} + +``` + +## Practical Understanding of Fees + +**Using Flow Emulator** + +You can start the [emulator using the Flow CLI](../../tools/emulator/index.md#running-the-emulator-with-the-flow-cli). Run your transaction and take a look at the events emitted: + +```shell +0|emulator | time="2022-04-06T17:13:22-07:00" level=info msg="⭐ Transaction executed" computationUsed=3 txID=a782c2210c0c1f2a6637b20604d37353346bd5389005e4bff6ec7bcf507fac06 +``` + +You should see the `computationUsed` field. Take a note of the value, you will use it in the next step. + +**On testnet or mainnet** + +Once a transaction is completed, you can use an explorer like [Flowscan](https://flowscan.io/) to review the transaction details and events emitted. For Flowscan, you can open the transaction in question and look for the event `FeesDeducted` from the [`FlowFees`](https://github.com/onflow/flow-core-contracts/blob/master/contracts/FlowFees.cdc) contract: + +![flowscan-fees](./_fees_images/flowscan-fees.png) + +In the event data on the right side, you will see a set of fields representing [the fees for a specific transaction.](https://github.com/onflow/flow-core-contracts/blob/master/contracts/FlowFees.cdc#L14): + +- Total Fees Paid +- Inclusion Effort +- Execution Effort + +Take a note of the last value in the list - the `executionEffort` value. You will use it in the next step. + +### Calculating final costs + +The cost for transactions can be calculated using the following FCL scripts on mainnet/testnet respectively. + +**On mainnet** + +```cadence +import FlowFees from 0xf919ee77447b7497 +access(all) fun main( + inclusionEffort: UFix64, + executionEffort: UFix64 +): UFix64 { + return FlowFees.computeFees(inclusionEffort: inclusionEffort, executionEffort: executionEffort) +} +``` + +**On testnet** + +```cadence +import FlowFees from 0x912d5440f7e3769e +access(all) fun main( + inclusionEffort: UFix64, + executionEffort: UFix64 +): UFix64 { + return FlowFees.computeFees(inclusionEffort: inclusionEffort, executionEffort: executionEffort) +} +``` + +## Configuring execution limits + +FCL SDKs allow you to set the execution effort limit for each transaction. Based on the execution effort limit determined in the previous step, you should set a reasonable maximum to avoid unexpected behavior and protect your users. The final transaction fee is computed from the actual execution effort used up to this maximum. + +> **Note**: Keep in mind that the limits are not for the final fees that the user will have to pay. The limits are for the execution efforts specifically. + +It is important to set a limit that isn't too high or too low. If it is set too high, the payer needs to have more funds in their account before sending the transaction. If it is too low, the execution could fail and all state changes are dropped. + +**Using FCL JS SDK** + +You need to set the `limit` parameter for the `mutate` function, for example: + +```js + + +const transactionId = await fcl.mutate({ + cadence: ` + transaction { + execute { + log("Hello from execute") + } + } + `, + proposer: fcl.currentUser, + payer: fcl.currentUser, + limit: 100 +}) + +const transaction = await fcl.tx(transactionId).onceExecuted(); +console.log(transaction;) +``` + +**Using FCL Go SDK** + +You need to call the `SetComputeLimit` method to set the fee limit, for example: + +```go +import ( + "github.com/onflow/flow-go-sdk" + "github.com/onflow/flow-go-sdk/crypto" +) + +var ( + myAddress flow.Address + myAccountKey flow.AccountKey + myPrivateKey crypto.PrivateKey +) + +tx := flow.NewTransaction(). + SetScript([]byte("transaction { execute { log(\"Hello, World!\") } }")). + SetComputeLimit(100). + SetProposalKey(myAddress, myAccountKey.Index, myAccountKey.SequenceNumber). + SetPayer(myAddress) +``` + +### Maximum transaction fees of a transaction + +The maximum possible fee imposed on the payer for a transaction can be calculated as the **inclusion cost plus the execution cost**. The execution cost is the fee calculated for running the transaction based on the [execution effort limit maximum specified](#configuring-execution-limits). + +The payer will never pay more than this amount for the transaction. + +## Optimizing Cadence code to reduce effort + +Several optimizations can lead to reduced execution time of transactions. Below is a list of some practices. This list is not exhaustive but rather exemplary. + +**Limit functions calls** + +Whenever you make function calls, make sure these are absolutely required. In some cases, you might be able to check prerequisites and avoid additional calls: + +```cadence +for obj in sampleList { + /// check if call is required + if obj.id != nil { + functionCall(obj) + } +} +``` + +**Limit loops and iterations** + +Whenever you want to iterate over a list, make sure it is necessary to iterate through all elements as opposed to a subset. Avoid loops to grow in size too much over time. Limit loops when possible. + +```cadence +// Iterating over long lists can be costly +access(all) fun sum(list: [Int]): Int { + var total = 0 + var i = 0 + // if list grows too large, this might not be possible anymore + while i < list.length { + total = total + list[i] + } + return total +} + +// Consider designing transactions (and scripts) in a way where work can be "chunked" into smaller pieces +access(all) fun partialSum(list: [Int], start: Int, end: Int): Int { + var partialTotal = 0 + var i = start + while i < end { + partialTotal = partialTotal + list[i] + } + return partialTotal +} +``` + +**Understand the impact of function calls** + +Some functions will require more execution efforts than others. You should carefully review what function calls are made and what execution they involve. + +```cadence +// be aware functions that call a lot of other functions +// (or call themselves) might cost a lot +access(all) fun fib(_ x: Int): Int { + if x == 1 || x== 0 { + return x + } + // + 2 function calls each recursion + return fib(x-1) + fib(x-2) +} + +// consider inlining functions with single statements, to reduce costs +access(all) fun add(_ a: Int, _ b: Int): Int { + // single statement; worth inlining + return a + b +} +``` + +**Avoid excessive load and save operations** + +Avoid costly loading and storage operations and [borrow references](https://cadence-lang.org/docs/design-patterns#avoid-excessive-load-and-save-storage-operations-prefer-in-place-mutations) where possible, for example: + +```cadence +transaction { + + prepare(acct: auth(BorrowValue) &Account) { + + // Borrows a reference to the stored vault, much less costly operation that removing the vault from storage + let vault <- acct.storage.borrow<&ExampleToken.Vault>(from: /storage/exampleToken) + + let burnVault <- vault.withdraw(amount: 10) + + destroy burnVault + + // No `save` required because we only used a reference + } +} +``` + +> **Note**: If the requested resource does not exist, no reading costs are charged. + +**Limit accounts created per transaction** + +Creating accounts and adding keys are associated with costs. Try to only create accounts and keys when necessary. + +**Check user's balance before executing transactions** + +You should ensure that the user's balance has enough balance to cover the highest possible fees. For FT transfers, you need to cover the amount to transfer in addition to the highest possible fees. + +## Educating users + +Wallets will handle the presentation of the final transaction costs but you can still facilitate the user experience by educating them within your application. + +If your user is using self-custody wallets, they may have to pay the transaction and want to understand the fees. Here are some suggestions. + +**Explain that costs can vary depending on the network usage** + +Suggested message: "Fees improve the security of the network. They are flexible to ensure fair pricing based on the impact on the network." + +**Explain that waiting for the network surge to pass is an option** + +Inevitably, network surges will cause higher fees. Users who might want to submit a transaction while the network usage is surging should consider sending the transaction at a later time to reduce costs. + +**Explain that the wallet might not allow the transaction due to a lack of funds** + +If dynamic fees increase to the highest possible level, the user's fund might not be enough to execute the transaction. Let the users know that they should either add funds or try when the network is less busy. + +## How to learn more + +There are several places to learn more about transaction fees: + +- [FLIP-660](https://github.com/onflow/flow/pull/660) +- [FLIP-753](https://github.com/onflow/flow/pull/753) +- [Flow Fees Contract](https://github.com/onflow/flow-core-contracts/blob/master/contracts/FlowFees.cdc) + +> **Note**: If you have thoughts on the implementation of transaction fees on Flow, you can [leave feedback on this forum post](https://forum.onflow.org/t/variable-transaction-fees-are-coming-to-flow/2941). + +## FAQs + +**When will the fee update go into effect?** + +The updates were rolled out with the [Spork on April 6, 2022](../../networks/node-ops/node-operation/past-upgrades#mainnet-17), and were enabled on [June 1st](https://forum.onflow.org/t/permissionless-contract-deployment-progress/2981) during the [weekly epoch transition](https://github.com/onflow/service-account/tree/main/transactions/set-execution-effort-weights/2022/jun-1). + +**Why are fees collected even when transactions fail?** + +Broadcasting and verifying a transaction requires execution, so costs are deducted appropriately. + +**What execution costs are considered above average?** + +There is no average for execution costs. Every function will vary significantly based on the logic implemented. You should review the optimization best practices to determine if you could reduce your costs. + +**Do hardware wallets like Ledger support segmented fees?** + +Yes. + +**What is the lowest execution cost?** + +The lowest execution cost is 1. This means your transaction included one function call or loop that didn't read or write any date. + +**Can I determine how much a transaction will cost on mainnet without actually paying?** + +You can estimate the costs in a two-way process: 1) determine execution costs for transactions (emulator or testnet) and 2) use an FCL SDK method to calculate the final transaction fees. + +**How accurate will testnet fees be to mainnet fees?** + +Final fees are determined by the surge factor on the network. The surge factor for the testnet will be different from the factor for the mainnet, so you need to expect a variation between mainnet and testnet estimates. + +**I use Blocto and I haven't paid any fees yet. Why is that?** + +That is because Blocto is acting as the payer for transactions. Self-custody wallets may have the user pay the transaction. Additionally, apps can sponsor the transaction if they choose. + +**Why would the same transaction have different fees when executed for different accounts?** + +Execution costs, among other things, include the cost to read data from account storage and since the data stored varies from account to account, so does the execution costs, and subsequently the transaction fees. + +Additional Details: + +- The most expensive operations in Cadence are reading and writing to storage. This isn't punitive! Every read needs to be sent to all Verification nodes for verification (with Merkel proofs), and every write requires a path of Merkel hashes to be updated. Reading and writing to storage is inherently expensive on any blockchain. +- The way data is stored in accounts is as a tree (the hint is in the name "atree" :wink:). So, the more elements in the account, the more levels of the tree, and therefore the more nodes of that tree that need to be read and updated. So, looking at the byte size of an account is a decent proxy for figuring out how much it's going to cost. +- Because it's a tree, the cost of reads and writes grows with log(n), but does scale. +- atree has an update queued up for [Crescendo](https://flow.com/upgrade/crescendo) that will improve this. The previous version erred on the side of adding new levels to the tree (to keep the code simple), while the new version tries to pack more data at each level. This should result in fewer levels for the same byte size. Additionally, it includes a more compact encoding leading to a reduction in the byte size of most accounts. +- Even with these improvements, this relationship is likely to remain indefinitely. The bigger the account, the more bookkeeping the nodes have to do, which will result in somewhat larger tx fees. \ No newline at end of file diff --git a/static/markdown/build/basics/flow-token.md b/static/markdown/build/basics/flow-token.md new file mode 100644 index 0000000000..58bec1ea78 --- /dev/null +++ b/static/markdown/build/basics/flow-token.md @@ -0,0 +1,127 @@ +--- +title: FLOW Coin +sidebar_position: 10 +description: Learn about the FLOW coin, its role as the native token of the Flow blockchain, and how to acquire, use, and build with it. Understand staking, delegation, and transaction fee mechanisms. +keywords: + - FLOW coin + - FLOW token + - native token + - fungible token + - staking + - delegation + - transaction fees + - Flow protocol + - Flow rewards + - token utility + - Flow wallet + - token custody + - Flow transactions + - Flow governance + - Flow ecosystem +--- + +## Introduction + +This section contains information about the FLOW Coin for individual backers, wallet providers, custodians and node operators. + +### FLOW as a Native Coin + +FLOW is the default coin for the Flow protocol, meaning it is used for all protocol-level fee payments, +rewards and staking transactions. FLOW implements the standard [Flow Fungible Token interface](https://github.com/onflow/flow-ft), +which all other on-chain fungible tokens also conform to. This interface is defined in Cadence, +Flow's native smart-contract programming language, which makes it easy to write applications that +interact with FLOW. + +## How to Get FLOW + +There are two ways to acquire FLOW Coins as yield: + +1. [Earn FLOW as a Validator or Delegator](../../networks/staking/06-technical-overview.md): Receive newly-minted FLOW as a reward for running a node. +1. [Earn FLOW as a Community Contributor](https://github.com/onflow/developer-grants): Flow offers grants for selected proposals as well as RFPs for teams to submit proposals for funded development + +## How to Use FLOW + +With FLOW, you can: + +- Spend +- Stake +- Delegate +- Hold +- Vote +- Send and share +- Create, develop, and grow your dapp + +### Spending FLOW + +All you need to spend FLOW is an account and a tool for signing transactions +(a wallet, custodian, or other signing service). +The FCL (Flow Client Library) makes it super duper easy to go to any dapp, +login with your account, have a great time, +and then sign with the wallet of your choice only once you decide to make a purchase. + +### Staking FLOW + +[You can use FLOW to operate a staked node.](../../networks/staking/06-technical-overview.md) Node operators receive newly-minted FLOW +as a reward for helping to secure the network. + +### Delegating FLOW + +[You can use FLOW for stake delegation.](../../networks/staking/06-technical-overview.md) Delegators receive newly-minted FLOW +as a reward for helping to secure the network. + +### Holding FLOW + +If you have already purchased FLOW and wish to hold it, you have a couple of options: + +- For relatively small, short term holdings - most people use a wallet. + Wallets are used to help you sign transactions (verify your actions) when using your FLOW tokens. + +- For larger, long term holdings - you may want to use a custody provider to keep your funds safe. + +You can find wallets and custodians supporting Flow in the [Flow Port](https://port.onflow.org/) + +### Voting with FLOW + +Participating in the Flow community is more than just running a node or building a dapp. +It's also about engaging in discussion, debate, and decision making about the protocol, +the content on it, and the people impacted by it. +You can use your Flow account to submit votes to community polls and other governance related activities. + +### Sending and Sharing FLOW + +If you simply want to share the love and bring your friends to Flow, it's easier than an edible arrangement. + +It is possible to use the Flow blockchain without holding any FLOW coins yourself. +Free to play games, trials, community polls, +and other community activities can all take place with only an account +(which may be created on a person's behalf) +and a small fixed fee which may be paid by a user agent. + +The protocol requires some FLOW coins to process these transactions, +but (and this is the cool part!) a product can support users who do not themselves hold FLOW +while still providing that user with all the underlying security guarantees the Flow protocol provides. + +Transferring FLOW, creating accounts, and updating keys are all actions made easy on [Flow Port](https://port.flow.com/) + +### Submitting Transactions and Updating Users + +Transactions are submitted using a Flow SDK via the Access API. + +On Flow, a transaction is identified by its hash - the hash that exists as soon as that transaction is signed and submitted to an Access or Collection node. +Results of transactions can be queried by transaction hash through the Access API. +A user can check the status of a transaction at any time via the [Flow Block Explorer](https://flowscan.io/). + +To expose these results natively in your app, you can use a Flow SDK to fetch transaction results, +[for example using the Flow Go SDK](https://github.com/onflow/flow-go-sdk#querying-transaction-results). + +Using a Flow SDK you can also fetch account state by address from a Flow Access API, +[for example using the Flow Go SDK](https://github.com/onflow/flow-go-sdk#querying-accounts). + +Once the transaction is sealed, an event is emitted and you will be able to read transaction events and update the user. + +The Flow SDKs also allow polling for events using the Flow Access API, +[for example using the Flow Go SDK](https://github.com/onflow/flow-go-sdk#querying-events). + +## How to Build with FLOW + +To get started building on Flow, please see the [Flow App Quickstart](../getting-started/fcl-quickstart.md) \ No newline at end of file diff --git a/static/markdown/build/basics/mev-resistance.md b/static/markdown/build/basics/mev-resistance.md new file mode 100644 index 0000000000..d20ba5d6d6 --- /dev/null +++ b/static/markdown/build/basics/mev-resistance.md @@ -0,0 +1,75 @@ +--- +title: MEV Resistance +description: How Flow’s unique architecture minimizes Maximal Extractable Value (MEV) to ensure fair and equitable access. +sidebar_position: 5 +keywords: + - MEV + - Maximal Extractable Value + - Flow Blockchain + - Equitable Access + - Transaction Ordering + - Blockchain Security +--- + +# How Flow Suppresses MEV to Ensure Equitable Access + +## The Hidden Cost of MEV in Decentralized Systems + +One of the most under-discussed benefits of decentralization is **equitable access**. Ideally, the value and quality-of-service you receive from a decentralized platform should not depend on your identity, computing power, or personal connections. However, **Maximal Extractable Value (MEV)** poses a significant threat to this principle. + +MEV allows block producers to manipulate transaction ordering for profit—often at the direct expense of users. The ability to front-run, back-run, or sandwich transactions can extract value from ordinary users, reinforcing inequalities rather than eliminating them. In most blockchain networks, MEV is not just an unfortunate side effect; it is structurally embedded in how transactions are processed. + +## Why MEV Persists on Most Blockchains + +MEV is difficult to prevent on most blockchains because **each block has a single builder**. This builder must have: + +- A full copy of the blockchain state +- The ability to simulate transactions before they are finalized +- Absolute control over transaction selection and ordering + +In practice, this means that **the entity responsible for adding your transaction to the blockchain can first simulate it to identify profit opportunities**. They can test hundreds or thousands of ways to rearrange transactions, inserting their own to extract MEV—often at **your** expense. + +For example, if a block builder can earn $10 by sandwiching your transaction, it means **you** likely lose $10 in value. This is functionally theft, and the worst part? If your transaction is airtight and offers no MEV opportunities, the block builder has no obligation to include it at all. Pay the toll, or get locked out. + +## How Flow Accomplishes MEV Resilience + +Unlike many blockchains, **Flow was designed from the ground up to minimize MEV** through a unique multi-role architecture. Flow introduces key design choices that break the typical MEV-enabling structure: + +### 1. **Separating Transaction Selection from Execution** +On Flow, **Collection Nodes** select transactions, but they do not have access to the execution state or computing power to simulate them. Meanwhile, **Execution Nodes** run transactions but cannot choose or reorder them. + +This separation significantly reduces the ability of block builders to test transactions before execution. Even if an attacker controls both a Collection Node and an Execution Node, they cannot easily extract MEV. + +### 2. **Separating Transaction Ordering from Execution** +Flow further decentralizes control by introducing **Consensus Nodes** that determine transaction order. These nodes are separate from both Collection Nodes and Execution Nodes. + +For an attacker to perform MEV, they would need to: +- Control a **Collection Node** to insert a transaction +- Control a **Consensus Node** to place it in the desired order +- Have execution state access to predict its effects + +This makes it vastly more difficult to extract MEV compared to traditional blockchains, where a single entity often controls all three functions. + +### 3. **Strict Transaction Execution Rules** +Execution Nodes on Flow have a **simple, enforceable rule**: +They **must** execute transactions exactly as ordered by Consensus Nodes—or they get slashed. + +Unlike traditional blockchains, where the same party both orders and executes transactions, Flow ensures that Execution Nodes cannot manipulate transaction order for profit. + +### 4. **Parallel Processing for Extra MEV Resistance** +Flow’s unique **pipelined execution model** adds another layer of complexity for potential attackers. + +While one block is being executed, the next block is undergoing consensus, and a third block is still collecting transactions. This means that **to front-run or sandwich attack on Flow, an attacker must successfully predict the outcome of at least two unexecuted blocks—one of which hasn’t even been built yet**. + +Even with significant resources, this makes profitable MEV attacks incredibly difficult. + +## The End Result: A Fairer Blockchain + +Flow’s architecture ensures that: +- The nodes selecting transactions **don’t know** their order +- The nodes ordering transactions **don’t know** the blockchain state +- The nodes executing transactions **can’t** modify the order + +By **intentionally separating powers**, Flow eliminates MEV at its root rather than merely mitigating its effects. + +This level of protection against MEV is not an afterthought—it has been a fundamental design goal of Flow since day one. If equitable access matters, **why settle for anything less?** \ No newline at end of file diff --git a/static/markdown/build/basics/network-architecture.md b/static/markdown/build/basics/network-architecture.md new file mode 100644 index 0000000000..c69f6a4605 --- /dev/null +++ b/static/markdown/build/basics/network-architecture.md @@ -0,0 +1,8 @@ +--- +sidebar_position: 0 +title: Network Architecture ↗️ +--- + + + +; \ No newline at end of file diff --git a/static/markdown/build/basics/scripts.md b/static/markdown/build/basics/scripts.md new file mode 100644 index 0000000000..a54f845b88 --- /dev/null +++ b/static/markdown/build/basics/scripts.md @@ -0,0 +1,128 @@ +--- +sidebar_position: 4 +title: Scripts +description: Learn about Flow scripts - read-only Cadence code that can query blockchain state without fees. Understand how to write, execute, and optimize scripts for accessing Flow network data. +keywords: + - scripts + - Cadence scripts + - blockchain queries + - read operations + - Flow scripts + - script execution + - state queries + - Flow API + - script limitations + - best practices + - historic data + - script arguments + - script returns + - Flow CLI + - computation limits +--- + +# Scripts + +A script provides a light-weight method to query chain data. + +It is executable Cadence code that can query for Flow execution state data but cannot modify it in any way. + +Unlike a Flow transaction, a script is not signed and requires no transaction fees. Also unlike a transaction, a script can return a value back to the caller. +You can think of executing a script as a read-only operation, very similar to the `eth_call` RPC method on Ethereum. + +Scripts are currently executed on either the Access Nodes or the Execution Nodes based on the Access node configuration. + +Scripts are defined by the following the Cadence code: + +```cadence +// The 'main' function is the entry point function and every script needs to have one. +access(all) fun main() { + // Cadence statements to be executed go here +} +``` + +Scripts can return a typed value: + +```cadence +access(all) fun main(): Int { + return 1 + 2 +} +``` + +Scripts can also accept arguments: + +```cadence +access(all) fun main(arg: String): String { + return "Hello ".concat(arg) +} +``` + +Scripts can call contract functions and query the state of a contract. To call a function on another contract, import it from its address and invoke the function: + +```cadence +import World from 0x01 + +access(all) fun main(): String { + return World.hello() +} +``` + +Scripts can also be run against previous blocks, allowing you to query historic data from the Flow network. This is particularly useful for retrieving historical states of contracts or tracking changes over time. + +## When to use a script? + +Scripts can be used for the following: + +1. Validating a transaction before submitting it e.g. checking if the payer has sufficient balance, the receiver account is setup correctly to receive a token or NFT etc. +2. Collecting chain data over time. +3. Continuously verifying accounts through a background job e.g. a Discord bot that verifies users by their Flow account. +4. Querying core contracts e.g. see [staking scripts and events](../../networks/staking/07-staking-scripts-events.md) for querying staking and epoch related information, see the scripts directory under each of the [core contract transactions](https://github.com/onflow/flow-core-contracts/tree/master/transactions) for other core contracts related scripts. + +## Executing Scripts + +### Access API + +A script can be executed by submitting it to the Access API provided by access nodes. Currently, there are three API endpoints that allow a user to execute scripts at the latest sealed block, a previous block height, or a previous block ID. + +[**gRPC Script API**](../../networks/access-onchain-data/index.md#scripts) + +[**REST Script API**](/http-api#tag/Scripts) + +There are multiple SDKs implementing the above APIs for different languages: + +[**Javascript SDK**](../../tools/clients/fcl-js/index.md) + +[**Go SDK**](../../tools/clients/flow-go-sdk/index.md) + +Find a list of all SDKs [here](../../tools/clients/index.md) + +### Flow CLI + +You can also execute a script by using the [Flow CLI](../../tools/flow-cli/scripts/execute-scripts): + +```sh +flow scripts execute ./helloWorld.cdc +``` + +A user can define their own scripts or can use already defined scripts by the contract authors that can be found by using the [FLIX](../../tools/flow-cli/flix) service. + +## Best Practices + +Following are some recommendations on how to write efficient scripts: + +1. **Simpler and shorter scripts**: Scripts, like transactions, are subject to computation limits (see [limitations](#limitations)). It is recommended to run shorter and simpler scripts which have low time complexity for a faster response. If you have a script with several nested loops, long iteration, or that queries many onchain fields, consider simplifying the script logic. + +2. **Fewer state reads**: A script reads execution state and to get a faster response, it is best to limit the amount of state that is read by the script. + +3. **Smaller length of array or dictionary type arguments**: If your script requires an array or a dictionary as an argument where each element causes a state lookup, instead of making a single script call passing in a long list, make multiple calls with a smaller subset of the array or dictionary. + +4. **NFTCatalog**: If your script uses the [NFTCatalog](https://github.com/onflow/nft-catalog) functions, ensure that you use the [latest functions](https://github.com/onflow/nft-catalog?tab=readme-ov-file#using-the-catalog-for-marketplaces-and-other-nft-applications) and do not use any of the deprecated functions such as `getCatalog()`. + +## Limitations + +1. **Rate limit** - Script execution is subjected to API rate-limits imposed by the Access nodes and the Execution nodes. The rate limits for the Public Access nodes hosted by QuickNode are outlined [here](https://www.quicknode.com/docs/flow#endpoint-rate-limits). + +2. **Computation limit** - Similar to a transaction, each script is also subjected to a computation limit. The specific value can be configured by individual Access and Execution node operators. Currently, the default compute (gas) limit for a script is 100,000. + +3. **Historic block data limit** + 1. Script execution on execution nodes is restricted to approximately the last 100 blocks. Any request for script execution on an execution node on a past block (specified by block ID or block height) will fail if that block is more than 100 blocks in the past. + 2. Script execution on an access node can go much beyond the last 100 blocks but is restricted to the height when the [last](https://developers.flow.com/networks/node-ops/node-operation/past-upgrades) network upgrade ([HCU](https://developers.flow.com/networks/node-ops/node-operation/hcu) or spork) occurred. \ No newline at end of file diff --git a/static/markdown/build/basics/smart-contracts.md b/static/markdown/build/basics/smart-contracts.md new file mode 100644 index 0000000000..b70e47760a --- /dev/null +++ b/static/markdown/build/basics/smart-contracts.md @@ -0,0 +1,23 @@ +--- +slug: /build/basics/smart-contracts +redirect: /build/smart-contracts/overview +title: Smart Contracts ↙ +description: Redirect page to comprehensive Flow smart contracts documentation and overview. +keywords: + - smart contracts + - Flow contracts + - Cadence + - contract development + - blockchain development + - Flow programming + - contract deployment + - contract overview +--- + +# Smart Contracts + +Go to [Smart Contracts](../../build/smart-contracts/overview.md) + + + +; \ No newline at end of file diff --git a/static/markdown/build/basics/transactions.md b/static/markdown/build/basics/transactions.md new file mode 100644 index 0000000000..5144c6405d --- /dev/null +++ b/static/markdown/build/basics/transactions.md @@ -0,0 +1,464 @@ +--- +sidebar_position: 3 +title: Transactions +description: Learn about Flow blockchain transactions, their structure, lifecycle, and signing process. Understand transaction roles, statuses, finality, and how to optimize transaction execution. +keywords: + - Flow transactions + - transaction speed + - transaction time + - transaction signing + - transaction roles + - transaction status + - transaction finality + - blockchain transactions + - multi-sig + - transaction fees + - sequence numbers + - proposal key + - authorizers + - transaction payload + - transaction lifecycle + - transaction submission +--- + +# Transactions + +Transactions are cryptographically signed data messages that contain a set of instructions that update the Flow state. They are a basic unit of computation that gets executed by execution nodes. In order for a transaction to be included in the Flow blockchain a fee is required from the payer. + +![Screenshot 2023-08-17 at 13.57.36.png](_transactions_images/Screenshot_2023-08-17_at_13.57.36.png) + +:::tip + +Transactions on Flow are fundamentally different from those on Ethereum. The main purpose of a transaction is not to send funds but to contain code that gets executed. This makes transactions very flexible and powerful. In addition to being able to access the authorizing accounts private assets, transactions can also read and call functions in public contracts, and access public domains in other users' accounts Transactions on Flow also feature different roles, such as defining third-party payer accounts, proposer accounts, and authorizers, which we will talk about in detail soon. + +::: + +In order for a transaction to be valid and executed it must contain signatures from accounts involved as well as some other information, let's take a look at all the required fields. + +![Screenshot 2023-08-17 at 14.52.56.png](_transactions_images/Screenshot_2023-08-17_at_14.52.56.png) + +### Script + +The script section contains instructions for transaction execution. This is a Cadence program in source code form (human-readable), and encoded as UTF-8. The transaction program must contain a `transaction` declaration. + +A transaction includes multiple optional phases `prepare`, `pre`, `execute`, and `post` phase. You can read more about it in the [Cadence reference document on transactions](https://cadence-lang.org/docs/language/transactions). Each phase has a purpose, the two most important phases are `prepare` and `execute`. + +In the `prepare` phase, we have access to `&Account` objects, which gives us the power to interact with those accounts. The accounts are called authorizers of transactions, so each account we want to interact with in the `prepare` phase must sign the transaction as an authorizer. +The `execute` phase does exactly what it says, it executes the main logic of the transaction. This phase is optional, but it is a best practice to add your main transaction logic in the section, so it is explicit. + +Again make sure to read Cadence [documentation on transactions](https://cadence-lang.org/docs/language/transactions) + +This is an example of a transaction script: + +```cadence +transaction(greeting: String) { + execute { + log(greeting.concat(", World!")) + } +} +``` + +### Arguments + +Transactions may declare parameters it needs during execution, these must be provided as input arguments when sending a transaction. You can think of them as function arguments. Currently, we provide [arguments in the JSON-Cadence Data Interchange Format](https://cadencelang.dev/docs/1.0/json-cadence-spec). Which is a human-readable JSON format. The sample script from above accepts a single `String` argument. + +### Reference Block + +A reference to a recent block used for expiry. A transaction is considered expired if it is submitted to Flow after reference block height + N, where N is a constant defined by the network. On mainnet current setting for N is 600 which amounts to approximately 10 minutes for expiry (please note this is subject to change). + +### Gas Limit + +When a transaction is executed each operation consumes a predefined amount of computational units (we define more about that in the Fees documentation). This defines the maximum amount of computation that is allowed to be done during this transaction. If a transaction completes execution using fewer computational units than the limit, it remains unaffected. However, if it hits this limit during execution, the transaction will fail, its changes will be reverted, but fees will still be applied. The maximum computational limit for Flow mainnet is currently at 9999, but this might change. The maximum network limit is defined to protect the network from transactions that would run forever. + +### Proposal Key + +Each transaction must declare a proposal key, which can be an account key from any Flow account (App, User or Wallet). The account that owns the proposal key is referred to as the *proposer*. + +Proposer is a role in a transaction that defines who is proposing the transaction, the effect of the transaction being submitted on the proposer is that it will increment the sequence number for the provided proposer key. This is done to ensure transactions are not resubmitted (replay attack) and thus sequencing actions. + +A proposal key definition declares the address, key ID, and up-to-date sequence number for the account key. A single proposer can have many transactions executed in parallel only limited by the key they use to propose the transaction. + +![Screenshot 2023-08-17 at 15.10.33.png](_transactions_images/Screenshot_2023-08-17_at_15.10.33.png) + +- Address identifies the account that will act as a proposer of this transaction. +- Key ID is an index number (starting at 0) that identifies the key on the account provided in the address. +- Sequence Number is a number on each key that increments by 1 with each transaction. This ensures that each transaction executes at most once and prevents many unwanted situations, such as [transaction replay attacks](https://en.wikipedia.org/wiki/Replay_attack). Each key in an account has a dedicated sequence number associated with it. Unlike Ethereum, there is no sequence number for the entire account. + +### Authorizers + +Authorizers are accounts that authorize a transaction to read and mutate their state. A transaction can specify zero or more authorizers, depending on how many accounts the transaction needs to access. + +The number of authorizers on the transaction must match the number of &Account parameters declared in the prepare statement of the Cadence script. + +Example transaction with multiple authorizers: + +```cadence +transaction { + prepare(authorizer1: auth(Capabilities) &Account, authorizer2: auth(Storage) &Account) { } +} +``` + +Each account defined as an authorizer must sign the transaction with its own key, +and by doing so it acknowledges the transaction it signed +will have access to that account and may modify it. +How it will modify it is understood from the list of account entitlements +that are granted in the `prepare` argument list and by reading the transaction script. +In an transaction, developers should only give the minimum set of account entitlements +that are required for the transaction to execute properly. +This ensures that users who are signing transactions can understand +what parts of their account a transaction can access. + +### Payer + +A payer is the account that pays the fees for the transaction. A transaction must specify exactly one payer. The payer is only responsible for paying the network and gas fees; the transaction is not authorized to access resources or code stored in the payer account. + +By explicitly specifying a payer a transaction can be paid by third-party services such as wallet providers. + +## Transaction Lifecycle + +Once a transaction has been submitted to the Flow network using the Access node APIs, it will begin its lifecycle and eventually reach a finality. Each submitted transaction can be identified with an ID. + +**Transaction ID** + +A transaction ID is a hash of the encoded transaction payload and can be calculated at any time. We don't submit transaction ID as part of the transaction payload as it can be derived from the data and thus would mean duplication of data. + +### Transaction Status + +The transaction status represents the state of a transaction on the Flow blockchain. Some statuses are mutable and some are immutable, they usually follow a timeline like so: + +![Screenshot 2023-08-17 at 16.08.18.png](_transactions_images/Screenshot_2023-08-17_at_16.08.18.png) + +- Unknown - The transaction has not yet been seen by the section of the network you communicate with. +- Pending - The transaction has been received by a collection node but has not yet been finalized in a block. +- Finalized - The consensus nodes have included the transaction in a block, but it has not been executed by execution nodes. +- Executed - Execution nodes have produced a result for the transaction. +- Sealed - The verification nodes have verified and agreed on the result of the transaction and the consensus node has included the seal in the latest block. +- Expired - The transaction was submitted past its expiration block height. + +:::danger + +It is **important to differentiate the transaction status and transaction result**. Transaction status will only provide you with information about the inclusion of the transaction in the blockchain, not whether the transaction was executed the way you intended. **A transaction can still fail to execute the way you intended and be sealed.** + +::: + +### Transaction Result + +Once a transaction is executed, its result will be available, providing details on its success or any errors encountered during execution. It also includes events the transaction may have emitted. + +![Screenshot 2023-08-17 at 16.29.30.png](_transactions_images/Screenshot_2023-08-17_at_16.29.30.png) + +:::danger + +From a developer perspective, a transaction is only successful if: + +- It is sealed +- It didn't encounter errors + +::: + +## Transaction Time + +Understanding how transaction times work across different blockchains is crucial for developers and users to optimize their operations and expectations. Flow's multi-node architecture allows for some of the fastest transaction times and finality times across chains. Read on for more detail on how it works and what it means for developers and users. + +### Two Key Transaction Questions + +Whenever a transaction is processed, two primary questions come to mind: + +1. **Inclusion**: Will this transaction be included in the final chain? +2. **Result**: What is the outcome of the transaction? + +Different blockchains tackle these questions in varied sequences. For instance, Bitcoin and Ethereum provide answers simultaneously. Layer 2 solutions (L2s) can sometimes address the outcome before confirming inclusion. But there's a catch: you can have an answer to those questions that might be wrong. Flow, on the other hand, prioritizes the inclusion question. + +### Transaction Finality + +Drawing a parallel to traditional finance, a vendor might instantly know if Visa approves a transaction, but the possibility of chargebacks lingers for weeks. This uncertainty introduces the concept of "finality" in blockchain transactions. + +In the dominant Proof-of-Stake (PoS) environment, which includes most chains except for Bitcoin, there are three key finality stages: + +- **Preliminary result**: It's an initial answer to the aforementioned questions. The preliminary result doesn't ensure correctness, and there are no economic penalties (like "slashing") if the informant provides false information. +- **Soft economic finality**: This stage provides an answer backed by cryptographic proof. If the informant is deceptive, they face economic repercussions or "slashing." +- **Hard economic finality**: The provided answer either holds true, or the entire blockchain requires a restart. The latter case sees at least one-third of the nodes facing economic penalties. + +![finality.png](./_transactions_images/finality.png) + +### Chain Comparisons + +Chain | Preliminary | Soft finality | Hard finality +---------|-------------|---------------|--------------- +Solana | 100ms | n/a | ~30s +Ethereum | 15s | n/a | ~15m +Flow | bypass | 4s | ~10s + +#### Flow + +Flow bypasses preliminary results entirely. It reaches soft finality ("Executed") in about 4 seconds and hard finality ("Sealed") in around 10 seconds. If an Access Node on Flow states a transaction has occurred, it's either correct or cryptographic proof exists that can lead to the node's slashing. + +![transaction-time.png](_transactions_images/chain-comparison.png) + +## Signing a Transaction + +Due to the existence of **weighted keys** and **split signing roles**, Flow transactions sometimes need to be signed multiple times by one or more parties. That is, multiple unique signatures may be needed to authorize a single transaction. + +A transaction can contain two types of signatures: **payload signatures** and **envelope signatures**. + +![Screenshot 2023-08-17 at 14.52.51.png](_transactions_images/Screenshot_2023-08-17_at_14.52.51.png) + +### Signer Roles +- **Proposer**: the account that specifies a proposal key. +- **Payer**: the account paying for the transaction fees. +- **Authorizers**: zero or more accounts authorizing the transaction to mutate their state. + +### Payload + +The transaction payload is the innermost portion of a transaction and contains the data that uniquely identifies the operations applied by the transaction as we have defined them above. In Flow, two transactions with the same payload will never be executed more than once. + +:::warning + +⚠️ The transaction proposer and authorizer are only required to sign the transaction payload. These signatures are the payload signatures. + +::: + +### Authorization Envelope + +The transaction authorization envelope contains both the transaction payload and the payload signatures. + +The transaction payer is required to sign the authorization envelope. These signatures are **envelope signatures**. + +:::danger + +Special case: if an account is both the payer and either a proposer or authorizer, it is required only to sign the envelope. + +::: + +### Payment Envelope + +The outermost portion of the transaction, which contains the payload and envelope signatures, is referred to as the payment envelope. + +:::danger + +Special case: if an account is both the payer and either a proposer or authorizer, it is required only to sign the envelope. + +::: + +### Payer Signs Last + +The payer must sign the portion of the transaction that contains the payload signatures, which means that the payer must always sign last. This ensures the payer that they are signing a valid transaction with all of the required payload signatures. + +:::danger + +Special case: if an account is both the payer and either a proposer or authorizer, it is required only to sign the envelope. + +::: + +### Signature Structure + +A transaction signature is a composite structure containing three fields: + +- Address +- Key ID +- Signature Data + +The *address* and *key ID* fields declare the account key that generated the signature, which is required in order to verify the signature against the correct public key. + +### Sequence Numbers + +Flow uses sequence numbers to ensure that each transaction executes at most once. This prevents many unwanted situations such as [transaction replay attacks](https://en.wikipedia.org/wiki/Replay_attack). + +Sequence numbers work similarly to transaction nonces in Ethereum, but with several key differences: + +- **Each key in an account has a dedicated sequence number** associated with it. Unlike Ethereum, there is no sequence number for the entire account. +- When creating a transaction, only the **proposer must specify a sequence number**. Payers and authorizers are not required to. + +:::tip + +The transaction proposer is only required to specify a sequence number for a single account key, even if it signs with multiple keys. This key is referred to as the proposal key. + +::: + +Each time an account key is used as a proposal key, its sequence number is incremented by 1. The sequence number is updated after execution, even if the transaction fails (reverts) during execution. + +A transaction is failed if its proposal key does not specify a sequence number equal to the sequence number stored on the account *at execution time.* + +## Common Signing Scenarios + +Below are several scenarios in which different signature combinations are required to authorize a transaction. + +### Single party, single signature + +The simplest Flow transaction declares a single account as the proposer, payer and authorizer. In this case, the account can sign the transaction with a single signature. + +This scenario is only possible if the signature is generated by a key with full signing weight. + +| Account | Key ID | Weight | +| ------- | ------ | ------ | +| 0x01 | 1 | 1000 | + +```json +{ + "payload": { + "proposalKey": { + "address": "0x01", + "keyId": 1, + "sequenceNumber": 42 + }, + "payer": "0x01", + "authorizers": [ "0x01" ] + }, + "payloadSignatures": [], // 0x01 is the payer, so only needs to sign envelope + "envelopeSignatures": [ + { + "address": "0x01", + "keyId": 1, + "sig": "0xabc123" + } + ] +} +``` + +### Single party, multiple signatures + +A transaction that declares a single account as the proposer, payer and authorizer may still specify multiple signatures if the account uses weighted keys to achieve multi-sig functionality. + +| Account | Key ID | Weight | +| ------- | ------ | ------ | +| 0x01 | 1 | 500 | +| 0x01 | 2 | 500 | + +```json +{ + "payload": { + "proposalKey": { + "address": "0x01", + "keyId": 1, + "sequenceNumber": 42 + }, + "payer": "0x01", + "authorizers": [ "0x01" ] + }, + "payloadSignatures": [], // 0x01 is the payer, so only needs to sign envelope + "envelopeSignatures": [ + { + "address": "0x01", + "keyId": 1, + "sig": "0xabc123" + }, + { + "address": "0x01", + "keyId": 2, + "sig": "0xdef456" + } + ] +} +``` + +### Multiple parties + +A transaction that declares different accounts for each signing role will require at least one signature from each account. + +| Account | Key ID | Weight | +| --- | --- | --- | +| 0x01 | 1 | 1000 | +| 0x02 | 1 | 1000 | + +```json +{ + "payload": { + "proposalKey": { + "address": "0x01", + "keyId": 1, + "sequenceNumber": 42 + }, + "payer": "0x02", + "authorizers": [ "0x01" ] + }, + "payloadSignatures": [ + { + "address": "0x01", // 0x01 is not payer, so only signs payload + "keyId": 1, + "sig": "0xabc123" + } + ], + "envelopeSignatures": [ + { + "address": "0x02", + "keyId": 1, + "sig": "0xdef456" + }, + ] +} +``` + +### Multiple parties, multiple signatures + +A transaction that declares different accounts for each signing role may require more than one signature per account if those accounts use weighted keys to achieve multi-sig functionality. + +| Account | Key ID | Weight | +| --- | --- | --- | +| 0x01 | 1 | 500 | +| 0x01 | 2 | 500 | +| 0x02 | 1 | 500 | +| 0x02 | 2 | 500 | + +```json +{ + "payload": { + "proposalKey": { + "address": "0x01", + "keyId": 1, + "sequenceNumber": 42 + }, + "payer": "0x02", + "authorizers": [ "0x01" ] + }, + "payloadSignatures": [ + { + "address": "0x01", // 0x01 is not payer, so only signs payload + "keyId": 1, + "sig": "0xabc123" + }, + { + "address": "0x01", // 0x01 is not payer, so only signs payload + "keyId": 2, + "sig": "0x123abc" + } + ], + "envelopeSignatures": [ + { + "address": "0x02", + "keyId": 1, + "sig": "0xdef456" + }, + { + "address": "0x02", + "keyId": 2, + "sig": "0x456def" + }, + ] +} +``` + +## Transaction Submission and Retrieval + +You can use the Flow CLI to get an existing transaction by ID: + +```sh +flow transactions get 1ec90051e3bc74fc36cbd16fc83df08e463dda8f92e8e2193e061f9d41b2ad92 -n mainnet +``` + +Find [more about the command in the CLI docs](../../tools/flow-cli/get-flow-data/get-blocks.md). + +A user can define their own transactions or it can use already defined transactions by the contract authors that can be found by using the FLIX service. + +Transactions can be submitted and obtained from the access node APIs, currently, there are two gRPC and REST APIs. You can find more information about them here: + +[**gRPC Transaction API**](../../networks/access-onchain-data/index.md#transactions) + +[**REST Transaction API**](/http-api#tag/Transactions) + +There are multiple SDKs implementing the above APIs for different languages: + +[**Javascript SDK**](../../tools/clients/fcl-js/index.md) + +[**Go SDK**](../../tools/clients/flow-go-sdk/index.md) + +Find a list of all SDKs [here](../../tools/clients/index.md) \ No newline at end of file diff --git a/static/markdown/build/core-contracts/02-fungible-token.md b/static/markdown/build/core-contracts/02-fungible-token.md new file mode 100644 index 0000000000..68ec01f36d --- /dev/null +++ b/static/markdown/build/core-contracts/02-fungible-token.md @@ -0,0 +1,163 @@ +--- +title: Fungible Token Contract +sidebar_position: 2 +sidebar_label: Fungible Token +description: Learn about Flow's Fungible Token standard contract, its implementation, events, and how to interact with fungible tokens on the Flow blockchain. +keywords: + - fungible token + - FT standard + - token contract + - Flow tokens + - token events + - token transactions + - token metadata + - token standard + - Flow FT + - token implementation + - token interface + - token deployment + - token addresses + - token events + - token specification +--- + +The `FungibleToken` contract implements the Fungible Token Standard. It is the second contract ever deployed on Flow. + +- [Basic Fungible Token Tutorial](https://cadence-lang.org/docs/tutorial/fungible-tokens) +- [Fungible Token Guide](../guides/fungible-token.md) +- [Fungible Token Standard Repo](https://github.com/onflow/flow-ft) + +The `FungibleTokenMetadataViews` and `FungibleTokenSwitchboard` contracts +are also deployed to the same account as `FungibleToken`. + +Source: [FungibleToken.cdc](https://github.com/onflow/flow-ft/blob/master/contracts/FungibleToken.cdc) + +| Network | Contract Address | +| ------------------------- | -------------------- | +| Emulator | `0xee82856bf20e2aa6` | +| Cadence Testing Framework | `0x0000000000000002` | +| Testnet | `0x9a0766d93b6608b7` | +| Mainnet | `0xf233dcee88fe0abe` | + +# Transactions + +All `FungibleToken` projects are encouraged to use +the generic token transactions and scripts in the `flow-ft` [repo](https://github.com/onflow/flow-ft/tree/master/transactions). +They can be used for any token that implements the fungible token standard properly +without changing any code besides import addresses on different networks. + +# Events + +Events emitted from all contracts follow a standard format: + +``` +A.{contract address}.{contract name}.{event name} +``` + +The components of the format are: + +- `contract address` - the address of the account the contract has been deployed to +- `contract name` - the name of the contract in the source code +- `event name` - the name of the event as declared in the source code + +## FungibleToken Events + +Contracts that implement the Fungible Token standard get access +to standard events that are emitted every time a relevant action occurs, +like depositing and withdrawing tokens. + +This means that projects do not have to implement their own custom events +unless the standard events do not satisfy requirements they have for events. + +The `FungibleToken` events will have the following format: + +``` +A.{contract address}.FungibleToken.Deposited +A.{contract address}.FungibleToken.Withdrawn +``` + +Where the `contract address` is the `FungibleToken` address on the network being queried. +The addresses on the various networks are shown above. + +### FungibleToken.Deposited + +```cadence +access(all) event Deposited ( + type: String, + amount: UFix64, + to: Address?, + toUUID: UInt64, + depositedUUID: UInt64, + balanceAfter: UFix64 +) +``` + +Whenever `deposit()` is called on a resource type that implements +`FungibleToken.Vault`, the `FungibleToken.Deposited` event is emitted +with the following arguments: + +- `type: String`: The type identifier of the token being deposited. + - Example: `A.4445e7ad11568276.FlowToken.Vault` +- `amount: UFix64`: The amount of tokens that were deposited. + - Example: `0.00017485` +- `to: Address?`: The address of the account that owns the Vault that received + the tokens. If the vault is not stored in an account, `to` will be `nil`. + - Example: `0x4445e7ad11568276` +- `toUUID: UInt64`: The UUID of the Vault that received the tokens. + - Example: `177021372071991` +- `depositedUUID`: The UUID of the Vault that was deposited (and therefore destroyed). + - Example: `177021372071991` +- `balanceAfter: UFix64`: The balance of the Vault that received the tokens after the deposit happened. + - Example: `1.00047545` + +### FungibleToken.Withdrawn + +```cadence +access(all) event Withdrawn ( + type: String, + amount: UFix64, + from: Address?, + fromUUID: UInt64, + withdrawnUUID: UInt64, + balanceAfter: UFix64 +) +``` + +Whenever `withdraw()` is called on a resource type that implements +`FungibleToken.Vault`, the `FungibleToken.Withdrawn` event is emitted +with the following arguments: + +- `type: String`: The type identifier of the token being withdrawn. + - Example: `A.4445e7ad11568276.FlowToken.Vault` +- `amount: UFix64`: The amount of tokens that were withdrawn. + - Example: `0.00017485` +- `from: Address?`: The address of the account that owns the Vault that the tokens + were withdrawn from. If the vault is not stored in an account, `to` will be `nil`. + - Example: `0x4445e7ad11568276` +- `fromUUID: UInt64`: The UUID of the Vault that the tokens were withdrawn from. + - Example: `177021372071991` +- `withdrawnUUID`: The UUID of the Vault that was withdrawn. + - Example: `177021372071991` +- `balanceAfter: UFix64`: The balance of the Vault that the tokens + were withdrawn from after the withdrawal. + - Example: `1.00047545` + +### FungibleToken.Burned + +```cadence +access(all) event Burned ( + type: String, + amount: UFix64, + fromUUID: UInt64 +) +``` + +Whenever a fungible token that implements `FungibleToken.Vault` is burned +via the `Burner.burn()` method, this event is emitted with the following arguments: + +- `type: String`: The type identifier of the token that was burnt. + - Example: `A.4445e7ad11568276.FlowToken.Vault` +- `amount: UFix64`: The amount of tokens that were burnt. + - Example: `0.00017485` +- `fromUUID: UInt64`: The UUID of the Vault that was burnt. + - Example: `177021372071991` \ No newline at end of file diff --git a/static/markdown/build/core-contracts/03-flow-token.md b/static/markdown/build/core-contracts/03-flow-token.md new file mode 100644 index 0000000000..4daa1290ae --- /dev/null +++ b/static/markdown/build/core-contracts/03-flow-token.md @@ -0,0 +1,179 @@ +--- +title: Flow Token Contract +sidebar_position: 3 +sidebar_label: Flow Token +description: Learn about the FLOW token smart contract, its implementation, events system, and deployment addresses across different networks. Understand how to interact with the native token of the Flow blockchain. +keywords: + - FLOW token + - Flow contract + - token events + - token transactions + - token minting + - token burning + - core contracts + - native token + - Flow protocol + - token implementation + - token deployment + - contract addresses + - token initialization + - Flow mainnet + - Flow testnet +--- + +The `FlowToken` contract defines the FLOW network token. + +Source: [FlowToken.cdc](https://github.com/onflow/flow-core-contracts/blob/master/contracts/FlowToken.cdc) + +| Network | Contract Address | +| ------------------------- | -------------------- | +| Emulator | `0x0ae53cb6e3f42a79` | +| Cadence Testing Framework | `0x0000000000000003` | +| Testnet | `0x7e60df042a9c0868` | +| Mainnet | `0x1654653399040a61` | + +# Transactions + +Transactions and scripts for `FlowToken` are in the `flow-core-contracts` [repo](https://github.com/onflow/flow-core-contracts/tree/master/transactions/flowToken). + +As mentioned in the `FungibleToken` page, developers are encouraged to use +the generic token transactions in the `flow-ft` [repo](https://github.com/onflow/flow-ft/tree/master/transactions) instead. + +# Events + +Flow relies on a set of core contracts that define key portions of the Flow protocol. Those contracts are core contracts +and are made to emit the events documented below. You can read about the [core contracts here](./index.md) +and view their source code and event definitions. + +Events emitted from core contracts follow a standard format: + +``` +A.{contract address}.{contract name}.{event name} +``` + +The components of the format are: + +- `contract address` - the address of the account the contract has been deployed to +- `contract name` - the name of the contract in the source code +- `event name` - the name of the event as declared in the source code + +### Flow Token Contract + +Description of events emitted from the [FLOW Token contract](./03-flow-token.md). +The contract defines the fungible FLOW token. Please note that events for the fungible token contracts are the same +if deployed to a different account but the `contract address` is +changed to the address of the account the contract has been deployed to. + +### Tokens Initialized + +Event that is emitted when the contract gets created. + +- Event name: `TokensInitialized` +- Mainnet event: `A.1654653399040a61.FlowToken.TokensInitialized` +- Testnet event: `A.7e60df042a9c0868.FlowToken.TokensInitialized` + +```cadence +access(all) event TokensInitialized(initialSupply: UFix64) +``` + +| Field | Type | Description | +| ------------- | ------ | -------------------------------- | +| initialSupply | UFix64 | The initial supply of the tokens | + +### Tokens Withdrawn + +Event that is emitted when tokens get withdrawn from a Vault. + +- Event name: `TokensWithdrawn` +- Mainnet event: `A.1654653399040a61.FlowToken.TokensWithdrawn` +- Testnet event: `A.7e60df042a9c0868.FlowToken.TokensWithdrawn` + +```cadence +access(all) event TokensWithdrawn(amount: UFix64, from: Address?) +``` + +| Field | Type | Description | +| ------ | -------- | --------------------------------------------------------------------------------------------------------------------------------------- | +| amount | UFix64 | The amount of tokens withdrawn | +| from | Address? | Optional address of the account that owns the vault where tokens were withdrawn from. `nil` if the vault is not in an account's storage | + +### Tokens Deposited + +Event that is emitted when tokens get deposited to a Vault. + +- Event name: `TokensDeposited` +- Mainnet event: `A.1654653399040a61.FlowToken.TokensDeposited` +- Testnet event: `A.7e60df042a9c0868.FlowToken.TokensDeposited` + +```cadence +access(all) event TokensDeposited(amount: UFix64, to: Address?) +``` + +| Field | Type | Description | +| ------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------- | +| amount | UFix64 | The amount of tokens withdrawn | +| to | Address? | Optional address of the account that owns the vault where tokens were deposited to. `nil` if the vault is not in an account's storage | + +### Tokens Minted + +Event that is emitted when new tokens gets minted. + +- Event name: `TokensMinted` +- Mainnet event: `A.1654653399040a61.FlowToken.TokensMinted` +- Testnet event: `A.7e60df042a9c0868.FlowToken.TokensMinted` + +```cadence +access(all) event TokensMinted(amount: UFix64) +``` + +| Field | Type | Description | +| ------ | ------ | ---------------------------- | +| amount | UFix64 | The amount of tokens to mint | + +### Tokens Burned + +Event that is emitted when tokens get destroyed. + +- Event name: `TokensBurned` +- Mainnet event: `A.1654653399040a61.FlowToken.TokensBurned` +- Testnet event: `A.7e60df042a9c0868.FlowToken.TokensBurned` + +```cadence +access(all) event TokensBurned(amount: UFix64) +``` + +| Field | Type | Description | +| ------ | ------ | ---------------------------- | +| amount | UFix64 | The amount of tokens to burn | + +### Minter Created + +Event that is emitted when a new minter resource gets created. + +- Event name: `MinterCreated` +- Mainnet event: `A.1654653399040a61.FlowToken.MinterCreated` +- Testnet event: `A.7e60df042a9c0868.FlowToken.MinterCreated` + +```cadence +access(all) event MinterCreated(allowedAmount: UFix64) +``` + +| Field | Type | Description | +| ------------- | ------ | ------------------------------------------------------- | +| allowedAmount | UFix64 | The amount of tokens that the minter is allowed to mint | + +### Burner Created + +Event that is emitted when a new burner Resource gets created. + +- Event name: `BurnerCreated` +- Mainnet event: `A.1654653399040a61.FlowToken.BurnerCreated` +- Testnet event: `A.7e60df042a9c0868.FlowToken.BurnerCreated` + +```cadence +access(all) event BurnerCreated() +``` + +### Staking Events + +To learn more about staking events, read [staking/events/](../../networks/staking/07-staking-scripts-events.md) \ No newline at end of file diff --git a/static/markdown/build/core-contracts/04-service-account.md b/static/markdown/build/core-contracts/04-service-account.md new file mode 100644 index 0000000000..dbc6c9d45c --- /dev/null +++ b/static/markdown/build/core-contracts/04-service-account.md @@ -0,0 +1,104 @@ +--- +title: Service Account Contracts +sidebar_position: 4 +sidebar_label: Service Account +description: Learn about Flow's service account contracts that manage core protocol requirements, including transaction fees, deployment permissions, random beacon history, and node versioning. +keywords: + - service account + - core contracts + - FlowServiceAccount + - transaction fees + - deployment permissions + - RandomBeaconHistory + - NodeVersionBeacon + - protocol versions + - Flow protocol + - core protocol + - contract addresses + - protocol management + - Flow governance + - network configuration +--- + +The service account is the account that manages the core protocol requirements of Flow. + +| Network | Contract Address | +| ------------------------- | -------------------- | +| Emulator | `0xf8d6e0586b0a20c7` | +| Cadence Testing Framework | `0x0000000000000001` | +| Testnet | `0x8c5303eaa26202d6` | +| Mainnet | `0xe467b9dd11fa00df` | + +Here are three important contracts deployed to the service account: + +# FlowServiceAccount + +`FlowServiceAccount` tracks transaction fees, deployment permissions, and provides +some convenience methods for Flow Token operations. + +Source: [FlowServiceAccount.cdc](https://github.com/onflow/flow-core-contracts/blob/master/contracts/FlowServiceAccount.cdc) + +## Events + +Important events from `FlowServiceAccount` are: + +```cadence +access(all) event TransactionFeeUpdated(newFee: UFix64) +access(all) event AccountCreationFeeUpdated(newFee: UFix64) +``` + +# RandomBeaconHistory + +- `RandomBeaconHistory` stores the history of random sources generated by + the Flow network. The defined Heartbeat resource is + updated by the Flow Service Account at the end of every block + with that block's source of randomness. + +Source: [RandomBeaconHistory.cdc](https://github.com/onflow/flow-core-contracts/blob/master/contracts/RandomBeaconHistory.cdc) + +## Events + +Important events from `RandomBeaconHistory` are: + +```cadence +// Event emitted when missing SoRs from past heartbeats are detected and will be backfilled: +// - `blockHeight` is the height where the gap is detected +// - `gapStartHeight` is the height of the first missing entry detected +access(all) event RandomHistoryMissing(blockHeight: UInt64, gapStartHeight: UInt64) + +// Event emitted when missing SoRs are backfilled on the current heartbeat: +// - `blockHeight` is the height where the backfill happened, it also defines the SoR used to backfill +// - `gapStartHeight` is the height of the first backfilled entry +// - `count` is the number of backfilled entries +// Note that in very rare cases, the backfilled gap may not be contiguous. This event does not +// fully define the backfilled entries in this case. +access(all) event RandomHistoryBackfilled(blockHeight: UInt64, gapStartHeight: UInt64, count: UInt64) +``` + +# NodeVersionBeacon + +- `NodeVersionBeacon` holds the past + and future protocol versions that should be used + to execute/handle blocks at a given block height. + +Source: [NodeVersionBeacon.cdc](https://github.com/onflow/flow-core-contracts/blob/master/contracts/NodeVersionBeacon.cdc) + +## Events + +Important events from `NodeVersionBeacon` are: + +```cadence +/// Event emitted when the version table is updated. +/// It contains the current version and all the upcoming versions +/// sorted by block height. +/// The sequence increases by one each time an event is emitted. +/// It can be used to verify no events were missed. +access(all) event VersionBeacon( + versionBoundaries: [VersionBoundary], + sequence: UInt64 +) + +/// Event emitted any time the version boundary freeze period is updated. +/// freeze period is measured in blocks (from the current block). +access(all) event NodeVersionBoundaryFreezePeriodChanged(freezePeriod: UInt64) +``` \ No newline at end of file diff --git a/static/markdown/build/core-contracts/05-flow-fees.md b/static/markdown/build/core-contracts/05-flow-fees.md new file mode 100644 index 0000000000..b8cb40073f --- /dev/null +++ b/static/markdown/build/core-contracts/05-flow-fees.md @@ -0,0 +1,78 @@ +--- +title: Flow Fees Contract +sidebar_position: 5 +sidebar_label: Flow Fees +description: Learn about Flow's fees contracts that handle transaction and storage fees, including fee collection, parameters, and storage capacity management. Understand how fees are processed and managed on the Flow blockchain. +keywords: + - Flow fees + - transaction fees + - storage fees + - fee collection + - fee parameters + - FlowFees + - FlowStorageFees + - fee events + - surge factor + - execution fees + - storage capacity + - fee management + - Flow protocol + - core contracts + - blockchain fees +--- + +## FlowFees + +The `FlowFees` contract is where all the collected flow fees are gathered. + +Source: [FlowFees.cdc](https://github.com/onflow/flow-core-contracts/blob/master/contracts/FlowFees.cdc) + +| Network | Contract Address | +| ------------------------- | -------------------- | +| Emulator | `0xe5a8b7f23e8b548f` | +| Cadence Testing Framework | `0x0000000000000004` | +| Testnet | `0x912d5440f7e3769e` | +| Mainnet | `0xf919ee77447b7497` | + +### Events + +Important events for `FlowFees` are: + +```cadence +// Event that is emitted when tokens are deposited to the fee vault +access(all) event TokensDeposited(amount: UFix64) + +// Event that is emitted when tokens are withdrawn from the fee vault +access(all) event TokensWithdrawn(amount: UFix64) + +// Event that is emitted when fees are deducted +access(all) event FeesDeducted(amount: UFix64, inclusionEffort: UFix64, executionEffort: UFix64) + +// Event that is emitted when fee parameters change +access(all) event FeeParametersChanged(surgeFactor: UFix64, inclusionEffortCost: UFix64, executionEffortCost: UFix64) +``` + +## FlowStorageFees + +The `FlowStorageFees` contract defines the parameters and utility methods for storage fees. + +Source: [FlowStorageFees.cdc](https://github.com/onflow/flow-core-contracts/blob/master/contracts/FlowStorageFees.cdc) + +| Network | Contract Address | +| ------------------------- | -------------------- | +| Emulator | `0xf8d6e0586b0a20c7` | +| Cadence Testing Framework | `0x0000000000000001` | +| Testnet | `0x8c5303eaa26202d6` | +| Mainnet | `0xe467b9dd11fa00df` | + +### Events + +Important events for `FlowStorageFees` are: + +```cadence +// Emitted when the amount of storage capacity an account has per reserved Flow token changes +access(all) event StorageMegaBytesPerReservedFLOWChanged(_ storageMegaBytesPerReservedFLOW: UFix64) + +// Emitted when the minimum amount of Flow tokens that an account needs to have reserved for storage capacity changes. +access(all) event MinimumStorageReservationChanged(_ minimumStorageReservation: UFix64) +``` \ No newline at end of file diff --git a/static/markdown/build/core-contracts/06-staking-contract-reference.md b/static/markdown/build/core-contracts/06-staking-contract-reference.md new file mode 100644 index 0000000000..76a0ddbb6d --- /dev/null +++ b/static/markdown/build/core-contracts/06-staking-contract-reference.md @@ -0,0 +1,116 @@ +--- +title: Flow Staking Contract Reference +sidebar_position: 6 +sidebar_label: Staking Table +description: Learn about Flow's staking contract (FlowIDTableStaking) that manages staked nodes, delegation, and rewards. Understand how to interact with staking functionality through transactions and scripts. +keywords: + - staking contract + - Flow staking + - node staking + - delegation + - staking rewards + - FlowIDTableStaking + - staking scripts + - staking events + - node management + - token delegation + - staking table + - epoch events + - staking transactions + - Flow protocol + - staking requirements +--- + +## Contract + +The `FlowIDTableStaking` contract is the central table that manages staked nodes, delegation and rewards. + +Source: [FlowIDTableStaking.cdc](https://github.com/onflow/flow-core-contracts/blob/master/contracts/FlowIDTableStaking.cdc) + +| Network | Contract Address | +| ------------------------- | -------------------- | +| Emulator | `0xf8d6e0586b0a20c7` | +| Cadence Testing Framework | `0x0000000000000001` | +| Testnet | `0x9eca2b38b18b5dfe` | +| Mainnet | `0x8624b52f9ddcd04a` | + +## Transactions and Scripts + +Transactions for the staking contract are in the `flow-core-contracts` repo. +Developers and users are advised to use [the staking collection transactions](../../networks/staking/14-staking-collection.md) +to stake tokens instead of the basic transactions that are used for tests. + +### Getting Staking Info with Scripts + +These scripts are read-only and get info about the current state of the staking contract. + +| ID | Name | Source | +| ----------- | ------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **`SC.01`** | Get Delegation Cut Percentage | [idTableStaking/get_cut_percentage.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/idTableStaking/scripts/get_cut_percentage.cdc) | +| **`SC.02`** | Get Minimum Stake Requirements | [idTableStaking/get_stake_requirements.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/idTableStaking/scripts/get_stake_requirements.cdc) | +| **`SC.03`** | Get Total Weekly Reward Payout | [idTableStaking/get_weekly_payout.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/idTableStaking/scripts/get_weekly_payout.cdc) | +| **`SC.04`** | Get Current Staked Node Table | [idTableStaking/get_current_table.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/idTableStaking/scripts/get_current_table.cdc) | +| **`SC.05`** | Get Proposed Staked Node Table | [idTableStaking/get_proposed_table.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/idTableStaking/scripts/get_proposed_table.cdc) | +| **`SC.06`** | Get Total Flow Staked | [idTableStaking/get_total_staked.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/idTableStaking/scripts/get_total_staked.cdc) | +| **`SC.07`** | Get Total Flow Staked by Node Type | [idTableStaking/get_total_staked_by_type.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/idTableStaking/scripts/get_total_staked_by_type.cdc) | +| **`SC.08`** | Get All Info about a single NodeID | [idTableStaking/get_node_info.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/idTableStaking/scripts/get_node_info.cdc) | +| **`SC.09`** | Get a node's total Commitment (delegators) | [idTableStaking/get_node_total_commitment.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/idTableStaking/scripts/get_node_total_commitment.cdc) | +| **`SC.10`** | Get All Info about a single Delegator | [idTableStaking/delegation/get_delegator_info.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/idTableStaking/delegation/get_delegator_info.cdc) | +| **`SC.11`** | Get a node's total Commitment | [idTableStaking/get_node_total_commitment_without_delegators.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/idTableStaking/scripts/get_node_total_commitment_without_delegators.cdc) | + +### Delegator Transactions + +Documentation for delegating with tokens is described in the staking documentation +for [the staking collection](../../networks/staking/14-staking-collection.md) + +## Events + +The `FlowIDTableStaking` contract emits an event whenever an important action occurs. +See the [staking events Documentation](../../networks/staking/07-staking-scripts-events.md) for more information about each event. + +```cadence + /// Epoch + access(all) event NewEpoch( + totalStaked: UFix64, + totalRewardPayout: UFix64, + newEpochCounter: UInt64 + ) + access(all) event EpochTotalRewardsPaid( + total: UFix64, + fromFees: UFix64, + minted: UFix64, + feesBurned: UFix64, + epochCounterForRewards: UInt64 + ) + + /// Node + access(all) event NewNodeCreated(nodeID: String, role: UInt8, amountCommitted: UFix64) + access(all) event TokensCommitted(nodeID: String, amount: UFix64) + access(all) event TokensStaked(nodeID: String, amount: UFix64) + access(all) event NodeTokensRequestedToUnstake(nodeID: String, amount: UFix64) + access(all) event TokensUnstaking(nodeID: String, amount: UFix64) + access(all) event TokensUnstaked(nodeID: String, amount: UFix64) + access(all) event NodeRemovedAndRefunded(nodeID: String, amount: UFix64) + access(all) event RewardsPaid(nodeID: String, amount: UFix64, epochCounter: UInt64) + access(all) event UnstakedTokensWithdrawn(nodeID: String, amount: UFix64) + access(all) event RewardTokensWithdrawn(nodeID: String, amount: UFix64) + access(all) event NetworkingAddressUpdated(nodeID: String, newAddress: String) + access(all) event NodeWeightChanged(nodeID: String, newWeight: UInt64) + + /// Delegator + access(all) event NewDelegatorCreated(nodeID: String, delegatorID: UInt32) + access(all) event DelegatorTokensCommitted(nodeID: String, delegatorID: UInt32, amount: UFix64) + access(all) event DelegatorTokensStaked(nodeID: String, delegatorID: UInt32, amount: UFix64) + access(all) event DelegatorTokensRequestedToUnstake(nodeID: String, delegatorID: UInt32, amount: UFix64) + access(all) event DelegatorTokensUnstaking(nodeID: String, delegatorID: UInt32, amount: UFix64) + access(all) event DelegatorTokensUnstaked(nodeID: String, delegatorID: UInt32, amount: UFix64) + access(all) event DelegatorRewardsPaid(nodeID: String, delegatorID: UInt32, amount: UFix64, epochCounter: UInt64) + access(all) event DelegatorUnstakedTokensWithdrawn(nodeID: String, delegatorID: UInt32, amount: UFix64) + access(all) event DelegatorRewardTokensWithdrawn(nodeID: String, delegatorID: UInt32, amount: UFix64) + + /// Contract Fields + access(all) event NewDelegatorCutPercentage(newCutPercentage: UFix64) + access(all) event NewWeeklyPayout(newPayout: UFix64) + access(all) event NewStakingMinimums(newMinimums: {UInt8: UFix64}) + access(all) event NewDelegatorStakingMinimum(newMinimum: UFix64) +``` \ No newline at end of file diff --git a/static/markdown/build/core-contracts/07-epoch-contract-reference.md b/static/markdown/build/core-contracts/07-epoch-contract-reference.md new file mode 100644 index 0000000000..a8254d721d --- /dev/null +++ b/static/markdown/build/core-contracts/07-epoch-contract-reference.md @@ -0,0 +1,84 @@ +--- +title: Flow Epoch Contracts Reference +sidebar_position: 7 +sidebar_label: Epoch Contracts +description: Learn about Flow's epoch-related contracts that manage network phases, quorum certificates, and distributed key generation. Understand how FlowEpoch, FlowClusterQC, and FlowDKG contracts work together. +keywords: + - epoch contracts + - FlowEpoch + - FlowClusterQC + - FlowDKG + - epoch phases + - quorum certificates + - distributed key generation + - epoch metadata + - epoch counter + - epoch scripts + - QC voting + - DKG participants + - network phases + - Flow protocol + - epoch management +--- + +# Contract + +The `FlowEpoch` contract is the state machine that manages Epoch phases and emits service events. +The `FlowClusterQC` and `FlowDKG` contracts manage the processes that happen during the Epoch Setup phase. + +These contracts are all deployed to the same account as the `FlowIDTableStaking` contract. + +Sources: + +- [FlowEpoch.cdc](https://github.com/onflow/flow-core-contracts/blob/master/contracts/epochs/FlowEpoch.cdc) +- [FlowClusterQC.cdc](https://github.com/onflow/flow-core-contracts/blob/master/contracts/epochs/FlowClusterQC.cdc) +- [FlowDKG.cdc](https://github.com/onflow/flow-core-contracts/blob/master/contracts/epochs/FlowDKG.cdc) + +| Network | Contract Address | +| ------------------------- | -------------------- | +| Emulator | `0xf8d6e0586b0a20c7` | +| Cadence Testing Framework | `0x0000000000000001` | +| Testnet | `0x9eca2b38b18b5dfe` | +| Mainnet | `0x8624b52f9ddcd04a` | + +# Transactions + +## Getting Epoch Info + +These scripts are read-only and get info about the current state of the epoch contract. + +| ID | Name | Source | +| ----------- | ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- | +| **`EP.01`** | Get Epoch Metadata | [epoch/get_epoch_metadata.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/epoch/scripts/get_epoch_metadata.cdc) | +| **`EP.02`** | Get Configurable Metadata | [epoch/get_config_metadata.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/epoch/scripts/get_config_metadata.cdc) | +| **`EP.03`** | Get Epoch Counter | [epoch/get_epoch_counter.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/epoch/scripts/get_epoch_counter.cdc) | +| **`EP.04`** | Get Epoch Phase | [epoch/get_epoch_phase.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/epoch/scripts/get_epoch_phase.cdc) | + +## Quorum Certificate Transactions and Scripts + +| ID | Name | Source | +| ----------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **`QC.01`** | Create QC Voter | [quorumCertificate/get_epoch_metadata.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/quorumCertificate/create_voter.cdc) | +| **`QC.02`** | Submit QC Vote | [quorumCertificate/get_config_metadata.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/quorumCertificate/submit_vote.cdc) | +| **`QC.03`** | Get Collector Cluster | [quorumCertificate/scripts/get_cluster.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/quorumCertificate/scripts/get_cluster.cdc) | +| **`QC.04`** | Get QC Enabled | [quorumCertificate/scripts/get_qc_enabled.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/quorumCertificate/scripts/get_qc_enabled.cdc) | +| **`QC.05`** | Get Node Has Voted | [quorumCertificate/scripts/get_node_has_voted.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/quorumCertificate/scripts/get_node_has_voted.cdc) | +| **`QC.06`** | Get QC Voting Complete | [quorumCertificate/scripts/get_voting_completed.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/quorumCertificate/scripts/get_voting_completed.cdc) | + +## DKG Transactions and Scripts + +| ID | Name | Source | +| ------------ | ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **`DKG.01`** | Create DKG Participant | [dkg/create_participant.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/dkg/create_participant.cdc) | +| **`DKG.02`** | Get Configurable Metadata | [dkg/send_whiteboard_message.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/dkg/send_whiteboard_message.cdc) | +| **`DKG.03`** | Send Final Submission | [dkg/send_final_submission.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/dkg/send_final_submission.cdc) | +| **`DKG.04`** | Get DKG Enabled | [dkg/scripts/get_dkg_enabled.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/dkg/scripts/get_dkg_enabled.cdc) | +| **`DKG.05`** | Get DKG Completed | [dkg/scripts/get_dkg_completed.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/dkg/scripts/get_dkg_completed.cdc) | +| **`DKG.06`** | Get Whiteboard Messages | [dkg/scripts/get_whiteboard_messages.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/dkg/scripts/get_whiteboard_messages.cdc) | +| **`DKG.07`** | Get Final Submissions | [dkg/scripts/get_final_submissions.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/dkg/scripts/get_final_submissions.cdc) | +| **`DKG.08`** | Get Node Has Submitted | [dkg/scripts/get_node_has_submitted.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/dkg/scripts/get_node_has_submitted.cdc) | + +# Events + +See the [epoch documentation](../../networks/staking/05-epoch-scripts-events.md) +for a list and documentation for important `FlowEpoch` events. \ No newline at end of file diff --git a/static/markdown/build/core-contracts/08-non-fungible-token.md b/static/markdown/build/core-contracts/08-non-fungible-token.md new file mode 100644 index 0000000000..73c778fdbc --- /dev/null +++ b/static/markdown/build/core-contracts/08-non-fungible-token.md @@ -0,0 +1,160 @@ +--- +title: Non-Fungible Token Contract +sidebar_position: 8 +sidebar_label: Non-Fungible Token +description: Learn about Flow's Non-Fungible Token (NFT) standard contract interface, its implementation, events system, and how to build NFT contracts on Flow. Understand the core NFT functionality and event handling. +keywords: + - NFT + - non-fungible token + - NFT standard + - token contract + - NFT events + - NFT transactions + - token interface + - Flow NFT + - NFT implementation + - token collection + - NFT deposits + - NFT withdrawals + - token updates + - NFT metadata + - digital assets +--- + +The `NonFungibleToken` contract interface implements the Fungible Token Standard. +All NFT contracts are encouraged to import and implement this standard. + +- [Basic Non-Fungible Token Tutorial](https://cadence-lang.org/docs/tutorial/non-fungible-tokens-1) +- [Non Fungible Token Guide](../guides/nft.md) +- [Non Fungible Token Standard Repo](https://github.com/onflow/flow-nft) + +Source: [NonFungibleToken.cdc](https://github.com/onflow/flow-nft/blob/master/contracts/NonFungibleToken.cdc) + +| Network | Contract Address | +| ------------------------- | -------------------- | +| Emulator | `0xf8d6e0586b0a20c7` | +| Cadence Testing Framework | `0x0000000000000001` | +| Testnet | `0x631e88ae7f1d7c20` | +| Mainnet | `0x1d7e57aa55817448` | + +# Transactions + +All `NonFungibleToken` projects are encouraged to use +the generic token transactions and scripts in the `flow-nft` [repo](https://github.com/onflow/flow-nft/tree/master/transactions). +They can be used for any token that implements the non-fungible token standard properly +without changing any code besides import addresses on different networks. + +# Events + +Events emitted from all contracts follow a standard format: + +``` +A.{contract address}.{contract name}.{event name} +``` + +The components of the format are: + +- `contract address` - the address of the account the contract has been deployed to +- `contract name` - the name of the contract in the source code +- `event name` - the name of the event as declared in the source code + +## NonFungibleToken Events + +Contracts that implement the Non-Fungible Token standard get access +to standard events that are emitted every time a relevant action occurs, +like depositing and withdrawing tokens. + +This means that projects do not have to implement their own custom events +unless the standard events do not satisfy requirements they have for events. + +The `NonFungibleToken` events will have the following format: + +``` +A.{contract address}.NonFungibleToken.Deposited +A.{contract address}.NonFungibleToken.Withdrawn +``` + +Where the `contract address` is the `NonFungibleToken` address on the network being queried. +The addresses on the various networks are shown above. + +### NonFungibleToken.Deposited + +```cadence +access(all) event Deposited ( + type: String, + id: UInt64, + uuid: UInt64, + to: Address?, + collectionUUID: UInt64 +) +``` + +Whenever `deposit()` is called on a resource type that implements +`NonFungibleToken.Collection`, the `NonFungibleToken.Deposited` event is emitted +with the following arguments: + +- `type: String`: The type identifier of the token being deposited. + - Example: `A.4445e7ad11568276.TopShot.NFT` +- `id: UInt64`: The ID of the token that was deposited. Note: This may or may not be the UUID. + - Example: `173838` +- `uuid: UInt64`: The UUID of the token that was deposited. + - Example: `177021372071991` +- `to: Address?`: The address of the account that owns the Collection that received + the token. If the collection is not stored in an account, `to` will be `nil`. + - Example: `0x4445e7ad11568276` +- `collectionUUID: UInt64`: The UUID of the Collection that received the token. + - Example: `177021372071991` + +### NonFungibleToken.Withdrawn + +```cadence +access(all) event Withdrawn ( + type: String, + id: UInt64, + uuid: UInt64, + from: Address?, + providerUUID: UInt64 +) +``` + +Whenever `withdraw()` is called on a resource type that implements +`NonFungibleToken.Collection`, the `NonFungibleToken.Withdrawn` event is emitted +with the following arguments: + +- `type: String`: The type identifier of the token being withdrawn. + - Example: `A.4445e7ad11568276.TopShot.NFT` +- `id: UInt64`: The id of the token that was withdrawn. Note: May or may not be the UUID. + - Example: `113838` +- `uuid: UInt64`: The UUID of the token that was withdrawn. + - Example: `177021372071991` +- `from: Address?`: The address of the account that owns the Collection that + the token was withdrawn from. If the collection is not stored in an account, `to` will be `nil`. + - Example: `0x4445e7ad11568276` +- `providerUUID: UInt64`: The UUID of the Collection that the token was withdrawn from. + - Example: `177021372071991` + +### NonFungibleToken.Updated + +```cadence +access(all) event Updated( + type: String, + id: UInt64, + uuid: UInt64, + owner: Address? +) +``` + +Whenever a non-fungible token is updated for whatever reason, +projects should call the `NonFungibleToken.emitNFTUpdated()` function +to emit this event. It indicates to event listeners that they should query +the NFT to update any stored information they have about the NFT in their database. + +- `type: String`: The type identifier of the token that was updated. + - Example: `A.4445e7ad11568276.TopShot.NFT` +- `id: UInt64`: The ID of the token that was updated. Note: This may or may not be the UUID. + - Example: `173838` +- `uuid: UInt64`: The UUID of the token that was updated. + - Example: `177021372071991` +- `owner: Address?`: The address of the account that owns the Collection that owns + the token. If the collection is not stored in an account, `to` will be `nil`. + - Example: `0x4445e7ad11568276` \ No newline at end of file diff --git a/static/markdown/build/core-contracts/09-nft-metadata.md b/static/markdown/build/core-contracts/09-nft-metadata.md new file mode 100644 index 0000000000..94f6240790 --- /dev/null +++ b/static/markdown/build/core-contracts/09-nft-metadata.md @@ -0,0 +1,46 @@ +--- +title: NFT Metadata Contract +sidebar_position: 9 +sidebar_label: NFT Metadata +description: Learn about Flow's NFT metadata standards implemented through ViewResolver and MetadataViews contracts. Understand how to attach and manage on-chain metadata for NFTs and integrate with the Flow NFT Catalog. +keywords: + - NFT metadata + - ViewResolver + - MetadataViews + - metadata standard + - NFT catalog + - on-chain metadata + - NFT interoperability + - metadata views + - FLIP-0636 + - NFT discovery + - metadata implementation + - Flow NFT + - NFT standards + - metadata integration + - NFT optimization +--- + +The `ViewResolver` and `MetadataViews` contracts implement a standard to attach on-chain metadata +to NFTs. This standard was originally proposed in [FLIP-0636](https://github.com/onflow/flips/blob/main/application/20210916-nft-metadata.md). + +It is deployed at the same address as the `NonFungibleToken` contract interface. + +Source: [ViewResolver.cdc](https://github.com/onflow/flow-nft/blob/master/contracts/ViewResolver.cdc) + +Source: [MetadataViews.cdc](https://github.com/onflow/flow-nft/blob/master/contracts/MetadataViews.cdc) + +| Network | Contract Address | +| ------------------------- | -------------------- | +| Emulator | `0xf8d6e0586b0a20c7` | +| Cadence Testing Framework | `0x0000000000000001` | +| Testnet | `0x631e88ae7f1d7c20` | +| Mainnet | `0x1d7e57aa55817448` | + +There exists a tool, [Flow NFT Catalog](https://flow-nft-catalog.com), which enables dapp developers the ability to unlock interoperability of your NFT collection across the Flow ecosystem. This will help make your NFT collection's metadata more discoverable and interoperable. + +To optimize your NFT collections for this catalog, you'll need to: + +1. Update your NFT contract to support `ViewResolver` and `MetadataViews` with implementation of the [core NFT views](../advanced-concepts/metadata-views.md). +2. Deploy the updated contract to both testnet and mainnet. +3. Afterwards, onboard your NFT to the Flow NFT catalog at [https://flow-nft-catalog.com](https://flow-nft-catalog.com). \ No newline at end of file diff --git a/static/markdown/build/core-contracts/10-nft-storefront.md b/static/markdown/build/core-contracts/10-nft-storefront.md new file mode 100644 index 0000000000..ff37034afc --- /dev/null +++ b/static/markdown/build/core-contracts/10-nft-storefront.md @@ -0,0 +1,506 @@ +--- +title: NFT Storefront Smart Contract +sidebar_position: 10 +sidebar_label: NFT Storefront +description: Learn about Flow's NFT Storefront contracts that enable non-custodial NFT marketplaces. Understand how to list NFTs for sale, handle purchases, manage commissions, and implement creator royalties. +keywords: + - NFT marketplace + - NFT storefront + - NFT listings + - NFT sales + - creator royalties + - marketplace commission + - non-custodial + - NFT trading + - NFT commerce + - listing management + - sale cuts + - NFT purchases + - marketplace integration + - NFT transactions + - Flow marketplace +--- + +The `NFTStorefront` contracts implement a standard way to list NFTs for sale +and buy them from listings. `NFTStorefrontV2` is the more powerful and full-featured +version, so developers and users are encouraged to use it instead of `NFTStorefront` +or their own implementation. + +Source: [NFTStorefrontV2.cdc] + +| Network | Contract Address | +| ------- | -------------------- | +| Testnet | `0x2d55b98eb200daef` | +| Mainnet | `0x4eb8a10cb9f87357` | + +Source: [NFTStorefront.cdc] + +| Network | Contract Address | +| ------- | -------------------- | +| Testnet | `0x94b06cfca1d8a476` | +| Mainnet | `0x4eb8a10cb9f87357` | + +## Primer + +The `NFTStorefrontV2` contract lets you create a _non-custodial Resource (NFT) marketplace_ on the FLOW blockchain. + +`NFTStorefrontV2` makes it simple for Sellers to list NFTs in dApp specific marketplaces. DApp developers leverage the APIs provided by the contract to manage listings being offered for sale and to transact NFT trades. + +![dapps_1](https://user-images.githubusercontent.com/14581509/191749748-714f9d8f-cb41-4be4-a3d2-ec84cb8b5ffb.png) + +Developers should use the `NFTStorefrontV2` to create their marketplace and to enable p2p purchases. The diagram below shows how dApps can facilitate the creation of NFT listings for different marketplaces and how marketplaces can filter their listings. + +Listings made through a specific dApp storefront can be simultaneously listed on 3rd party marketplaces beyond that dApp. Well known 3rd party marketplaces listen for compatible NFT listing events enabling the automation of listings into their marketplace dashboards. + +![dapps_2](https://user-images.githubusercontent.com/14581509/191753605-e1c48a57-0c3c-4509-808b-8fee4e7d32e8.png) + +Using the `NFTStorefrontV2`, marketplaces can instantly and easily tap into the vibrant FLOW NFT ecosystem and allow NFT holders to list their NFTs and enables creator royalties. + +Marketplaces then process an NFT trade by interacting directly with seller storefronts. Flow's account based model ensures that NFTs listed for sale always reside in the Seller account until traded, regardless of how many listings are posted across any number of marketplaces, for the same NFT. + +![marketplace_1](https://user-images.githubusercontent.com/14581509/191755699-fe0570cb-80a3-408c-8eef-4051e3209481.png) + +## Functional Overview + +A general purpose sale support contract for NFTs implementing the Flow [`NonFungibleToken`] standard. +Each account that wants to list NFTs for sale creates a `Storefront` resource to store in their account and lists individual sales within that Storefront as Listings. There is usually one Storefront per account held at the `/storage/NFTStorefrontV2`. + +Each listing can define one or more sale cuts taken out of the sale price to go to one or more addresses. Listing fees, royalties, or other considerations can be paid using sale cuts. Also, the listing can include a commission as one of these sale cuts is paid to whoever facilitates the purchase. + +Listings can have an optional list of marketplace [receiver capabilities] used to receive the commission for fulfilling the listing. An NFT may be listed in one or more Listings, and the validity of each listing can easily be checked. + +Interested parties can globally track Listing events on-chain and filter by NFT types, IDs and other characteristics to determine which to make available for purchase within their own marketplace UIs." + +## Selling NFTs + +`NFTStorefrontV2` offers a generic process for creating the listing for an NFT. It provides all the essential APIs to manage those listings independently. + +Many marketplaces create a single storefront resource to manage different individual listings. We recommend creating the listing under the user-owned storefront resource to make it trustless and platform-independent. Users should possess the `Storefront` resource under their account to create the listing using the storefront contract. + +## Creating a successful listing using the NFTStorefrontV2 contract. + +As recommended above, the first step is to create and store the [Storefront resource] in the user account using the [setup_account] transaction. + +The next step is to create a listing under the newly created storefront resource. If the user (repetitive) already holds the storefront resource, then use the existing resource. The seller can come with multiple requirements for listing their NFTs, and We try our best to cover most of them below. + +### **Scenario 1:** Selling NFTs corresponds to more than one cryptocurrency, i.e. FLOW, USDC etc. + +The `NFTStorefrontV2` contract doesn't support selling an NFT for multiple different currencies with a single listing. However, this can be achieved by creating multiple listings for the same NFT for each different currency. + +**Example -** Alice wants to sell a kitty and is open to receiving FLOW and USDC + +![scenario_1](./scenario_1.png) + +Putting an NFT on sell called listing, seller can create a listing using [sell_item] transaction by providing some required details to list an NFT, i.e. Receiving currency type, [Capability] from where NFT will be deducted etc. If interested look [`createListing`] for more details. + +To receive a different currency seller has to provide a different **Receiver currency type** , i.e. `salePaymentVaultType` As depicted in the above diagram, There are two listing formations with almost the same inputs. The only differentiator is the `salePaymentVaultType` parameter that needs to be different when creating duplicate NFT listings with different sale currency types. + +### **Scenario 2:** Peer-to-Peer (p2p) listing of NFT: A listing anyone can fulfil. + +Dapps can leverage the **NFTStorefrontV2** to facilitate the creation of a listing for the seller independent of any marketplace. Dapps or marketplaces can list those listings on their platforms, or seller can settle it p2p. + +The seller can use [sell_item] transaction to create a p2p listing, providing the `marketplacesAddress` with an empty array. The seller has a choice of providing [commission] to the facilitator of sale, which can also act as a discount if the facilitator and the purchaser are the same. + +### **Scenario 3:** The seller wants to list its NFT in different marketplaces. + +`NFTStorefrontV2` offers two different ways of doing it. + +- The seller can create a listing and provide the `marketplacesAddress` that it wants to have a listing on using [sell_item] transaction. + + Marketplaces can listen to `ListingAvailable` events and check whether their address is included in the `commissionReceivers` list; If yes, the marketplace would be rewarded during the successful fulfilment of the listing. + + Example - Bob wants to list on marketplace 0xA, 0xB & 0xC and is willing to offer 10% commission on the sale price of the listing to the marketplaces. + + ![scenario_3](https://user-images.githubusercontent.com/14581509/190966834-8eda4ec4-e9bf-49ef-9dec-3c47a236d281.png) + +- Another way to accomplish this is to create separate listings for each marketplace on which a user wants their listing using [sell_item_with_marketplace_cut] transaction. In this case, the marketplace would be incentivized by earning one of the parts of the [`saleCut`] by appending marketplace saleCut in `saleCuts` array during the creation of the listing. + +### Considerations + +1. **Ghost listings -** _Ghost listings are listings which don't have an underlying NFT in the seller's account. However, the listing is still available for buyers to attempt to purchase_. StorefrontV2 is not immune to ghost listings. Usually, ghost listings will cause a purchaser's transaction to fail, which is annoying but isn't a significant problem. Ghost listings become a problem for the seller when the listed NFT comes back to the seller's account after its original sale. The ghost listing will no longer be invalid when it comes back, and anyone can purchase it even if the seller doesn't want to sell it at that price anymore. + + **Note -** _We recommend that marketplaces and p2p dApps create an off-chain notification service that tells their users (i.e., sellers) to remove the listings if they don't hold the NFT anymore in the same account._ + +2. **Expired listings -** `NFTStorefrontV2` introduces a safety measure to specify that a listing will expire after a certain period that can be set during the creation so no one can purchase the listing anymore. It is not a fool-proof safety measure, but it does give some safe ground to the sellers for the ghost listings & stale listings. + + **Note -** _We recommended for marketplaces and p2p dApps not to show the expired listings on their dashboards._ + +## Purchasing NFTs + +Purchasing NFTs through the `NFTStorefrontV2` is simple. The buyer has to provide the payment vault and the `commissionRecipient` , if applicable, during the purchase. p2p dApps don't need any intermediaries to facilitate the purchase of listings. [`purchase`] API offered by the `Listing` resource gets used to facilitate the purchase of NFT. + +During the listing purchase all saleCuts are paid automatically. This also includes distributing royalties for that NFT, if applicable. If the vault provided by the buyer lacks sufficient funds then the transaction will fail. + +### Considerations + +1. **Auto cleanup -** `NFTStorefrontV2` offers a unique ability to do auto cleanup of duplicate listings during a purchase. It comes with a drawback if one NFT has thousands of duplicate listings. It will become the bottleneck during purchasing one of the listings as it will likely trigger an out-of-gas error. + + **Note -** _We recommended NOT to have more than 50 (TBD) duplicate listings of any given NFT._ + +2. **Unsupported receiver capability** - A common pitfall during the purchase of an NFT that some saleCut receivers don't have a supported receiver capability because that entitled sale cut would transfer to first valid sale cut receiver. However, it can be partially solved by providing the generic receiver using the [`FungibleTokenSwitchboard`] contract and adding all the currency capabilities the beneficiary wants to receive. More on the `FungibleTokenSwitchboard` can be read in [Fungible Token Switchboard] + +## Enabling creator royalties for NFTs + +The `NFTStorefrontV2` contract optionally supports paying royalties to the minter account for secondary resales of that NFT after the original sale. Marketplaces decide for themselves whether to support creator royalties when validating listings for sale eligibility. We encourage all marketplaces to support creator royalties and support community creators in the **FLOW** ecosystem. + +Providing that a seller's NFT supports the [Royalty Metadata View] standard, then marketplaces can honor royalties payments at time of purchase. `NFTStorefrontV2` dynamically calculates the royalties owed at the time of listing creation and applies it as a saleCut of the listing at the time of purchase. + +```cadence +// Check whether the NFT implements the MetadataResolver or not. +if nft.getViews().contains(Type()) { + // Resolve the royalty view + let royaltiesRef = nft.resolveView(Type()) + ?? panic("Unable to retrieve the royalties view for the NFT with type " + .concat(nft.getType().identifier).concat(" and ID ") + .concat(nft.id.toString()).concat(".") + // Fetch the royalties. + let royalties = (royaltiesRef as! MetadataViews.Royalties).getRoyalties() + + // Append the royalties as the salecut + for royalty in royalties { + self.saleCuts.append(NFTStorefrontV2.SaleCut(receiver: royalty.receiver, amount: royalty.cut * effectiveSaleItemPrice)) + totalRoyaltyCut = totalRoyaltyCut + royalty.cut * effectiveSaleItemPrice + } +} +``` + +Complete transaction can be viewed in [sell_item]. + +saleCut only supports a single token receiver type and therefore beneficiaries of a `saleCut` can also only receive the token type used for the purchase. To support different token types for saleCuts we recommend using the [`FungibleTokenSwitchboard`] contract. The contract defines a generic receiver for fungible tokens which itself handles routing of tokens to the respective vault for that token type. Learn more about this in [Fungible Token Switchboard]. + +## Enabling marketplace commissions for NFT sales + +`NFTStorefrontV2` enables optional commissions on trades for marketplaces which require it as a condition to list a NFT for sale. Commission & commission receivers are set by the seller during initial listing creation. At time of purchase the commission amount is paid once only to the commission receiver matching the marketplace receiver address which facilitated the sale. + +For NFT listings in marketplaces which don't require commission, commission receivers can be set as nil. Setting the buyer of the NFT and `commissionRecipient` to the same has the effect of applying a discount for the buyer. + +![scenario_2](https://user-images.githubusercontent.com/14581509/190966499-c176203f-b6a6-4422-860f-1bf6f2bcdbb6.png). + +## APIs & Events offered by NFTStorefrontV2 + +## Resource Interface `ListingPublic` + +```cadence +resource interface ListingPublic { + access(all) fun borrowNFT(): &NonFungibleToken.NFT? + access(all) fun purchase( + payment: @FungibleToken.Vault, + commissionRecipient: Capability<&{FungibleToken.Receiver}>?, + ): @NonFungibleToken.NFT + access(all) fun getDetails(): ListingDetail + access(all) fun getAllowedCommissionReceivers(): [Capability<&{FungibleToken.Receiver}>]? +} +``` + +An interface providing a useful public interface to a Listing. + +### Functions + +#### **fun `borrowNFT()`** + +```cadence +fun borrowNFT(): &NonFungibleToken.NFT? +``` + +This will assert in the same way as the NFT standard borrowNFT() +if the NFT is absent, for example if it has been sold via another listing. + +--- + +#### **fun `purchase()`** + +```cadence +fun purchase(payment FungibleToken.Vault, commissionRecipient Capability<&{FungibleToken.Receiver}>?): NonFungibleToken.NFT +``` + +Facilitates the purchase of the listing by providing the payment vault +and the commission recipient capability if there is a non-zero commission for the given listing. +Respective saleCuts are transferred to beneficiaries and funtion return underlying or listed NFT. + +--- + +#### **fun `getDetails()`** + +```cadence +fun getDetails(): ListingDetails +``` + +Fetches the details of the listings + +--- + +#### **fun `getAllowedCommissionReceivers()`** + +```cadence +fun getAllowedCommissionReceivers(): [Capability<&{FungibleToken.Receiver}>]? +``` + +Fetches the allowed marketplaces capabilities or commission receivers for the underlying listing. +If it returns `nil` then commission is up to grab by anyone. + +--- + +## Resource `Storefront` + +```cadence +resource Storefront { + access(all) fun createListing( + nftProviderCapability: Capability<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic}>, + nftType: Type, + nftID: UInt64, + salePaymentVaultType: Type, + saleCuts: [SaleCut], + marketplacesCapability: [Capability<&{FungibleToken.Receiver}>]?, + customID: String?, + commissionAmount: UFix64, + expiry: UInt64 + ): UInt64 + access(all) fun removeListing(listingResourceID: UInt64) + access(all) fun getListingIDs(): [UInt64] + access(all) fun getDuplicateListingIDs(nftType: Type, nftID: UInt64, listingID: UInt64): [UInt64] + access(all) fun cleanupExpiredListings(fromIndex: UInt64, toIndex: UInt64) + access(all) fun borrowListing(listingResourceID: UInt64): &Listing{ListingPublic}? +} +``` + +A resource that allows its owner to manage a list of Listings, and anyone to interact with them +in order to query their details and purchase the NFTs that they represent. + +Implemented Interfaces: + +- `StorefrontManager` +- `StorefrontPublic` + +### Initializer + +```cadence +fun init() +``` + +### Functions + +#### **fun `createListing()`** + +```cadence +fun createListing(nftProviderCapability Capability<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic}>, nftType Type, nftID UInt64, salePaymentVaultType Type, saleCuts [SaleCut], marketplacesCapability [Capability<&{FungibleToken.Receiver}>]?, customID String?, commissionAmount UFix64, expiry UInt64): UInt64 +``` + +insert +Create and publish a Listing for an NFT. + +--- + +#### **fun `removeListing()`** + +```cadence +fun removeListing(listingResourceID UInt64) +``` + +removeListing +Remove a Listing that has not yet been purchased from the collection and destroy it. + +--- + +#### **fun `getListingIDs()`** + +```cadence +fun getListingIDs(): [UInt64] +``` + +getListingIDs +Returns an array of the Listing resource IDs that are in the collection + +--- + +#### **fun `getDuplicateListingIDs()`** + +```cadence +fun getDuplicateListingIDs(nftType Type, nftID UInt64, listingID UInt64): [UInt64] +``` + +getDuplicateListingIDs +Returns an array of listing IDs that are duplicates of the given `nftType` and `nftID`. + +--- + +#### **fun `cleanupExpiredListings()`** + +```cadence +fun cleanupExpiredListings(fromIndex UInt64, toIndex UInt64) +``` + +cleanupExpiredListings +Cleanup the expired listing by iterating over the provided range of indexes. + +--- + +#### **fun `borrowListing()`** + +```cadence +fun borrowListing(listingResourceID: UInt64): &{ListingPublic}? +``` + +borrowListing +Returns a read-only view of the listing for the given listingID if it is contained by this collection. + +--- + +## Resource Interface `StorefrontPublic` + +```cadence +resource interface StorefrontPublic { + access(all) fun getListingIDs(): [UInt64] + access(all) fun getDuplicateListingIDs(nftType: Type, nftID: UInt64, listingID: UInt64): [UInt64] + access(all) fun cleanupExpiredListings(fromIndex: UInt64, toIndex: UInt64) + access(all) fun borrowListing(listingResourceID: UInt64): &Listing{ListingPublic}? + access(all) fun cleanupPurchasedListings(listingResourceID: UInt64) + access(all) fun getExistingListingIDs(nftType: Type, nftID: UInt64): [UInt64] +} +``` + +StorefrontPublic +An interface to allow listing and borrowing Listings, and purchasing items via Listings +in a Storefront. + +### Functions + +#### **fun `getListingIDs()`** + +```cadence +fun getListingIDs(): [UInt64] +``` + +getListingIDs Returns an array of the Listing resource IDs that are in the collection + +--- + +#### **fun `getDuplicateListingIDs()`** + +```cadence +fun getDuplicateListingIDs(nftType Type, nftID UInt64, listingID UInt64): [UInt64] +``` + +getDuplicateListingIDs Returns an array of listing IDs that are duplicates of the given nftType and nftID. + +--- + +#### **fun `borrowListing()`** + +```cadence +fun borrowListing(listingResourceID UInt64): &Listing{ListingPublic}? +``` + +borrowListing Returns a read-only view of the listing for the given listingID if it is contained by this collection. + +--- + +#### **fun `cleanupExpiredListings()`** + +```cadence +fun cleanupExpiredListings(fromIndex UInt64, toIndex UInt64) +``` + +cleanupExpiredListings Cleanup the expired listing by iterating over the provided range of indexes. + +--- + +#### **fun `cleanupPurchasedListings()`** + +```cadence +fun cleanupPurchasedListings(listingResourceID: UInt64) +``` + +cleanupPurchasedListings +Allows anyone to remove already purchased listings. + +--- + +#### **fun `getExistingListingIDs()`** + +```cadence +fun getExistingListingIDs(nftType Type, nftID UInt64): [UInt64] +``` + +getExistingListingIDs +Returns an array of listing IDs of the given `nftType` and `nftID`. + +--- + +## Events + +**event `StorefrontInitialized`** + +```cadence +event StorefrontInitialized(storefrontResourceID: UInt64) +``` + +A Storefront resource has been created. Consumers can now expect events from this Storefront. Note that we do not specify an address: we cannot and should not. Created resources do not have an owner address, and may be moved +after creation in ways we cannot check. `ListingAvailable` events can be used to determine the address +of the owner of the Storefront at the time of the listing but only at that precise moment in that precise transaction. If the seller moves the Storefront while the listing is valid, that is on them. + +--- + +**event `StorefrontDestroyed`** + +```cadence +event StorefrontDestroyed(storefrontResourceID: UInt64) +``` + +A Storefront has been destroyed. Event consumers can now stop processing events from this Storefront. +Note - we do not specify an address. + +--- + +**event `ListingAvailable`** + +```cadence +event ListingAvailable(storefrontAddress: Address, listingResourceID: UInt64, nftType: Type, nftUUID: UInt64, nftID: UInt64, salePaymentVaultType: Type, salePrice: UFix64, customID: String?, commissionAmount: UFix64, commissionReceivers: [Address]?, expiry: UInt64) +``` + +Above event gets emitted when a listing has been created and added to a Storefront resource. The Address values here are valid when the event is emitted, but the state of the accounts they refer to may change outside of the +`NFTStorefrontV2` workflow, so be careful to check when using them. + +--- + +**event `ListingCompleted`** + +```cadence +event ListingCompleted(listingResourceID: UInt64, storefrontResourceID: UInt64, purchased: Bool, nftType: Type, nftUUID: UInt64, nftID: UInt64, salePaymentVaultType: Type, salePrice: UFix64, customID: String?, commissionAmount: UFix64, commissionReceiver: Address?, expiry: UInt64) +``` + +The listing has been resolved. It has either been purchased, removed or destroyed. + +--- + +**event `UnpaidReceiver`** + +```cadence +event UnpaidReceiver(receiver: Address, entitledSaleCut: UFix64) +``` + +A entitled receiver has not been paid during the sale of the NFT. + +--- + +**Holistic process flow diagram of NFTStorefrontV2 -** + +![NFT Storefront Process flow](https://user-images.githubusercontent.com/14581509/191960793-ff153e5d-2934-410c-b724-5c5dffd2c20f.png) + + + +[NFTStorefrontV2.cdc]: https://github.com/onflow/nft-storefront/blob/main/contracts/NFTStorefrontV2.cdc +[NFTStorefront.cdc]: https://github.com/onflow/nft-storefront/blob/main/contracts/NFTStorefront.cdc +[`NonFungibleToken`]: https://github.com/onflow/flow-nft/blob/master/contracts/NonFungibleToken.cdc +[receiver capabilities]: https://cadence-lang.org/docs/language/capabilities +[Storefront resource]: #resource-storefront +[setup_account]: https://github.com/onflow/nft-storefront/blob/main/transactions/setup_account.cdc +[sell_item]: https://github.com/onflow/nft-storefront/blob/main/transactions/sell_item.cdc +[Capability]: https://cadence-lang.org/docs/language/capabilities +[`createListing`]: #fun-createlisting +[Fungible Token Switchboard]: https://github.com/onflow/flow-ft#fungible-token-switchboard +[commission]: #enabling-marketplace-commissions-for-nft-sales +[sell_item_with_marketplace_cut]: https://github.com/onflow/nft-storefront/blob/main/transactions/sell_item_with_marketplace_cut.cdc +[`saleCut`]: https://github.com/onflow/nft-storefront/blob/160e97aa802405ad26a3164bcaff0fde7ee52ad2/contracts/NFTStorefrontV2.cdc#L104 +[`purchase`]: #fun-purchase +[`FungibleTokenSwitchboard`]: https://github.com/onflow/flow-ft/blob/master/contracts/FungibleTokenSwitchboard.cdc +[Royalty Metadata View]: https://github.com/onflow/flow-nft/blob/21c254438910c8a4b5843beda3df20e4e2559625/contracts/MetadataViews.cdc#L335 \ No newline at end of file diff --git a/static/markdown/build/core-contracts/11-staking-collection.md b/static/markdown/build/core-contracts/11-staking-collection.md new file mode 100644 index 0000000000..532eb2e001 --- /dev/null +++ b/static/markdown/build/core-contracts/11-staking-collection.md @@ -0,0 +1,110 @@ +--- +title: Flow Staking Collection Contract Reference +sidebar_position: 11 +sidebar_label: Staking Collection +description: Learn about Flow's Staking Collection contract that manages user stake and delegation resources. Understand how to interact with nodes, delegators, and locked tokens through the collection interface. +keywords: + - staking collection + - Flow staking + - node management + - delegation + - locked tokens + - machine accounts + - staking operations + - node registration + - delegator registration + - stake management + - token delegation + - staking interface + - Flow protocol + - staking transactions + - collection events +--- + +# Contract + +The `FlowStakingCollection` contract is a contract that manages a resource containing a user's stake and delegation objects. + +The `FlowStakingCollection` allows a user to manage multiple active nodes or delegators +and interact with node or delegator objects stored in either their optional locked account +or in the StakingCollection itself (stored in the main account). +If a user has locked tokens, StakingCollection allows a user to interact with their locked tokens +to perform staking actions for any of their nodes or delegators. + +The staking collection also manages creating a node's machine accounts if they have any collector or consensus nodes. +It also allows them to deposit and withdraw tokens from any of their machine accounts through the staking collection. + +See the [Staking Collection Docs](../../networks/staking/14-staking-collection.md) for more information on the design of the staking collection contract. + +Source: [FlowStakingCollection.cdc](https://github.com/onflow/flow-core-contracts/blob/master/contracts/FlowStakingCollection.cdc) + +| Network | Contract Address | +| ------------------------- | -------------------- | +| Emulator | `0xf8d6e0586b0a20c7` | +| Cadence Testing Framework | `0x0000000000000001` | +| Testnet | `0x95e019a17d0e23d7` | +| Mainnet | `0x8d0e87b65159ae63` | + +## Transactions + +Use the following transactions to interact with the StakingCollection. + +\_Note: The StakingCollection differentiates between stake and delegation requests through +passing an optional DelegatorID argument. For example, if you wish to Stake New Tokens for an active node, +pass `nil` as the optional DelegatorID argument to the Stake New Tokens transaction. +The same applies for all the other staking operation transactions. + +| ID | Name | Source | +| ------------ | ----------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **`SCO.01`** | Setup Staking Collection | [stakingCollection/setup_staking_collection.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/stakingCollection/setup_staking_collection.cdc) | +| **`SCO.02`** | Register Delegator | [stakingCollection/register_delegator.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/stakingCollection/register_delegator.cdc) | +| **`SCO.03`** | Register Node | [stakingCollection/register_node.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/stakingCollection/register_node.cdc) | +| **`SCO.04`** | Create Machine Account | [stakingCollection/create_machine_account.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/stakingCollection/create_machine_account.cdc) | +| **`SCO.05`** | Request Unstaking | [stakingCollection/request_unstaking.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/stakingCollection/request_unstaking.cdc) | +| **`SCO.06`** | Stake New Tokens | [stakingCollection/stake_new_tokens.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/stakingCollection/stake_new_tokens.cdc) | +| **`SCO.07`** | Stake Rewarded Tokens | [stakingCollection/stake_rewarded_tokens.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/stakingCollection/stake_rewarded_tokens.cdc) | +| **`SCO.08`** | Stake Unstaked Tokens | [stakingCollection/stake_unstaked_tokens.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/stakingCollection/stake_unstaked_tokens.cdc) | +| **`SCO.09`** | Unstake All | [stakingCollection/unstake_all.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/stakingCollection/unstake_all.cdc) | +| **`SCO.10`** | Withdraw Rewarded Tokens | [stakingCollection/withdraw_rewarded_tokens.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/stakingCollection/withdraw_rewarded_tokens.cdc) | +| **`SCO.11`** | Withdraw Unstaked Tokens | [stakingCollection/withdraw_unstaked_tokens.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/stakingCollection/withdraw_unstaked_tokens.cdc) | +| **`SCO.12`** | Close Stake | [stakingCollection/close_stake.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/stakingCollection/close_stake.cdc) | +| **`SCO.13`** | Transfer Node | [stakingCollection/transfer_node.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/stakingCollection/transfer_node.cdc) | +| **`SCO.14`** | Transfer Delegator | [stakingCollection/transfer_delegator.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/stakingCollection/transfer_delegator.cdc) | +| **`SCO.15`** | Withdraw From Machine Account | [stakingCollection/withdraw_from_machine_account.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/stakingCollection/withdraw_from_machine_account.cdc) | +| **`SCO.22`** | Update Networking Address | [stakingCollection/update_networking_address.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/stakingCollection/update_networking_address.cdc) | + +## Scripts + +| ID | Name | Source | +| ------------ | ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **`SCO.16`** | Get All Delegator Info | [stakingCollection/scripts/get_all_delegator_info.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/stakingCollection/scripts/get_all_delegator_info.cdc) | +| **`SCO.15`** | Get All Node Info | [stakingCollection/scripts/get_all_node_info.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/stakingCollection/scripts/get_all_node_info.cdc) | +| **`SCO.22`** | Get Delegator Ids | [stakingCollection/scripts/get_delegator_ids.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/stakingCollection/scripts/get_delegator_ids.cdc) | +| **`SCO.17`** | Get Node Ids | [stakingCollection/scripts/get_node_ids.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/stakingCollection/scripts/get_node_ids.cdc) | +| **`SCO.18`** | Get Does Stake Exist | [stakingCollection/scripts/get_does_stake_exist.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/stakingCollection/scripts/get_does_stake_exist.cdc) | +| **`SCO.19`** | Get Locked Tokens Used | [stakingCollection/scripts/get_locked_tokens_used.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/stakingCollection/scripts/get_locked_tokens_used.cdc) | +| **`SCO.20`** | Get Unlocked Tokens Used | [stakingCollection/scripts/get_unlocked_tokens_used.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/stakingCollection/scripts/get_unlocked_tokens_used.cdc) | +| **`SCO.21`** | Get Machine Accounts | [stakingCollection/scripts/get_machine_accounts.cdc](https://github.com/onflow/flow-core-contracts/blob/master/transactions/stakingCollection/scripts/get_machine_accounts.cdc) | + +## Setup Transaction + +To setup the Staking Collection for an account, use the `SC.01` transaction. + +The setup process finds any node or delegator records already stored in the main account's storage, +as well as any in the associated locked account if an associated locked account exists. +It connects these node and delegator records with the new Staking Collection, allowing them +to be interacted with using the Staking Collection API. + +## Events + +The `StakingCollection` contract emits an event whenever an important action occurs. + +```cadence + access(all) event NodeAddedToStakingCollection(nodeID: String, role: UInt8, amountCommitted: UFix64, address: Address?) + access(all) event DelegatorAddedToStakingCollection(nodeID: String, delegatorID: UInt32, amountCommitted: UFix64, address: Address?) + + access(all) event NodeRemovedFromStakingCollection(nodeID: String, role: UInt8, address: Address?) + access(all) event DelegatorRemovedFromStakingCollection(nodeID: String, delegatorID: UInt32, address: Address?) + + access(all) event MachineAccountCreated(nodeID: String, role: UInt8, address: Address) +``` \ No newline at end of file diff --git a/static/markdown/build/core-contracts/12-hybrid-custody.md b/static/markdown/build/core-contracts/12-hybrid-custody.md new file mode 100644 index 0000000000..6f4ca79b41 --- /dev/null +++ b/static/markdown/build/core-contracts/12-hybrid-custody.md @@ -0,0 +1,33 @@ +--- +title: Flow Account Linking Contract Address +sidebar_position: 12 +sidebar_label: Account Linking +description: Learn about Flow's Account Linking contracts that enable hybrid custody solutions. Understand how to manage child accounts and share specific resources between parent and child accounts securely. +keywords: + - account linking + - hybrid custody + - child accounts + - parent accounts + - account management + - resource sharing + - custody solution + - account security + - wallet integration + - Flow accounts + - contract browser + - account permissions + - resource access + - account control + - custody model +--- + +# Contract + +The Account Linking contracts manage ChildAccounts to permit hybrid custody in scenarios where apps only want to share a subset of resources on their accounts with various parents. In many cases, this will be a user's primary wallet outside of the application a child account came from. + +You can see the docs for account linking [here](https://developers.flow.com/build/advanced-concepts/account-linking) + +| Network | Contract Address | +| ------- | ------------------------------------------------------------------------------ | +| Testnet | [`0x294e44e1ec6993c6`](https://contractbrowser.com/account/0x294e44e1ec6993c6) | +| Mainnet | [`0xd8a7e05a7ac670c0`](https://contractbrowser.com/account/0xd8a7e05a7ac670c0) | \ No newline at end of file diff --git a/static/markdown/build/core-contracts/13-evm.md b/static/markdown/build/core-contracts/13-evm.md new file mode 100644 index 0000000000..7d6f5bce2f --- /dev/null +++ b/static/markdown/build/core-contracts/13-evm.md @@ -0,0 +1,41 @@ +--- +title: Flow EVM +sidebar_position: 13 +sidebar_label: EVM +description: Learn about Flow's EVM contract that enables Ethereum Virtual Machine compatibility on Flow. Understand how to interact with EVM from Cadence and access Flow's EVM equivalence features. +keywords: + - Flow EVM + - EVM compatibility + - Ethereum Virtual Machine + - EVM tooling + - Cadence EVM + - EVM contract + - EVM integration + - blockchain interop + - smart contracts + - EVM equivalence + - contract deployment + - Flow protocol + - cross-chain + - EVM support + - FLIP 223 +--- + +# Contract + +The `EVM` contract is the entrypoint from Cadence to Flow EVM. While many developers may choose to interact with EVM +via [EVM-equivalent tooling paths](../../evm/using.mdx), all access to Flow EVM ultimately interfaces via Cadence at +some level. + +If you would like to interact with EVM directly from Cadence, you can use the `EVM` contract and it's constructs. Read +more about the EVM contract and its role in Flow's EVM equivalence in [FLIP +#223](https://github.com/onflow/flips/blob/main/protocol/20231116-evm-support.md). + +Mainnet/Testnet Source: [`EVM.cdc`](https://github.com/onflow/flow-go/blob/master/fvm/evm/stdlib/contract.cdc) + +| Network | Contract Address | +| ------------------------- | -------------------------------------------------------------------------- | +| Emulator | `0xf8d6e0586b0a20c7` | +| Cadence Testing Framework | `0x0000000000000001` | +| Testnet | [`0x8c5303eaa26202d6`](https://contractbrowser.com/A.8c5303eaa26202d6.EVM) | +| Mainnet | [`0xe467b9dd11fa00df`](https://contractbrowser.com/A.e467b9dd11fa00df.EVM) | \ No newline at end of file diff --git a/static/markdown/build/core-contracts/14-burner.md b/static/markdown/build/core-contracts/14-burner.md new file mode 100644 index 0000000000..585fe57f2f --- /dev/null +++ b/static/markdown/build/core-contracts/14-burner.md @@ -0,0 +1,40 @@ +--- +title: Flow Burner Contract Address +sidebar_position: 14 +sidebar_label: Burner +description: Learn about Flow's Burner contract that enables custom destruction logic for resources. Understand how to implement the Burnable interface and safely destroy resources with custom callbacks. +keywords: + - resource burning + - Burner contract + - resource destruction + - burn callback + - Burnable interface + - resource management + - Flow resources + - custom destruction + - safe burning + - resource cleanup + - Flow protocol + - contract safety + - resource lifecycle + - destruction logic + - burn operations +--- + +# Contract + +The [Burner](https://github.com/onflow/flow-ft/blob/master/contracts/utility/Burner.cdc) contract provides a way for resources to define +custom logic that is executed when the resource is destroyed. +Resources that want to utilize this functionality should implement +the `Burner.Burnable` interface which requires that they include +a `burnCallback()` function that includes the custom logic. + +It is recommended that regardless of the resource, all users and developers +should use `Burner.burn()` when destroying a resource instead of `destroy`. + +| Network | Contract Address | +| ------- | ------------------------------------------------------------------------------ | +| Cadence Testing Framework | `0x0000000000000001` | +| Emulator | `0xee82856bf20e2aa6` | +| Testnet | [`0x294e44e1ec6993c6`](https://contractbrowser.com/account/0x294e44e1ec6993c6) | +| Mainnet | [`0xd8a7e05a7ac670c0`](https://contractbrowser.com/account/0xd8a7e05a7ac670c0) | \ No newline at end of file diff --git a/static/markdown/build/core-contracts/15-bridge.md b/static/markdown/build/core-contracts/15-bridge.md new file mode 100644 index 0000000000..9c153de76f --- /dev/null +++ b/static/markdown/build/core-contracts/15-bridge.md @@ -0,0 +1,81 @@ +--- +title: VM Bridge Contracts +sidebar_position: 15 +sidebar_label: VM Bridge +description: Learn about Flow's bridge contracts that manage bridging tokens between the Cadence and EVM environments. +keywords: + - core contracts + - transaction fees + - EVM + - bridge + - fungible tokens + - non fungible tokens + - nft +--- + +The Flow VM bridge is the account and series of smart contracts that manage how +assets are safely bridged between the Cadence and EVM Flow Environments. + +| Network | Contract Address | +| ------------------------- | -------------------- | +| Emulator | `0xf8d6e0586b0a20c7` | +| Cadence Testing Framework | `0x0000000000000001` | +| Testnet | `0xdfc20aee650fcbdf` | +| Mainnet | `0x1e4aa0b87d10b141` | + +# Contracts + +There are many important contracts deployed to the bridge account. +You should refer to [the bridge repo](https://github.com/onflow/flow-evm-bridge) +and [the bridge guides](../../tutorials/cross-vm-apps/vm-bridge.md) +for more detailed information about the bridge and tutorials for how to use the bridge properly. + +Here is a list of each Cadence contract used for the bridge: + +| Contract | Purpose | +| ------------------------------------- | --------------------------------------------------------------------------------------------------------- | +| `CrossVMNFT` | Contract defining cross-VM NFT-related interfaces | +| `CrossVMToken` | Contract defining cross-VM Fungible Token Vault interface | +| `FlowEVMBridgeHandlerInterfaces` | Defines interface for custom bridged token handlers | +| `IBridgePermissions` | Defines an interface to prevent bridging for a specific token | +| `ICrossVM` | Defines an interface to get EVM contract addresses | +| `ICrossVMAsset` | Defines an interface to represent a Cadence bridged version of an EVM asset | +| `IEVMBridgeNFTMinter` | Defines an interface that allows the bridge to mint NFTs | +| `IEVMBridgeTokenMinter` | Defines an interface that allows the bridge to mint FTs | +| `IFlowEVMNFTBridge` | Defines core methods for bridging NFTs | +| `IFlowEVMTokenBridge` | Defines core methods for bridging FTs | +| `FlowEVMBridge` | The main entrypoint for briding tokens across Flow VMs | +| `FlowEVMBridgeAccessor` | Defines methods to route bridge requests from the EVM contract to the Flow-EVM bridge contract | +| `FlowEVMBridgeConfig` | Used to store configuration options for the VM Bridge | +| `FlowEVMBridgeCustomAssociations` | Stores configuration information about custom bridged asset configurations | +| `FlowEVMBridgeCustomAssociationTypes` | Defines interfaces used to specify custom bridged asset associations | +| `FlowEVMBridgeHandlers` | Defines mechanisms for handling assets with custom associations (Deprecated) | +| `FlowEVMBridgeNFTEscrow` | Handles locking of NFTs that are bridged from Flow to EVM and back | +| `FlowEVMBridgeResolver` | Defines methods to resolve Metadata Views for bridged assets | +| `FlowEVMBridgeTemplates` | Serves Cadence code from chunked templates for bridge-deployed assets | +| `FlowEVMBridgeTokenEscrow` | Handles locking of FTs that are bridged from Flow to EVM and back | +| `FlowEVMBridgeUtils` | Defines many different utility methods that are used by bridge contracts | +| `ArrayUtils` | Provides useful utility functions for manipulating arrays | +| `ScopedFTProviders` | Provides utilities for creating provider capabilities for tokens that are restricted to a specific amount | +| `Serialize` | Provides utilities for serializing common types to json-compatible strings | +| `SerializeMetadata` | Provides methods for serializing NFT metadata as a JSON compatible string | +| `StringUtils` | Provides useful utility functions for manipulating strings | + +# EVM Bridge Solidity Contracts + +There are also Solidity contracts that are deployed in Flow EVM that are needed for the bridge. +Here are their addresses: + +| Contracts | Testnet | Mainnet | +| ------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- | +| `FlowEVMBridgeFactory.sol` | [`0xf8146b4aef631853f0eb98dbe28706d029e52c52`](https://evm-testnet.flowscan.io/address/0xF8146B4aEF631853F0eB98DBE28706d029e52c52) | [`0x1c6dea788ee774cf15bcd3d7a07ede892ef0be40`](https://evm.flowscan.io/address/0x1C6dEa788Ee774CF15bCd3d7A07ede892ef0bE40) | +| `FlowEVMBridgeDeploymentRegistry.sol` | [`0x8781d15904d7e161f421400571dea24cc0db6938`](https://evm-testnet.flowscan.io/address/0x8781d15904d7e161f421400571dea24cc0db6938) | [`0x8fdec2058535a2cb25c2f8cec65e8e0d0691f7b0`](https://evm.flowscan.io/address/0x8FDEc2058535A2Cb25C2f8ceC65e8e0D0691f7B0) | +| `FlowEVMBridgedERC20Deployer.sol` | [`0x4d45CaD104A71D19991DE3489ddC5C7B284cf263`](https://evm-testnet.flowscan.io/address/0x4d45CaD104A71D19991DE3489ddC5C7B284cf263) | [`0x49631Eac7e67c417D036a4d114AD9359c93491e7`](https://evm.flowscan.io/address/0x49631Eac7e67c417D036a4d114AD9359c93491e7) | +| `FlowEVMBridgedERC721Deployer.sol` | [`0x1B852d242F9c4C4E9Bb91115276f659D1D1f7c56`](https://evm-testnet.flowscan.io/address/0x1B852d242F9c4C4E9Bb91115276f659D1D1f7c56) | [`0xe7c2B80a9de81340AE375B3a53940E9aeEAd79Df`](https://evm.flowscan.io/address/0xe7c2B80a9de81340AE375B3a53940E9aeEAd79Df) | + +And below are the bridge escrow's EVM addresses. These addresses are [`CadenceOwnedAccount`s (COA)](https://developers.flow.com/tutorials/cross-vm-apps/interacting-with-coa#coa-interface) and they are stored stored in the same Flow account as you'll find the Cadence contracts (see above). + +| Network | Address | +| ------- | ---------------------------------------------------------------------------------------------------------------------------------- | +| Testnet | [`0x0000000000000000000000023f946ffbc8829bfd`](https://evm-testnet.flowscan.io/address/0x0000000000000000000000023f946FFbc8829BFD) | +| Mainnet | [`0x00000000000000000000000249250a5c27ecab3b`](https://evm.flowscan.io/address/0x00000000000000000000000249250a5C27Ecab3B) | \ No newline at end of file diff --git a/static/markdown/build/core-contracts/index.md b/static/markdown/build/core-contracts/index.md new file mode 100644 index 0000000000..63b9293498 --- /dev/null +++ b/static/markdown/build/core-contracts/index.md @@ -0,0 +1,50 @@ +--- +title: Flow Core Contracts +description: The smart contracts that power the Flow protocol +sidebar_label: Core Smart Contracts +sidebar_position: 9 +sidebar_custom_props: + icon: 📝 + description: Explore the foundational contracts driving the Flow blockchain and learn how to utilize these vital building blocks for your own smart contract development. +keywords: + - core contracts + - Flow protocol + - smart contracts + - FungibleToken + - FlowToken + - ServiceAccount + - FlowFees + - FlowIDTableStaking + - NonFungibleToken + - MetadataViews + - StakingCollection + - NFTStorefront + - AccountLinking + - EVM + - protocol contracts + - Flow standards + - blockchain infrastructure + - contract standards +--- + +Flow relies on a set of core contracts that define key portions of the +Flow protocol. + +These contracts control the following: + +- Standard fungible token behavior. ([FungibleToken, FungibleTokenMetadataViews, FungibleTokenSwitchboard, Burner](./02-fungible-token.md)) +- Flow Protocol Token. ([FlowToken](./03-flow-token.md)) +- Flow Service Account. ([ServiceAccount, NodeVersionBeacon, RandomBeaconHistory](./04-service-account.md)) +- Account, transaction and storage fee payments. ([FlowFees and FlowStorageFees](./05-flow-fees.md)) +- Staking and delegation ([FlowIDTableStaking](./06-staking-contract-reference.md)) +- Epochs ([FlowEpoch, FlowClusterQC, FlowDKG](./07-epoch-contract-reference.md)) + +There are other important contracts that aren't part of the core protocol +but are nevertheless important to developers on Flow: + +- Standard Non-Fungible Token Behavior. ([NonFungibleToken](./08-non-fungible-token.md)) +- NFT Metadata Standard. ([MetadataViews, ViewResolver](./09-nft-metadata.md)) +- Staking Collection. ([StakingCollection](./11-staking-collection.md)) +- NFT Storefronts. ([NFTStorefront](./10-nft-storefront.md)) +- Account linking and Hybrid Custody. ([AccountLinking](./12-hybrid-custody.md)) +- EVM interfacing contract. ([EVM](./13-evm.md)) \ No newline at end of file diff --git a/static/markdown/build/differences-vs-evm/index.md b/static/markdown/build/differences-vs-evm/index.md new file mode 100644 index 0000000000..9ee5bf63e1 --- /dev/null +++ b/static/markdown/build/differences-vs-evm/index.md @@ -0,0 +1,228 @@ +--- +sidebar_position: 2 +title: Differences vs. EVM +sidebar_custom_props: + icon: ↔️ +description: Understand the key differences between Flow and EVM-based blockchains. Learn about Flow's unique account model, Cadence programming language, and transaction structure compared to Ethereum. +keywords: + - Flow vs EVM + - Cadence vs Solidity + - blockchain differences + - account model + - smart contracts + - transactions + - Flow nodes + - development tools + - Flow architecture + - blockchain comparison + - Flow capabilities + - resource orientation + - Flow security model + - blockchain SDK + - developer tools +--- + +Flow [Cadence] is designed with many improvements over prior blockchain networks. As a result, you'll notice many differences between Flow vs. other blockchains, especially Ethereum. This document will be most useful to developers who are already familiar with building on the EVM, but contains details useful to all developers. Check out [Why Flow] for a more general overview of the Flow blockchain. + +:::tip + +Remember, Flow also supports full [EVM] equivalence! You can start by moving over your existing contracts, then start building new features that take advantage of the power of Cadence. + +::: + +## The Flow Cadence Account Model + +Key pairs establish ownership on blockchains. In other blockchains (e.g. Bitcoin and Ethereum), the user's address is also calculated based on their public key, making a unique one-to-one relationship between accounts (addresses) and public keys. This also means there is no concrete "account creation" process other than generating a valid key pair. + +With the advent of smart contracts, Ethereum introduced a new account type for deploying contracts that can use storage space (i.e., to store contract bytecode). You can learn more about the distinction between EOA and Contract [accounts on Ethereum]. + +The [Flow account model] combines the concepts of EOAs and Contract Accounts into a single account model and decouples accounts and public keys. Flow accounts are associated with one or more public keys of varying weights that specify interested parties that need to produce valid cryptographic signatures for each transaction authorized by that account. + +![Screenshot 2023-08-16 at 16.43.07.png](../basics/_accounts_images/Screenshot_2023-08-16_at_16.43.07.png) + +This natively enables interesting use cases, like key revocation, rotation, and multi-signature transactions. All Flow accounts can use network storage (e.g., for deploying contracts and storing resources like NFTs) based on the number of FLOW tokens they hold. + +:::warning + +You must run an explicit account creation transaction on Flow to create a new account. [Flow CLI] can create an account on any network with a given public key. Doing so requires a [very small fee] to be paid in FLOW. + +::: + +Another key difference is that [storage] for data and assets related to an account are stored in the account, **not** in the contract as with the EVM. + +Check out the [Accounts] concept document to learn more about Flow accounts. + +## Smart Contracts + +On Flow, smart contracts can be written in [Cadence], or Solidity. Cadence syntax is user-friendly and inspired by modern languages like Swift. Notable features of Cadence that make it unique and the key power of the Flow blockchain are: + +- **Resource-oriented**: Cadence introduces a new type called Resources. Resources enable onchain representation of digital assets natively and securely. Resources can only exist in one location at a time and are strictly controlled by the execution environment to avoid common mishandling mistakes. Each resource has a unique `uuid` associated with it on the blockchain. Examples of usage are fungible tokens, NFTs, or any custom data structure representing a real-world asset. Check out [Resources] to learn more. +- **Capability-based**: Cadence offers a [Capability-based Security] model. This also enables the use of Resources as structures to build access control. Capabilities and [Entitlements] can provide fine-grained access to the underlying objects for better security. For example, when users list an NFT on a Flow marketplace, they create a new Capability to the stored NFT in their account so the buyer can withdraw the asset when they provide the tokens. Check out [Capability-based Access Control] to learn more about Capabilities on Cadence. + +:::warning + +Cadence is not compiled. All contracts are public and unobfuscated on Flow. This isn't that different from the EVM, where it's trivial to decompile a contract back into Solidity. + +::: + +Check out the [Cadence] website to learn the details of the Cadence programming language. + +If you are a Solidity developer, we recommend you start with Cadence's [Guide for Solidity Developers] to dive deeper into the differences between the two languages. + +Here are some additional resources that can help you get started with Cadence: + +- [The Cadence tutorial] +- ERC-20 equivalent on Flow is the Flow Fungible Token Standard + - [Repository](https://github.com/onflow/flow-ft) + - [Tutorial](https://cadence-lang.org/docs/tutorial/fungible-tokens) +- ERC-721 equivalent on Flow is the Flow Non-Fungible Token Standard + - [Repository](https://github.com/onflow/flow-nft) + - [Tutorial](https://cadence-lang.org/docs/tutorial/non-fungible-tokens-1) +- Asset marketplaces with Cadence + - [Tutorial](https://cadence-lang.org/docs/tutorial/marketplace-setup) + - [NFT Storefront](https://github.com/onflow/nft-storefront/) is an example marketplace standard + +## Transactions and Scripts + +You can interact with the state on most other blockchains by cryptographically authorizing smart contract function calls. On Flow, transactions offer rich functionality through Cadence code. This allows you to seamlessly combine multiple contracts and function calls into a single transaction that updates the blockchain state - all executing together as one unified operation. + +Here is a sample transaction that mints an NFT from `ExampleNFT` contract on Testnet: + +```cadence +import NonFungibleToken from 0x631e88ae7f1d7c20 +import ExampleNFT from 0x2bd9d8989a3352a1 + +/// Mints a new ExampleNFT into recipient's account + +transaction(recipient: Address) { + + /// Reference to the receiver's collection + let recipientCollectionRef: &{NonFungibleToken.Collection} + + /// Previous NFT ID before the transaction executes + let mintingIDBefore: UInt64 + + prepare(signer: &Account) { + + self.mintingIDBefore = ExampleNFT.totalSupply + + // Borrow the recipient's public NFT collection reference + self.recipientCollectionRef = getAccount(recipient) + .capabilities.get<&{NonFungibleToken.Collection}>(ExampleNFT.CollectionPublicPath) + .borrow() + ?? panic("The recipient does not have a NonFungibleToken Receiver at " + .concat(ExampleNFT.CollectionPublicPath.toString()) + .concat(" that is capable of receiving an NFT.") + .concat("The recipient must initialize their account with this collection and receiver first!")) + + } + + execute { + + let currentIDString = self.mintingIDBefore.toString() + + // Mint the NFT and deposit it to the recipient's collection + ExampleNFT.mintNFT( + recipient: self.recipientCollectionRef, + name: "Example NFT #".concat(currentIDString), + description: "Example description for #".concat(currentIDString), + thumbnail: "https://robohash.org/".concat(currentIDString), + royalties: [] + ) + } + + post { + self.recipientCollectionRef.getIDs().contains(self.mintingIDBefore): "The next NFT ID should have been minted and delivered" + ExampleNFT.totalSupply == self.mintingIDBefore + 1: "The total supply should have been increased by 1" + } +} +``` + +### Authorizing Transactions + +The process to authorize a transaction on Flow Cadence is more complex, but also much more powerful than an EVM transaction: + +- [Accounts] can have multiple keys with varying weights +- Multiple accounts can sign a single transaction (`prepare` takes any number of arguments) +- Transaction computation fees can be paid by a different account, called the `Payer` account. +- The [transaction nonce] is provided by the `Proposer` account. This enables rate control and order to be dictated by a different party if needed. +- All of the above roles can be the same account. + +The same powerful concept also exists for querying the blockchain state using Scripts. Here is a sample script that fetches the `ExampleNFT` IDs owned by a given account on Testnet: + +```cadence +/// Script to get NFT IDs in an account's collection + +import NonFungibleToken from 0x631e88ae7f1d7c20 +import ExampleNFT from 0x2bd9d8989a3352a1 + +access(all) fun main(address: Address, collectionPublicPath: PublicPath): [UInt64] { + + let account = getAccount(address) + + let collectionRef = account + .capabilities.get<&{NonFungibleToken.Collection}>(collectionPublicPath) + .borrow() + ?? panic("The account with address " + .concat(address.toString()) + .concat("does not have a NonFungibleToken Collection at " + .concat(ExampleNFT.CollectionPublicPath.toString()) + .concat(". The account must initialize their account with this collection first!"))) + + return collectionRef.getIDs() + +} +``` + +Check out [Transactions] and [Scripts] to learn more about the concepts. You can also read the Cadence language reference on [Transactions] to dive deeper. + +## Flow Nodes + +Developers need a blockchain node to send transactions and fetch state. Flow is based on a multi-node architecture that separates tasks like consensus and computation into separate nodes. You can learn more about the Flow architecture in the [Flow Primer]. + +Access Nodes are the node type that are most useful for developers, as they provide access to the Flow network [via an API]. + +## SDKs and Tools + +If you're already familiar with blockchain development, here's a comparison between popular software packages and Flow's tooling: + +- [hardhat](https://hardhat.org/) / [Truffle](https://trufflesuite.com/) / [Foundry](https://github.com/foundry-rs/foundry) + - [Flow CLI](https://github.com/onflow/flow-cli/) provides local development tools and the [Flow Emulator](https://github.com/onflow/flow-emulator) +- [OpenZeppelin](https://www.openzeppelin.com/) + - [Emerald OZ](https://oz.ecdao.org/overview) +- [go-ethereum](https://geth.ethereum.org/) + - [Flow Go SDK](https://github.com/onflow/flow-go-sdk/) + - [FCL](https://github.com/onflow/fcl-js/) also provides Backend API for Flow in JS +- [web3.js](https://github.com/web3/web3.js) + - [FCL](https://github.com/onflow/fcl-js/) + - [flow-cadut](https://github.com/onflow/flow-cadut) provides more utilities for using Flow on Web +- [Remix](https://remix.ethereum.org/) + - [Flow Playground](https://play.flow.com/) provides basic experimentation on the web + - [Cadence VSCode Extension](https://marketplace.visualstudio.com/items?itemName=onflow.cadence) is strongly suggested to install for local development +- [Testing Smart Contracts](https://ethereum.org/en/developers/docs/smart-contracts/testing/) + - [Cadence testing framework](https://cadence-lang.org/docs/testing-framework) enables native tests in Cadence. + - [overflow](https://github.com/bjartek/overflow) for testing in Go. + + + +[Why Flow]: ../flow.md +[EVM]: ../../evm/about.md +[accounts on Ethereum]: https://ethereum.org/en/developers/docs/accounts +[Flow CLI]: ../../tools/flow-cli/accounts/create-accounts.md +[very small fee]: ../basics/fees.md#fee-structure +[Flow account model]: ../basics/accounts.md +[Accounts]: ../basics/accounts.md +[storage]: ../basics/accounts.md#storage +[Cadence]: https://cadence-lang.org/ +[Resources]: https://cadence-lang.org/docs/language/resources +[Capability-based Security]: https://en.wikipedia.org/wiki/Capability-based_security +[Entitlements]: https://cadence-lang.org/docs/language/access-control#entitlements +[Capability-based Access Control]: https://cadence-lang.org/docs/language/capabilities +[Guide for Solidity Developers]: https://cadence-lang.org/docs/solidity-to-cadence +[The Cadence tutorial]: https://cadence-lang.org/docs/tutorial/first-steps +[transaction nonce]: https://ethereum.org/en/developers/docs/accounts/#an-account-examined +[Transactions]: ../basics/transactions.md +[Scripts]: ../basics/scripts.md +[Transactions]: https://cadence-lang.org/docs/language/transactions +[Flow Primer]: https://flow.com/primer#primer-how-flow-works +[via an API]: ../../networks/flow-networks/index.md \ No newline at end of file diff --git a/static/markdown/build/explore-more.md b/static/markdown/build/explore-more.md new file mode 100644 index 0000000000..d72d06a497 --- /dev/null +++ b/static/markdown/build/explore-more.md @@ -0,0 +1,115 @@ +--- +title: Explore More +sidebar_label: Explore More +description: Discover additional tutorials, guides, and resources for building on Flow blockchain. Learn about NFTs, fungible tokens, dApp development, and core blockchain concepts. +sidebar_position: 999 +keywords: + - Flow tutorials + - dApp development + - NFT guide + - fungible tokens + - Flow CLI + - FCL quickstart + - web3 apps + - Flow basics + - blockchain tutorials + - Emerald Academy + - Flow guides + - smart contracts + - Flow development + - learning resources + - Flow ecosystem +--- + + + + + +Below are some additional tutorials to help you get started with Flow: + +, + author: { + name: 'Flow Blockchain', + profileImage: + 'https://avatars.githubusercontent.com/u/62387156?s=200&v=4', + }, + }, + }, + { + type: 'link', + label: 'Fungible Token Guide', + href: '/build/guides/fungible-token', + description: 'Steps to create, deploy, mint, and transfer fungible tokens on Flow', + customProps: { + icon: , + author: { + name: 'Flow Blockchain', + profileImage: + 'https://avatars.githubusercontent.com/u/62387156?s=200&v=4', + }, + }, + }, + { + type: 'link', + label: 'NFT Guide', + href: 'https://academy.ecdao.org/en/quickstarts/1-non-fungible-token-next', + description: 'A DApp that lets users create an empty collection, mint some pre-loaded NFTs, and transfer them to another account on Flow testnet.', + customProps: { + icon: , + author: { + name: 'Emerald City DAO', + profileImage: + 'https://pbs.twimg.com/profile_images/1687225095557632005/tUCmv8_P_400x400.jpg', + }, + }, + }, + { + type: 'link', + label: 'Walkthrough Guides', + href: '/build/getting-started/fcl-quickstart', + description: 'Longer form guides to help you get started with Flow', + customProps: { + icon: , + author: { + name: 'Flow Blockchain', + profileImage: + 'https://avatars.githubusercontent.com/u/62387156?s=200&v=4', + }, + }, + }, + { + type: 'link', + label: 'Emerald Academy', + href: 'https://academy.ecdao.org/en/quickstarts', + description: 'Quickstart Tutorials for Flow created by Emerald City Dao', + customProps: { + icon: '/images/logos/ea-logo.png', + author: { + name: 'Emerald City DAO', + profileImage: + 'https://pbs.twimg.com/profile_images/1687225095557632005/tUCmv8_P_400x400.jpg', + }, + }, + }, + { + type: 'link', + label: 'Basic Concepts', + href: '/build/basics/blocks', + description: 'Basic Concepts of Flow Blockchain', + customProps: { + icon: , + author: { + name: 'Flow Blockchain', + profileImage: + 'https://avatars.githubusercontent.com/u/62387156?s=200&v=4', + }, + }, + } +]} /> \ No newline at end of file diff --git a/static/markdown/build/flow.md b/static/markdown/build/flow.md new file mode 100644 index 0000000000..cbaca3e7c0 --- /dev/null +++ b/static/markdown/build/flow.md @@ -0,0 +1,165 @@ +--- +title: Why Flow +sidebar_label: Why Flow +sidebar_position: 1 +description: Learn why Flow blockchain is uniquely designed for consumer-scale decentralized applications. Understand Flow's multi-role architecture, native account abstraction, and EVM equivalence. +keywords: + - Flow blockchain + - blockchain scaling + - multi-role architecture + - Cadence language + - EVM equivalence + - account abstraction + - blockchain security + - Flow features + - blockchain trilemma + - Flow EVM + - smart contracts + - Flow token + - blockchain architecture + - decentralization + - consumer apps + - MEV + - miner-extractable value + - maximum extractable value +--- + +# Why Flow + +Flow was built by consumer-facing, onchain app developers to solve the problem of building consumer-facing, onchain apps. Dieter Shirley, Chief Architect of Flow and co-author of the [ERC-721 NFT standard] calls it: + +>**A computer that anyone can use, everyone can trust, and no one can shut down.** + +Much of the protocol design is based on lessons learned from building web3 applications while working at [Dapper Labs], particularly [CryptoKitties] - the first onchain game to reach [widespread popularity]. The game went viral, then [struggled under its own success] when it caused so much traffic that Ethereum network itself was overwhelmed by the load. + +The design of Flow was guided by the need to alleviate this burden while creating the best experience possible for both developers and users. The blockchain network of the future must be able to handle millions of users while upholding the key pillars of decentralization: + +1. Verifiability +1. Predictability/Reliability +1. Equitable Access for All +1. Permissionless Composability +1. Interoperability +1. Security + +Flow solves the [blockchain trilemma] and represents the next generation of blockchain technology. It's built to enable seamless consumer-scale apps without compromising decentralization or user experience and is the chosen blockchain network for [NBA Top Shot], [NFL All Day], [Mattel Creations], and [Disney Pinnacle]. + +## What Makes Flow Unique + +Flow is a fast, decentralized, and developer-friendly blockchain designed to be the foundation for a new generation of games, apps, and the [digital assets] that power them. It is based on a unique [multi-role architecture], and designed to [scale without sharding], allowing for massive improvements in speed and throughput while preserving a developer-friendly, ACID-compliant environment. It natively allows development of smart contracts in the powerful [Cadence] language, and also supports full [Ethereum Virtual Machine (EVM)] equivalence with contracts written in Solidity. + +### Flow Blockchain + +- **Multi-role architecture:** The [multi-role architecture] of Flow allows the network to [scale without sharding] to serve billions of users without reducing the decentralization of consensus and verification. +- **True Fast Finality**: For most other networks, it takes minutes, [a day], or even [a week] to reach hard finality - the point in which a transaction cannot be reversed. On Flow, the median time for finality is [under 10 seconds], without compromising security. +- **Native VRF**: Flow provides [onchain randomness] at the protocol level. Instead of implementing a complex setup and [paying $10+ USD per number], simply call the built-in function. +- **MEV Resistance**: Flow is designed to [ensure equitable access] by resisting MEV. Maximum Extractable Value, also know as Miner-Extractable Value (MEV), is a practice common in other blockchains in which the builder of a block can profit at your expense by manipulating where and how your transaction is included. +- **Consumer Onboarding:** Flow was designed for mainstream consumers, with payment onramps catalyzing a safe and low-friction path from fiat to crypto. +- **EVM Equivalence**: The [Cadence] Virtual Machine (VM) is powerful enough to allow other VMs to run inside of it, almost like a Docker Container. The first one integrated in this way is [EVM] and the EVM RPC API. +- **Efficient Gas Costs**: The Flow blockchain is extremely efficient, allowing apps to do more computation at lower costs. + +### Flow Cadence + +- **Native Account Abstraction**: Flow has protocol-native [account abstraction]. All accounts are smart accounts, supporting scripting, multiple keys, multi-signature transactions, and walletless onboarding with social logins. +- **Gasless Transactions**: Flow has multiple [signing roles] for each transaction. Most notably, the payer can be set independently of the authorizer. In other words, having one account sign a transaction and another pay for that transaction is a built-in feature. +- **Security:** Smart contracts on Flow are natively written in [Cadence], an easier, safer, and more secure programming language for crypto assets and apps. It's the first high-level, [resource-oriented] programming language. +- **Developer Ergonomics:** The Flow network is designed to maximize developer productivity. Examples range from upgradeable smart contracts to built-in logging support to the Flow Emulator. + +### Flow EVM + +- **Speed, Cost, and Compatibility**: Flow EVM can already run all of your audited Solidity contracts at an average of less than 1 cent per transaction ([usually way less!]). Unlike L2 solutions, Flow EVM reaches true finality in seconds - not in [a week]. 😳 +- **Bridge from Other EVM Networks**: You can [bridge] hundreds of assets from dozens of chains to Flow. +- **VM Token Bridge**: Assets can be bridged between Flow Cadence and Flow EVM easily and atomically with the VM token bridge. Assets can even be bridged **and used** in a **single** transaction, allowing full composability between the EVM and Cadence environments. +- **Access to Cadence**: Access Cadence features and contracts from Flow EVM to take advantage of native [VRF], higher computation for lower cost, and any asset on Cadence Flow. You can also build [cross-vm apps] on top of the wagmi/viem/RainbowKit stack, enabling batched transactions and more. +- **EVM Equivalence:** Flow EVM is truly _EVM Equivalent_, not just _EVM Compatible_. It runs exactly the same as EVM mainnet, which means builders won't run into "minor" variances or endless "quirks" when they try to integrate. If it works on Ethereum Mainnet, it will work with Flow EVM. + +## Learning Shortcuts + +To get a complete picture on how to build on Flow, follow the 👈 sidebar top to bottom. This path will give you the most thorough onboarding experience. + +If you like to jump right into the deep end of the pool, take a look below for direct links to advanced topics! + +### Learn Cadence + +[Cadence] is a modern smart contract programming language designed to work with Flow. Learning a new language is an investment, but you'll find that Cadence is safer, more explicit, and less dangerous than other blockchain languages. Plus, it unlocks the full power of the Flow protocol! + +:::tip + +If you're already comfortable with Solidity, be sure to check out how [Cadence] works in our [Guide for Solidity Developers]! + +::: + +### Build with the EVM + +Not ready to take the plunge and learn [Cadence]? Try out "EVM++" by deploying existing [EVM] contracts to see that Flow EVM is faster and cheaper than nearly every other EVM solution without compromising on security. + +Deploying on Flow EVM also gives your Solidity contracts access to many Flow Cadence features, such as native [VRF]. + +### Getting Started with App Development + +The [Getting Started] tutorial covers everything you need to know to build a Flow Cadence application: + +- Setting up your local development environment (it's fast and easy!) +- Deploying and interacting with Flow Cadence contracts +- Building a frontend that can interact with smart contracts written by you, or other developers + +### Core Contracts + +The Flow blockchain implements core functionality using its own smart contract language, [Cadence]. The core functionality is split into a set of contracts, called the [core contracts]: + +- **Fungible Token:** The FungibleToken contract implements the Fungible Token Standard. It is the second contract ever deployed on Flow. +- **Flow Token:** The FlowToken contract defines the FLOW network token. +- **Flow Fees:** The FlowFees contract is where all the collected Flow fees are gathered. +- **Service Account:** The FlowServiceAccount contract tracks transaction fees and deployment permissions and provides convenient methods for Flow Token operations. +- **Staking Table:** The FlowIDTableStaking contract is the central table that manages staked nodes, delegation, and rewards. +- **Epoch Contract:** The FlowEpoch contract is the state machine that manages Epoch phases and emits service events. + +### FLOW Token + +The [FLOW] (or $FLOW) token is the native currency for the Flow network. Developers and users can use FLOW to transact on the network. Developers can integrate FLOW directly into their apps for peer-to-peer payments, service charges, or consumer rewards. FLOW can be held, transferred, or transacted peer-to-peer. + +- To understand more about Flow Token Economics and the FLOW token, read the [Flow Token Economics] guide. +- FLOW tokens are the native Fungible Token on Flow. To learn more about how to work with them in your applications, review the [FLOW] article. + +### Technical Background + +- The [Flow Technical Primer] is a great place to start to understand how Flow works. +- The [Three technical whitepapers] cover the unique innovation behind the Flow blockchain network in-depth. + + + +[ERC-721 NFT standard]: https://github.com/ethereum/eips/issues/721 +[CryptoKitties]: https://www.cryptokitties.co/ +[Dapper Labs]: https://www.dapperlabs.com/ +[struggled under its own success]: https://spectrum.ieee.org/cryptokitties +[blockchain trilemma]: https://coinmarketcap.com/academy/glossary/blockchain-trilemma +[NBA Top Shot]: https://nbatopshot.com/ +[NFL All Day]: https://nflallday.com/ +[Mattel Creations]: https://creations.mattel.com/pages/virtual +[Disney Pinnacle]: https://disneypinnacle.com/ +[digital assets]: https://www.onflow.org/post/flow-blockchain-cadence-programming-language-resources-assets +[widespread popularity]: https://www.cnn.com/style/article/cryptokitty-blockchain/index.html +[multi-role architecture]: https://www.onflow.org/primer +[onchain randomness]: ./advanced-concepts/randomness.md +[paying $10+ USD per number]: https://docs.chain.link/vrf/v2-5/billing +[ensure equitable access]: ./basics/mev-resistance.md +[scale without sharding]: https://www.onflow.org/post/flow-blockchain-multi-node-architecture-advantages +[a day]: https://docs.zksync.io/zk-stack/concepts/finality#finality-on-zksync-era +[a week]: https://docs.optimism.io/stack/rollup/overview#fault-proofs +[usually way less!]: https://evm.flowscan.io/stats +[under 10 seconds]: ./basics/transactions.md#flow +[signing roles]: ./basics/transactions.md#signer-roles +[Cadence]: https://cadence-lang.org/ +[resource-oriented]: https://flow.com/post/resources-programming-ownership +[Ethereum Virtual Machine (EVM)]: https://flow.com/upgrade/crescendo/evm.md +[EVM]: https://flow.com/upgrade/crescendo/evm.md +[Guide for Solidity Developers]: https://cadence-lang.org/docs/solidity-to-cadence +[account abstraction]: https://flow.com/account-abstraction +[bridge]: ../ecosystem/bridges.md +[cross-vm apps]: ../tutorials/cross-vm-apps/index.md +[Getting Started]: ./getting-started/contract-interaction.md +[core contracts]: ./core-contracts/index.md +[FLOW]: ./core-contracts/03-flow-token.md +[Flow Technical Primer]: https://www.onflow.org/primer +[Three technical whitepapers]: https://www.onflow.org/technical-paper +[Flow Token Economics]: https://www.onflow.org/flow-token-economics +[VRF]: ../evm/guides/vrf.md \ No newline at end of file diff --git a/static/markdown/build/getting-started/contract-interaction.md b/static/markdown/build/getting-started/contract-interaction.md new file mode 100644 index 0000000000..c59b52e972 --- /dev/null +++ b/static/markdown/build/getting-started/contract-interaction.md @@ -0,0 +1,151 @@ +--- +sidebar_position: 1 +sidebar_label: Contract Interaction +title: Contract Interaction +description: Learn how to interact with your first smart contract on Flow's Testnet. Understand how to read data from Cadence contracts, execute scripts, and explore the Counter contract example. +keywords: + - smart contracts + - Flow Testnet + - contract interaction + - Cadence scripts + - Counter contract + - contract deployment + - Flow CLI + - contract examples + - blockchain interaction + - Flow development + - contract reading + - script execution + - Flow dApps + - contract tutorial + - Flow quickstart +--- + + + +# Contract Interaction + +In this quickstart guide, you'll interact with your first smart contract on the Flow Testnet. `Testnet` is a public instance of the Flow blockchain designed for experimentation, where you can deploy and invoke smart contracts without incurring any real-world costs. + +Smart contracts on Flow are permanent pieces of code that live on the blockchain. They allow you to encode business logic, define digital assets, and much more. By leveraging smart contracts, you can create decentralized applications (dApps) that are transparent, secure, and open to anyone. + +Flow supports modern smart contracts written in [Cadence], a resource-oriented programming language designed specifically for smart contracts. Cadence focuses on safety and security, making it easier to write robust contracts. Flow also supports traditional [EVM]-compatible smart contracts written in Solidity, allowing developers to port their existing Ethereum contracts to Flow. In this guide, we'll focus on interacting with Cadence smart contracts. + +## Objectives + +After completing this guide, you'll be able to: + +* Read data from a [Cadence] smart contract deployed on Flow. +* Understand how to interact with contracts on Flow's `testnet`. +* Retrieve and display data from a deployed smart contract via scripts. + +In later steps, you'll learn how to: + +* Create a Flow project using the [Flow CLI](../../tools/flow-cli/index.md). +* Add an already-deployed contract to your project with the [Dependency Manager](../../tools/flow-cli/dependency-manager.md). +* Deploy a smart contract locally to the [Flow Emulator](../../tools/emulator/index.md). +* Write and execute transactions to interact with a deployed smart contract. +* Display data from a Cadence smart contract on a React frontend using the [Flow Client Library](../../tools/clients/fcl-js/index.md). + +## Calling a Contract With a Script + +The `Counter` contract exposes a public function named `getCount()` that returns the current value of the counter. We can retrieve its value using a simple script written in the [Cadence] programming language. Scripts in Cadence are read-only operations that allow you to query data from the blockchain without changing any state. + +Here's the script: + +```cadence +import Counter from 0x8a4dce54554b225d + +access(all) +fun main(): Int { + return Counter.getCount() +} +``` + +Let's break down what this script does: + +- **Import Statement**: `import Counter from 0x8a4dce54554b225d` tells the script to use the `Counter` contract deployed at the address `0x8a4dce54554b225d` on the `testnet`. +- **Main Function**: `access(all) fun main(): Int` defines the entry point of the script, which returns an `Int`. +- **Return Statement**: `return Counter.getCount()` calls the `getCount()` function from the `Counter` contract and returns its value. + +### Steps to Execute the Script + +- **Run the Script**: Click the Run button to execute the script. +- **View the Output**: Observe the output returned by the script. You should see the current value of the `count` variable, which is `0` unless it has been modified. + + + +## Understanding the `Counter` Contract + +To fully grasp how the script works, it's important to understand the structure of the `Counter` contract. Below is the source code for the contract: + +```cadence +access(all) contract Counter { + + access(all) var count: Int + + // Event to be emitted when the counter is incremented + access(all) event CounterIncremented(newCount: Int) + + // Event to be emitted when the counter is decremented + access(all) event CounterDecremented(newCount: Int) + + init() { + self.count = 0 + } + + // Public function to increment the counter + access(all) fun increment() { + self.count = self.count + 1 + emit CounterIncremented(newCount: self.count) + } + + // Public function to decrement the counter + access(all) fun decrement() { + self.count = self.count - 1 + emit CounterDecremented(newCount: self.count) + } + + // Public function to get the current count + view access(all) fun getCount(): Int { + return self.count + } +} +``` + +### Breakdown of the Contract + +- **Contract Declaration**: `access(all) contract Counter` declares a new contract named `Counter` that is accessible to everyone. +- **State Variable**: `access(all) var count: Int` declares a public variable `count` of type `Int`. The `access(all)` modifier means that this variable can be read by anyone. +- **Events**: Two events are declared: + - `CounterIncremented(newCount: Int)`: Emitted when the counter is incremented. + - `CounterDecremented(newCount: Int)`: Emitted when the counter is decremented. +- **Initializer**: The `init()` function initializes the `count` variable to `0` when the contract is deployed. +- **Public Functions**: + - `increment()`: Increases the `count` by `1` and emits the `CounterIncremented` event. + - `decrement()`: Decreases the `count` by `1` and emits the `CounterDecremented` event. + - `getCount()`: Returns the current value of `count`. The `view` modifier indicates that this function does not modify the contract's state. + +### Key Points + +- **Public Access**: The `count` variable and the functions `increment()`, `decrement()`, and `getCount()` are all public, allowing anyone to interact with them. +- **State Modification**: The `increment()` and `decrement()` functions modify the state of the contract by changing the value of `count` and emitting events. +- **Read Costs**: Reading data from the blockchain is free on Flow. Executing scripts like the one you ran does not incur any costs. However, transactions that modify state, such as calling `increment()` or `decrement()`, will incur costs and require proper authorization. + +### What's Next? + +In the upcoming tutorials, you'll learn how to: + +- **Modify the Counter**: Invoke the `increment()` and `decrement()` functions to update the `count` value. +- **Deploy Contracts**: Use the Flow CLI to deploy your own smart contracts. +- **Interact with Contracts Locally**: Use the Flow Emulator to test contracts in a local development environment. +- **Build Frontend Applications**: Display data from smart contracts in a React application using the Flow Client Library. + +By understanding the `Counter` contract and how to interact with it, you're building a solid foundation for developing more complex applications on the Flow blockchain. + +Proceed to the next tutorial to learn how to create your own contracts and deploy them live using the Flow CLI. + + + +[Cadence]: https://cadence-lang.org/ +[EVM]: https://flow.com/upgrade/crescendo/evm \ No newline at end of file diff --git a/static/markdown/build/getting-started/fcl-quickstart.md b/static/markdown/build/getting-started/fcl-quickstart.md new file mode 100644 index 0000000000..4c00a4c7f8 --- /dev/null +++ b/static/markdown/build/getting-started/fcl-quickstart.md @@ -0,0 +1,459 @@ +--- +sidebar_position: 3 +sidebar_label: Simple Frontend +title: Building a Simple Frontend with "@onflow/kit" +description: Learn how to build a Next.js frontend application using @onflow/kit to interact with Flow smart contracts. Set up wallet authentication, read contract data, send transactions with kit's React hooks, and display transaction status updates. +keywords: + - '@onflow/kit' + - Next.js + - frontend development + - wallet integration + - smart contract interaction + - Flow emulator + - Dev Wallet + - authentication + - transactions + - blockchain queries + - React development + - dApp development + - Flow development + - web3 frontend +--- + +# Simple Frontend with `@onflow/kit` + +Building on the `Counter` contract you deployed in [Step 1: Contract Interaction] and [Step 2: Local Development], this tutorial shows you how to create a simple Next.js frontend that interacts with the `Counter` smart contract deployed on your local Flow emulator. Instead of using FCL directly, you'll leverage [**@onflow/kit**] to simplify authentication, querying, transactions, and to display real-time transaction status updates using convenient React hooks. + +## Objectives + +After finishing this guide, you will be able to: + +- Wrap your Next.js app with a Flow provider using [**@onflow/kit**]. +- Read data from a Cadence smart contract (`Counter`) using kit's query hook. +- Send a transaction to update the smart contract's state using kit's mutation hook. +- Monitor a transaction's status in real time using kit's transaction hook. +- Authenticate with the Flow blockchain using kit's built-in hooks and the local [Dev Wallet]. + +## Prerequisites + +- Completion of [Step 1: Contract Interaction] and [Step 2: Local Development]. +- [Flow CLI] installed. +- Node.js and npm installed. + +## Setting Up the Next.js App + +Follow these steps to set up your Next.js project and integrate [**@onflow/kit**]. + +### Step 1: Create a New Next.js App + +Run the following command in your project directory: + +```bash +npx create-next-app@latest kit-app-quickstart +``` + +During setup, choose the following options: + +- **Use TypeScript**: **Yes** +- **Use src directory**: **Yes** +- **Use App Router**: **Yes** + +This command creates a new Next.js project named `kit-app-quickstart` inside your current directory. We're generating the frontend in a subdirectory so we can next move it into our existing project structure from the previous steps (you can't create an app in a non-empty directory). + +### Step 2: Move the Next.js App Up a Directory + +Move the contents of the `kit-app-quickstart` directory into your project root. You can use the gui in your editor, or the console. + +:::warning + +You'll want to consolidate both `.gitignore` files, keeping the contents of both in the file that ends up in the root. + +::: + +On macOS/Linux: + +```bash +mv kit-app-quickstart/* . +mv kit-app-quickstart/.* . # To move hidden files (e.g. .env.local) +rm -r kit-app-quickstart +``` + +On Windows (PowerShell): + +```powershell +Move-Item -Path .\kit-app-quickstart\* -Destination . -Force +Move-Item -Path .\kit-app-quickstart\.* -Destination . -Force +Remove-Item -Recurse -Force .\kit-app-quickstart +``` + +**Note:** When moving hidden files (those beginning with a dot) like `.gitignore`, be cautious not to overwrite any important files. + +### Step 3: Install @onflow/kit + +Install the kit library in your project: + +```bash +npm install @onflow/kit +``` + +This library wraps FCL internally and exposes a set of hooks for authentication, querying, sending transactions, and tracking transaction status. + +## Configuring the Local Flow Emulator and Dev Wallet + +:::warning + +You should already have the Flow emulator running from the local development step. If it's not running, you can start it again — but note that restarting the emulator will clear all blockchain state, including any contracts deployed in [Step 2: Local Development]. + +::: + +### Start the Flow Emulator (if not already running) + +Open a new terminal window in your project directory and run: + +```bash +flow emulator start +``` + +This will start the Flow emulator on `http://localhost:8888`. Make sure to keep it running in a separate terminal. + +### Start the Dev Wallet + +In another terminal window, run: + +```bash +flow dev-wallet +``` + +This will start the [Dev Wallet] on `http://localhost:8701`, which you'll use for authentication during development. + +## Wrapping Your App with FlowProvider + +[**@onflow/kit**] provides a `FlowProvider` component that sets up the Flow Client Library configuration. In Next.js using the App Router, add or update your `src/app/layout.tsx` as follows: + +```tsx +// src/app/layout.tsx +'use client'; + + + + +export default function RootLayout({ + children, +}: { + children: React.ReactNode; +}) { + return ( + + + + {children} + + + + ); +} +``` + +This configuration initializes the kit with your local emulator settings and maps contract addresses based on your `flow.json` file. + +For more information on Discovery configurations, refer to the [Wallet Discovery Guide]. + +## Interacting With the Chain + +Now that we've set our provider, lets start interacting with the chain. + +### Querying the Chain + +First, use the kit's [`useFlowQuery`] hook to read the current counter value from the blockchain. + +```jsx + + +const { data, isLoading, error, refetch } = useFlowQuery({ + cadence: ` + import "Counter" + import "NumberFormatter" + + access(all) + fun main(): String { + let count: Int = Counter.getCount() + let formattedCount = NumberFormatter.formatWithCommas(number: count) + return formattedCount + } + `, + enabled: true, +}); + +// Use the count data in your component as needed. +``` + +This script fetches the counter value, formats it via the `NumberFormatter`, and returns the formatted string. + +:::info + +- **Import Syntax:** The imports (`import "Counter"` and `import "NumberFormatter"`) don't include addresses because those are automatically resolved using the `flow.json` file configured in your `FlowProvider`. This keeps your Cadence scripts portable and environment-independent. +- **`enabled` Flag:** This controls whether the query should run automatically. Set it to `true` to run on mount, or pass a condition (e.g. `!!user?.addr`) to delay execution until the user is available. This is useful for queries that depend on authentication or other asynchronous data. + +::: + +### Sending a Transaction + +Next, use the kit's [`useFlowMutate`] hook to send a transaction that increments the counter. + +```jsx + + +const { + mutate: increment, + isPending: txPending, + data: txId, + error: txError, +} = useFlowMutate(); + +const handleIncrement = () => { + increment({ + cadence: ` + import "Counter" + + transaction { + prepare(acct: &Account) { + // Authorization handled via wallet + } + execute { + Counter.increment() + let newCount = Counter.getCount() + log("New count after incrementing: ".concat(newCount.toString())) + } + } + `, + }); +}; +``` + +#### Explanation + +This sends a Cadence transaction to the blockchain using the `mutate` function. The transaction imports the `Counter` contract and calls its `increment` function. Authorization is handled automatically by the connected wallet during the `prepare` phase. Once submitted, the returned `txId` can be used to track the transaction's status in real time. + +### Subscribing to Transaction Status + +Use the kit's [`useFlowTransaction`] hook to monitor and display the transaction status in real time. + +```jsx +const { transactionStatus, error: txStatusError } = useFlowTransaction( + txId || '', +); + +useEffect(() => { + if (txId && transactionStatus?.status === 3) { + refetch(); + } +}, [transactionStatus?.status, txId, refetch]); + +// You can then use transactionStatus (for example, its statusString) to show updates. +``` + +#### Explanation: + +- `useFlowTransaction(txId)` subscribes to real-time updates about a transaction's lifecycle using the transaction ID. +- `transactionStatus.status` is a numeric code representing the state of the transaction: + - `0`: **Unknown** – The transaction status is not yet known. + - `1`: **Pending** – The transaction has been submitted and is waiting to be included in a block. + - `2`: **Finalized** – The transaction has been included in a block, but not yet executed. + - `3`: **Executed** – The transaction code has run successfully, but the result has not yet been sealed. + - `4`: **Sealed** – The transaction is fully complete, included in a block, and now immutable on-chain. +- We recommend calling `refetch()` when the status reaches **3 (Executed)** to update your UI more quickly after the transaction runs, rather than waiting for sealing. +- The `statusString` property gives a human-readable version of the current status you can display in the UI. + +#### Why `Executed` is Recommended for UI Updates: + +Waiting for `Sealed` provides full on-chain confirmation but can introduce a delay — especially in local or test environments. Since most transactions (like incrementing a counter) don't require strong finality guarantees, you can typically refetch data once the transaction reaches `Executed` for a faster, more responsive user experience. + +However: + +- If you're dealing with critical state changes (e.g., token transfers or contract deployments), prefer waiting for `Sealed`. +- For non-critical UI updates, `Executed` is usually safe and significantly improves perceived performance. + +### Integrating Authentication and Building the Complete UI + +Finally, integrate the query, mutation, and transaction status hooks with authentication using `useCurrentFlowUser`. Combine all parts to build the complete page. + +```jsx +// src/app/page.js + +"use client"; + + +import { + useFlowQuery, + useFlowMutate, + useFlowTransaction, + useCurrentFlowUser, +} from "@onflow/kit"; + +export default function Home() { + const { user, authenticate, unauthenticate } = useCurrentFlowUser(); + const [lastTxId, setLastTxId] = useState(); + + const { data, isLoading, error, refetch } = useFlowQuery({ + cadence: ` + import "Counter" + import "NumberFormatter" + + access(all) + fun main(): String { + let count: Int = Counter.getCount() + let formattedCount = NumberFormatter.formatWithCommas(number: count) + return formattedCount + } + `, + enabled: true, + }); + + const { + mutate: increment, + isPending: txPending, + data: txId, + error: txError, + } = useFlowMutate(); + + const { transactionStatus, error: txStatusError } = useFlowTransaction( + txId || "", + ); + + useEffect(() => { + if (txId && transactionStatus?.status === 4) { + refetch(); + } + }, [transactionStatus?.status, txId, refetch]); + + const handleIncrement = () => { + increment({ + cadence: ` + import "Counter" + + transaction { + prepare(acct: &Account) { + // Authorization handled via wallet + } + execute { + Counter.increment() + let newCount = Counter.getCount() + log("New count after incrementing: ".concat(newCount.toString())) + } + } + `, + }); + }; + + return ( +
    +

    @onflow/kit App Quickstart

    + + {isLoading ? ( +

    Loading count...

    + ) : error ? ( +

    Error fetching count: {error.message}

    + ) : ( +
    +

    Count: {data as string}

    +
    + )} + + {user.loggedIn ? ( +
    +

    Address: {user.addr}

    + + + +
    + Latest Transaction Status:{" "} + {transactionStatus?.statusString || "No transaction yet"} +
    + + {txError &&

    Error sending transaction: {txError.message}

    } + + {lastTxId && ( +
    +

    Transaction Status

    + {transactionStatus ? ( +

    Status: {transactionStatus.statusString}

    + ) : ( +

    Waiting for status update...

    + )} + {txStatusError &&

    Error: {txStatusError.message}

    } +
    + )} +
    + ) : ( + + )} +
    + ); +} +``` + +In this complete page: + +- **Step 1** queries the counter value. +- **Step 2** sends a transaction to increment the counter and stores the transaction ID. +- **Step 3** subscribes to transaction status updates using the stored transaction ID and uses a `useEffect` hook to automatically refetch the updated count when the transaction is sealed (status code 4). +- **Step 4** integrates authentication via `useCurrentFlowUser` and combines all the pieces into a single user interface. + +:::tip + +In this tutorial, we inlined Cadence code for simplicity. For real projects, we recommend storing Cadence in separate `.cdc` files, using the [Cadence VSCode extension], and importing them with the [`flow-cadence-plugin`](https://github.com/chasefleming/flow-cadence-plugin) for Next.js or Webpack projects. + +::: + +## Running the App + +Start your development server: + +```bash +npm run dev +``` + +:::warning + +If you have the Flow wallet browser extension installed, you might automatically log into the app. Normally this is desirable for your users, but you don't want to use it here. + +Log out, and log back in selecting the Dev Wallet instead of the Flow Wallet. + +::: + +Then visit [http://localhost:3000](http://localhost:3000) in your browser. You should see: + +- The current counter value displayed (formatted with commas using `NumberFormatter`). +- A **Log In** button that launches the kit Discovery UI with your local [Dev Wallet]. +- Once logged in, your account address appears with options to **Log Out** and **Increment Count**. +- When you click **Increment Count**, the transaction is sent; its status updates are displayed in real time below the action buttons, and once the transaction is sealed, the updated count is automatically fetched. + +## Wrapping Up + +By following these steps, you've built a simple Next.js dApp that interacts with a Flow smart contract using [**@onflow/kit**]. In this guide you learned how to: + +- Wrap your application in a `FlowProvider` to configure blockchain connectivity. +- Use kit hooks such as `useFlowQuery`, `useFlowMutate`, `useFlowTransaction`, and `useCurrentFlowUser` to manage authentication, query on-chain data, submit transactions, and monitor their status. +- Integrate with the local Flow emulator and Dev Wallet for a fully functional development setup. + +For additional details and advanced usage, refer to the [@onflow/kit documentation] and other Flow developer resources. + +[Step 1: Contract Interaction]: contract-interaction.md +[Step 2: Local Development]: ./flow-cli.md +[Wallet Discovery Guide]: ../../tools/clients/fcl-js/discovery.md +[`useFlowQuery`]: ../../tools/kit#useflowquery +[`useFlowMutate`]: ../../tools/kit#useflowmutate +[Dev Wallet]: ../../tools/flow-dev-wallet +[@onflow/kit documentation]: ../../tools/kit/index.md +[**@onflow/kit**]: ../../tools/kit/index.md +[Flow CLI]: ../../tools/flow-cli/install.md +[Cadence VSCode extension]: ../../tools/vscode-extension \ No newline at end of file diff --git a/static/markdown/build/getting-started/flow-cli.md b/static/markdown/build/getting-started/flow-cli.md new file mode 100644 index 0000000000..de55c71eb1 --- /dev/null +++ b/static/markdown/build/getting-started/flow-cli.md @@ -0,0 +1,412 @@ +--- +sidebar_position: 2 +sidebar_label: Local Development +title: Local Development with Flow CLI +description: Learn how to use the Flow Command Line Interface (CLI) for local blockchain development. Create projects, run tests, manage dependencies, deploy contracts, and interact with the Flow emulator. +keywords: + - Flow CLI + - local development + - Flow emulator + - smart contracts + - contract deployment + - dependency management + - blockchain testing + - Flow projects + - contract testing + - script execution + - transactions + - Flow tools + - development environment + - contract management + - blockchain development +--- + +# Local Development + +The [Flow Command Line Interface] (CLI) is a set of tools that developers can use to interact with the Flow blockchain by managing accounts, sending transactions, deploying smart contracts, running the emulator, and more. This quickstart will get you familiar with its main concepts and functionality. + +## Objectives + +After completing this guide, you'll be able to: + +- Create a Flow project using the [Flow Command Line Interface] +- Run tests for a smart contract +- Add an already-deployed contract to your project with the [Dependency Manager] +- Deploy a smart contract locally to the Flow Emulator +- Write and execute scripts to interact with a deployed smart contract + +## Installation + +The first thing you'll need to do is install the Flow CLI. If you have [homebrew] installed you can run: + +```zsh +brew install flow-cli +``` + +For other ways of installing, please refer to the [installation guide]. + +## Creating a New Project + +To create a new project, navigate to the directory where you want to create your project and run: + +```zsh +flow init +``` + +Upon running this command, you'll be prompted to enter a project name. Enter a name and press `Enter`. + +You'll also be asked if you'd like to install any core contracts (such as `FungibleToken`, `NonFungibleToken`, etc.) using the [Dependency Manager](../../tools/flow-cli/dependency-manager.md). For this tutorial, you can select `No`. + +The `init` command will create a new directory with the project name and the following files: + +- `flow.json`: This file contains the configuration for your project. +- `emulator-account.pkey`: This file contains the private key for the default emulator account. +- `flow.json`: This file contains the configuration for your project. +- `cadence/`: This directory contains your Cadence code. Inside there are subdirectories for contracts, scripts, transactions, and tests. + +Inside the `cadence/contracts` directory, you'll find a `Counter.cdc` file. This is the same as the `Counter` contract in the previous step. + +Next, `cd` into your new project directory. + +:::info + +For additional details on how `flow.json` is configured, review the [configuration docs]. + +::: + +### Running the Tests + +To run the example test for the `Counter` contract located in `cadence/tests`, you can run: + +```zsh +flow test +``` + +:::tip + +For a more detailed guide on running Cadence tests, check out the [tests documentation](../../tools/flow-cli/tests.md). + +::: + +## Deploying the Contract to Emulator + +The emulator is a local version of the Flow blockchain that you can use to test your contracts and scripts. It's a great way to develop and test your contracts locally - before you try them on the `testnet` or `mainnet`. + +Before we deploy, let's open a new terminal window and run the emulator. From the root of your project directory, where your `emulator-account.pkey` and `flow.json` files are located, run: + +```zsh +flow emulator start +``` + +Your emulator will now be running. + +### Deploying a Contract + +#### Creating an Account + +When you created a project you'll see that a `Counter` contract was added to your `flow.json` configuration file, but it's not set up for deployment yet. We could deploy it to the automatically created `emulator-account`, but for this example lets also create a new account on the emulator to deploy it to. + +:::info + +**Reminder**: On Flow Cadence, contracts are deployed to the storage of the account that deploys them. + +::: + +Leave your emulator running, and open a second terminal. Run the following command: + +```zsh +flow accounts create +``` + +When prompted, give your account the name `test-account` and select `Emulator` as the network. You'll now see this account in your `flow.json`. + +#### Configuring the Deployment + +To deploy the `Counter` contract to the emulator, you'll need to add it to your project configuration. You can do this by running: + +```zsh +flow config add deployment +``` + +First, pick `emulator` as the network for deployment. Select your `test-account` as the account to deploy to. Next, pick `Counter` as the contract to deploy. Finally, choose `no` when asked if you wish to deploy more contracts. + +#### Deploying the Contract + +To deploy the `Counter` contract to the emulator, run: + +```zsh +flow project deploy +``` + +You'll see something similar to: + +```zsh +Deploying 1 contracts for accounts: test-account + +Counter -> 0x179b6b1cb6755e31 (a98c155fe7afc8eb2af5551748759b08a80a0ae85d1b09f92f1afc293c61ca98) + +🎉 All contracts deployed successfully +``` + +That's it! You've just deployed your first contract to the Flow Emulator. + +::warning + +You can't deploy the same contract to multiple accounts at the same time with the `deploy` command. If you've experimented with the above, you may need to manually edit the `"deployments"` property in `flow.json` to remove extra deployments. + +::: + +## Running Scripts + +Scripts are used to read data from the Flow blockchain. There is no state modification. In our case, we are going to read a greeting from the `HelloWorld` contract. + +If we wanted to generate a new script, we could run: + +```zsh +flow generate script ScriptName +``` + +But the default project already has a `GetCounter` script for reading the count of the `Counter` contract. Open `cadence/scripts/GetCounter.cdc` in your editor to see the script. + +To run the script, you can run: + +```zsh +flow scripts execute cadence/scripts/GetCounter.cdc +``` + +You should see zero as the result since the `Counter` contract initializes the count to zero and we haven't run any transactions to increment it. + +```zsh +Result: 0 +``` + +:::tip + +If you'll like to learn more about writing scripts, please check out the docs for [basic scripts]. + +::: + +## Executing Transactions + +Transactions are used to modify the state of the blockchain. In our case, we want to increment the count of the `Counter` contract. Luckily, we already have a transaction for that in the project that was generated for us. Open `cadence/transactions/IncrementCounter.cdc` in your editor to see the transaction. + +To run the transaction, you can run: + +```zsh +flow transactions send cadence/transactions/IncrementCounter.cdc +``` + +By default, this uses the `emulator-account` to sign the transaction and the emulator network. If you want to use your `test-account` account, you can specify the `--signer` flag with the account name. + +```zsh +Transaction ID: 9cc7ac4d3d5239016965aba89b9692d3401a48a090d1ad1a8d9ef9cfca685e6e + +Block ID b8537860b0fc9ca8b3195b121e762502f9a220874b605d6a810998e8b62321a3 +Block Height 3 +Status ✅ SEALED +ID 9cc7ac4d3d5239016965aba89b9692d3401a48a090d1ad1a8d9ef9cfca685e6e +Payer f8d6e0586b0a20c7 +Authorizers [f8d6e0586b0a20c7] + +Proposal Key: + Address f8d6e0586b0a20c7 + Index 0 + Sequence 1 + +No Payload Signatures + +Envelope Signature 0: f8d6e0586b0a20c7 +Signatures (minimized, use --include signatures) + +Events: + Index 0 + Type A.179b6b1cb6755e31.Counter.CounterIncremented + Tx ID 9cc7ac4d3d5239016965aba89b9692d3401a48a090d1ad1a8d9ef9cfca685e6e + Values + - newCount (Int): 1 + +Code (hidden, use --include code) + +Payload (hidden, use --include payload) + +Fee Events (hidden, use --include fee-events) +``` + +Run the script to check the counter again. You'll see that it has incremented: + +```zsh +Result: 0 +``` + +:::tip + +If you want to learn more about writing transactions, please read the docs for [basic transactions]. + +::: + +## Installing & Interacting With External Dependencies + +In addition to creating your own contracts, you can also install contracts that have already been deployed to the network by using the [Dependency Manager]. This is useful for interacting with contracts that are part of the Flow ecosystem or that have been deployed by other developers. + +For example, let's say we want to format the result of our `GetCounter` script so that we display the number with commas if it's greater than 999. To do that we can install a contract called [`NumberFormatter`] from `testnet` that has a function to format numbers. + +To grab it, run: + +```zsh +flow dependencies install testnet://8a4dce54554b225d.NumberFormatter +``` + +When prompted for the account to deploy the contract to, select any account and ignore the prompt for an alias. This is if you wanted to configure a `mainnet` address for the contract. + +This will add the `NumberFormatter` contract and any of its dependencies to an `imports` directory in your project. It will also add any dependencies to your `flow.json` file. In addition, the prompt will configure the deployment of the contract to the account you selected. Make sure to select the `emulator-account` account to deploy the contract to the emulator. + +You'll then see the `NumberFormatter` in your deployments for emulator in your `flow.json`. + +Now we can deploy the `NumberFormatter` contract to the emulator by running: + +```zsh +flow project deploy +``` + +```zsh +Deploying 2 contracts for accounts: test-account + +Counter -> 0x179b6b1cb6755e31 [skipping, no changes found] +NumberFormatter -> 0x179b6b1cb6755e31 (f8ce6dfa1771c7bad216e72e7f7aac7f1987c4261d425d27e689c701b9ec69cd) + +🎉 All contracts deployed successfully +``` + +Now that we have the `NumberFormatter` contract deployed, we can update our `GetCounter` script to format the result. Open `cadence/scripts/GetCounter.cdc` and update it to use the following code: + +```cadence +import "Counter" +import "NumberFormatter" + +access(all) +fun main(): String { + // Retrieve the count from the Counter contract + let count: Int = Counter.getCount() + + // Format the count using NumberFormatter + let formattedCount = NumberFormatter.formatWithCommas(number: count) + + // Return the formatted count + return formattedCount +} +``` + +The things to note here are: + +- We import the `NumberFormatter` contract. +- We call the `formatWithCommas` function from the `NumberFormatter` contract to format the count. +- We return the formatted count as a `String`. + +:::warning + +Do **not** simply add a new file. Use `flow generate transaction IncrementBy1000.cdc` + +::: + +Add a new transaction called `IncrementBy1000.cdc`. Fill it with a variant of `IncrementCounter.cdc` that instead loops through the `increment` function 1000 times. + +```cadence +import "Counter" + +transaction { + + prepare(acct: &Account) { + // Authorizes the transaction + } + + execute { + // Increment the counter 1000 times + var i = 0 + while i < 1000 { + Counter.increment() + i = i + 1 + } + + // Retrieve the new count and log it + let newCount = Counter.getCount() + log("New count after incrementing: ".concat(newCount.toString())) + } +} +``` + +Try out your new transaction with: + +```zsh + +``` + +Finally, to test the updated script, you can run: + +```zsh +flow scripts execute cadence/scripts/GetCounter.cdc +``` + +You should now see the result with commas. + +:::info + +If you're a Solidity developer, did you catch what we just did here? We updated the features and functionality available in the smart contract **without updating the contract itself!** + +Even more importantly, we did this **without needing access or permission.** You can use the power of composability in Flow Cadence to add new features to contracts you don't own. + +::: + +## More + +If you want to continue on generating your own contracts, you can also use the the `generate` subcommand to create a new contract file. See more in the [`generate` documentation]. + +After that, it's easy to add your contract to your project configuration using the Flow CLI [`config` commands]. + +## Conclusion + +In this tutorial, we've accomplished all of our learning objectives: + +1. ✅ Created a Flow project using the Flow CLI + + - Initialized a new project with `flow init` + - Set up the project structure with contracts, scripts, and tests + - Configured the project using `flow.json` + +2. ✅ Ran tests for a smart contract + + - Executed the example test for the `Counter` contract + - Learned about the testing capabilities of the Flow CLI + +3. ✅ Added an already-deployed contract to your project + + - Used the Dependency Manager to install the `NumberFormatter` contract + - Configured the contract deployment in `flow.json` + - Deployed the contract to the emulator + +4. ✅ Deployed a smart contract locally to the Flow Emulator + + - Started the Flow Emulator + - Created a test account + - Deployed the `Counter` contract to the emulator + - Deployed the `NumberFormatter` contract + +5. ✅ Wrote and executed scripts to interact with deployed contracts + - Created and executed the `GetCounter` script + - Modified the script to use the `NumberFormatter` contract + - Created and executed the `IncrementBy1000` transaction + - Demonstrated the power of Cadence's composability + + + +[Flow Command Line Interface]: ../../tools/flow-cli/index.md +[Cadence]: https://cadence-lang.org/ +[configuration docs]: ../../tools/flow-cli/flow.json/configuration.md +[homebrew]: https://brew.sh/ +[installation guide]: ../../tools/flow-cli/install +[0xa1296b1e2e90ca5b]: https://contractbrowser.com/A.9dca641e9a4b691b.HelloWorld +[Dependency Manager]: ../../tools/flow-cli/dependency-manager +[basic scripts]: ../basics/scripts.md +[basic transactions]: ../basics/transactions.md +[`generate` documentation]: ../../tools/flow-cli/boilerplate.md +[`config` commands]: ../../tools/flow-cli/flow.json/manage-configuration.md +[`NumberFormatter`]: https://contractbrowser.com/A.8a4dce54554b225d.NumberFormatter \ No newline at end of file diff --git a/static/markdown/build/guides/account-linking-with-dapper.md b/static/markdown/build/guides/account-linking-with-dapper.md new file mode 100644 index 0000000000..c46df32349 --- /dev/null +++ b/static/markdown/build/guides/account-linking-with-dapper.md @@ -0,0 +1,768 @@ +--- +title: Account Linking With NBA Top Shot +description: Use Account Linking between the Dapper Wallet and Flow Wallet to effortlessly use NBA Top Shot Moments in your app. +sidebar_position: 5 +sidebar_custom_props: + icon: ⛓️ +keywords: + - NBA Top Shot + - Dapper Wallet + - account linking + - Flow wallet + - NFT integration + - Moments NFTs + - wallet connection + - Flow dApp + - blockchain integration + - smart contracts + - wallet management + - NFT display + - Flow development + - wallet interoperability + - asset management +--- + +# Account Linking With NBA Top Shot + +[Account Linking] is a powerful Flow feature that allows users to connect their wallets, enabling linked wallets to view and manage assets in one wallet with another. This feature helps reduce or even eliminate the challenges posed by other account abstraction solutions, which often lead to multiple isolated wallets and fragmented assets. + +In this tutorial, you'll build a [simple onchain app] that allows users to sign into your app with their Flow wallet and view [NBA Top Shot] Moments that reside in their [Dapper Wallet] - without those users needing to sign in with Dapper. + +## Objectives + +After completing this guide, you'll be able to: + +* Pull your users' NBA Top Shot Moments into your Flow app without needing to transfer them out of their Dapper wallet +* Retrieve and list all NFT collections in any child wallet linked to a given Flow address +* Write a [Cadence] script to iterate through the storage of a Flow wallet to find NFT collections +* Run Cadence Scripts from the frontend + +## Prerequisites + +### Next.js and Modern Frontend Development + +This tutorial uses [Next.js]. You don't need to be an expert, but it's helpful to be comfortable with development using a current React framework. You'll be on your own to select and use a package manager, manage Node versions, and other frontend environment tasks. If you don't have your own preference, you can just follow along with us and use [Yarn]. + +### Flow Wallet + +You'll need a [Flow Wallet], but you don't need to deposit any funds. + +## Moments NFTs + +You'll need a [Dapper Wallet] containing some Moments NFTs, such as [NBA Top Shot] Moments. + +## Getting Started + +This tutorial will use a [Next.js] project as the foundation of the frontend. Create a new project with: + +```zsh +npx create-next-app@latest +``` + +We will be using TypeScript and the App Router, in this tutorial. + +Open your new project in the editor of your choice, install dependencies, and run the project. + +```zsh +yarn install +yarn run dev +``` + +If everything is working properly, you'll be able to navigate to `localhost:3000` and see the default [Next.js] page. + +## Flow Cadence Setup + +You'll need a few more dependencies to efficiently work with Cadence inside of your app. + +### Flow CLI and Types + +The [Flow CLI] contains a number of command-line tools for interacting with the Flow ecosystem. If you don't already have it installed, you can add it with Brew (or using [other installation methods]): + +```zsh +brew install flow-cli +``` + +Once it's installed, you'll need to initialize Flow in your Next.js project. From the root, run: + +```zsh +flow init --config-only +``` + +The `--config-only` flag [initializes a project] with the just the config file. This allows the Flow CLI to interact with your project without adding any unnecessary files. + +Next, you'll need to do a little bit of config work so that your project knows how to read Cadence files. Install the Flow Cadence Plugin: + +```zsh +yarn add flow-cadence-plugin --dev +``` + +Finally, open `next.config.ts` and update it to use the plugin with Raw Loader: + +```tsx +// next.config.ts + + + +const nextConfig: NextConfig = { + webpack: (config) => { + config.plugins.push(new FlowCadencePlugin()) + + return config; + }, +}; + +export default nextConfig; +``` + +## Frontend Setup + +We'll use the Flow Client Library [FCL] to manage blockchain interaction from the frontend. It's similar to viem, ethers, or web3.js, but works with the Flow blockchain and transactions and scripts written in Cadence. + +```zsh +yarn add @onflow/fcl +``` + +Go ahead and install `dotenv` as well: + +``` +yarn add dotenv +``` + +### Provider Setup + +A fair amount of boilerplate code is needed to set up your provider. We'll provide it, but since it's not the purpose of this tutorial, we'll be brief on explanations. For more details, check out the [App Quickstart Guide]. + +Add `app/providers/AuthProvider.tsx`: + +```tsx +'use client'; +/* eslint-disable @typescript-eslint/no-explicit-any */ + + + + +interface State { + user: any; + loggedIn: any; + logIn: any; + logOut: any; +} + +const AuthContext = createContext(undefined); + +interface AuthProviderProps { + children: ReactNode; +} + +const AuthProvider: React.FC = ({ children }) => { + const [user, loggedIn, logIn, logOut] = useCurrentUser(); + + return ( + + {children} + + ); +}; + +export default AuthProvider; + +export const useAuth = (): State => { + const context = useContext(AuthContext); + + if (context === undefined) { + throw new Error('useAuth must be used within a AuthProvider'); + } + + return context; +}; +``` + +Then, add `app/hooks/use-current-user-hook.tsx`: + +```tsx + + + +export default function useCurrentUser() { + const [user, setUser] = useState({ addr: null }); + + const logIn = () => { + fcl.authenticate(); + }; + + const logOut = () => { + fcl.unauthenticate(); + }; + + useEffect(() => { + fcl.currentUser().subscribe(setUser); + }, []); + + return {user, loggedIn: user?.addr != null, logIn, logOut}; +} +``` + +## .env + +Add a `.env` to the root and fill it with: + +```text +NEXT_PUBLIC_ACCESS_NODE_API="https://rest-mainnet.onflow.org" +NEXT_PUBLIC_FLOW_NETWORK="mainnet" +NEXT_PUBLIC_WALLETCONNECT_ID= +``` + +:::warning + +Don't forget to replace `` with your own [Wallet Connect] app id! + +::: + +### Implement the Provider and Flow Config + +Finally, open `layout.tsx`. Start by importing Flow dependencies and the AuthProvider: + +```tsx + + + + +``` + +Then add your Flow config: + +```tsx +fcl.config({ + "discovery.wallet": "https://fcl-discovery.onflow.org/authn", + 'accessNode.api': process.env.NEXT_PUBLIC_ACCESS_NODE_API, + 'flow.network': process.env.NEXT_PUBLIC_FLOW_NETWORK, + 'walletconnect.projectId': process.env.NEXT_PUBLIC_WALLETCONNECT_ID +}).load({ flowJSON }); +``` + +:::warning + +We're going to force some things client side to get this proof-of-concept working quickly. Use Next.js best practices for a production app. + +::: + +Add a `'use client';` directive to the top of the file and **delete** the import for Metadata and fonts, as well as the code related to them. + +Finally, update the `` to remove the font references and suppress hydration warnings: + +```tsx + +``` + +Your code should be: + +```tsx +// layout.tsx +'use client'; +import "./globals.css"; + + + + + +fcl.config({ + "discovery.wallet": "https://fcl-discovery.onflow.org/authn", + 'accessNode.api': process.env.NEXT_PUBLIC_ACCESS_NODE_API, + 'flow.network': process.env.NEXT_PUBLIC_FLOW_NETWORK, + 'walletconnect.projectId': process.env.NEXT_PUBLIC_WALLETCONNECT_ID +}).load({ flowJSON }); + +export default function RootLayout({ + children, +}: { + children: React.ReactNode; +}) { + return ( + + + + {children} + + + + ); +} +``` + +### Add the Connect Button + +Open `page.tsx` and clean up the demo code leaving only the `
    ` block: + +```tsx + + +export default function Home() { + return ( +
    +
    +
    TODO
    +
    +
    + ); +} +``` + +Add a `'use client';` directive, import the `useAuth` hook and instantiate it in the `Home` function: + +```tsx +'use client'; + +``` + +```tsx +const { user, loggedIn, logIn, logOut } = useAuth(); +``` + +Then add a button in the `
    ` to handle logging in or out: + +```tsx +
    +
    Welcome
    + +
    +``` + +## Testing Pass + +Run the app: + +```zsh +yarn dev +``` + +You'll see your `Log In` button in the middle of the window. + +![Welcome](welcome.png) + +Click the button and log in with your Flow wallet. + +![Flow Wallet](flow-wallet.png) + +## Account Linking + +Now that your app is set up, you can make use of [Account Linking] to to pull your NFTs from your Dapper Wallet, through your Flow Wallet, and into the app. + +### Setting Up Account Linking + +If you haven't yet, you'll need to [link your Dapper Wallet] to your Flow Wallet. + +:::warning + +The Dapper Wallet requires that you complete KYC before you can use Account Linking. While this may frustrate some members of the community, it makes it much easier for app developers to design onboarding rewards and bonuses that are less farmable. + +::: + +### Discovering the NFTs with a Script + +With your accounts linked, your Flow Wallet now has a set of capabilities related to your Dapper Wallet and it's permitted to use those to view and even manipulate those NFTs and assets. + +Before you can add a script that can handle this, you'll need to import the `HybridCustody` contract using the [Flow Dependency Manager]: + +```zsh +flow dependencies install mainnet://d8a7e05a7ac670c0.HybridCustody +``` + +Choose `none` to skip deploying on the `emulator` and skip adding testnet aliases. There's no point, these NFTs are on mainnet! + +You'll get a complete summary from the Dependency Manager: + +```zsh +📝 Dependency Manager Actions Summary + +🗃️ File System Actions: +✅️ Contract HybridCustody from d8a7e05a7ac670c0 on mainnet installed +✅️ Contract MetadataViews from 1d7e57aa55817448 on mainnet installed +✅️ Contract FungibleToken from f233dcee88fe0abe on mainnet installed +✅️ Contract ViewResolver from 1d7e57aa55817448 on mainnet installed +✅️ Contract Burner from f233dcee88fe0abe on mainnet installed +✅️ Contract NonFungibleToken from 1d7e57aa55817448 on mainnet installed +✅️ Contract CapabilityFactory from d8a7e05a7ac670c0 on mainnet installed +✅️ Contract CapabilityDelegator from d8a7e05a7ac670c0 on mainnet installed +✅️ Contract CapabilityFilter from d8a7e05a7ac670c0 on mainnet installed + +💾 State Updates: +✅ HybridCustody added to emulator deployments +✅ Alias added for HybridCustody on mainnet +✅ HybridCustody added to flow.json +✅ MetadataViews added to flow.json +✅ FungibleToken added to flow.json +✅ ViewResolver added to flow.json +✅ Burner added to flow.json +✅ NonFungibleToken added to flow.json +✅ CapabilityFactory added to emulator deployments +✅ Alias added for CapabilityFactory on mainnet +✅ CapabilityFactory added to flow.json +✅ CapabilityDelegator added to emulator deployments +✅ Alias added for CapabilityDelegator on mainnet +✅ CapabilityDelegator added to flow.json +✅ CapabilityFilter added to emulator deployments +✅ Alias added for CapabilityFilter on mainnet +✅ CapabilityFilter added to flow.json +``` + +Add `app/cadence/scripts/FetchNFTsFromLinkedAccts.cdc`. In it, add this script. Review the inline comments to see what each step is doing: + +```cadence +import "HybridCustody" +import "NonFungibleToken" +import "MetadataViews" + +// This script iterates through a parent's child accounts, +// identifies private paths with an accessible NonFungibleToken.Provider, and returns the corresponding typeIds + +access(all) fun main(addr: Address): AnyStruct { + let manager = getAuthAccount(addr).storage.borrow(from: HybridCustody.ManagerStoragePath) + ?? panic ("manager does not exist") + + var typeIdsWithProvider: {Address: [String]} = {} + var nftViews: {Address: {UInt64: MetadataViews.Display}} = {} + + let providerType = Type() + let collectionType: Type = Type<@{NonFungibleToken.CollectionPublic}>() + + for address in manager.getChildAddresses() { + let acct = getAuthAccount(address) + let foundTypes: [String] = [] + let views: {UInt64: MetadataViews.Display} = {} + let childAcct = manager.borrowAccount(addr: address) ?? panic("child account not found") + + // Iterate through storage paths to find NFTs that are controlled by the parent account + // To just find NFTs, check if thing stored is nft collection and borrow it as NFT collection and get IDs + for s in acct.storage.storagePaths { + // Iterate through capabilities + for c in acct.capabilities.storage.getControllers(forPath: s) { + if !c.borrowType.isSubtype(of: providerType){ + // If this doen't have providerType, it's not an NFT collection + continue + } + + // We're dealing with a Collection but we need to check if accessible from the parent account + if let cap: Capability = childAcct.getCapability(controllerID: c.capabilityID, type: providerType) { // Part 1 + let providerCap = cap as! Capability<&{NonFungibleToken.Provider}> + + if !providerCap.check(){ + // If I don't have access to control the account, skip it. + // Disable this check to do something else. + // + continue + } + + foundTypes.append(cap.borrow<&AnyResource>()!.getType().identifier) + typeIdsWithProvider[address] = foundTypes + // Don't need to keep looking at capabilities, we can control NFT from parent account + break + } + } + } + + // Iterate storage, check if typeIdsWithProvider contains the typeId, if so, add to views + acct.storage.forEachStored(fun (path: StoragePath, type: Type): Bool { + + if typeIdsWithProvider[address] == nil { + return true + } + + for key in typeIdsWithProvider.keys { + for idx, value in typeIdsWithProvider[key]! { + let value = typeIdsWithProvider[key]! + + if value[idx] != type.identifier { + continue + } else { + if type.isInstance(collectionType) { + continue + } + if let collection = acct.storage.borrow<&{NonFungibleToken.CollectionPublic}>(from: path) { + // Iterate over IDs & resolve the Display view + for id in collection.getIDs() { + let nft = collection.borrowNFT(id)! + if let display = nft.resolveView(Type())! as? MetadataViews.Display { + views.insert(key: id, display) + } + } + } + continue + } + } + } + return true + }) + nftViews[address] = views + } + return nftViews +} +``` + +:::warning + +The above script is a relatively naive implementation. For production, you'll want to filter for only the collections you care about, and you will eventually need to add handling for very large collections in a wallet. + +::: + +### Running the Script and Displaying the NFTs + +Add a component in `app/components` called `DisplayLinkedNFTs.cdc`. + +In it, import dependencies from React and FCL, as well as the script you just added: + +```tsx + + + + + +``` + +As we're using TypeScript, you should add some types as well to manage the data from the NFTs nicely. For now, just add them to this file: + +```typescript +type Thumbnail = { + url: string; +}; + +type Moment = { + name: string; + description: string; + thumbnail: Thumbnail; +}; + +type MomentsData = { + [momentId: string]: Moment; +}; + +type ApiResponse = { + [address: string]: MomentsData; +}; + +interface AddressDisplayProps { + address: string; +} +``` + +Then, add the function for the component: + +```tsx +const DisplayLinkedNFTs: React.FC = ({ address }) => { + // TODO... + + return ( +
    Nothing here yet
    + ) +} + +export default DisplayLinkedNFTs; +``` + +In the function, add a state variable to store the data retrieved by the script: + +```typescript +const [responseData, setResponseData] = useState(null); +``` + +Then, use `useEffect` to fetch the NFTs with the script and `fcl.query`: + +```tsx +useEffect(() => { + const fetchLinkedAddresses = async () => { + if (!address) return; + + try { + const cadenceScript = FetchNFTs; + + // Fetch the linked addresses + const response: ApiResponse = await fcl.query({ + cadence: cadenceScript, + args: () => [fcl.arg(address, t.Address)], + }); + + console.log(JSON.stringify(response, null, 2)); + + setResponseData(response); + } catch (error) { + console.error("Error fetching linked addresses:", error); + } + }; + + fetchLinkedAddresses(); +}, [address]); +``` + +Return to `page.tsx`, import your new component, and add an instance of `` that passes in the user's address and is only displayed while `loggedIn`. + +```tsx +{loggedIn && } +``` + +### Testing + +Run the app again. If you have linked your account and have NFTs in that account, you'll see them in the console! + +### Displaying the Moments + +Now that they're here, all to do is display them nicely! Return to `DisplayLinkedNFTs.tsx`. Add a helper function to confirm each returned NFT matches the Moments format. You can update this to handle other NFTs you'd like to show as well. + +:::warning + +Remember, you'll also need to update the script in a production app to filter for only the collections you want, and handle large collections. + +::: + +```tsx +// Type-checking function to validate moment structure +// eslint-disable-next-line @typescript-eslint/no-explicit-any +const isValidMoment = (moment: any): moment is Moment => { + const isValid = + typeof moment.name === 'string' && + typeof moment.description === 'string' && + moment.thumbnail && + typeof moment.thumbnail.url === 'string'; + + if (!isValid) { + console.warn('Invalid moment data:', moment); + } + + return isValid; +}; +``` + +Next, add a rendering function with some basic styling: + +```tsx +// Function to render moments with validation +const renderMoments = (data: ApiResponse) => { + return Object.entries(data).map(([addr, moments]) => ( +
    +

    Linked Wallet: {addr}

    +
    + {Object.entries(moments).map(([momentId, moment]) => ( + isValidMoment(moment) ? ( +
    +
    {moment.name}
    +

    {moment.description}

    + {moment.name} +
    + ) : null + ))} +
    +
    + )); +}; +``` + +Finally, update the `return` with some more styling and the rendered NFT data: + +```tsx +return ( +
    + {address ? ( +
    +

    Moments Data:

    +
    + {responseData ? renderMoments(responseData) : ( +

    No Moments Data Available

    + )} +
    +
    + ) : ( +
    No Address Provided
    + )} +
    +); +``` + +### Further Polish + +Finally, you can polish up your `page.tsx` to look a little nicer, and guide your users to the Account Linking process in the Dapper Wallet: + +```tsx +'use client'; + + + +export default function Home() { + const { user, loggedIn, logIn, logOut } = useAuth(); + + return ( +
    +
    + {/* Message visible for all users */} +

    + Please link your Dapper wallet to view your NFTs. For more information, check the{" "} + + Account Linking and FAQ + . +

    + +
    + {/* Display user address or linked NFTs if logged in */} + {loggedIn ? ( +
    + Address: {user.addr} +
    + ) : ( +
    + Please log in to view your linked NFTs. +
    + )} + + {/* Login/Logout Button */} + +
    + + {/* Display NFTs if logged in */} + {loggedIn && } +
    +
    + ); +} +``` + +Your app will now look like the [simple onchain app] demo! + +## Conclusion + +In this tutorial, you took your first steps towards building powerful new experiences that meet you customers where they are. They can keep their assets in the wallet associate with one app, but also give your app the ability to use them - seamlessly, safely, and beautifully! + +[Account Linking]: ./account-linking/index.md +[NBA Top Shot]: https://nbatopshot.com +[simple onchain app]: https://nextjs-topshot-account-linking.vercel.app +[Dapper Wallet]: https://meetdapper.com +[Cadence]: https://cadence-lang.org/docs +[Next.js]: https://nextjs.org/docs/app/getting-started/installation +[Yarn]: https://yarnpkg.com +[Flow CLI]: ../../tools/flow-cli/index.md +[other installation methods]: ../../tools/flow-cli/install.md +[initializes a project]: ../../tools/flow-cli/super-commands.md#init +[Flow Dependency Manager]: ../../tools/flow-cli/dependency-manager.md +[FCL]: ../../tools/clients/fcl-js/index.md +[App Quickstart Guide]: ../getting-started/fcl-quickstart.md +[Wallet Connect]: https://cloud.walletconnect.com/sign-in +[Flow Wallet]: https://wallet.flow.com +[link your Dapper Wallet]: https://support.meetdapper.com/hc/en-us/articles/20744347884819-Account-Linking-and-FAQ \ No newline at end of file diff --git a/static/markdown/build/guides/account-linking/child-accounts.md b/static/markdown/build/guides/account-linking/child-accounts.md new file mode 100644 index 0000000000..957037e5d5 --- /dev/null +++ b/static/markdown/build/guides/account-linking/child-accounts.md @@ -0,0 +1,734 @@ +--- +title: Building Walletless Applications Using Child Accounts +sidebar_position: 1 +description: Learn how to implement progressive onboarding flows using Flow's Hybrid Custody model. Create walletless applications, manage child accounts, and enable account linking for seamless user experiences. +keywords: + - child accounts + - hybrid custody + - account linking + - walletless onboarding + - progressive onboarding + - Flow accounts + - custody model + - account delegation + - blockchain onboarding + - account capabilities + - parent accounts + - account management + - Flow development + - account security + - user onboarding +--- + +In this doc, we'll dive into a progressive onboarding flow, including the Cadence scripts & transactions that go into +its implementation in your app. These components will enable any implementing app to create a custodial account, mediate +the user's onchain actions on their behalf, and later delegate access of that app-created account to the user's wallet. +We'll refer to this custodial pattern as the Hybrid Custody Model and the process of delegating control of the app +account as Account Linking. + +## Objectives + +- Create a [walletless onboarding](https://flow.com/post/flow-blockchain-mainstream-adoption-easy-onboarding-wallets) + transaction +- Link an existing app account as a child to a newly authenticated parent account +- Get your app to recognize "parent" accounts along with any associated "child" accounts +- Put it all together to create a blockchain-native onboarding transaction +- View fungible and non-fungible Token metadata relating to assets across all of a user's associated accounts - their + wallet-mediated "parent" account and any "child" accounts +- Facilitate transactions acting on assets in child accounts + +## Point of Clarity + +Before diving in, let's make a distinction between "account linking" and "linking accounts". + +### Account Linking + +:::info + +Note that since account linking is a sensitive action, transactions where an account may be linked are designated by a +topline pragma `#allowAccountLinking`. This lets wallet providers inform users that their account may be linked in the +signed transaction. + +::: + +Very simply, account linking is a [feature in Cadence](https://github.com/onflow/flips/pull/53) that let's an +[Account](https://cadence-lang.org/docs/language/accounts#authaccount) create a +[Capability](https://cadence-lang.org/docs/language/capabilities) on itself. + +Below is an example demonstrating how to issue an `&Account` Capability from a signing account + +transaction: + +```cadence link_account.cdc +#allowAccountLinking + +transaction(linkPathSuffix: String) { + prepare(signer: auth(IssueAccountCapabilityController) &Account) { + // Issues a fully-entitled Account Capability + let accountCapability = signer.capabilities + .account + .issue() + } +} +``` + +From there, the signing account can retrieve the privately linked `&Account` Capability and delegate it to another +account, revoking the Capability if they wish to revoke delegated access. + +Note that in order to link an account, a transaction must state the `#allowAccountLinking` pragma in the top line of the +transaction. This is an interim safety measure so that wallet providers can notify users they're about to sign a +transaction that may create a Capability on their `Account`. + +### Linking Accounts + +Linking accounts leverages this account link, otherwise known as an **`&Account` Capability**, and encapsulates it. The +[components and actions](https://github.com/onflow/flips/pull/72) involved in this process - what the Capability is +encapsulated in, the collection that holds those encapsulations, etc. is what we'll dive into in this doc. + +## Terminology + +**Parent-Child accounts** - For the moment, we'll call the account created by the app the "child" account and the +account receiving its `&Account` Capability the "parent" account. Existing methods of account access & delegation (i.e. +keys) still imply ownership over the account, but insofar as linked accounts are concerned, the account to which both +the user and the app share access via `&Account` Capability will be considered the "child" account. + +**Walletless onboarding** - An onboarding flow whereby an app creates a custodial account for a user, onboarding them to +the app, obviating the need for user wallet authentication. + +**Blockchain-native onboarding** - Similar to the already familiar Web3 onboarding flow where a user authenticates with +their existing wallet, an app onboards a user via wallet authentication while additionally creating a custodial app +account and linking it with the authenticated account, resulting in a "hybrid custody" model. + +**Hybrid Custody Model** - A custodial pattern in which an app and a user maintain access to an app created account and +user access to that account has been mediated via account linking. + +**Account Linking** - Technically speaking, account linking in our context consists of giving some other account an +`&Account` Capability from the granting account. This Capability is maintained in standardized resource called a +`HybridCustody.Manager`, providing its owning user access to any and all of their linked accounts. + +**Progressive Onboarding** - An onboarding flow that walks a user up to self-custodial ownership, starting with +walletless onboarding and later linking the app account with the user's authenticated wallet once the user chooses to do +so. + +**Restricted Child Account** - An account delegation where the access on the delegating account is restricted according +to rules set by the linking child account. The distinctions between this and the subsequent term ("owned" account) will +be expanding on later. + +**Owned Account** - An account delegation where the delegatee has unrestricted access on the delegating child account, +thereby giving the delegatee presiding authority superseding any other "restricted" parent accounts. + +## Account Linking + +Linking an account is the process of delegating account access via `&Account` Capability. Of course, we want to do this +in a way that allows the receiving account to maintain that Capability and allows easy identification of the accounts on +either end of the linkage - the user's main "parent" account and the linked "child" account. This is accomplished in the +`HybridCustody` contract which we'll continue to use in this guidance. + +### Prerequisites + +Since account delegation is mediated by developer-defined rules, you should make sure to first configure the resources +that contain those rules. Contracts involved in defining and enforcing this ruleset are +[`CapabilityFilter`](https://github.com/onflow/hybrid-custody/blob/main/contracts/CapabilityFilter.cdc) and +[`CapabilityFactory`](https://github.com/onflow/hybrid-custody/blob/main/contracts/CapabilityFactory.cdc). The former +enumerates those types that are and are not accessible from a child account while the latter enables the access of those +allowable Capabilities such that the returned values can be properly typed - e.g. retrieving a Capability that can be +cast to `Capability<&NonFungibleToken.Collection>` for example. + +Here's how you would configure an `AllowlistFilter` and add allowed types to it: + +```cadence setup_allow_all_filter.cdc +import "CapabilityFilter" + +transaction(identifiers: [String]) { + prepare(acct: auth(BorrowValue, SaveValue, StorageCapabilities, PublishCapability, UnpublishCapability) &Account) { + // Setup the AllowlistFilter + if acct.storage.borrow<&AnyResource>(from: CapabilityFilter.StoragePath) == nil { + acct.storage.save( + <-CapabilityFilter.createFilter(Type<@CapabilityFilter.AllowlistFilter>()), + to: CapabilityFilter.StoragePath) + } + + // Ensure the AllowlistFilter is linked to the expected PublicPath + acct.capabilities.unpublish(CapabilityFilter.PublicPath) + acct.capabilities.publish( + acct.capabilities.storage.issue<&{CapabilityFilter.Filter}>(CapabilityFilter.StoragePath), + at: CapabilityFilter.PublicPath + ) + + // Get a reference to the filter + let filter = acct.storage.borrow( + from: CapabilityFilter.StoragePath + ) ?? panic("filter does not exist") + + // Add the given type identifiers to the AllowlistFilter + // **Note:** the whole transaction fails if any of the given identifiers are malformed + for identifier in identifiers { + let c = CompositeType(identifier)! + filter.addType(c) + } + } +} +``` + +And the following transaction configures a `CapabilityFactory.Manager`, adding NFT-related `Factory` objects: + +:::info + +Note that the Manager configured here enables retrieval of castable Capabilities. It's recommended that you implement +Factory resource definitions to support any NFT Collections related with the use of your application so that users can +retrieve Typed Capabilities from accounts linked from your app. + +::: + +```cadence setup_factory.cdc +import "NonFungibleToken" + +import "CapabilityFactory" +import "NFTCollectionPublicFactory" +import "NFTProviderAndCollectionFactory" +import "NFTProviderFactory" +import "NFTCollectionFactory" + +transaction { + prepare(acct: auth(BorrowValue, SaveValue, StorageCapabilities, PublishCapability, UnpublishCapability) &Account) { + // Check for a stored Manager, saving if not found + if acct.storage.borrow<&AnyResource>(from: CapabilityFactory.StoragePath) == nil { + let f <- CapabilityFactory.createFactoryManager() + acct.storage.save(<-f, to: CapabilityFactory.StoragePath) + } + + // Check for Capabilities where expected, linking if not found + acct.capabilities.unpublish(CapabilityFactory.PublicPath) + acct.capabilities.publish( + acct.capabilities.storage.issue<&CapabilityFactory.Manager>(CapabilityFactory.StoragePath), + at: CapabilityFactory.PublicPath + ) + + assert( + acct.capabilities.get<&CapabilityFactory.Manager>(CapabilityFactory.PublicPath).check(), + message: "CapabilityFactory is not setup properly" + ) + + let manager = acct.storage.borrow(from: CapabilityFactory.StoragePath) + ?? panic("manager not found") + + /// Add generic NFT-related Factory implementations to enable castable Capabilities from this Manager + manager.updateFactory(Type<&{NonFungibleToken.CollectionPublic}>(), NFTCollectionPublicFactory.Factory()) + manager.updateFactory(Type(), NFTProviderAndCollectionFactory.Factory()) + manager.updateFactory(Type(), NFTProviderFactory.Factory()) + manager.updateFactory(Type(), NFTCollectionFactory.WithdrawFactory()) + manager.updateFactory(Type<&{NonFungibleToken.Collection}>(), NFTCollectionFactory.Factory()) + } +} +``` + +![resources/hybrid_custody_high_level](./resources/hybrid_custody_high_level.png) + +_In this scenario, a user custodies a key for their main account which maintains access to a wrapped `Account` +Capability, providing the user restricted access on the app account. The app maintains custodial access to the account +and regulates the access restrictions to delegatee "parent" accounts._ + +Linking accounts can be done in one of two ways. Put simply, the child account needs to get the parent an `Account` +Capability, and the parent needs to save that Capability so they can retain access. This delegation must be done manner +that represents each side of the link while safeguarding the integrity of any access restrictions an application puts in +place on delegated access. + +We can achieve issuance from the child account and claim from the parent account pattern by either: + +1. Leveraging [Cadence's `Account.Inbox`](https://cadence-lang.org/docs/language/accounts#account-inbox) to publish the + Capability from the child account & have the parent claim the Capability in a subsequent transaction. +2. Executing a multi-party signed transaction, signed by both the child and parent accounts. + +Let's take a look at both. + +:::info + +You'll want to consider whether you would like the parent account to be configured with some app-specific resources or +Capabilities and compose you multisig or claim transactions to include such configurations. + +For example, if your app deals with specific NFTs, you may want to configure the parent account with Collections for +those NFTs so the user can easily transfer them between their linked accounts. + +::: + +### Publish & Claim + +#### Publish + +Here, the account delegating access to itself links its `&Account` Capability, and publishes it to be claimed by the +designated parent account. + +```cadence publish_to_parent.cdc +import "HybridCustody" +import "CapabilityFactory" +import "CapabilityFilter" +import "CapabilityDelegator" + +transaction(parent: Address, factoryAddress: Address, filterAddress: Address) { + prepare(acct: auth(BorrowValue) &Account) { + // NOTE: The resources and Capabilities needed for this transaction are assumed to have be pre-configured + + // Borrow the OwnedAccount resource + let owned = acct.storage.borrow( + from: HybridCustody.OwnedAccountStoragePath + ) ?? panic("owned account not found") + + // Get a CapabilityFactory.Manager Capability + let factory = getAccount(factoryAddress).capabilities + .get<&CapabilityFactory.Manager>( + CapabilityFactory.PublicPath + ) + assert(factory.check(), message: "factory address is not configured properly") + + // Get a CapabilityFilter.Filter Capability + let filter = getAccount(filterAddress).capabilities + .get<&{CapabilityFilter.Filter}>( + CapabilityFilter.PublicPath + ) + assert(filter.check(), message: "capability filter is not configured properly") + + // Publish the OwnedAccount to the designated parent account + owned.publishToParent(parentAddress: parent, factory: factory, filter: filter) + } +} +``` + +#### Claim + +On the other side, the receiving account claims the published `ChildAccount` Capability, adding it to the signer's +`HybridCustody.Manager.childAccounts` indexed on the child account's Address. + +```cadence redeem_account.cdc +import "MetadataViews" +import "ViewResolver" + +import "HybridCustody" +import "CapabilityFilter" + +transaction(childAddress: Address, filterAddress: Address?, filterPath: PublicPath?) { + prepare(acct: auth(Storage, Capabilities, Inbox) &Account) { + // Get a Manager filter if a path is provided + var filter: Capability<&{CapabilityFilter.Filter}>? = nil + if filterAddress != nil && filterPath != nil { + filter = getAccount(filterAddress!).capabilities + .get<&{CapabilityFilter.Filter}>( + filterPath! + ) + } + + // Configure a Manager if not already configured + if acct.storage.borrow<&HybridCustody.Manager>(from: HybridCustody.ManagerStoragePath) == nil { + let m <- HybridCustody.createManager(filter: filter) + acct.storage.save(<- m, to: HybridCustody.ManagerStoragePath) + + for c in acct.capabilities.storage.getControllers(forPath: HybridCustody.ManagerStoragePath) { + c.delete() + } + + acct.capabilities.unpublish(HybridCustody.ManagerPublicPath) + + acct.capabilities.publish( + acct.capabilities.storage.issue<&{HybridCustody.ManagerPublic}>( + HybridCustody.ManagerStoragePath + ), + at: HybridCustody.ManagerPublicPath + ) + + acct.capabilities + .storage + .issue( + HybridCustody.ManagerStoragePath + ) + } + + // Claim the published ChildAccount Capability + let inboxName = HybridCustody.getChildAccountIdentifier(acct.address) + let cap = acct.inbox.claim(inboxName, provider: childAddress) + ?? panic("child account cap not found") + + // Get a reference to the Manager and add the account & add the child account + let manager = acct.storage.borrow(from: HybridCustody.ManagerStoragePath) + ?? panic("manager no found") + manager.addAccount(cap: cap) + } +} +``` + +### Multi-Signed Transaction + +We can combine the two transactions in [Publish](#publish) and [Claim](#claim) into a single multi-signed transaction to +achieve Hybrid Custody in a single step. + +:::info + +Note that while the following code links both accounts in a single transaction, in practicality you may find it easier +to execute publish and claim transactions separately depending on your custodial infrastructure. + +::: + +```cadence setup_multi_sig.cdc +#allowAccountLinking + +import "HybridCustody" + +import "CapabilityFactory" +import "CapabilityDelegator" +import "CapabilityFilter" + +import "MetadataViews" +import "ViewResolver" + +transaction(parentFilterAddress: Address?, childAccountFactoryAddress: Address, childAccountFilterAddress: Address) { + prepare(childAcct: auth(Storage, Capabilities) &Account, parentAcct: auth(Storage, Capabilities, Inbox) &Account) { + // --------------------- Begin setup of child account --------------------- + var optCap: Capability? = nil + let t = Type() + for c in childAcct.capabilities.account.getControllers() { + if c.borrowType.isSubtype(of: t) { + optCap = c.capability as! Capability + break + } + } + + if optCap == nil { + optCap = childAcct.capabilities.account.issue() + } + let acctCap = optCap ?? panic("failed to get account capability") + + if childAcct.storage.borrow<&HybridCustody.OwnedAccount>(from: HybridCustody.OwnedAccountStoragePath) == nil { + let ownedAccount <- HybridCustody.createOwnedAccount(acct: acctCap) + childAcct.storage.save(<-ownedAccount, to: HybridCustody.OwnedAccountStoragePath) + } + + for c in childAcct.capabilities.storage.getControllers(forPath: HybridCustody.OwnedAccountStoragePath) { + c.delete() + } + + // configure capabilities + childAcct.capabilities.storage.issue<&{HybridCustody.BorrowableAccount, HybridCustody.OwnedAccountPublic, ViewResolver.Resolver}>(HybridCustody.OwnedAccountStoragePath) + childAcct.capabilities.publish( + childAcct.capabilities.storage.issue<&{HybridCustody.OwnedAccountPublic, ViewResolver.Resolver}>(HybridCustody.OwnedAccountStoragePath), + at: HybridCustody.OwnedAccountPublicPath + ) + + // --------------------- End setup of child account --------------------- + + // --------------------- Begin setup of parent account --------------------- + var filter: Capability<&{CapabilityFilter.Filter}>? = nil + if parentFilterAddress != nil { + filter = getAccount(parentFilterAddress!).capabilities.get<&{CapabilityFilter.Filter}>(CapabilityFilter.PublicPath) + } + + if parentAcct.storage.borrow<&HybridCustody.Manager>(from: HybridCustody.ManagerStoragePath) == nil { + let m <- HybridCustody.createManager(filter: filter) + parentAcct.storage.save(<- m, to: HybridCustody.ManagerStoragePath) + } + + for c in parentAcct.capabilities.storage.getControllers(forPath: HybridCustody.ManagerStoragePath) { + c.delete() + } + + parentAcct.capabilities.publish( + parentAcct.capabilities.storage.issue<&{HybridCustody.ManagerPublic}>(HybridCustody.ManagerStoragePath), + at: HybridCustody.ManagerPublicPath + ) + parentAcct.capabilities.storage.issue(HybridCustody.ManagerStoragePath) + + // --------------------- End setup of parent account --------------------- + + // Publish account to parent + let owned = childAcct.storage.borrow(from: HybridCustody.OwnedAccountStoragePath) + ?? panic("owned account not found") + + let factory = getAccount(childAccountFactoryAddress).capabilities.get<&CapabilityFactory.Manager>(CapabilityFactory.PublicPath) + assert(factory.check(), message: "factory address is not configured properly") + + let filterForChild = getAccount(childAccountFilterAddress).capabilities.get<&{CapabilityFilter.Filter}>(CapabilityFilter.PublicPath) + assert(filterForChild.check(), message: "capability filter is not configured properly") + + owned.publishToParent(parentAddress: parentAcct.address, factory: factory, filter: filterForChild) + + // claim the account on the parent + let inboxName = HybridCustody.getChildAccountIdentifier(parentAcct.address) + let cap = parentAcct.inbox.claim(inboxName, provider: childAcct.address) + ?? panic("child account cap not found") + + let manager = parentAcct.storage.borrow(from: HybridCustody.ManagerStoragePath) + ?? panic("manager no found") + + manager.addAccount(cap: cap) + } +} +``` + +## Onboarding Flows + +Given the ability to establish an account and later delegate access to a user, apps are freed from the constraints of +dichotomous custodial & self-custodial paradigms. A developer can choose to onboard a user via traditional Web2 identity +and later delegate access to the user's wallet account. Alternatively, an app can enable wallet authentication at the +outset, creating an app-specific account & linking with the user's wallet account. As specified above, these two flows +are known as "walletless" and "blockchain-native" onboarding respectively. Developers can choose to implement one for +simplicity or both for maximum flexibility. + +### Walletless Onboarding + +The following transaction creates an account, funding creation via the signer and adding the provided public key. You'll +notice this transaction is pretty much your standard account creation. The magic for you will be how you custody the key +for this account (locally, KMS, wallet service, etc.) in a manner that allows your app to mediate onchain interactions +on behalf of your user. + +```cadence walletless_onboarding +import "FungibleToken" +import "FlowToken" + +transaction(pubKey: String, initialFundingAmt: UFix64) { + + prepare(signer: auth(BorrowValue) &Account) { + + /* --- Account Creation --- */ + // **NOTE:** your app may choose to separate creation depending on your custodial model) + // + // Create the child account, funding via the signer + let newAccount = Account(payer: signer) + // Create a public key for the new account from string value in the provided arg + // **NOTE:** You may want to specify a different signature algo for your use case + let key = PublicKey( + publicKey: pubKey.decodeHex(), + signatureAlgorithm: SignatureAlgorithm.ECDSA_P256 + ) + // Add the key to the new account + // **NOTE:** You may want to specify a different hash algo & weight best for your use case + newAccount.keys.add( + publicKey: key, + hashAlgorithm: HashAlgorithm.SHA3_256, + weight: 1000.0 + ) + + /* --- (Optional) Additional Account Funding --- */ + // + // Fund the new account if specified + if initialFundingAmt > 0.0 { + // Get a vault to fund the new account + let fundingProvider = signer.storage.borrow( + from: /storage/flowTokenVault + )! + // Fund the new account with the initialFundingAmount specified + let receiver = newAccount.capabilities.get<&FlowToken.Vault>( + /public/flowTokenReceiver + ).borrow()! + let fundingVault <-fundingProvider.withdraw( + amount: initialFundingAmt + ) + receiver.deposit(from: <-fundingVault) + } + + /* --- Continue with use case specific setup --- */ + // + // At this point, the newAccount can further be configured as suitable for + // use in your app (e.g. Setup a Collection, Mint NFT, Configure Vault, etc.) + // ... + } +} +``` + +### Blockchain-Native Onboarding + +This onboarding flow is really a single-transaction composition of the steps covered above. This is a testament to the +power of the complex transactions you can compose on Flow with Cadence! + +:::info + +Recall the [prerequisites](#prerequisites) needed to be satisfied before linking an account: + +1. CapabilityFilter Filter saved and linked +2. CapabilityFactory Manager saved and linked as well as Factory implementations supporting the Capability Types you'll + want accessible from linked child accounts as Typed Capabilities. + +::: + +#### Account Creation & Linking + +Compared to walletless onboarding where a user does not have a Flow account, blockchain-native onboarding assumes a user +already has a wallet configured and immediately links it with a newly created app account. This enables the app to sign +transactions on the user's behalf via the new child account while immediately delegating control of that account to the +onboarding user's main account. + +After this transaction, both the custodial party (presumably the client/app) and the signing parent account will have +access to the newly created account - the custodial party via key access and the parent account via their +`HybridCustody.Manager` maintaining the new account's `ChildAccount` Capability. + +```cadence blockchain_native_onboarding.cdc +#allowAccountLinking + +import "FungibleToken" +import "FlowToken" +import "MetadataViews" +import "ViewResolver" + +import "HybridCustody" +import "CapabilityFactory" +import "CapabilityFilter" +import "CapabilityDelegator" + +transaction( + pubKey: String, + initialFundingAmt: UFix64, + factoryAddress: Address, + filterAddress: Address +) { + + prepare(parent: auth(Storage, Capabilities, Inbox) &Account, app: auth(Storage, Capabilities) &Account) { + /* --- Account Creation --- */ + // + // Create the child account, funding via the signing app account + let newAccount = Account(payer: app) + // Create a public key for the child account from string value in the provided arg + // **NOTE:** You may want to specify a different signature algo for your use case + let key = PublicKey( + publicKey: pubKey.decodeHex(), + signatureAlgorithm: SignatureAlgorithm.ECDSA_P256 + ) + // Add the key to the new account + // **NOTE:** You may want to specify a different hash algo & weight best for your use case + newAccount.keys.add( + publicKey: key, + hashAlgorithm: HashAlgorithm.SHA3_256, + weight: 1000.0 + ) + + /* --- (Optional) Additional Account Funding --- */ + // + // Fund the new account if specified + if initialFundingAmt > 0.0 { + // Get a vault to fund the new account + let fundingProvider = app.storage.borrow(from: /storage/flowTokenVault)! + // Fund the new account with the initialFundingAmount specified + newAccount.capabilities.get<&{FungibleToken.Receiver}>(/public/flowTokenReceiver)! + .borrow()! + .deposit( + from: <-fundingProvider.withdraw( + amount: initialFundingAmt + ) + ) + } + + /* Continue with use case specific setup */ + // + // At this point, the newAccount can further be configured as suitable for + // use in your dapp (e.g. Setup a Collection, Mint NFT, Configure Vault, etc.) + // ... + + /* --- Link the AuthAccount Capability --- */ + // + let acctCap = newAccount.capabilities.account.issue() + + // Create a OwnedAccount & link Capabilities + let ownedAccount <- HybridCustody.createOwnedAccount(acct: acctCap) + newAccount.storage.save(<-ownedAccount, to: HybridCustody.OwnedAccountStoragePath) + + newAccount.capabilities.storage.issue<&{HybridCustody.BorrowableAccount, HybridCustody.OwnedAccountPublic, ViewResolver.Resolver}>(HybridCustody.OwnedAccountStoragePath) + newAccount.capabilities.publish( + newAccount.capabilities.storage.issue<&{HybridCustody.OwnedAccountPublic, ViewResolver.Resolver}>(HybridCustody.OwnedAccountStoragePath), + at: HybridCustody.OwnedAccountPublicPath + ) + + // Get a reference to the OwnedAccount resource + let owned = newAccount.storage.borrow(from: HybridCustody.OwnedAccountStoragePath)! + + // Get the CapabilityFactory.Manager Capability + let factory = getAccount(factoryAddress).capabilities.get<&CapabilityFactory.Manager>(CapabilityFactory.PublicPath) + assert(factory.check(), message: "factory address is not configured properly") + + // Get the CapabilityFilter.Filter Capability + let filter = getAccount(filterAddress).capabilities.get<&{CapabilityFilter.Filter}>(CapabilityFilter.PublicPath) + assert(filter.check(), message: "capability filter is not configured properly") + + // Configure access for the delegatee parent account + owned.publishToParent(parentAddress: parent.address, factory: factory, filter: filter) + + /* --- Add delegation to parent account --- */ + // + // Configure HybridCustody.Manager if needed + if parent.storage.borrow<&AnyResource>(from: HybridCustody.ManagerStoragePath) == nil { + let m <- HybridCustody.createManager(filter: filter) + parent.storage.save(<- m, to: HybridCustody.ManagerStoragePath) + + for c in parent.capabilities.storage.getControllers(forPath: HybridCustody.ManagerStoragePath) { + c.delete() + } + + // configure Capabilities + parent.capabilities.storage.issue<&{HybridCustody.ManagerPrivate, HybridCustody.ManagerPublic}>(HybridCustody.ManagerStoragePath) + parent.capabilities.publish( + parent.capabilities.storage.issue<&{HybridCustody.ManagerPublic}>(HybridCustody.ManagerStoragePath), + at: HybridCustody.ManagerPublicPath + ) + } + + + // Claim the ChildAccount Capability + let inboxName = HybridCustody.getChildAccountIdentifier(parent.address) + let cap = parent + .inbox + .claim( + inboxName, + provider: newAccount.address + ) ?? panic("child account cap not found") + + // Get a reference to the Manager and add the account + let managerRef = parent.storage.borrow(from: HybridCustody.ManagerStoragePath) + ?? panic("manager not found") + managerRef.addAccount(cap: cap) + } +} +``` + +## Funding & Custody Patterns + +Aside from implementing onboarding flows & account linking, you'll want to also consider the account funding & custodial +pattern appropriate for the app you're building. The only pattern compatible with walletless onboarding (and therefore +the only one showcased above) is one in which the app custodies the child account's key and funds account creation. + +In general, the funding pattern for account creation will determine to some extent the backend infrastructure needed to +support your app and the onboarding flow your app can support. For example, if you want to to create a service-less +client (a totally local app without backend infrastructure), you could forego walletless onboarding in favor of a +user-funded blockchain-native onboarding to achieve a hybrid custody model. Your app maintains the keys to the app +account locally to sign on behalf of the user, and the user funds the creation of the the account, linking to their main +account on account creation. This would be a **user-funded, app custodied** pattern. + +Again, custody may deserve some regulatory insight depending on your jurisdiction. If building for production, you'll +likely want to consider these non-technical implications in your technical decision-making. Such is the nature of +building in crypto. + +Here are the patterns you might consider: + +### App-Funded, App-Custodied + +If you want to implement walletless onboarding, you can stop here as this is the only compatible pattern. In this +scenario, a backend app account funds the creation of a new account and the app custodies the key for said account +either on the user's device or some backend KMS. + +### App-Funded, User-Custodied + +In this case, the backend app account funds account creation, but adds a key to the account which the user custodies. In +order for the app to act on the user's behalf, it has to be delegated access via `&Account` Capability which the backend +app account would maintain in a `HybridCustody.Manager`. This means that the new account would have two parent accounts +- the user's and the app. + +While this pattern provides the user maximum ownership and authority over the child account, it may present unique +considerations and edge cases for you as a builder depending on your app's access to the child account. Also note that +this and the following patterns are incompatible with walletless onboarding in that the user must have a wallet +pre-configured before onboarding. + +### User-Funded, App-Custodied + +As mentioned above, this pattern unlocks totally service-less architectures - just a local client & smart contracts. An +authenticated user signs a transaction creating an account, adding the key provided by the client, and linking the +account as a child account. At the end of the transaction, hybrid custody is achieved and the app can sign with the +custodied key on the user's behalf using the newly created account. + +### User-Funded, User-Custodied + +While perhaps not useful for most apps, this pattern may be desirable for advanced users who wish to create a shared +access account themselves. The user funds account creation, adding keys they custody, and delegates secondary access to +some other account. \ No newline at end of file diff --git a/static/markdown/build/guides/account-linking/index.md b/static/markdown/build/guides/account-linking/index.md new file mode 100644 index 0000000000..5448f03474 --- /dev/null +++ b/static/markdown/build/guides/account-linking/index.md @@ -0,0 +1,211 @@ +--- +title: Account Linking (FLIP 72) +sidebar_position: 4 +description: Learn about Flow's unique account linking feature that enables shared ownership of accounts. Understand how accounts can be accessed, delegated, and managed through capabilities and hybrid custody. +keywords: + - account linking + - FLIP 72 + - account capabilities + - hybrid custody + - account access + - account delegation + - Flow accounts + - account ownership + - account security + - parent accounts + - child accounts + - account management + - Flow protocol + - account control + - custody model +--- + +# Account Linking + +Account linking is a unique Flow concept that enables sharing ownership over [accounts](../../basics/accounts.md). In +order to understand how we can achieve that we must first understand how accounts on Flow are accessed. + +Accounts on flow can be accessed in Cadence through two types, `PublicAccount` and `Account`. As the name implies the +`PublicAccount` type gives access to all public account information such as address, balance, storage capacity, etc., +but doesn't allow changes to the account. The `Account` type (or more specifically, an +[entitled](https://cadence-lang.org/docs/language/access-control#entitlements) `&Account`) allows the same access as +`PublicAccount` but also allows changes to the account, including adding/revoking account keys, managing the deployed +contracts, as well as linking and publishing Capabilities. + +![Flow account structure](resources/account-structure.png) + +## Accessing Account + +Accessing `Account` allows for modification to account storage, so it's essential to safeguard this access by mandating +that transactions are signed by the account being accessed. [Account +entitlements](https://cadence-lang.org/docs/language/accounts/#performing-write-operations) enable for more granular +access control over the specific parts of the account that can be accessed from within the signed transaction. A +transaction can list multiple authorizing account it wants to access as part of the `prepare` section of the +transaction. Read more about transaction signing in the [transaction documentation](../../basics/transactions.md). + +Since access to the `Account` object enables state change, the idea of account ownership actually translates to the +ability to access the underlying account. Traditionally, you might consider this the same as having key access on an +account, but we'll see in just a minute how programmatic, ownership-level access is unlocked with [Capabilities on +Flow](https://cadence-lang.org/docs/language/capabilities). + +## Account Capabilities + +Before proceeding the reader will need a clear understanding of [Cadence +capabilities](https://cadence-lang.org/docs/language/capabilities) to follow this section. Advanced features such as +Account Capabilities are powerful but if used incorrectly can put your app or users at risk. + +Cadence allows the creation of Capabilities to delegate access to account storage, meaning any account obtaining a valid +Ccapability to another account object in the storage can access it. This is a powerful feature on its own - accessing +another account programmatically without the need for an active key on the accessible account. The access to the object +can be limited when creating a Capability so only intended functions or fields can be accessed. + +Account linking is made possible by the extension of Capabilities on the `Account` object itself. Similar to how storage +capabilities allow access to a value stored in an account's storage, `&Account` Capabilities allow delegated access to +the issuing `Account`. These Capabilities allow for access to key assignment, contract deployment, and other privileged +actions on the delegating `Account` - effectively sharing ownership of the account without ever adding or sharing a key. +This Capability can of course be revoked at any time by the delegating account. + +### Creating Account Links + +When referring to 'account linking' we mean that an `&Account` Capability is created by the parent account and published +to another account. The account owning the `&Account` Capability which was made available to another account is the child +account. The account in possession of the Capability given by the child account becomes its parent account. + +![Account linking on Flow relational diagram](resources/account-linking-relational-diagram.png) + +A link between two existing accounts on Flow can be created in two steps: + +1. A child account creates an `&Account` Capability and publishes it to the parent account. +2. The parent account, claims that Capability and can access the child's account through it. + +![Account linking steps on Flow](resources/account-linking-steps-high-level.png) + +These two steps are implemented in Cadence as two transactions: + +************************************Create capability************************************ + +The account B creates and publishes the `&Account` Capability to the account A at the address `0x01` + +```cadence +#allowAccountLinking + +transaction { + prepare(signer: auth(IssueAccountCapabilityController, PublishInboxCapability) &Account) { + // Issue a fully-entitled account capability + let capability = signer.capabilities + .account + .issue() + // Publish the capability for the specified recipient + signer.inbox.publish(capability, name: "accountCapA", recipient: 0x1) + } +} +``` + +****************************Claim capability**************************** + +The account A claims the Capability published by account B. + +```cadence +transaction { + prepare(signer: auth(ClaimInboxCapability) &Account) { + let capabilityName = "accountCapB" + let providerAddress = 0x2 + // Claim the capability published by the account 0x2 + let capability = signer.inbox + .claim( + capabilityName, + provider: providerAddress + ) ?? panic( + "Capability with name ".concat(capabilityName) + .concat(" from provider ").concat(providerAddress.toString()) + .concat(" not found") + ) + // Simply borrowing an Account reference here for demonstration purposes + let accountRef = capability.borrow()! + } +} +``` + +## What is account linking most useful for? + +Account linking was specifically designed to enable smooth and seamless custodial onboarding of users to your Flow based +application without them first requiring a wallet to do so. This pattern overcomes both the technical hurdle, as well as +user's reluctance to install a wallet, opening access to Flow applications to every user. Users can experience an app +without any delay while still offering a path to self-sovreign ownership. + +Naturally, users may expect to use their account with another application, or otherwise move assets stored in that +account elsewhere - at minimum from their wallet. When an app initially leverages account linking, the app creates the +account instead of the user and stores that user's specific state in the app-created account. At a later point, users +can take ownership of the app account providing they possess a full [Flow account](../../basics/accounts.md), typically +by installing a wallet app. + +Account linking enables users to possess multiple linked child accounts from different apps. Complexities associated +with accessing those child accounts are eliminated by abstracting access to them through the user's parent account. + +:::info + +Simply put, child accounts are accessed and can be treated as a seamless part of the parent account. + +::: + +All assets in the app account can now jump the walled garden to play in the rest of the Flow ecosystem. The user does +not need to rely on the custodial app to execute transactions moving assets from the child account as the parent account +already has access to the assets in the child account. + +![Multiple parent-child accounts on Flow](resources/account-linking-multiple-accounts.png) + +This shared control over the digital items in the in-app account enables users to establish real ownership of the items +beyond the context of the app, where they can use their parent account to view inventory, take the items to other apps +in the ecosystem, such as a marketplace or a game. + +Most importantly, users are able to do this without the need to transfer the digital items between accounts, making it +seamless to continue using the original app while also enjoying their assets in other contexts. + +## Security Considerations + +Account linking is a _very_ powerful Cadence feature, and thus it must be treated with care. So far in this document, +we've discussed account linking between two accounts we own, even if the child account is managed by a third-party +application. But, we can't make the same trust assumptions about custodial accounts in the real world. + +Creating an `&Account` Capability and publishing it to an account we don't own means we are giving that account full +access to our account. This should be seen as an anti-pattern. + +:::warning + +Creating an `&Account` Capability and sharing it with third-party account effectually the same as giving that person your +account's private keys. + +::: + +Because unfiltered account linking can be dangerous, Flow introduces the [`HybridCustody` +contract](./parent-accounts.md) that helps custodial applications regulate access while enabling parent accounts to +manage their many child accounts and assets within them. + +## Hybrid Custody and Account Linking + +Apps need assurances that their own resources are safe from malicious actors, so giving out full access might not be the +form they want. Using hybrid custody contracts, the app still maintains control of their managed accounts, but they can: + +1. Share capabilities freely, with a few built-in controls over the types of capabilities that can be retrieved by + parent accounts via helper contracts (the `CapabilityFactory`, and `CapabilityFilter`) +2. Share additional capabilities (public or private) with a parent account via a `CapabilityDelegator` resource + +Learn more about it in the [Hybrid Custody documentation](./parent-accounts.md). + +### Guides + +- [Building Walletless Applications Using Child Accounts](./child-accounts.md) covers how apps can leverage Account + Linking to create a seamless user experience and enable future self-custody. +- [Working With Parent Accounts](./parent-accounts.md) covers features enabled by the core `HybridCustody` contract to + access child account assets from parent accounts. This is useful for apps like marketplaces or wallets that are + working with accounts that have potential child accounts. + +### Resources + +- [Forum Post](https://forum.onflow.org/t/hybrid-custody/4016) where core concepts were introduced and discussed. +- [GitHub repository](https://github.com/onflow/hybrid-custody) where `HybridCustody` core contracts and scripts are + maintained. Check out the repository for more advanced script or transaction examples. +- [Example](https://github.com/jribbink/magic-link-hc-sample/) Account Linking project with + [Magic](https://magic.link/). +- [Starter template](https://github.com/Niftory/niftory-samples/tree/main/walletless-onboarding) for + [Niftory](https://niftory.com/) Account Linking API. \ No newline at end of file diff --git a/static/markdown/build/guides/account-linking/parent-accounts.md b/static/markdown/build/guides/account-linking/parent-accounts.md new file mode 100644 index 0000000000..a7efe6a01b --- /dev/null +++ b/static/markdown/build/guides/account-linking/parent-accounts.md @@ -0,0 +1,464 @@ +--- +title: Working With Parent Accounts +sidebar_position: 2 +description: Learn how to work with parent accounts in Flow's hybrid custody model. Understand how to manage child accounts, access assets across accounts, and implement unified account experiences in wallets and marketplaces. +keywords: + - parent accounts + - hybrid custody + - account management + - child accounts + - account access + - NFT management + - token balances + - wallet integration + - marketplace integration + - Flow accounts + - account delegation + - asset management + - account hierarchy + - capability management + - account security +--- + +In this doc, we'll continue from the perspective of a wallet or marketplace app seeking to facilitate a unified account +experience, abstracting away the partitioned access between accounts into a single dashboard for user interactions on +all their owned assets. + +## Objectives + +- Understand the Hybrid Custody account model +- Differentiate between restricted child accounts and unrestricted owned accounts +- Get your app to recognize "parent" accounts along with any associated "child" accounts +- View Fungible and NonFungible Token metadata relating to assets across all of a user's associated accounts - their + wallet-mediated "parent" account and any hybrid custody model "child" accounts +- Facilitate transactions acting on assets in child accounts + +## Design Overview + +:::info + +TL;DR: An account's +[`HybridCustody.Manager`](https://github.com/onflow/hybrid-custody/blob/main/contracts/HybridCustody.cdc) is the entry +point for all of a user's associated accounts. + +::: + +The basic idea in the Hybrid Custody model is relatively simple. A parent account is one that has received delegated +(albeit restricted) access on another account. The account which has delegated authority over itself to the parent +account is the child account. + +In the [Hybrid Custody Model](https://forum.onflow.org/t/hybrid-custody/4016), this child account would have shared +access between the app - the entity which created and likely custodies the account - and the linked parent account. + +How does this delegation occur? Typically when we think of shared account access in crypto, we think keys. However, +Cadence enables [accounts to link Capabilities on +themselves](https://cadence-lang.org/docs/language/accounts/capabilities#accountcapabilities) and issue those +Capabilities to other parties (more on [capability-based access +here](https://cadence-lang.org/docs/language/capabilities)). + +This feature has been leveraged in an ecosystem standard so that apps can implement a hybrid custody model whereby the app +creates an account it controls, then later delegates access on that account to the user once they've authenticated with +their wallet. + +All related constructs are used together in the [`HybridCustody` +contract](https://github.com/onflow/hybrid-custody/tree/main) to define the standard. + +Parent accounts own a `Manager` resource which stores Capabilities to `ChildAccount` (restricted access) and +`OwnedAccount` (unrestricted access) resources, both of which are stored in any given child account. + +Therefore, the presence of a `Manager` in an account implies there are potentially associated accounts for which the +owning account has delegated access. This resource is intended to be configured with a public Capability that enables +querying of an account's child account addresses via `getAccountAddresses()` and `getOwnedAccountAddresses()`. As you can +deduce from these two methods, there is a notion of "owned" accounts which we'll expand on in a bit. + +A wallet or marketplace wishing to discover all of a user's accounts and assets within them can do so by first looking +to the user's `Manager`. + +### Identifying Account Hierarchy + +To clarify, insofar as the standard is concerned, an account is a parent account if it contains a `Manager` resource, +and an account is a child account if it contains at minimum an `OwnedAccount` or additionally a `ChildAccount` resource. + +Within a user's `Manager`, its mapping of `childAccounts` points to the addresses of its child accounts in each key, +with corresponding values giving the `Manager` access to those accounts via corresponding `ChildAccount` Capability. + +![HybridCustody Conceptual Overview](./resources/hybrid_custody_conceptual_overview.png) + +Likewise, the child account's `ChildAccount.parentAddress` (which owns a `Manager`) points to the user's account as its +parent address. This makes it easy to both identify whether an account is a parent, child, or both, and its associated +parent/child account(s). + +`OwnedAccount` resources underly all account delegations, so can have multiple parents whereas `ChildAccount`s are 1:1. +This provides more granular revocation as each parent account has its own Capability path on which its access relies. + +#### Restricted vs. Owned Accounts + +It's worth noting here that `ChildAccount` Capabilities enable access to the underlying account according to rules +configured by the child account delegating access. The `ChildAccount` maintains these rules along with an `OwnedAccount` +Capability within which the `&Account` Capability is stored. Anyone with access to the surface level `ChildAccount` +can then access the underlying `Account`, but only according the pre-defined rule set. These rules are fundamentally +a list of Types that can/cannot be retrieved from an account. + +The app developer can codify these rule sets on allowable Capability types in a +[`CapabilityFilter`](https://github.com/onflow/hybrid-custody/blob/main/contracts/CapabilityFilter.cdc) along with a +[`CapabilityFactory`](https://github.com/onflow/hybrid-custody/blob/main/contracts/CapabilityFactory.cdc) defining retrieval +patterns for those Capabilities. When delegation occurs, the developer would provide the `CapabilityFilter` and +`CapabilityFactory` Capabilities to an `OwnedAccount` resource which stores them in a `ChildAccount` resource. Then, +capabilities are created for the `OwnedAccount` and `ChildAccount` resource and are given to the specified parent +account. + +So, if an app developer wants to enable Hybrid Custody but doesn't want to allow parent accounts to access FungibleToken +Vaults, for example, the app developer can codify rule sets enumerating allowable Capability types in a +`CapabilityFilter` along with a `CapabilityFactory` defining retrieval patterns for those Capabilities. + +When delegation occurs, they would provide the `CapabilityFilter` and `CapabilityFactory` Capabilities to an +`OwnedAccount`. This `OwnedAccount` then wraps the given filter & factory Capabilities in a `ChildAccount` along with a +Capability to itself before publishing the new `ChildAccount` Capability for the specified parent account to claim. + +:::info + +Note that by enumerating allowable Types in your `CapabilityFilter.Filter` implementation, you're by default excluding +access to anything other than the Types you declare as allowable. + +::: + +As mentioned earlier, `Manager`s also maintain access to "owned" accounts - accounts which define unrestricted access as +they allow direct retrieval of encapsulated `&Account` Capabilities. These owned accounts, found in `Manager.ownedAccounts`, +are simply `OwnedAccount` Capabilities instead of `ChildAccount` Capabilities. + +![HybridCustody Total Overview](./resources/hybrid_custody_low_level.png) + +### Considerations + +Do note that this construction does not prevent an account from having multiple parent accounts or a child account from +being the parent to other accounts. While initial intuition might lead one to believe that account associations are a +tree with the user at the root, the graph of associated accounts among child accounts may lead to cycles of association. + +We believe it would be unlikely for a use case to demand a user delegates authority over their main account (in fact +we'd discourage such constructions), but delegating access between child accounts could be useful. As an example, +consider a set of local game clients across mobile and web platforms, each with self-custodied app accounts having +delegated authority to each other while both are child accounts of the user's main account. + +Ultimately, it will be up to the implementing wallet/marketplace how far down the graph of account associations they'd +want to traverse and display to the user. + +## Implementation + +From the perspective of a wallet or marketplace app, some relevant things to know about the user are: + +- Does this account have associated linked (child) accounts? +- What are those associated linked accounts, if any? +- What NFTs are owned by this user across all associated accounts? +- What are the balances of all FungibleTokens across all associated accounts? + +And with respect to acting on the assets of child accounts and managing child accounts themselves: + +- Accessing an NFT from a linked account's Collection +- Removing a linked account + +## Examples + +### Query Whether an Address Has Associated Accounts + +This script will return `true` if a `HybridCustody.Manager` is stored and `false` otherwise + +```cadence has_child_accounts.cdc +import "HybridCustody" + +access(all) fun main(parent: Address): Bool { + let acct = getAuthAccount(parent) + if let manager = acct.storage.borrow<&HybridCustody.Manager>(from: HybridCustody.ManagerStoragePath) { + return manager.getChildAddresses().length > 0 + } + return false +} +``` + +### Query All Accounts Associated with Address + +The following script will return an array of addresses associated with a given account's address, inclusive of the +provided address. If a `HybridCustody.Manager` is not found, the script will revert. + +```cadence get_child_addresses.cdc +import "HybridCustody" + +access(all) fun main(parent: Address): [Address] { + let acct = getAuthAccount(parent) + let manager = acct.storage.borrow<&HybridCustody.Manager>(from: HybridCustody.ManagerStoragePath) + ?? panic("manager not found") + return manager.getChildAddresses() +} +``` + +### Query All Owned NFT Metadata + +While it is possible to iterate over the storage of all associated accounts in a single script, memory limits prevent +this approach from scaling well. + +Since some accounts hold thousands of NFTs, we recommend breaking up iteration, utilizing several queries to iterate +over accounts and the storage of each account. Batching queries on individual accounts may even be required based on the +number of NFTs held. + +1. Get all associated account addresses (see above) +2. Looping over each associated account address client-side, get each address's owned NFT metadata + +For simplicity, we'll show a condensed query, returning NFT display views from all accounts associated with a given +address for a specified NFT Collection path. + +```cadence get_nft_display_view_from_public.cdc +import "NonFungibleToken" +import "MetadataViews" +import "HybridCustody" + +/// Returns resolved Display from given address at specified path for each ID or nil if ResolverCollection is not found +/// +access(all) +fun getViews(_ address: Address, _ resolverCollectionPath: PublicPath): {UInt64: MetadataViews.Display} { + + let account: PublicAccount = getAccount(address) + let views: {UInt64: MetadataViews.Display} = {} + + // Borrow the Collection + if let collection = account.capabilities.borrow<&{NonFungibleToken.Collection}>(resolverCollectionPath) { + // Iterate over IDs & resolve the view + for id in collection.getIDs() { + if let nft = collection.borrowNFT(id) { + if let display = nft.resolveView(Type()) as? MetadataViews.Display { + views.insert(key: id, display) + } + } + } + } + + return views +} + +/// Queries for MetadataViews.Display each NFT across all associated accounts from Collections at the provided +/// PublicPath +/// +access(all) +fun main(address: Address, resolverCollectionPath: PublicPath): {Address: {UInt64: MetadataViews.Display}} { + + let allViews: {Address: {UInt64: MetadataViews.Display}} = { + address: getViews(address, resolverCollectionPath) + } + + /* Iterate over any associated accounts */ + // + let seen: [Address] = [address] + if let managerRef = getAuthAccount(address) + .storage + .borrow<&HybridCustody.Manager>(from: HybridCustody.ManagerStoragePath) { + + for childAccount in managerRef.getChildAddresses() { + allViews.insert(key: childAccount, getViews(address, resolverCollectionPath)) + seen.append(childAccount) + } + + for ownedAccount in managerRef.getOwnedAddresses() { + if seen.contains(ownedAccount) == false { + allViews.insert(key: ownedAccount, getViews(address, resolverCollectionPath)) + seen.append(ownedAccount) + } + } + } + + return allViews +} +``` + +At the end of this query, the caller will have a mapping of `Display` views indexed on the NFT ID and grouped by account +Address. Note that this script does not take batching into consideration and assumes that each NFT resolves the +`MetadataViews.Display` view type. + +### Query All Account FungibleToken Balances + +Similar to the previous example, we recommend breaking up this task due to memory limits. + +1. Get all linked account addresses (see above) +2. Looping over each associated account address client-side, get each address's owned FungibleToken Vault metadata + +However, we'll condense both of these steps down into one script for simplicity: + +```cadence get_all_vault_bal_from_storage.cdc +import "FungibleToken" +import "MetadataViews" +import "HybridCustody" + +/// Returns a mapping of balances indexed on the Type of resource containing the balance +/// +access(all) +fun getAllBalancesInStorage(_ address: Address): {Type: UFix64} { + // Get the account + let account = getAuthAccount(address) + // Init for return value + let balances: {Type: UFix64} = {} + // Track seen Types in array + let seen: [Type] = [] + // Assign the type we'll need + let balanceType: Type = Type<@{FungibleToken.Balance}>() + // Iterate over all stored items & get the path if the type is what we're looking for + account.forEachStored(fun (path: StoragePath, type: Type): Bool { + if (type.isInstance(balanceType) || type.isSubtype(of: balanceType)) && !type.isRecovered { + // Get a reference to the resource & its balance + let vaultRef = account.borrow<&{FungibleToken.Balance}>(from: path)! + // Insert a new values if it's the first time we've seen the type + if !seen.contains(type) { + balances.insert(key: type, vaultRef.balance) + } else { + // Otherwise just update the balance of the vault (unlikely we'll see the same type twice in + // the same account, but we want to cover the case) + balances[type] = balances[type]! + vaultRef.balance + } + } + return true + }) + return balances +} + +/// Queries for FT.Vault balance of all FT.Vaults in the specified account and all of its associated accounts +/// +access(all) +fun main(address: Address): {Address: {Type: UFix64}} { + + // Get the balance for the given address + let balances: {Address: {Type: UFix64}} = { address: getAllBalancesInStorage(address) } + // Tracking Addresses we've come across to prevent overwriting balances (more efficient than checking dict entries (?)) + let seen: [Address] = [address] + + /* Iterate over any associated accounts */ + // + if let managerRef = getAuthAccount(address) + .storage + .borrow<&HybridCustody.Manager>(from: HybridCustody.ManagerStoragePath) { + + for childAccount in managerRef.getChildAddresses() { + balances.insert(key: childAccount, getAllBalancesInStorage(address)) + seen.append(childAccount) + } + + for ownedAccount in managerRef.getOwnedAddresses() { + if seen.contains(ownedAccount) == false { + balances.insert(key: ownedAccount, getAllBalancesInStorage(address)) + seen.append(ownedAccount) + } + } + } + + return balances +} +``` + +The above script returns a dictionary of balances indexed on the type and further grouped by account Address. + +The returned data at the end of address iteration should be sufficient to achieve a unified balance of all Vaults of +similar types across all of a user's associated account as well as a more granular per account view. + +You might consider resolving +[`FungibleTokenMetadataViews`](https://github.com/onflow/flow-ft/blob/master/contracts/FungibleTokenMetadataViews.cdc) +to aggregate more information about the underlying Vaults. + +### Access NFT in Child Account from Parent Account + +A user with NFTs in their child accounts will likely want to utilize said NFTs. In this example, the user will sign a +transaction with their authenticated account that retrieves a reference to a child account's +`NonFungibleToken.Provider`, enabling withdrawal from the child account having signed as the parent account. + +```cadence withdraw_nft_from_child.cdc +import "NonFungibleToken" +import "FlowToken" +import "HybridCustody" + +transaction( + childAddress: Address, // Address of the child account + storagePath: StoragePath, // Path to the Collection in the child account + collectionType: Type, // Type of the requested Collection from which to withdraw + withdrawID: UInt64 // ID of the NFT to withdraw + ) { + + let providerRef: auth(NonFungibleToken.Withdraw) &{NonFungibleToken.Provider} + + prepare(signer: auth(BorrowValue) &Account) { + // Get a reference to the signer's HybridCustody.Manager from storage + let managerRef = signer.storage.borrow( + from: HybridCustody.ManagerStoragePath + ) ?? panic("Could not borrow reference to HybridCustody.Manager in signer's account at expected path!") + + // Borrow a reference to the signer's specified child account + let account = managerRef + .borrowAccount(addr: childAddress) + ?? panic("Signer does not have access to specified child account") + + // Get the Capability Controller ID for the requested collection type + let controllerID = account.getControllerIDForType( + type: collectionType, + forPath: storagePath + ) ?? panic("Could not find Capability controller ID for collection type ".concat(collectionType.identifier) + .concat(" at path ").concat(storagePath.toString())) + + // Get a reference to the child NFT Provider and assign to the transaction scope variable + let cap = account.getCapability( + controllerID: controllerID, + type: Type() + ) ?? panic("Cannot access NonFungibleToken.Provider from this child account") + + // We'll need to cast the Capability - this is possible thanks to CapabilityFactory, though we'll rely on the relevant + // Factory having been configured for this Type or it won't be castable + let providerCap = cap as! Capability + self.providerRef = providerCap.borrow() ?? panic("Provider capability is invalid - cannot borrow reference") + } + + execute { + // Withdraw the NFT from the Collection + let nft <- self.providerRef.withdraw(withdrawID: withdrawID) + // Do stuff with the NFT + // NOTE: Without storing or burning the NFT before scope closure, this transaction will fail. You'll want to + // fill in the rest of the transaction with the necessary logic to handle the NFT + // ... + } +} + + + +``` + +At the end of this transaction, you withdrew an NFT from the specified account using an NFT `Provider` Capability. A +similar approach could get you any allowable Capabilities from a signer's child account. + +### Revoking Secondary Access on a Linked Account + +The expected uses of child accounts for progressive onboarding implies that they will be accounts with shared access. A +user may decide that they no longer want secondary parties to have access to the child account. + +There are two ways a party can have delegated access to an account - keys and `&Account` Capability. With +`ChildAccount` mediated access, a user wouldn't be able to revoke anyone's access except for their own. With +unrestricted access via `OwnedAccount`, one could remove parents (`OwnedAccount.removeParent(parent: Address)`) thereby +unlinking relevant Capabilities and further destroying their `ChildAccount` and `CapabilityDelegator` resources. + +For now, we recommend that if users want to revoke secondary access, they transfer any assets from the relevant child +account and remove it from their `Manager` altogether. + +### Remove a Child Account + +As mentioned above, if a user no longer wishes to share access with another party, it's recommended that desired assets +be transferred from that account to either their main account or other linked accounts and the linked account be removed +from their `HybridCustody.Manager`. Let's see how to complete that removal. + +```cadence remove_child_account.cdc +import "HybridCustody" + +transaction(child: Address) { + prepare (acct: auth(BorrowValue) &Account) { + let manager = acct.storage.borrow( + from: HybridCustody.ManagerStoragePath + ) ?? panic("manager not found") + manager.removeChild(addr: child) + } +} +``` + +After removal, the signer no longer has delegated access to the removed account via their `Manager` and the caller is +removed as a parent of the removed child. + +Note also that it's possible for a child account to remove a parent. This is necessary to give application developers +and ultimately the owners of these child accounts the ability to revoke secondary access on owned accounts. \ No newline at end of file diff --git a/static/markdown/build/guides/fungible-token.md b/static/markdown/build/guides/fungible-token.md new file mode 100644 index 0000000000..1422b32be7 --- /dev/null +++ b/static/markdown/build/guides/fungible-token.md @@ -0,0 +1,1132 @@ +--- +title: Creating a Fungible Token +description: Learn how to create and deploy a fungible token on Flow using Cadence. Follow this guide to implement the Flow Fungible Token standard, manage token minting, transfers, and vault management. +sidebar_position: 6 +keywords: + - fungible token + - Flow token + - token standard + - smart contract + - Cadence + - token minting + - token transfers + - vault management + - Flow CLI + - token deployment + - FT standard + - token balance + - Flow development + - token contract + - blockchain tokens +--- + +:::info + +This guide is an in-depth tutorial on launching a Fungible Token contract from scratch. To launch in 2 minutes using a tool check out [Toucans](https://toucans.ecdao.org/) + +::: + +## What are Fungible Tokens? + +Fungible tokens are digital assets that are interchangeable and indistinguishable with other tokens of the same type. This means that each token is identical in specification to every other token in circulation. Think of them like traditional money; every dollar bill has the same value as every other dollar bill. Fungible tokens play a crucial role in web3 ecosystems, serving as both a means of payment and an incentive for network participation. They can take on various roles including currencies, structured financial instruments, shares of index funds, and even voting rights in decentralized autonomous organizations. + +## Vaults on Flow + +On the Flow blockchain and in the Cadence programming language, +fungible tokens are stored in structures called resources. +Resources are objects in Cadence that store data, +but have special restrictions about how they can be stored and transferred, +making them perfect for representing digital objects with real value. + +You can learn more about resources in the Cadence [documentation](https://cadence-lang.org/docs/language/resources) +and [tutorials](https://cadence-lang.org/docs/tutorial/resources). + +For fungible tokens specifically, tokens are represented by a resource type called a `Vault`: + +```cadence +access(all) resource interface Vault { + + /// Field that tracks the balance of a vault + access(all) var balance: UFix64 + +} +``` + +Think of a `Vault` as a digital piggy bank. +Users who own fungible tokens store vault objects that track their balances +directly in their account storage. This is opposed to languages +that track user balances in a central ledger smart contract. + +When you transfer tokens from one vault to another: + +1. The transferor's vault creates a temporary vault holding the transfer amount. +2. The original vault's balance decreases by the transfer amount. +3. The recipient's vault receives the tokens from the temporary vault + and adds the temporary vault's balance to the its own balance. +4. The temporary vault is then destroyed. + +This process ensures secure and accurate token transfers on the Flow blockchain. + +## Fungible Token Standard + +The [Fungible Token Standard](https://github.com/onflow/flow-ft) defines how a fungible token should behave on Flow. +Wallets and other platforms need to recognize these tokens, +so they adhere to a specific interface, which defines fields like balance, +totalSupply, withdraw functionality, and more. +This interface ensures that all fungible tokens on Flow have a consistent structure and behavior. +Clink the link to the fungible token standard to see the full standard +and learn about specific features and requirements. + +[Learn more about interfaces here](https://developers.flow.com/cadence/language/interfaces). + +## Setting Up a Project + +To start creating a Fungible Token on the Flow blockchain, you'll first need some tools and configurations in place. + +### Installing Flow CLI + +The **Flow CLI** (Command Line Interface) provides a suite of tools that allow developers to interact seamlessly with the Flow blockchain. + +If you haven't installed the Flow CLI yet and have [Homebrew](https://brew.sh/) installed, +you can run `brew install flow-cli`. If you don't have Homebrew, +please follow [the installation guide here](https://developers.flow.com/tools/flow-cli/install). + +### Initializing a New Project + +> 💡 Note: Here is [a link to the completed code](https://github.com/chasefleming/FooToken) if you want to skip ahead or reference as you follow along. + +Once you have the Flow CLI installed, you can set up a new project using the `flow init` command. This command initializes the necessary directory structure and a `flow.json` configuration file (a way to configure your project for contract sources, deployments, accounts, and more): + +```bash +flow init FooToken +``` + +> Note: Select "No" when it asks you to install core contracts for the purposes of this tutorial. + +Upon execution, the command will generate the following directory structure: + +``` +/cadence + /contracts + /scripts + /transactions + /tests +flow.json +``` + +Now, navigate into the project directory: + +```bash +cd FooToken +``` + +In our configuration file, called `flow.json`, for the network we want to use, +we are going to state the address the `FungibleToken` contract is deployed +to via `aliases` in a new `contracts` section. Since it is a standard contract, +it has already been deployed to the emulator, a tool that runs and emulates +a local development version of the Flow Blockchain, for us. +You can find addresses for other networks, like Testnet and Mainnet, on the [Fungible Token Standard repo](https://github.com/onflow/flow-ft). + +We'll also need to add the addresses for `ViewResolver`, `MetadataViews`, +and `FungibleTokenMetadataViews`, which are other important contracts to use. +These contracts are deployed to the Flow emulator by default, +so there is not need to copy their code into your repo. +The addresses below are the addresses in the emulator that your contract +will import them from. + +```json +"contracts": { + "FungibleToken": { + "aliases": { + "emulator": "0xee82856bf20e2aa6" + } + }, + "FungibleTokenMetadataViews": { + "aliases": { + "emulator": "0xee82856bf20e2aa6" + } + }, + "ViewResolver": { + "aliases": { + "emulator": "0xf8d6e0586b0a20c7" + } + }, + "MetadataViews": { + "aliases": { + "emulator": "0xf8d6e0586b0a20c7" + } + } +} +``` + +## Writing Our Token Contract + +Next let's create a `FooToken` contract at `cadence/contract/FooToken.cdc` using the boilerplate `generate` command from the Flow CLI: + +```bash +flow generate contract FooToken +``` + +This will create a new file called `FooToken.cdc` in the `contracts` directory. Let's open it up and add some code. + +In this contract file, we want to import our `FungibleToken` contract that we've defined in `flow.json`. + +```cadence +import "FungibleToken" +``` + +In this same file, let's create our contract which implements the `FungibleToken` contract interface (it does so by setting it following the `FooToken:`). +We'll also include fields for standard storage and public paths +for our resource definitions. +In our `init` — which runs on the contract's first deployment and is used to set initial values — let's set an starting total supply of 1,000 tokens for this example. + +```cadence +// ...previous code + +access(all) contract FooToken: FungibleToken { + access(all) var totalSupply: UFix64 + + access(all) let VaultStoragePath: StoragePath + access(all) let VaultPublicPath: PublicPath + access(all) let MinterStoragePath: StoragePath + + init() { + self.totalSupply = 1000.0 + self.VaultStoragePath = /storage/fooTokenVault + self.VaultPublicPath = /public/fooTokenVault + self.MinterStoragePath = /storage/fooTokenMinter + } +} +``` + +### Creating a Vault + +Inside of this contract, we'll need to create a resource for a `Vault`. +The `FungibleToken` standard requires that your vault implements the `FungibleToken.Vault` interface. +This interface inherits from [many other interfaces](https://github.com/onflow/flow-ft/blob/master/contracts/FungibleToken.cdc#L140) +which enforce different functionality that you can learn about in the standard. + +```cadence +import "FungibleToken" + +access(all) contract FooToken: FungibleToken { + // ...totalSupply and path code + + access(all) resource Vault: FungibleToken.Vault { + + access(all) var balance: UFix64 + + init(balance: UFix64) { + self.balance = balance + } + } + + // ...init code +} +``` + +In order to give an account a vault, we need to create a function +that creates a vault of our FooToken type and returns it to the account. +This function takes a `vaultType: Type` argument that allows the caller +to specify which type of `Vault` they want to create. +Contracts that implement multiple `Vault` types can use this argument, +but since your contract is only implementing one `Vault` type, +it can ignore the argument. + +A simpler version of this function with no parameter +should also be added to your `Vault` implementation. + +```cadence +import "FungibleToken" + +access(all) contract FooToken: FungibleToken { + // ...other code + + access(all) resource Vault: FungibleToken.Vault { + + // ...other vault code + + access(all) fun createEmptyVault(): @FooToken.Vault { + return <-create Vault(balance: 0.0) + } + + // ...vault init code + } + + // ...other code + + access(all) fun createEmptyVault(vaultType: Type): @FooToken.Vault { + return <- create Vault(balance: 0.0) + } + + // ...FooToken.init() code +} +``` + +Inside our `Vault` resource, we also need a way to withdraw balances. +To do that, we need to add a `withdraw()` function that returns a new vault +with the transfer amount and decrements the existing balance. + +```cadence +import "FungibleToken" + +access(all) contract FooToken: FungibleToken { + + // ...previous code + + access(all) resource Vault: FungibleToken.Vault { + + // ...other vault code + + access(FungibleToken.Withdraw) fun withdraw(amount: UFix64): @FooToken.Vault { + self.balance = self.balance - amount + return <-create Vault(balance: amount) + } + + // ...vault init code + } + + // ...additional code +} +``` + +As you can see, this function has an `access(FungibleToken.Withdraw)` access modifier. +This is an example of entitlements in Cadence. +[Entitlements](https://cadence-lang.org/docs/language/access-control#entitlements) +are a way for developers to restrict access to privileged fields and functions +in a composite type like a resource when a reference is created for it. +In this example, the `withdraw()` function is always accessible to code that +controls the full `Vault` object, but if a reference is created for it, +the `withdraw()` function can only be called if the reference +is authorized by the owner with `FungibleToken.Withdraw`, +which is [a standard entitlement](https://github.com/onflow/flow-ft/blob/master/contracts/FungibleToken.cdc#L53) +defined by the FungibleToken contract: + +```cadence +// Example of an authorized entitled reference to a FungibleToken.Vault + +``` + +Entitlements are important to understand because they are what protects +privileged functionality in your resource objects from being accessed by third-parties. +It is recommended to read the [entitlements documentation](https://cadence-lang.org/docs/language/access-control#entitlements) +to understand how to use the feature properly. + +[References](https://cadence-lang.org/docs/language/references) can be freely up-casted and down-casted in Cadence, so it is important +for privileged functionality to be protected by an entitlement so that it can +only be accessed if it is authorized. + +In addition to withdrawing, the vault also needs a way to deposit. +We'll [typecast](https://cadence-lang.org/docs/language/operators#casting-operators) +to make sure we are dealing with the correct token, update the vault balance, +and destroy the vault. Add this code to your resource: + +```cadence +import "FungibleToken" + +access(all) contract FooToken: FungibleToken { + + // ...previous code + + access(all) resource Vault: FungibleToken.Vault { + + // ...other vault code + + access(all) fun deposit(from: @{FungibleToken.Vault}) { + let vault <- from as! @FooToken.Vault + self.balance = self.balance + vault.balance + destroy vault + } + + // ...vault init + + } + + // ...additional code +} +``` + +Many projects rely on events the signal when withdrawals, deposits, or burns happen. +Luckily, the `FungibleToken` standard handles the definition and emission +of events for projects, so there is no need for you to add any events +to your implementation for withdraw, deposit, and burn. + +Here are the `FungibleToken` event definitions: + +```cadence +/// The event that is emitted when tokens are withdrawn from a Vault +access(all) event Withdrawn(type: String, amount: UFix64, from: Address?, fromUUID: UInt64, withdrawnUUID: UInt64, balanceAfter: UFix64) + +/// The event that is emitted when tokens are deposited to a Vault +access(all) event Deposited(type: String, amount: UFix64, to: Address?, toUUID: UInt64, depositedUUID: UInt64, balanceAfter: UFix64) + +/// Event that is emitted when the global burn method is called with a non-zero balance +access(all) event Burned(type: String, amount: UFix64, fromUUID: UInt64) +``` + +These events are [emitted by the `Vault` interface](https://github.com/onflow/flow-ft/blob/master/contracts/FungibleToken.cdc#L198) +in the `FungibleToken` contract whenever the relevant function is called on any implementation. + +One important piece to understand about the `Burned` event in particular +is that in order for it to be emitted when a `Vault` is burned, it needs to +be burnt via [the `Burner` contract's `burn()` method](https://github.com/onflow/flow-ft/blob/master/contracts/utility/Burner.cdc#L23). + +The [`Burner` contract](../core-contracts/14-burner.md) defines a standard +that all projects should use for handling the destruction of any resource. +It allows projects to define custom logic that can be executed when a resource is destroyed, +like emitting events, or updating a field in the contract to show that the resource was destroyed. + +This will call the resource's `burnCallback()` function, which emits the event. +You'll need to also add this function to your token contract now: + +```cadence +import "FungibleToken" + +access(all) contract FooToken: FungibleToken { + + // ...previous code + + access(all) resource Vault: FungibleToken.Vault { + + // ...other vault code + + /// Called when a fungible token is burned via the `Burner.burn()` method + access(contract) fun burnCallback() { + if self.balance > 0.0 { + FooToken.totalSupply = FooToken.totalSupply - self.balance + } + self.balance = 0.0 + } + + // ...vault init + + } + + // ...additional code +} +``` + +If you ever need to destroy a `Vault` with a non-zero balance, +you should destroy it via the `Burner.burn` method so this important function can be called. + +There are three other utility methods that need to be added to your `Vault` +to get various information: + +```cadence +import "FungibleToken" + +access(all) contract FooToken: FungibleToken { + + // ...previous code + + access(all) resource Vault: FungibleToken.Vault { + + // ...other vault code + + /// getSupportedVaultTypes optionally returns a list of vault types that this receiver accepts + access(all) view fun getSupportedVaultTypes(): {Type: Bool} { + let supportedTypes: {Type: Bool} = {} + supportedTypes[self.getType()] = true + return supportedTypes + } + + /// Says if the Vault can receive the provided type in the deposit method + access(all) view fun isSupportedVaultType(type: Type): Bool { + return self.getSupportedVaultTypes()[type] ?? false + } + + /// Asks if the amount can be withdrawn from this vault + access(all) view fun isAvailableToWithdraw(amount: UFix64): Bool { + return amount <= self.balance + } + + // ...vault init + + } + + // ...additional code +} +``` + +### Adding Support for Metadata Views + +The Fungible Token standard also enforces that implementations +provide functionality to return a set of standard views about the tokens +via the [ViewResolver](https://github.com/onflow/flow-nft/blob/master/contracts/ViewResolver.cdc) +and [FungibleTokenMetadataViews](https://github.com/onflow/flow-ft/blob/master/contracts/FungibleTokenMetadataViews.cdc) definitions. +(You will need to add these imports to your contract now) +These provide developers with standard ways of representing metadata +about a given token such as supply, token symbols, website links, and standard +account paths and types that third-parties can access in a standard way. +You can see the [metadata views documentation](../advanced-concepts/metadata-views.md) +for a more thorough guide using a NFT contract as an example. + +For now, you can add this code to your contract to support the important metadata views: + +```cadence +import "FungibleToken" + +// Add these imports +import "MetadataViews" +import "FungibleTokenMetadataViews" + +access(all) contract FooToken: FungibleToken { + // ...other code + + access(all) view fun getContractViews(resourceType: Type?): [Type] { + return [ + Type(), + Type(), + Type(), + Type() + ] + } + + access(all) fun resolveContractView(resourceType: Type?, viewType: Type): AnyStruct? { + switch viewType { + case Type(): + return FungibleTokenMetadataViews.FTView( + ftDisplay: self.resolveContractView(resourceType: nil, viewType: Type()) as! FungibleTokenMetadataViews.FTDisplay?, + ftVaultData: self.resolveContractView(resourceType: nil, viewType: Type()) as! FungibleTokenMetadataViews.FTVaultData? + ) + case Type(): + let media = MetadataViews.Media( + file: MetadataViews.HTTPFile( + // Change this to your own SVG image + url: "https://assets.website-files.com/5f6294c0c7a8cdd643b1c820/5f6294c0c7a8cda55cb1c936_Flow_Wordmark.svg" + ), + mediaType: "image/svg+xml" + ) + let medias = MetadataViews.Medias([media]) + return FungibleTokenMetadataViews.FTDisplay( + // Change these to represent your own token + name: "Example Foo Token", + symbol: "EFT", + description: "This fungible token is used as an example to help you develop your next FT #onFlow.", + externalURL: MetadataViews.ExternalURL("https://developers.flow.com/build/guides/fungible-token"), + logos: medias, + socials: { + "twitter": MetadataViews.ExternalURL("https://twitter.com/flow_blockchain") + } + ) + case Type(): + return FungibleTokenMetadataViews.FTVaultData( + storagePath: self.VaultStoragePath, + receiverPath: self.VaultPublicPath, + metadataPath: self.VaultPublicPath, + receiverLinkedType: Type<&FooToken.Vault>(), + metadataLinkedType: Type<&FooToken.Vault>(), + createEmptyVaultFunction: (fun(): @{FungibleToken.Vault} { + return <-FooToken.createEmptyVault(vaultType: Type<@FooToken.Vault>()) + }) + ) + case Type(): + return FungibleTokenMetadataViews.TotalSupply( + totalSupply: FooToken.totalSupply + ) + } + return nil + } + + // ...other code + + access(all) resource Vault: FungibleToken.Vault { + + // ...other vault code + + access(all) view fun getViews(): [Type] { + return FooToken.getContractViews(resourceType: nil) + } + + access(all) fun resolveView(_ view: Type): AnyStruct? { + return FooToken.resolveContractView(resourceType: nil, viewType: view) + } + + // ...other vault code + } + + // ...other FooToken code +} +``` + +### Creating a Minter + +Let's create a minter resource which is used to mint vaults that have tokens in them. We can keep track of tokens we are minting with totalSupply + +If we want the ability to create new tokens, we'll need a way to mint them. To do that, let's create another resource on the `FooToken` contract. This will have a `mintToken`function which can increase the total supply of the token. + +```cadence +import "FungibleToken" +import "MetadataViews" +import "FungibleTokenMetadataViews" + +access(all) contract FooToken: FungibleToken { + + // ...additional contract code + + // Add this event + access(all) event TokensMinted(amount: UFix64, type: String) + + /// Minter + /// + /// Resource object that token admin accounts can hold to mint new tokens. + /// + access(all) resource Minter { + /// mintTokens + /// + /// Function that mints new tokens, adds them to the total supply, + /// and returns them to the calling context. + /// + access(all) fun mintTokens(amount: UFix64): @FooToken.Vault { + FooToken.totalSupply = FooToken.totalSupply + amount + let vault <-create Vault(balance: amount) + emit TokensMinted(amount: amount, type: vault.getType().identifier) + return <-vault + } + } + + // ...additional contract code +} +``` + +We also want to decide which account/s we want to give this ability to. +In our example, we'll give it to the account where the contract is deployed. +We can set this in the contract init function below the setting of total supply +so that when the contract is created the minter is stored on the same account. + +```cadence +import "FungibleToken" +import "MetadataViews" +import "FungibleTokenMetadataViews" + +access(all) contract FooToken: FungibleToken { + + // ...additional contract code + + init() { + self.totalSupply = 1000.0 // existed before + self.account.save(<- create Minter(), to: self.MinterStoragePath) + } +} +``` + +After each of these steps, your `FooToken.cdc` contract file should now look like this: + +```cadence +import "FungibleToken" +import "MetadataViews" +import "FungibleTokenMetadataViews" + +access(all) contract FooToken: FungibleToken { + + /// The event that is emitted when new tokens are minted + access(all) event TokensMinted(amount: UFix64, type: String) + + /// Total supply of FooTokens in existence + access(all) var totalSupply: UFix64 + + /// Storage and Public Paths + access(all) let VaultStoragePath: StoragePath + access(all) let VaultPublicPath: PublicPath + access(all) let ReceiverPublicPath: PublicPath + access(all) let MinterStoragePath: StoragePath + + access(all) view fun getContractViews(resourceType: Type?): [Type] { + return [ + Type(), + Type(), + Type(), + Type() + ] + } + + access(all) fun resolveContractView(resourceType: Type?, viewType: Type): AnyStruct? { + switch viewType { + case Type(): + return FungibleTokenMetadataViews.FTView( + ftDisplay: self.resolveContractView(resourceType: nil, viewType: Type()) as! FungibleTokenMetadataViews.FTDisplay?, + ftVaultData: self.resolveContractView(resourceType: nil, viewType: Type()) as! FungibleTokenMetadataViews.FTVaultData? + ) + case Type(): + let media = MetadataViews.Media( + file: MetadataViews.HTTPFile( + // Change this to your own SVG image + url: "https://assets.website-files.com/5f6294c0c7a8cdd643b1c820/5f6294c0c7a8cda55cb1c936_Flow_Wordmark.svg" + ), + mediaType: "image/svg+xml" + ) + let medias = MetadataViews.Medias([media]) + return FungibleTokenMetadataViews.FTDisplay( + // Change these to represent your own token + name: "Example Foo Token", + symbol: "EFT", + description: "This fungible token is used as an example to help you develop your next FT #onFlow.", + externalURL: MetadataViews.ExternalURL("https://developers.flow.com/build/guides/fungible-token"), + logos: medias, + socials: { + "twitter": MetadataViews.ExternalURL("https://twitter.com/flow_blockchain") + } + ) + case Type(): + return FungibleTokenMetadataViews.FTVaultData( + storagePath: self.VaultStoragePath, + receiverPath: self.VaultPublicPath, + metadataPath: self.VaultPublicPath, + receiverLinkedType: Type<&FooToken.Vault>(), + metadataLinkedType: Type<&FooToken.Vault>(), + createEmptyVaultFunction: (fun(): @{FungibleToken.Vault} { + return <-FooToken.createEmptyVault(vaultType: Type<@FooToken.Vault>()) + }) + ) + case Type(): + return FungibleTokenMetadataViews.TotalSupply( + totalSupply: FooToken.totalSupply + ) + } + return nil + } + + access(all) resource Vault: FungibleToken.Vault { + + /// The total balance of this vault + access(all) var balance: UFix64 + + // initialize the balance at resource creation time + init(balance: UFix64) { + self.balance = balance + } + + /// Called when a fungible token is burned via the `Burner.burn()` method + access(contract) fun burnCallback() { + if self.balance > 0.0 { + FooToken.totalSupply = FooToken.totalSupply - self.balance + } + self.balance = 0.0 + } + + access(all) view fun getViews(): [Type] { + return FooToken.getContractViews(resourceType: nil) + } + + access(all) fun resolveView(_ view: Type): AnyStruct? { + return FooToken.resolveContractView(resourceType: nil, viewType: view) + } + + access(all) view fun getSupportedVaultTypes(): {Type: Bool} { + let supportedTypes: {Type: Bool} = {} + supportedTypes[self.getType()] = true + return supportedTypes + } + + access(all) view fun isSupportedVaultType(type: Type): Bool { + return self.getSupportedVaultTypes()[type] ?? false + } + + access(all) view fun isAvailableToWithdraw(amount: UFix64): Bool { + return amount <= self.balance + } + + access(FungibleToken.Withdraw) fun withdraw(amount: UFix64): @FooToken.Vault { + self.balance = self.balance - amount + return <-create Vault(balance: amount) + } + + access(all) fun deposit(from: @{FungibleToken.Vault}) { + let vault <- from as! @FooToken.Vault + self.balance = self.balance + vault.balance + vault.balance = 0.0 + destroy vault + } + + access(all) fun createEmptyVault(): @FooToken.Vault { + return <-create Vault(balance: 0.0) + } + } + + access(all) resource Minter { + /// mintTokens + /// + /// Function that mints new tokens, adds them to the total supply, + /// and returns them to the calling context. + /// + access(all) fun mintTokens(amount: UFix64): @FooToken.Vault { + FooToken.totalSupply = FooToken.totalSupply + amount + let vault <-create Vault(balance: amount) + emit TokensMinted(amount: amount, type: vault.getType().identifier) + return <-vault + } + } + + access(all) fun createEmptyVault(vaultType: Type): @FooToken.Vault { + return <- create Vault(balance: 0.0) + } + + init() { + self.totalSupply = 1000.0 + + self.VaultStoragePath = /storage/fooTokenVault + self.VaultPublicPath = /public/fooTokenVault + self.MinterStoragePath = /storage/fooTokenMinter + + // Create the Vault with the total supply of tokens and save it in storage + // + let vault <- create Vault(balance: self.totalSupply) + emit TokensMinted(amount: vault.balance, type: vault.getType().identifier) + self.account.storage.save(<-vault, to: self.VaultStoragePath) + + // Create a public capability to the stored Vault that exposes + // the `deposit` method and getAcceptedTypes method through the `Receiver` interface + // and the `balance` method through the `Balance` interface + // + let fooTokenCap = self.account.capabilities.storage.issue<&FooToken.Vault>(self.VaultStoragePath) + self.account.capabilities.publish(fooTokenCap, at: self.VaultPublicPath) + + let minter <- create Minter() + self.account.storage.save(<-minter, to: self.MinterStoragePath) + } +} +``` + +## Deploying the Contract + +In order to use the contract, we need to deploy it to the network we want to use it on. +In our case we are going to deploy it to emulator while developing. + +Back in our `flow.json`, let's add our `FooToken` to the `contracts` after `FungibleToken` with the path of the source code: + +```json +"FooToken": "cadence/contracts/FooToken.cdc" +``` + +Let's also add a new `deployments` section to `flow.json` with the network +we want to deploy it to, `emulator`, the account we want it deployed to `emulator-account`, +and the list of contracts we want deployed in the array. + +```json +"deployments": { + "emulator": { + "emulator-account": ["FooToken"] + } +} +``` + +Next, using the Flow CLI, we will start the emulator. As mentioned, +this will give us a local development environment for the Flow Blockchain. + +```bash +flow emulator start +``` + +Open a new terminal and run the following to deploy your project: + +```bash +flow project deploy +``` + +Congrats, you've deployed your contract to the Flow Blockchain emulator. +To read more about deploying your project to other environments, +see the [CLI docs](https://developers.flow.com/tools/flow-cli/deployment/deploy-project-contracts). + +## Reading the Token's Total Supply + +Let's now check that our total supply was initialized with 1,000 FooTokens. Go ahead and create a script called `get_total_supply.cdc` using the `generate` command. + +```bash +flow generate script get_total_supply +``` + +In `cadence/scripts/get_total_supply.cdc` (which was just created), let's add this code which will log the `totalSupply` value from the `FooToken` contract: + +```cadence +import "FooToken" + +access(all) fun main(): UFix64 { + return FooToken.totalSupply +} +``` + +To run this using the CLI, enter this in your terminal: + +```bash +flow scripts execute cadence/scripts/get_total_supply.cdc +``` + +In the terminal where you started the emulator, you should see `Result: 1000.0` + +To learn more about running scripts using Flow CLI, [see the docs](https://developers.flow.com/tools/flow-cli/scripts/execute-scripts). + +## Giving Accounts the Ability to Receive Tokens + +On Flow, newly created accounts cannot receive arbitrary assets. +They need to be initialized to receive resources. +In our case, we want to give accounts tokens and we'll need to create +a `Vault` (which acts as a receiver) on each account that we want +to have the ability to receive tokens. To do this, we'll need to run a transaction +which will create the vault and set it in their storage +using the `createEmptyVault()` function we created earlier on the contract. + +Let's first create the file at `cadence/transactions/setup_ft_account.cdc` using the `generate` command: + +```bash +flow generate transaction setup_ft_account +``` + +Then add this code to it. +This will call the `createEmptyVault` function, save it in storage, +and create a capability for the vault which will later allow us to read from it +(To learn more about capabilities, see [the Cadence docs here](https://developers.flow.com/cadence/language/capabilities)). + +```cadence +import "FungibleToken" +import "FooToken" + +transaction () { + + prepare(signer: auth(BorrowValue, IssueStorageCapabilityController, PublishCapability, SaveValue) &Account) { + + // Return early if the account already stores a FooToken Vault + if signer.storage.borrow<&FooToken.Vault>(from: FooToken.VaultStoragePath) != nil { + return + } + + let vault <- FooToken.createEmptyVault(vaultType: Type<@FooToken.Vault>()) + + // Create a new FooToken Vault and put it in storage + signer.storage.save(<-vault, to: FooToken.VaultStoragePath) + + // Create a public capability to the Vault that exposes the Vault interfaces + let vaultCap = signer.capabilities.storage.issue<&FooToken.Vault>( + FooToken.VaultStoragePath + ) + signer.capabilities.publish(vaultCap, at: FooToken.VaultPublicPath) + } +} +``` + +There are also examples of [generic transactions](https://github.com/onflow/flow-ft/blob/master/transactions/metadata/setup_account_from_address.cdc) +that you can use to setup an account for ANY fungible token using metadata views! +You should check those out and try to use generic transactions whenever it is possible. + +Next let's create a new emulator account using the CLI. We'll use this account to create a new vault and mint tokens into it. Run: + +```bash +flow accounts create +``` + +Let's call it `test-acct` and select "Emulator" for the network: + +```bash +test-acct +``` + +This will have added a new account, called `test-acct` to your `flow.json`. + +To call our setup account transaction from the CLI, we'll run the following: + +```bash +flow transactions send ./cadence/transactions/setup_ft_account.cdc --signer test-acct --network emulator +``` + +To learn more about running transactions using CLI, [see the docs](https://developers.flow.com/tools/flow-cli/transactions/send-transactions). + +## Reading a Vault's Balance + +Let's now read the balance of the newly created account (`test-acct`) to check it's zero. + +Create this new script file `cadence/scripts/get_footoken_balance.cdc`: + +```bash +flow generate script get_footoken_balance +``` + +Add this code which attempts to borrow the capability from the account requested and logs the vault balance if permitted: + +```cadence +import "FungibleToken" +import "FooToken" +import "FungibleTokenMetadataViews" + +access(all) fun main(address: Address): UFix64 { + let vaultData = FooToken.resolveContractView(resourceType: nil, viewType: Type()) as! FungibleTokenMetadataViews.FTVaultData? + ?? panic("Could not get FTVaultData view for the FooToken contract") + + return getAccount(address).capabilities.borrow<&{FungibleToken.Balance}>( + vaultData.metadataPath + )?.balance + ?? panic("Could not borrow a reference to the FooToken Vault in account " + .concat(address.toString()).concat(" at path ").concat(vaultData.metadataPath.toString()) + .concat(". Make sure you are querying an address that has an FooToken Vault set up properly.")) +} +``` + +To run this script using the CLI, enter the following in your terminal. +Note: you'll need to replace `123` with the address created by CLI +in your `flow.json` for the `test-acct` address. + +```bash +flow scripts execute cadence/scripts/get_footoken_balance.cdc 123 // change "123" to test-acct address +``` + +You should see a balance of zero logged. + +## Minting More Tokens + +Now that we have an account with a vault, let's mint some tokens into it +using the Minter we created on the contract account. + +To do this, let's create a new transaction file `cadence/transactions/mint_footoken.cdc`: + +```bash +flow generate transaction mint_footoken +``` + +Next, let's add the following code to the `mint_footoken.cdc` file. +This code will attempt to borrow the minting capability +and mint 20 new tokens into the receivers account. + +```cadence +import "FungibleToken" +import "FooToken" + +transaction(recipient: Address, amount: UFix64) { + + /// Reference to the Example Token Minter Resource object + let tokenMinter: &FooToken.Minter + + /// Reference to the Fungible Token Receiver of the recipient + let tokenReceiver: &{FungibleToken.Receiver} + + prepare(signer: auth(BorrowValue) &Account) { + + // Borrow a reference to the admin object + self.tokenMinter = signer.storage.borrow<&FooToken.Minter>(from: FooToken.MinterStoragePath) + ?? panic("Cannot mint: Signer does not store the FooToken Minter in their account!") + + self.tokenReceiver = getAccount(recipient).capabilities.borrow<&{FungibleToken.Receiver}>(FooToken.VaultPublicPath) + ?? panic("Could not borrow a Receiver reference to the FungibleToken Vault in account " + .concat(recipient.toString()).concat(" at path ").concat(FooToken.VaultPublicPath.toString()) + .concat(". Make sure you are sending to an address that has ") + .concat("a FungibleToken Vault set up properly at the specified path.")) + } + + execute { + + // Create mint tokens + let mintedVault <- self.tokenMinter.mintTokens(amount: amount) + + // Deposit them to the receiever + self.tokenReceiver.deposit(from: <-mintedVault) + } +} +``` + +To run this transaction, enter this in your terminal. +Note: `123` should be replaced with address of `test-acct` found in your `flow.json`. +This command also states to sign with our `emulator-account` on the Emulator network. + +```bash +flow transactions send ./cadence/transactions/mint_footoken.cdc 123 20.0 --signer emulator-account --network emulator +``` + +Let's go ahead and read the vault again. Remember to replace `123` with the correct address. + +```bash +flow scripts execute cadence/scripts/get_footoken_balance.cdc 123 +``` + +It should now say 20 tokens are in the vault. + +## Transferring Tokens Between Accounts + +The final functionality we'll add is the ability to transfer tokens from one account to another. + +To do that, create a new `cadence/transactions/transfer_footoken.cdc` transaction file: + +```bash +flow generate transaction transfer_footoken +``` + +Let's add the code which states that the signer of the transaction +will withdraw from their vault and put it into the receiver's vault +which will be passed as a transaction argument. + +```cadence +import "FungibleToken" +import "FooToken" + +transaction(to: Address, amount: UFix64) { + + // The Vault resource that holds the tokens that are being transferred + let sentVault: @{FungibleToken.Vault} + + prepare(signer: auth(BorrowValue) &Account) { + + // Get a reference to the signer's stored vault + let vaultRef = signer.storage.borrow(from: FooToken.VaultStoragePath) + ?? panic("The signer does not store an FooToken.Vault object at the path " + .concat(FooToken.VaultStoragePath.toString()) + .concat(". The signer must initialize their account with this vault first!")) + + // Withdraw tokens from the signer's stored vault + self.sentVault <- vaultRef.withdraw(amount: amount) + } + + execute { + + // Get the recipient's public account object + let recipient = getAccount(to) + + // Get a reference to the recipient's Receiver + let receiverRef = recipient.capabilities.borrow<&{FungibleToken.Receiver}>(FooToken.VaultPublicPath) + ?? panic("Could not borrow a Receiver reference to the FooToken Vault in account " + .concat(recipient.toString()).concat(" at path ").concat(FooToken.VaultPublicPath.toString()) + .concat(". Make sure you are sending to an address that has ") + .concat("a FooToken Vault set up properly at the specified path.")) + + // Deposit the withdrawn tokens in the recipient's receiver + receiverRef.deposit(from: <-self.sentVault) + } +} +``` + +To send our tokens, we'll need to create a new account to send them to. Let's make one more account on emulator. Run: + +```bash +flow accounts create +``` + +And pick the name: + +```bash +test-acct-2 +``` + +Make sure to select Emulator as the network. + +Don't forget the new account will need a vault added, so let's run the following transaction to add one: + +```bash +flow transactions send ./cadence/transactions/setup_ft_account.cdc --signer test-acct-2 --network emulator +``` + +Now, let's send 1 token from our earlier account to the new account. Remember to replace `123` with account address of `test-acct-2`. + +```bash +flow transactions send ./cadence/transactions/transfer_footoken.cdc 123 1.0 --signer test-acct --network emulator +``` + +After that, read the balance of `test-acct-2` (replace the address `123`). + +```bash +flow scripts execute cadence/scripts/get_footoken_balance.cdc 123 +``` + +You should now see 1 token in `test-acct-2` account! + +The transfer transaction also has a [generic version](https://github.com/onflow/flow-ft/blob/master/transactions/generic_transfer_with_address.cdc) that developers are encouraged to use! + +## More + +- [View a repo of this example code](https://github.com/chasefleming/FooToken) +- [Review an `ExampleToken` contract implementing all of the remaining FungibleToken interface](https://github.com/onflow/flow-ft/blob/master/contracts/ExampleToken.cdc) +- [View the Flow Token Standard](https://github.com/onflow/flow-ft/blob/master/contracts/FungibleToken.cdc) \ No newline at end of file diff --git a/static/markdown/build/guides/mobile/ios-quickstart.md b/static/markdown/build/guides/mobile/ios-quickstart.md new file mode 100644 index 0000000000..2ac667884a --- /dev/null +++ b/static/markdown/build/guides/mobile/ios-quickstart.md @@ -0,0 +1,281 @@ +--- +title: IOS Development +sidebar_label: IOS Development +sidebar_position: 3 +description: Learn how to build native iOS applications on Flow blockchain using the Monster Maker sample project. Understand wallet integration, transaction signing, and NFT management in mobile apps. +keywords: + - iOS development + - Flow mobile + - Monster Maker + - mobile dApp + - FCL Swift + - wallet integration + - NFT mobile + - iOS blockchain + - mobile wallet + - transaction signing + - native app + - Flow SDK + - mobile development + - iOS sample + - blockchain mobile +--- + +# Overview + +The following documentation aims to educate you on building a native mobile application on Flow. It first presents Monster Maker, a starter project we've built to represent simple Flow mobile concepts. Next it presents various developer resources related to building mobile native Flow applications. + +# Monster Maker + +![monster_maker_logo.png](resources/monster_maker_logo.png) + +Monster Maker is a native iOS app that allows users to connect a wallet, sign a transaction to mint an NFT (a monster) and display their collection of NFTs (their monsters) within the app. It's meant to be a lightweight sample project to exemplify how to build a mobile native Flow project. If you're looking to build a native mobile application for Flow, exploring the Monster Maker code base first or even building off of it is a great way to get started. + + + +## Github Repo + +The Monster Maker Github Repo can be found here: + +https://github.com/onflow/monster-maker + +## Building to Device + +Before you run Monster Maker on your device, please make sure you have installed the [Xcode14](https://apps.apple.com/au/app/xcode/id497799835?mt=12) from Mac App Store. Once you clone the repo, open the [MonsterMaker.xcodeproj](https://github.com/onflow/monster-maker/tree/main/iOS/MonsterMaker.xcodeproj) under the iOS folder. + +Xcode should automatically setup the project for you. If you do see any error related to dependencies, run `Xcode Menu -> File -> Packages -> Reset Package Cache` to resolve the issue. + +In the meantime, you can choose a simulator or your iPhone to run. For more detail here is the [official doc](https://developer.apple.com/documentation/xcode/running-your-app-in-simulator-or-on-a-device). +For run in real device, there are a few steps to deal with signing: + +1. Add your apple account to the Xcode which can be accessed from `Xcode Menu -> Settings -> Add account`. +2. Change the Team to your Personal Apple account from the **Signing & Capabilities** under the project target menu. For more detail, please check the screenshot below. + + ![XCode Target Setup](resources/xcode_setup.png) + +## Connecting to a Wallet + +To connect with wallets, there is native wallet discovery in the app. Once you click on connect, it will bring out the list of the wallets which support `HTTP/POST` or `WC/RPC` method. + +### FCL Config + +To make sure, the wallet can recognise your dApp, there is a few field you will need to config before connect to a wallet. The account proof config is optional. In addition, you will need to create a project id from [walletconnect](https://cloud.walletconnect.com/app) cloud before you can connect to the `WC/RPC` compatible wallet such as [Flow Wallet](https://wallet.flow.com/). + +```swift +import FCL + +// Config the App +let defaultProvider: FCL.Provider = .dapperPro +let defaultNetwork: Flow.ChainID = .testnet // or .mainnet + +// Optinal: Config for account proof +let accountProof = FCL.Metadata.AccountProofConfig(appIdentifier: "Monster Maker") + +// Config for WC/RPC compatible wallet +let walletConnect = FCL.Metadata.WalletConnectConfig(urlScheme: "monster-maker://", projectID: "12ed93a2aae83134c4c8473ca97d9399") + +// Config basic dApp info +let metadata = FCL.Metadata(appName: "Monster Maker", + appDescription: "Monster Maker Demo App for mobile", + appIcon: URL(string: "https://i.imgur.com/jscDmDe.png")!, + location: URL(string: "https://monster-maker.vercel.app/")!, + accountProof: accountProof, + walletConnectConfig: walletConnect) +fcl.config(metadata: metadata, + env: defaultNetwork, + provider: defaultProvider) + +// Import keywords replacement for cadence query and transaction +fcl.config + .put("0xFungibleToken", value: "0x631e88ae7f1d7c20") + .put("0xMonsterMaker", value: "0xfd3d8fe2c8056370") + .put("0xMetadataViews", value: "0x631e88ae7f1d7c20") + .put("0xTransactionGeneration", value: "0x44051d81c4720882") +``` + +### Open wallet discovery + +![In Monster Maker, the Connect button triggers opening of Wallet Discovery](resources/connect.png) + +In Monster Maker, the Connect button triggers opening of Wallet Discovery + +For the wallet support `HTTP/POST`, it will use webview to show the following actions. + +For the wallet support `WC/RPC`, it will use deep-link to the wallet for actions. + +You can open the native wallet discovery to make the selection, but also you can connect to the specific wallet as well. + +Here is the code snippet of it: + +```swift +import FCL + +// Open discovery view +fcl.openDiscovery() + +// Or manual connect to specific wallet +try fcl.changeProvider(provider: provider, env: .testnet) +try await fcl.authenticate() +``` + +## Signing a Transaction + +![In Monster Maker, Initializing the NFT collection with the Initialize button triggers a transaction.](resources/initialize.png) + +In Monster Maker, Initializing the NFT collection with the Initialize button triggers a transaction. + +Similar to what we have on fcl-js, native sdk also use `query` and `mutate` for on-chain interactions. To request a signature from user, you can simply use `fcl.mutate` method. By default, the user will be the payer, proposer and authorizer, if you want to add custom authorizer please refer to the code from [Server](https://github.com/onflow/monster-maker/blob/main/server/pages/api/signAsMinter/index.ts) and [iOS](https://github.com/onflow/monster-maker/blob/main/iOS/MonsterMaker/Flow/MintHelper.swift) end. + +```swift +guard let user = fcl.currentUser else { + // Not signin + return +} + +let txId = try await fcl.mutate( + cadence: """ + transaction(test: String, testInt: Int) { + prepare(signer: &Account) { + log(signer.address) + log(test) + log(testInt) + } + } + """, + args: [ + .string("Hello"), + .int(10) + ], + gasLimit: 999, + authorizors: [user]) + +print("txId -> \(txId)") +``` + +## View NFT + +![The View page in Monster Maker exemplifies showing Monster Maker NFTs held by the connected wallet](resources/collection.png) + +The View page in Monster Maker exemplifies showing Monster Maker NFTs held by the connected wallet + +During development, you always can query your NFT with `fcl.query`. Here is an example: + +- Query cadence + + ```cadence + import NonFungibleToken from 0xNonFungibleToken + import MonsterMaker from 0xMonsterMaker + import MetadataViews from 0xMetadataViews + + access(all) struct Monster { + access(all) let name: String + access(all) let description: String + access(all) let thumbnail: String + access(all) let itemID: UInt64 + access(all) let resourceID: UInt64 + access(all) let owner: Address + access(all) let component: MonsterMaker.MonsterComponent + + init( + name: String, + description: String, + thumbnail: String, + itemID: UInt64, + resourceID: UInt64, + owner: Address, + component: MonsterMaker.MonsterComponent + ) { + self.name = name + self.description = description + self.thumbnail = thumbnail + self.itemID = itemID + self.resourceID = resourceID + self.owner = owner + self.component = component + } + } + + access(all) fun getMonsterById(address: Address, itemID: UInt64): Monster? { + + if let collection = getAccount(address).capabilities.get<&MonsterMaker.Collection>(MonsterMaker.CollectionPublicPath).borrow() { + + if let item = collection.borrowMonsterMaker(id: itemID) { + if let view = item.resolveView(Type()) { + let display = view as! MetadataViews.Display + let owner: Address = item.owner!.address! + let thumbnail = display.thumbnail as! MetadataViews.HTTPFile + + return Monster( + name: display.name, + description: display.description, + thumbnail: thumbnail.url, + itemID: itemID, + resourceID: item.uuid, + owner: address, + component: item.component + ) + } + } + } + + return nil + } + + access(all) fun main(address: Address): [Monster] { + let account = getAccount(address) + let collectionRef = account.capabilities.get<&{NonFungibleToken.Collection}>(MonsterMaker.CollectionPublicPath).borrow() + ?? panic("The account with address " + .concat(address.toString) + .concat(" does not have a NonFungibleToken Collection at ") + .concat(MonsterMaker.CollectionPublicPath.toString()) + .concat(". Make sure the account address is correct and is initialized their account with a MonsterMaker Collection!")) + + let ids = collectionRef.getIDs() + + let monsters : [Monster] = [] + + for id in ids { + if let monster = getMonsterById(address: address, itemID: id) { + monsters.append(monster) + } + } + + return monsters + } + ``` + +```swift +let nftList = try await fcl.query(script: cadenceScript, + args: [.address(address)]) + .decode([NFTModel].self) +``` + +# External Resources + +**FCL Swift** + +FCL Swift is the iOS native SDK for FCL. This SDK is integrated into the Monster Maker sample. + +https://github.com/Outblock/fcl-swift + +**FCL Android** + +FCL Android is the Android native SDK for FCL. + +https://github.com/Outblock/fcl-android + +**FCL Wallet Connect 2.0** + +One of the easiest ways to connect to a wallet via a mobile native dApp is through Flow's new support for Wallet Connect 2.0. This is the pattern that Monster Maker uses to connect to the [Flow Wallet](https://wallet.flow.com/). For more information on FCL Wallet Connect 2.0, check out this page: + +[FCL Wallet Connect](../../../tools/clients/fcl-js/wallet-connect.md) + +**How to Build a Native iOS Dapp** + +The Agile Monkeys has written a very comprehensive guide on how to build a native mobile application on iOS and interface with fcl-swift. Found here: + +[How to Build a Native iOS Dapper](https://dev.to/theagilemonkeys/how-to-buid-a-native-ios-dapp-that-uses-the-flow-blockchain-as-the-backend-n9k) +[Source Code](https://github.com/jfsagasti/FlowNotes) \ No newline at end of file diff --git a/static/markdown/build/guides/mobile/overview.md b/static/markdown/build/guides/mobile/overview.md new file mode 100644 index 0000000000..d64edb73b2 --- /dev/null +++ b/static/markdown/build/guides/mobile/overview.md @@ -0,0 +1,73 @@ +--- +title: Overview +sidebar_label: Overview +sidebar_position: 1 +description: Discover Flow's mobile development capabilities for building native blockchain applications. Learn about Flow's unique features for mobile apps, including secure key management, wallet integration, and progressive onboarding. +keywords: + - Flow mobile + - mobile development + - blockchain apps + - native applications + - mobile SDK + - secure enclave + - wallet integration + - WalletConnect + - account linking + - mobile security + - Flow features + - mobile wallets + - Cadence mobile + - user experience + - blockchain mobile +--- + +Building mobile native applications that interact with the blockchain enables a much richer end user experiences and provides access to OS capabilities. With Flow Mobile, developers can build native applications for iOS and Android leveraging SDKs and mobile wallets. + +## Why Flow + +Millions of users with Flow accounts are exploring the ecosystem and looking for applications. Most of these users purchased Flow NFTs and are comfortable with web3 principles. + +In addition to the existing user base, developers can tap into smart contracts deployed on the Flow blockchain. These contracts, including their on-chain state, provide unique possibilities to build experiences that enrich applications users are already using. + +The following key capabilities make Flow a standout choice for mobile applications: +- On-device key encryption via Secure Enclave & Keychain +- Mobile wallet compatibility and support for WalletConnect 2.0 +- Simple, progressive onboarding experience with postponed account linking +- Seamless in-app experience with on-chain interactions without constant signing requests +- Account flexibility enabling secure account recovery and sharing + +## Why Flow Mobile + +### Proven + +Flow is built with mainstream adoption in mind. Mobile applications can leverage the best-in-class user experiences millions of users have enjoyed on the web, through applications like NBA TopShot or NFL AllDay. + +### Best-in-class UX + +Flow's Client Library makes it very intuitive to sign up and sign in with their wallet of choice. For transaction signing, Flow offers human readable security, so users get a clear understanding of what they are approving. An increased sense of trust for Flow applications is the outcome. + +Furthermore, Flow's powerful account model allows for seamless user flows of on-chain operations. Apps can perform transactions on behalf of the users (with their approval) in the background, without the need to switch between apps. The account model also allows apps to pay for transactions to postpone fiat on-ramps to get them to experience the value of an application before committing to buying tokens. + +Last but not least, developers can leverage progressive web3 onboarding, in which any identity provider can be used to authenticate users, without having to deal with keys. Developers can create Flow accounts for the users and link them to a wallet at a later point in time. + +### Security first + +Flow's mobile SDKs use on-device key encryption via Apple's Secure Enclave and Android's Keystore. The flexible account model makes it possible for an account to have multiple keys with different weights, which enables secure social recovery, account sharing, and much more. + +## Smart contract language inspired by mobile languages + +Cadence, Flow's smart contract language, will look and feel very familiar to mobile languages developers are already familiar with. Cadence was inspired by Move, Swift, and Kotlin. This reduces the ramp-up period to develop mobile applications leveraging on-chain logic. + +## What is available + +Developers can leverage the following features to get productive quickly: + +- Swift & Kotlin FCL SDKs to auth and interact with the Flow blockchain (query + execute scripts) +- FCL-compatible mobile wallets +- User auth using WalletConnect 2.0 +- Basic mobile sample application (MonsterMaker) + +Coming soon: + +- Samples for key in-app functionality, like in-app purchasing +- Progressive user onboarding \ No newline at end of file diff --git a/static/markdown/build/guides/mobile/react-native-quickstart.md b/static/markdown/build/guides/mobile/react-native-quickstart.md new file mode 100644 index 0000000000..33c9f2442f --- /dev/null +++ b/static/markdown/build/guides/mobile/react-native-quickstart.md @@ -0,0 +1,657 @@ +--- +title: React Native Development +sidebar_label: React Native Development +sidebar_position: 4 +description: Learn how to build decentralized applications using React Native and Flow Client Library (FCL). Follow this guide to set up authentication, query the blockchain, and execute transactions in a React Native app. +keywords: + - React Native + - Flow FCL + - mobile dApp + - blockchain development + - FCL integration + - React Native Flow + - mobile blockchain + - smart contracts + - wallet integration + - transaction signing + - blockchain queries + - dApp development + - Flow mobile + - React Native tutorial + - mobile development +--- + +**Last Updated:** January 11th 2022 + +> **Note**: This page will walk you through a very bare bones project to get started building a web3 dapp using the Flow Client Library (FCL). If you are looking for a clonable repo, Flow community members have created quickstart templates for different JavaScript frameworks (e.g. [Next.js](https://github.com/muttoni/fcl-nextjs-quickstart), [SvelteKit](https://github.com/muttoni/fcl-sveltekit-quickstart), [Nuxt](https://github.com/bluesign/nuxt3-fcl)). You can consult the complete list [here](https://github.com/ph0ph0/Get-The-Flow-Down#fcl). + +## Introduction + +FCL-JS is the easiest way to start building decentralized applications. FCL (aka Flow Client Library) wraps much of the logic you'd have to write yourself on other blockchains. Follow this quick start and you'll have a solid overview of how to build a shippable dapp on Flow. + +We're going to make an assumption that you know or understand React; however, the concepts should be easy to understand and transfer to another framework. While this tutorial will make use of Cadence (Flow's smart contract language), you do not need to know it. Instead, we recommend later diving into [learning the Cadence language](https://cadence-lang.org/docs/language/) once you've gotten the core FCL concepts down. + +In this tutorial, we are going to interact with an existing smart contract on Flow's testnet known as the [Profile Contract](https://testnet.flowdiver.io/contract/A.ba1132bc08f82fe2.Profile). Using this contract, we will create a new profile and edit the profile information, both via a wallet. In order to do this, the FCL concepts we'll cover are: + +- [Installation](#installation) +- [Configuration](#configuration) +- [Authentication](#authentication) +- [Querying the Blockchain](#querying-the-blockchain) +- [Initializing an Account](#initializing-an-account) +- [Mutating the Blockchain](#mutating-the-blockchain) + +And if you ever have any questions we're always happy to help on [Discord](https://discord.gg/flowblockchain). There are also links at the end of this article for diving deeper into building on Flow. + +## Installation + +The first step is to generate a React app using Next.js and [create-expo-app](https://docs.expo.dev/get-started/create-a-project/). From your terminal, run the following: + +```sh +npx create-expo-app flow-react-native +cd flow-react-native +``` + +Next, install FCL so we can use it in our app. + +```sh +npm install @onflow/fcl@alpha @react-native-async-storage/async-storage expo-web-browser --save +``` + +Now run the app using the following command in your terminal. + +```sh +npm run start +``` + +You should now see your app running. + +## Configuration + +Now that your app is running, you can configure FCL. Within the main project directory, create a folder called `flow` and create a file called `config.js`. This file will contain configuration information for FCL, such as what Access Node and wallet discovery endpoint to use (e.g. testnet or a local emulator). Add the following contents to the file: + +**Note**: These values are required to use FCL with your app. + +> **Create file:** `./flow/config.js` + +```javascript ./flow/config.js + + +config({ + "accessNode.api": "https://rest-testnet.onflow.org", // Mainnet: "https://rest-mainnet.onflow.org" + "discovery.wallet": "https://fcl-discovery.onflow.org/testnet/authn", // Mainnet: "https://fcl-discovery.onflow.org/authn" + "discovery.authn.endpoint": "https://fcl-discovery.onflow.org/api/testnet/authn", // Mainnet: "https://fcl-discovery.onflow.org/api/authn" +}) +``` +📣 **Tip**: It's recommend to replace these values with environment variables for easy deployments across different environments like development/production or Testnet/Mainnet. + +- The `accessNode.api` key specifies the address of a Flow access node. Flow provides these, but in the future access to Flow may be provided by other 3rd parties, through their own access nodes. +- `discovery.wallet` and `discovery.authn.endpoint` are addresses that point to a service that lists FCL compatible wallets. Flow's FCL Discovery service is a service that FCL wallet providers can be added to, and be made 'discoverable' to any application that uses the `discovery.wallet` and `discovery.authn.endpoint`. + +> Learn more about [configuring Discovery](../../../tools/clients/fcl-js/discovery.md) or [setting configuration values](../../../tools/clients/fcl-js/api.md#setting-configuration-values). + +> If you are running a Wallet Discovery locally and want to use it in the React Native app, change `https://fcl-discovery.onflow.org/` to `http://:/` +> For Example: +> using local [Wallet Discovery](../../../tools/clients/fcl-js/discovery.md) and local [Dev Wallet](../../../tools/flow-dev-wallet/index.md): +> +> ```javascript ./flow/config.js +> +> +> config({ +> ... +> "discovery.wallet": "http://10.0.0.1:3002/local/authn", +> "discovery.authn.endpoint": "http://10.0.0.1:3002/api/local/authn", +> ... +> }) +> ``` + +The main screen for React Native apps is located in `./App.js` or in `./App.tsx`. So let's finish configuring our dapp by going in the root directory and importing the config file into the top of our `App.js` file. We'll then swap out the default component in `App.js` to look like this: + +> **Replace file:** `./App.js` + +```jsx ./App.js + + +import "./flow/config"; + +export default function App() { + return ( + + Open up App.js to start working on your app! + + + ); +} + +const styles = StyleSheet.create({ + container: { + flex: 1, + backgroundColor: '#fff', + alignItems: 'center', + justifyContent: 'center', + }, +}); + +``` + +Now we're ready to start talking to Flow! + +## Authentication + +To authenticate a user, you'll need to render a `ServiceDiscovery` component provided by `fcl-react-native`. Alternatively you can build your own component using `useServiceDiscovery`. + +Unauthenticate is as simple as calling `fcl.unauthenticate()`. Once authenticated, FCL sets an object called `fcl.currentUser` which exposes methods for watching changes in user data, signing transactions, and more. For more information on the `currentUser`, read more [here](../../../tools/clients/fcl-js/api.md#current-user). + +Let's add in a few components and buttons buttons for sign up/login and also subscribe to changes on the `currentUser`. When the user is updated (which it will be after authentication), we'll set the user state in our component to reflect this. To demonstrate user authenticated sessions, we'll conditionally render a component based on if the user is or is not logged in. + +This is what your file should look like now: + +> **Replace file:** `./App.js` + +```jsx ./App.js + +import "./flow/config"; + + + + +export default function App() { + + const [user, setUser] = useState({loggedIn: null}) + + useEffect(() => fcl.currentUser.subscribe(setUser), []) + + const AuthedState = () => { + return ( + + Address: {user?.addr ?? "No Address"} + + )} +
    + + + setIsProfileModalOpen(false)} + /> + + {/* QuickNode Modal */} + setActiveModal(null)} + title="QuickNode" + > +
    +
    +
    +

    $100 Credit for Builders

    +

    Enterprise-grade Web3 infrastructure

    +
    + QuickNode +
    + +
    +
    +

    Features

    +
    +
    +
    • Lightning-fast RPC endpoints
    +
    • Real-time WebSocket streams
    +
    • Historical data backfills
    +
    +
    +
    • Multi-chain support
    +
    • Advanced monitoring tools
    +
    • 24/7 developer support
    +
    +
    +
    + +
    +

    How to Claim

    +
    + + 1. Visit QuickNode signup → + +
    +
    2. Enter promo code:
    +
    + BUILDWITHFLOW + +
    +
    +
    +
    +
    +
    +
    + + {/* Olympix Modal */} + setActiveModal(null)} + title="Olympix" + > +
    +
    +
    +

    $2000 in Security Tools Credits

    +

    Developer-first security assurance

    +
    + Olympix +
    + +
    +
    +

    Features

    +
    +
    +
    Team Size
    +
    1-2 developers
    +
    +
    +
    Revenue Requirement
    +
    $5,000+ per year
    +
    +
    +
    + +
    +

    How to Apply

    +
    +
    +
    Send email to:
    +
    sarah@olympix.ai
    +
    CC:builders@flow.com
    +
    +
    +
    Include:
    +
    • Subject: "Olympix Flow Perk"
    +
    • Your GitHub username
    +
    • Link to your project
    +
    +
    +
    +
    +
    +
    + + {/* Gas Subsidy Modal */} + setActiveModal(null)} + title="Gas Subsidy" + > +
    +
    +
    +

    Get Gas to Launch Today

    +

    Flow is offering all builders a one-time subsidy to bring their project to life and scale

    +
    + Flow +
    + +
    +
    +

    Features

    +
    +
    +
    Transaction Coverage
    +
    Sponsor up to 10,000 user transactions
    +
    +
    +
    Usage Impact
    +
    Up to 4x more app engagement
    +
    +
    +
    Contract Deployment
    +
    Launch your contracts on Mainnet for FREE
    +
    +
    +
    + +
    +

    How to Apply

    +
    +
    +
    Send email to:
    +
    builders@flow.com
    +
    +
    +
    Include:
    +
    • Subject: "Gas Subsidy Request"
    +
    • Your GitHub username
    +
    • Your deployer address
    +
    +
    +
    +
    +
    +
    + + {/* Alchemy Modal */} + setActiveModal(null)} + title="Alchemy" + > +
    +
    +
    +

    Startup Program Access

    +

    Accelerate your project growth

    +
    + Alchemy +
    + +
    +
    +

    Features

    +
    +
    +
    • Free infrastructure credits
    +
    • Product discounts
    +
    • Technical support
    +
    +
    +
    • Partner network access
    +
    • Launch amplification
    +
    • Community perks
    +
    +
    +
    + +
    +

    How to Apply

    +
    + + 1. Apply to Startup Program → + +
    +
    2. Send follow-up email:
    +
    To: zaib@alchemy.com
    +
    CC: builders@flow.com
    +
    Subject: "Flow Alchemy Perk"
    +
    Include your GitHub username and project link
    +
    +
    +
    +
    +
    +
    + + {/* Thirdweb Modal */} + setActiveModal(null)} + title="Thirdweb" + > +
    +
    +
    +

    1 Month Growth & Engine Access

    +

    $99 value in production tools

    +
    + Thirdweb +
    + +
    +
    +

    Features

    +
    +
    +
    • Production-grade RPCs
    +
    • Custom branding options
    +
    • User analytics dashboard
    +
    +
    +
    • Transaction management
    +
    • Automatic retries
    +
    • Team access controls
    +
    +
    +
    + + + +
    +

    How to Claim

    +
    + + 1. Visit Thirdweb Dashboard → + +
    +
    2. Apply coupon code:
    +
    + 3WEBDEV-FLOW + +
    +
    +
    + 3. Upgrade to Growth tier and deploy your Engine instance +
    +
    +
    +
    +
    +
    + + ); +}; + + \ No newline at end of file diff --git a/static/markdown/ecosystem/data-indexers.md b/static/markdown/ecosystem/data-indexers.md new file mode 100644 index 0000000000..a6d688d0b8 --- /dev/null +++ b/static/markdown/ecosystem/data-indexers.md @@ -0,0 +1,37 @@ +--- +title: Data Indexers +sidebar_label: Data Indexers +sidebar_position: 4 +--- + +# Data Indexers + +When building applications that leverage Flow data, developers have multiple Data Indexers to choose from. These platforms offer flexible options, allowing you to index all data on Flow, including information from both the Cadence VM and EVM. Alternatively, if your application doesn't require Cadence, you can opt to index only EVM data. This flexibility ensures that you can tailor your data indexing strategy to fit the specific needs of your application. + +## EVM & Cadence + +### **SimpleHash** + +[SimpleHash](https://simplehash.com/) is a comprehensive multi-chain NFT data platform that provides developers with easy access to token data across 60+ blockchain networks. It offers a robust API for querying NFT metadata, media, collection details, sales, floor prices, listings, and bids, streamlining the process of building NFT-powered applications. + +**Getting Started with SimpleHash** + +Developers can begin using SimpleHash by [signing up for an API key](https://simplehash.com/) on their website. The platform provides comprehensive [documentation](https://docs.simplehash.com/reference/overview) to help developers integrate SimpleHash into their projects. + +## **EVM Only** + +### Moralis + +[Moralis](https://moralis.io/) provides a robust suite of data APIs designed to support a wide array of blockchain applications. These APIs deliver both indexed and real-time data across 16+ blockchain networks, including comprehensive details on portfolio and wallet balances, NFT data, token metrics, price feeds, candlestick charts, and net worth calculations. Moralis enhances this data with additional layers of metadata, parsed events, and address labels to provide deeper insights and context. + +**Getting Started with Moralis** + +To integrate Moralis into your project, begin by [creating an account](https://moralis.io/). Detailed API references and integration guides are available in the Moralis [documentation](https://docs.moralis.io/). For step-by-step tutorials and use cases, visit their [YouTube channel](https://www.youtube.com/c/MoralisWeb3). + +### **Alchemy** + +[Alchemy](https://www.alchemy.com/) is a powerful blockchain development platform that provides enhanced APIs and advanced analytics to streamline the process of creating and scaling Web3 applications. + +**Getting Started with Alchemy** + +To begin using Alchemy, developers can [sign up for an account](https://www.alchemy.com/) on the Alchemy website. The platform offers extensive [documentation](https://docs.alchemy.com/) including API references, tutorials, and guides to help developers integrate Alchemy into their projects. \ No newline at end of file diff --git a/static/markdown/ecosystem/defi-liquidity/add-token-to-metamask.md b/static/markdown/ecosystem/defi-liquidity/add-token-to-metamask.md new file mode 100644 index 0000000000..aca71a1b6d --- /dev/null +++ b/static/markdown/ecosystem/defi-liquidity/add-token-to-metamask.md @@ -0,0 +1,94 @@ +--- +title: How To Add Token To MetaMask +description: How to import a Flow token in MetaMask +sidebar_label: Add Token To MetaMask +sidebar_position: 3 +keywords: + - add token to MetaMask + - MetaMask Flow EVM + - Flow EVM token + - import token MetaMask + - add custom token MetaMask + - Flow token contract address + - Flow EVM DeFi + - MetaMask Flow EVM network + - how to add token MetaMask + - Flow EVM block explorer + - Flow EVM Dexscreener + - Gecko Terminal Flow EVM + - Dexscreener Flow EVM + - evm.flowscan.io tokens + - wrapped Flow MetaMask + - Flow EVM liquidity + - Flow EVM DeFi tokens + - import Flow token + - Flow blockchain MetaMask +--- + + + + +:::info + +Want to add a token to MetaMask on Flow EVM? + +You can find a list of tokens on Flow at [evm.flowscan.io/tokens][1] or check the most popular DeFi token contract addresses [here][2] + +::: + +## Objectives + +After completing this guide, you'll be able to: + +- Add ERC20 tokens to MetaMask via [Flowscan][5]. +- Manually add a custom token to MetaMask using a contract address. +- Locate Flow EVM token contract addresses on various platforms. + +## Add a Token to MetaMask via Flowscan + +1. Visit [https://evm.flowscan.io/tokens][1] to find the token you want to add to MetaMask. + +2. Hover over the token you want to import, and a MetaMask icon will appear. Click on it to add the token. + +:::note + +If you haven't yet added the Flow EVM network to your MetaMask, you will receive a prompt to add the network before adding the token. + +::: + +![Add Token Via Flowscan](add_wrapped_flow_to_metamask.jpg) + +![Add wrapped Flow](add_wrapped_flow_to_metamask_2.png) + +## Add a Custom Token in MetaMask Wallet + +If you have a token contract address, you can manually add it to MetaMask. + +### Steps to Add a Custom Token + +1. Open your MetaMask and go to the **Tokens** tab. + +2. Scroll down and click on **Import tokens**. + +3. Enter the token contract address. + +4. Click **Next**, then **Import** to add the token. + +![Add custom token in MetaMask](add_custom_token_metamask.gif) + +## How to Find The Token Contract Address + +You can find token contract addresses on: + +- [Flowscan Token List][1] +- The [DeFi Contracts][2] page +- [Dexscreener Flow EVM][3] +- [Gecko Terminal Flow EVM][4] + +If you're unsure, check the Flow EVM block explorer at [evm.flowscan.io][5] + +[1]: https://evm.flowscan.io/tokens +[2]: /docs/ecosystem/defi-liquidity/defi-contracts.md +[3]: https://dexscreener.com/flowevm +[4]: https://www.geckoterminal.com/flow-evm/pools +[5]: https://evm.flowscan.io \ No newline at end of file diff --git a/static/markdown/ecosystem/defi-liquidity/cross-chain-swaps.md b/static/markdown/ecosystem/defi-liquidity/cross-chain-swaps.md new file mode 100644 index 0000000000..c2f6140aee --- /dev/null +++ b/static/markdown/ecosystem/defi-liquidity/cross-chain-swaps.md @@ -0,0 +1,50 @@ +--- +id: cross-chain-swaps +title: Cross-chain swaps on Flow EVM +description: An overview of cross-chain options on Flow EVM +keywords: + - cross-chain token swap + - cross-chain bridge + - intent based bridge + - liquidity based bridge + - bridges + - Flow blockchain + - Flow EVM + - EVM + - Relay.link + - DeBridge + - Stargate + - LayerZero + - Celer +sidebar_position: 2 +sidebar_label: Cross-chain swaps on Flow EVM +--- + + + +The following bridges offer cross-chain swaps (token bridging including swap) to or from Flow EVM. + +## Liquidity Pool Based Cross-chain Swaps + +### Stargate + +[Stargate](https://stargate.finance) employs unified liquidity pools shared across multiple chains to enable native asset transfers and cross-chain swaps +without wrapped tokens. It is built on LayerZero's cross-chain messaging protocol. + +### Celer + +[Celer](https://cbridge.celer.network) is a hybrid liquidity network bridge that combines multiple bridging models and is based on the Celer +Inter-Chain Messaging Framework. + +## Intent Based Cross-chain Swaps + +Intent based bridges do not depend on pre-funded liquidity pools which can improve user experience, transaction speed and capital efficiency. + +### Relay + +[Relay.link](https://relay.link/bridge/base) allows users to specify desired cross-chain swap outcomes for orders. + +### DeBridge + +[DeBridge](https://app.debridge.finance/) achieves efficient cross-chain swaps with minimal slippage in a decentralized environment +through a peer-to-peer transaction mechanism. \ No newline at end of file diff --git a/static/markdown/ecosystem/defi-liquidity/defi-contracts.md b/static/markdown/ecosystem/defi-liquidity/defi-contracts.md new file mode 100644 index 0000000000..2b746c1776 --- /dev/null +++ b/static/markdown/ecosystem/defi-liquidity/defi-contracts.md @@ -0,0 +1,151 @@ +--- +id: defi-contracts +title: DeFi Contracts on Flow +description: A reference table of frequently used DeFi contracts on Flow, including their addresses for both Flow EVM and Flow Cadence. +keywords: + - DeFi contracts + - Flow blockchain + - Flow EVM + - Flow Cadence + - stablecoins + - wrapped assets + - AMMs + - DEXs + - KittyPunch + - PunchSwap +sidebar_position: 1 +sidebar_label: DeFi Contracts +--- + + + +Flow is a Layer 1 blockchain that supports EVM equivalency, offering two environments Flow EVM and Flow Cadence. Fungible and non-fungible tokens can seamlessly transfer between these environments via the native VM token bridge. As a result, many tokens have both a Flow EVM mainnet contract address and a Flow Cadence mainnet contract address, allowing developers to choose their preferred environment. + +Below is a list of commonly used DeFi contracts on Flow: + +## Stablecoins & Wrapped Assets + +#### Flow EVM Mainnet + + + +#### Flow Cadence Mainnet + + + +## AMMs & DEXs + +#### Flow EVM Mainnet + +| Contract Name | Flow EVM Mainnet Address | +| -------------------------------------------- | -------------------------------------------- | +| [StableKittyFactoryNG.sol (KittyPunch)][1] | `0x4412140D52C1F5834469a061927811Abb6026dB7` | +| [TwoKittyFactory.sol (KittyPunch)][2] | `0xf0E48dC92f66E246244dd9F33b02f57b0E69fBa9` | +| [TriKittyFactory.sol (KittyPunch)][3] | `0xebd098c60b1089f362AC9cfAd9134CBD29408226` | +| [KittyRouterNgPoolsOnly.sol (KittyPunch)][4] | `0x87048a97526c4B66b71004927D24F61DEFcD6375` | +| [PunchSwapV2Router02.sol (KittyPunch)][5] | `0xf45AFe28fd5519d5f8C1d4787a4D5f724C0eFa4d` | +| [PunchSwapV2Factory.sol (KittyPunch)][6] | `0x29372c22459a4e373851798bFd6808e71EA34A71` | +| [TrenchesTokensBuyer.sol (KittyPunch)][7] | `0x6D0e081Acc28eA9ee6b7fD293eC03F97147b026d` | + +#### Flow Cadence Mainnet + +| Contract Name | Flow Cadence Mainnet Address | +| ----------------------------------- | ---------------------------- | +| [SwapFactory.cdc (IncrementFi)][22] | `0xb063c16cac85dbd1` | +| [SwapPair (IncrementFi)][23] | `0xecbda466e7f191c7` | +| [SwapError (IncrementFi)][24] | `0xb78ef7afa52ff906` | +| [SwapInterfaces (IncrementFi)][25] | `0xb78ef7afa52ff906` | +| [SwapConfig (IncrementFi)][26] | `0xb78ef7afa52ff906` | +| [SwapRouter (IncrementFi)][27] | `0xa6850776a94e6551` | + +## Bridges & Cross-Chain Messaging + +| Bridge / Protocol | Reference Docs | +|----------------------------------------------|--------------------------| +| Stargate Bridge ([stargate.finance][8]) | [Mainnet Contracts][9] | +| Hyperlane Bridge ([trump.hyperlane.xyz][10]) | [Mainnet Contracts][11] | +| Flow Bridge ([bridge.flow.com][12]) | [Superbridge Docs][13] | +| Celer cBridge ([cbridge.celer.network][14]) | [Celer cBridge Docs][15] | +| DeBridge ([app.debridge.finance][34]) | [DeBridge Contracts][35] | +| Relay ([relay.link][36]) | [Relay Contracts][37] | +| LayerZero | [Mainnet Contracts][16] | +| Axelar | [Axelar Docs][17] | + +## Oracles + +#### Flow EVM Mainnet + +| Contract Name | Flow EVM Mainnet Address | +|--------------------------------| -------------------------------------------- | +| [ERC1967Proxy.sol (Pyth)][18] | `0x2880aB155794e7179c9eE2e38200202908C17B43` | +| [ERC1967Proxy.sol (Stork)][28] | `0xacC0a0cF13571d30B4b8637996F5D6D774d4fd62` | + +#### Flow Cadence Testnet + +| Contract Name | Flow Cadence Testnet Address | +|-------------------------------------------|------------------------------| +| [PublicPriceOracle.cdc (IncrementFi)][31] | `0x8232ce4a3aff4e94` | +| [BandOracle.cdc (Band)][32] | `0x2c71de7af78d1adf` | + +#### Flow Cadence Mainnet + +| Contract Name | Flow Cadence Mainnet Address | +|-------------------------------------------| ---------------------------- | +| [PublicPriceOracle.cdc (IncrementFi)][19] | `0xec67451f8a58216a` | +| [BandOracle.cdc (Band) Protocol][33] | `0x6801a6222ebf784a` | + +## Ethereum Attestation Service + +More information can be found on the Credora docs site for [EAS on Flow](https://credora.gitbook.io/eas-for-flow). + +Testnet EAS Explorer: [https://flow-testnet.easscan.credora.io] (https://flow-testnet.easscan.credora.io) + +| Contract Name | Flow EVM Testnet Address | +|---------------------------------------------------------|----------------------------------------------| +| [SchemaRegistry.sol (Ethereum Attestation Service)][29] | `0x97900F59828Da4187607Cb8F84f49e3944199d18` | +| [EAS.sol (Ethereum Attestation Service)][30] | `0xBCF2dA8f82fb032A2474c92Ec5b70C95A83fc0cc` | + +Mainnet EAS Explorer: [https://flow.easscan.credora.io] (https://flow.easscan.credora.io) + +| Contract Name | Flow EVM Mainnet Address | +| ------------------------------------------------------- | -------------------------------------------- | +| [SchemaRegistry.sol (Ethereum Attestation Service)][20] | `0xB0cF748a05AEA8D59e15834446CFC95bcFF510F0` | +| [EAS.sol (Ethereum Attestation Service)][21] | `0xc6376222F6E009A705a34dbF1dF72fEf8efB3964` | + +[1]: https://evm.flowscan.io/address/0x4412140D52C1F5834469a061927811Abb6026dB7?tab=contract +[2]: https://evm.flowscan.io/address/0xf0E48dC92f66E246244dd9F33b02f57b0E69fBa9?tab=contract +[3]: https://evm.flowscan.io/address/0xebd098c60b1089f362AC9cfAd9134CBD29408226?tab=contract +[4]: https://evm.flowscan.io/address/0x87048a97526c4B66b71004927D24F61DEFcD6375?tab=contract +[5]: https://evm.flowscan.io/address/0xf45AFe28fd5519d5f8C1d4787a4D5f724C0eFa4d?tab=contract +[6]: https://evm.flowscan.io/address/0x29372c22459a4e373851798bFd6808e71EA34A71?tab=contract +[7]: https://evm.flowscan.io/address/0x6D0e081Acc28eA9ee6b7fD293eC03F97147b026d?tab=contract +[8]: https://stargate.finance/bridge?srcChain=ethereum&srcToken=0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48&dstChain=flow&dstToken=0xF1815bd50389c46847f0Bda824eC8da914045D14 +[9]: https://stargateprotocol.gitbook.io/stargate/v2-developer-docs/technical-reference/mainnet-contracts#flow +[10]: https://trump.hyperlane.xyz/ +[11]: https://docs.hyperlane.xyz/docs/reference/addresses/mailbox-addresses +[12]: https://bridge.flow.com/ +[13]: https://docs.superbridge.app/ +[14]: https://cbridge.celer.network/1/747/USDC-intermediary +[15]: https://cbridge-docs.celer.network/tutorial/flow-cadence-bridging-guide +[16]: https://docs.layerzero.network/v1/developers/evm/technical-reference/deployed-contracts?chains=flow +[17]: https://docs.axelar.dev/validator/external-chains/flow/ +[18]: https://evm.flowscan.io/address/0x2880aB155794e7179c9eE2e38200202908C17B43?tab=contract +[19]: https://contractbrowser.com/A.ec67451f8a58216a.PublicPriceOracle +[20]: https://evm.flowscan.io/address/0xB0cF748a05AEA8D59e15834446CFC95bcFF510F0?tab=contract +[21]: https://evm.flowscan.io/address/0xc6376222F6E009A705a34dbF1dF72fEf8efB3964?tab=contract +[22]: https://contractbrowser.com/A.b063c16cac85dbd1.SwapFactory +[23]: https://contractbrowser.com/A.ecbda466e7f191c7.SwapPair +[24]: https://contractbrowser.com/A.b78ef7afa52ff906.SwapError +[25]: https://contractbrowser.com/A.b78ef7afa52ff906.SwapInterfaces +[26]: https://contractbrowser.com/A.b78ef7afa52ff906.SwapConfig +[27]: https://contractbrowser.com/A.a6850776a94e6551.SwapRouter +[28]: https://evm.flowscan.io/address/0xacC0a0cF13571d30B4b8637996F5D6D774d4fd62?tab=contract +[29]: https://evm-testnet.flowscan.io/address/0x97900F59828Da4187607Cb8F84f49e3944199d18?tab=contract +[30]: https://evm-testnet.flowscan.io/address/0xBCF2dA8f82fb032A2474c92Ec5b70C95A83fc0cc?tab=contract +[31]: https://contractbrowser.com/A.8232ce4a3aff4e94.PublicPriceOracle +[32]: https://contractbrowser.com/A.2c71de7af78d1adf.BandOracle +[33]: https://contractbrowser.com/A.6801a6222ebf784a.BandOracle +[34]: https://app.debridge.finance/ +[35]: https://docs.debridge.finance/dln-the-debridge-liquidity-network-protocol/deployed-contracts +[36]: https://relay.link/bridge +[37]: https://docs.relay.link/resources/contract-addresses \ No newline at end of file diff --git a/static/markdown/ecosystem/defi-liquidity/faq.md b/static/markdown/ecosystem/defi-liquidity/faq.md new file mode 100644 index 0000000000..4e93a1eed2 --- /dev/null +++ b/static/markdown/ecosystem/defi-liquidity/faq.md @@ -0,0 +1,227 @@ +--- +id: faq +title: Stablecoins & Bridges on Flow FAQ +description: Frequently asked questions about stablecoins, liquidity, and bridging on the Flow blockchain. +keywords: + - stablecoins + - bridges + - Flow blockchain + - USDC + - USDT + - USDF + - decentralized exchanges + - DEX + - yield farming + - liquidity +sidebar_position: 3 +sidebar_label: Stablecoins & Bridges FAQ +--- + + + +# DeFi & Liquidity FAQ + +Below are common questions regarding stablecoins, liquidity, and bridging on Flow. Click on each question to expand and view the answer. + +## Bridging and Gas + +
    +No, Flow uses $FLOW as the gas token. [WETH](./defi-contracts#stablecoins--wrapped-assets) is supported on Flow EVM when [bridging](../bridges.md) from another chain. $WFLOW is used as an ERC20 in DeFi apps and not used for gas. +
    + +
    +When using Flow EVM for the first time, your EOA will automatically be credited 0.05 FLOW to cover gas costs when bridging into Flow. +If further top-ups are required you can use [Gas.zip](https://www.gas.zip/). See [Fees](../../evm/fees) for information on gas pricing. + +Flow Wallet users do not pay for gas since the wallet subsidizes all transaction fees. +
    + +## Stablecoins on Flow + +
    +USDC (USD Coin) - Issued by Circle + +USDT (Tether USD) - Issued by Tether + +USDF (USD Flow) - Backed by PYUSD (PayPal USD) issued by PayPal + +
    + +
    +You can find all the contract addresses for the stablecoins and bridges on Flow here: +[DeFi Contracts on Flow][0] +
    + +
    +Stablecoins can be traded on major Flow-based decentralized exchanges (DEXs) like: + +- KittyPunch, PunchSwap - [https://swap.kittypunch.xyz/][1] +- IncrementFi, IncrementSwap - [https://app.increment.fi/swap][2] +
    + +
    +You can earn yield through: + +- Lending Platforms - Supply stablecoins on [IncrementFi][3], [Sturdy Finance][19] & [MoreMarkets][4] to earn interest. +- Liquidity Pools - Provide liquidity on [IncrementFi][5] or [KittyPunch][6] to earn trading fees and farm LP tokens. +- Yield Aggregators (Coming soon) - Use [KittyPunch][7] to automate stablecoin yield strategies. +
    + +
    +Stablecoins on Flow are designed to be secure and efficient but as with any blockchain asset, there are risks to be aware of: + +- Depegging - While rare, some stablecoins have lost their peg in the past due to liquidity issues or market crashes. Flow stablecoins like USDC and USDF are backed by trusted issuers to maintain stability. +- Smart Contract Risks - Bugs or exploits in DeFi platforms can lead to losses. +- Centralization Risks - USDC and USDT are controlled by centralized issuers who can freeze assets. +- Bridging Risks - Flow stablecoins (USDC, USDT, USDF) use LayerZero for bridging, a secure and widely adopted cross-chain solution. While all bridges carry some risk, LayerZero is built with advanced security measures to reduce vulnerabilities. +
    + +
    +You can bridge USDC, USDT, and USDF via [https://bridge.flow.com/][8] or [https://stargate.finance/bridge][9] + +### Step-by-step example USDC to Flow + +1. Go to any of the bridges (e.g. [https://stargate.finance/bridge][9]) +2. Connect your wallet that holds USDC +3. Select the source chain (e.g. Ethereum, BNB Chain, Base) +4. Choose Flow as the destination chain +5. Enter the amount of USDC you want to bridge +6. Approve and confirm the transaction +7. Wait for the transfer to complete - It usually takes a few minutes +
    + +
    +Flow’s transaction fees are extremely low (typically less than $0.000179 per transaction), making stablecoin transfers and trading much cheaper than on any other chain. + +In many cases, Flow Wallet or Flow-based apps sponsor the gas fees, meaning users can transact stablecoins without paying any gas. This makes Flow an ideal chain for cost-efficient DeFi transactions. + +
    + +
    +Stablecoins can be used for payments on Flow with services like: + +[Beezie][10], [Flowty][11], [Flowverse][12] and many other platforms. + +
    + +
    +- DeFi integrations with RWAs (Real World Assets). +- Stay tuned on [Flow X account][13] or via the community [Flowverse][14] +
    + +## Stargate and LayerZero on Flow + +
    +LayerZero is an omnichain interoperability protocol that enables seamless cross-chain communication between different blockchains. It allows assets, messages, and data to move securely between chains without relying on traditional bridges. +
    + +
    +Stargate is a liquidity transfer protocol built on LayerZero that allows users to bridge assets across multiple blockchains with minimal slippage and deep liquidity. +
    + +
    +With Stargate now supporting Flow, users can bridge assets to and from Flow blockchain via [Stargate Finance][9]. This enables Flow to interact with other major chains like Ethereum, Base, Arbitrum One, and BNB Chain, unlocking global onchain liquidity for Flow-based apps and DeFi protocols. +
    + +
    +Currently, Stargate supports bridging USDC, USDT, and ETH between Flow and other chains. Additional assets may be added in the future. +
    + +
    +- Total fees: You pay gas fees + relayer fees, typically less than $1.5 per bridge transaction. +- Gas fees vary depending on network congestion and gas prices. +- Bridging from Ethereum costs around 0.0003868 ETH (~$1.04) in gas fees, plus LayerZero relayer fees of 0.00003536 ETH ($0.095). +- Flow’s transaction fees are extremely low (typically less than $0.000179 per transaction), making stablecoin transfers and trading significantly cheaper than other chains. +- In many cases, Flow Wallet or Flow-based apps sponsor gas fees, allowing users to bridge and transact stablecoins with zero cost on Flow. +
    + +
    +- Most transactions settle within a few minutes (~3 mins). +- Congestion on the source chain can cause delays. +
    + +
    +Stargate is built on LayerZero, a well-audited and widely used interoperability protocol. + +- Secure & Trusted – Used by top DeFi ecosystems with rigorous security audits. +- Efficient & Cost-Effective – Fast transactions with low fees, especially on Flow. +- Reliable Bridged Assets – USDC, USDT, and ETH bridged via Stargate are fully supported in Flow’s DeFi ecosystem. + +Tip: Always verify official links to ensure a safe bridging experience. + +
    + +
    +- Direct USDC transfers between Flow and other blockchains. +- Unlocks cross-chain DeFi use cases (e.g., lending, trading, staking). +- Low fees and high-speed transactions on Flow. +
    + +
    +Currently, Stargate only supports stablecoins like USDC and USDT, but NFT and asset bridging may be possible in the future via LayerZero-based messaging. +
    + +
    +- **DeFi**: Seamless liquidity transfer between Flow and other ecosystems. +- **Gaming**: Cross-chain in-game assets & currency settlements. +- **Payments**: Fast and low-cost USDC/USDT/USDF transactions. +- **NFTs**: Future potential for cross-chain NFT bridging. +
    + +
    +You can use any EVM wallet such as Metamask, Coinbase Wallet, and Flow Wallet. +
    + +
    +You can see a full list of stablecoins here: +[DeFi Contracts on Flow][0] + +Trading pools for USDF and stgUSDC (USDC via Stargate) are already live and available for immediate use on Flow EVM and can be seamlessly transferred to any Flow Cadence address. + +
    + +
    +Cadence applications can use USDC.e as the default, but they now also have the option to support USDF or stgUSDC based on their needs. + +If you have questions you can join [Flow Discord][15] to get free technical support. + +
    + +## Support and Additional Resources + +
    +- Use [Stargate’s Explorer][9] to track your transfer. +- You can also check Flow transactions on [evm.flowscan.io][16] +- You can also visit [https://bridge.flow.com/][8] and connect your wallet to view activity. +
    + +
    +- **Stargate Discord**: [https://discord.com/invite/9sFqx9U][17] +- **Flow Discord**: [https://discord.gg/flow][15] +
    + +
    +- **Flow Twitter/X:** [https://x.com/flow_blockchain][13] +- **Flow Discord**: [https://discord.gg/flow][15] +
    + +[0]: ./defi-contracts.md +[1]: https://swap.kittypunch.xyz/ +[2]: https://app.increment.fi/swap?in=A.1654653399040a61.FlowToken&out= +[3]: https://app.increment.fi/dashboard +[4]: https://app.more.markets/ +[5]: https://app.increment.fi/liquidity +[6]: https://www.kittypunch.xyz/ +[7]: https://app.kittypunch.xyz/ +[8]: https://bridge.flow.com/ +[9]: https://stargate.finance/bridge +[10]: https://beezie.io/ +[11]: https://www.flowty.io/ +[12]: https://nft.flowverse.co/ +[13]: https://x.com/flow_blockchain +[14]: https://x.com/flowverse_ +[15]: https://discord.gg/flow +[16]: https://evm.flowscan.io +[17]: https://discord.com/invite/9sFqx9U +[19]: https://v2.sturdy.finance/overview +[20]: https://www.flowverse.co/?categories=defi \ No newline at end of file diff --git a/static/markdown/ecosystem/defi-liquidity/index.md b/static/markdown/ecosystem/defi-liquidity/index.md new file mode 100644 index 0000000000..55020006d6 --- /dev/null +++ b/static/markdown/ecosystem/defi-liquidity/index.md @@ -0,0 +1,50 @@ +--- +title: DeFi & Liquidity +description: Mechanisms that connect different blockchain networks, allowing secure and decentralized transfer of assets and data across platforms. +keywords: + - DeFi + - liquidity + - decentralized finance + - blockchain networks + - cross-chain transfer + - decentralized transfer + - Flow blockchain + - DEX + - lending platforms + - stablecoin protocols + - liquidity solutions +sidebar_position: 5 +sidebar_custom_props: + icon: 💧 +--- + +# DeFi & Liquidity on Flow + +**Fast, scalable, and capital-efficient DeFi.** Flow delivers a seamless DeFi experience without congestion, unlocking new possibilities for developers and users alike. + +Flow is designed for **next-generation DeFi**, enabling developers to build high-performance **DEXs, lending platforms, stablecoin protocols, and liquidity solutions**—all without the friction of high fees or complex scaling layers. + +## Why DeFi on Flow? + +**Ultra-low fees** – Cost-efficient swaps, lending, and staking +**Fast finality** – Transactions are confirmed quickly with guaranteed execution +**Capital-efficient execution** – No MEV, no congestion, seamless scaling +**Composable DeFi** – Built-in interoperability between assets + +**Start integrating DeFi on Flow today.** + +**[DeFi Contracts](./defi-contracts.md)** +**[Cross-chain swaps](./cross-chain-swaps.md)** +**[Read the FAQ](./faq.md)** + +Explore the [FlowVerse DeFi ecosystem](https://www.flowverse.co/?categories=defi) page for more information. + +## Securing DeFi on Flow EVM + +Flow EVM supports secure multi-sig from Safe.Global (formerly Gnosis Safe) or Fireblocks. Both offer robust solutions for +developers seeking to enhance the security and management of tokenized assets with a focus on institutional-grade practices and scalability. + +* [Safe.Global](https://safe.flow.com/) +* [Fireblocks](https://www.fireblocks.com/) + +--- \ No newline at end of file diff --git a/static/markdown/ecosystem/developer-profile.md b/static/markdown/ecosystem/developer-profile.md new file mode 100644 index 0000000000..587563fd05 --- /dev/null +++ b/static/markdown/ecosystem/developer-profile.md @@ -0,0 +1,97 @@ +--- +title: Developer Profile +sidebar_label: Developer Profile +description: Learn about Developer Profile - Flow's upcoming developer recognition and learning platform. Create your builder profile. In the future, you'll be able to track your learning journey, showcase your projects, and connect with the Flow ecosystem. +sidebar_position: 4 +sidebar_custom_props: + icon: ⭐ +keywords: + - Developer Profile program + - Flow developers + - builder profiles + - learning paths + - developer challenges + - Flow ecosystem + - developer recognition + - Flow community + - learning platform + - developer achievements + - Flow certification + - builder network + - developer tools + - Flow education + - developer onboarding +--- + +The Developer Profile is the beginning of Flow's developer recognition and learning platform where builders can create profiles, track their learning journey, complete challenges, and showcase their contributions to the Flow ecosystem. + +It's fully onchain! + +:::tip + +The Developer Profile is currently in alpha. Please let us know what you think! + +::: + +## What is the Developer Profile? + +The Developer Profile is a platform designed to help developers: + +- Create and manage their Flow builder profiles +- Track their learning progress through structured paths +- Complete challenges and earn recognition +- Connect with other builders in the ecosystem +- Showcase their projects and contributions + +Currently, the Developer Profile is in alpha. You can: + +- Create your profile +- Share your GitHub handle +- Add your deployed contract addresses +- Complete the First Challenge + +## Getting Started + +The Developer Profile is accessed by logging in with your wallet. Click the "Connect Button" in the top right. + +![Developer Profile Connect](profile-connect.png) + +:::tip + +The Developer Profile is on Flow Cadence. You'll need to use a wallet that supports Cadence transactions, such as the [Flow Wallet] or [Blocto]. + +::: + +Once connected, you can see your progress by clicking `Progress` in the dropdown menu. + +![Progress](progress.png) + +![Developer Profile Progress](profile-progress.png) + +### 1. Create Your Profile + +Click `Profile` in the dropdown menu. + +- Choose a unique handle +- Add your Github handle +- Add your deployed contract addresses +- Share how you discovered Flow + +### 2. Complete the First Challenge + +**After** you've created your profile, you can complete the first challenge. + +Click `Progress` in the dropdown menu. + +Click the button at the bottom of the page. + +Complete the challenge! + +## Next Steps + +We'll be updating the Developer Profile with new features and challenges. Check back soon! + + + +[Flow Wallet]: https://wallet.flow.com/ +[Blocto]: https://blocto.app/ \ No newline at end of file diff --git a/static/markdown/ecosystem/faucets.md b/static/markdown/ecosystem/faucets.md new file mode 100644 index 0000000000..fe7119442e --- /dev/null +++ b/static/markdown/ecosystem/faucets.md @@ -0,0 +1,110 @@ +--- +sidebar_position: 9 +description: Get free Flow tokens for testing. Faucets are like taps for tokens, useful for trying Flow without buying tokens. +sidebar_custom_props: + icon: 💧 +--- + +# Faucets + +Network Faucets provide free Flow tokens for testing purposes, functioning like taps that dispense tokens. They are valuable tools for experimenting with Flow without the need to purchase tokens. + +
    + +## Flow Faucet + +[Flow Faucet](https://testnet-faucet.onflow.org/) is a dedicated tool that provides a seamless way to acquire small amounts of Flow tokens for testing and development purposes on the Flow blockchain's testnet environment. + +### Supported Networks + +- [Testnet](https://testnet-faucet.onflow.org/) + +## LearnWeb3 Flow Faucet + +[LearnWeb3 Flow Faucet](https://learnweb3.io/faucets/flow) is a community faucet tool that provides a seamless way to acquire small amounts of Flow tokens for testing and development purposes on the Flow blockchain's testnet environment. + +### Supported Networks + +- [Testnet](https://learnweb3.io/faucets/flow) + +
    + +## Using Flow Faucet + +### Funding Your Account + +If you already have a Flow account, you can fund it directly from the Faucet's landing page. Simply paste the address of the account you want to fund, complete the CAPTCHA, and click "Fund Your Account." + +![fund-your-account](./faucet-fund-account.png) + +After a few seconds, you'll see your account's FLOW balance as a confirmation. Note, the Faucet will automatically determine if the address you paste is a Flow or EVM address and will fund the account accordingly. + +### Creating a Flow Account + +#### Generate a Key Pair + +To create a Flow-native account, you'll need to generate a key pair. You can do this most easily [Flow CLI](../build/getting-started/flow-cli.md) with the [`keys generate` command](../tools/flow-cli/keys/generate-keys.md) + +```sh +flow keys generate +``` + +You'll receive a private key and a public key pair with default `ECDSA_P256` signature and `SHA3_256` hash algorithms. + +```sh +❯ flow keys generate + +🔴️ Store private key safely and don't share with anyone! +Private Key +Public Key +Mnemonic +Derivation Path m/44'/539'/0'/0/0 +Signature Algorithm ECDSA_P256 +``` + +You can then use the public key to create a new Flow account on the Faucet. Copy the resulting public key for the next step. + +#### Create a Flow-Native Account + +From the Faucet's landing page, click on the "Create Account" button. You'll be prompted to enter your public key. Paste the public key you generated using the Flow CLI and click "Create Account." + +:::tip + +Know that there is a distinction between Flow native accounts and EVM accounts. Native accounts allow you to interact with the Cadence runtime, while EVM accounts are used for interacting with Flow's EVM. To create an EVM account, you can use EVM tooling to generate an Ethereum Owned Account (EOA) and simply fund the associated address. Alternatively, you can create an EVM account controlled by your Flow native account - known as a Cadence Owned Account (COA) - in which case you'll need a Flow native account and should continue with the steps below. + +For more information interacting with EVM via COAs, see the [Interacting With COAs documentation](../tutorials/cross-vm-apps/interacting-with-coa.md). + +::: + +![create-flow-account](./faucet-create-account.png) + +You can then paste your public key into the input field, complete the CAPTCHA, and click "Create Account." + +![input-public-key](./faucet-input-public-key.png) + +You'll be met with a confirmation screen, showing your Flow account address and the funded balance. + +![account-created](./faucet-account-created.png) + +#### Using your Flow Account + +Once your account has been created, you can add the account to your `flow.json` configuration file under the `accounts` attribute, like so: + +```json +{ + "accounts": { + "testnet-dev-account": { + "address": "", + "key": "" + } + } +} +``` + +:::warning + +If you plan on using your flow.json in a production environment, you'll want to look at alternative methods to manage your keys more securely, at minimum using environment variables instead of storing your account private keys in plain text. See [How to Securely Use CLI](../tools/flow-cli/flow.json/security.md) for more information on alternate key management strategies and how to configure them in your `flow.json` file. + +::: + +After adding your account to your `flow.json` file, you're ready to use your account in your project. You can now deploy contracts, run transactions, and interact with the Flow blockchain using your new account. \ No newline at end of file diff --git a/static/markdown/ecosystem/grants.md b/static/markdown/ecosystem/grants.md new file mode 100644 index 0000000000..5366a47d50 --- /dev/null +++ b/static/markdown/ecosystem/grants.md @@ -0,0 +1,26 @@ +--- +title: Grants +description: Discover grant opportunities and funding programs available for Flow developers +sidebar_position: 10 +sidebar_custom_props: + icon: 🌱 +--- + +# Flow Developer Grants + +The Flow Foundation provides grants to support developers and teams building tools and products that enhance the Flow ecosystem. + +## Focus Areas + +We are particularly interested in projects across these key areas: + +- **Telegram Miniapps**: Building integrations and applications for the Telegram ecosystem +- **DeFi**: Innovative decentralized finance solutions +- **AI Agents**: Artificial intelligence and autonomous systems +- **Sports**: Applications and platforms in the sports and gaming sector + +## How to Apply + +1. Visit the [Flow Developer Grants Repository](https://github.com/onflow/developer-grants) +2. Create a new issue using the "Grant Application" template +3. Fill out all required details about your project \ No newline at end of file diff --git a/static/markdown/ecosystem/hackathons.md b/static/markdown/ecosystem/hackathons.md new file mode 100644 index 0000000000..8ee9a82d1b --- /dev/null +++ b/static/markdown/ecosystem/hackathons.md @@ -0,0 +1,33 @@ +--- +title: Hackathons +description: Participate in Flow hackathons to build, learn, and win prizes +sidebar_position: 11 +sidebar_custom_props: + icon: 🚀 +--- + +# Flow World Tour Hackathons + +Some of the most groundbreaking blockchain projects began as hackathon ideas—CryptoKitties, the game that revolutionized NFTs, was first built at the ETHGlobal Waterloo hackathon. Your project could be next. + +## Flow World Tour + +We're bringing together builders, creators, and innovators through a series of global hackathons—both in-person and online. These events are more than just competitions; they’re an opportunity to experiment, collaborate, and turn bold ideas into reality. + +### Why Join? + +#### **Build & Learn** + +Get hands-on experience with Flow while accessing expert mentorship, technical workshops, and valuable resources to refine your skills on the cutting edge, from AI agents to next-gen DeFi. + +#### **Network & Connect** + +Meet like-minded builders, potential co-founders, and potential investors. These events are a gateway to becoming part of the global Flow community. + +#### **Win & Launch** + +With substantial prize pools, industry recognition, and the chance to launch your project, hackathons can be the stepping stone to your next big startup, side-project, or public good. + +## Find Your Flow State + +Stay ahead of upcoming hackathons and exclusive announcements. [Join Flow World Tour on Telegram](https://t.me/flow_world_tour). \ No newline at end of file diff --git a/static/markdown/ecosystem/index.md b/static/markdown/ecosystem/index.md new file mode 100644 index 0000000000..fd1c434666 --- /dev/null +++ b/static/markdown/ecosystem/index.md @@ -0,0 +1,33 @@ +--- +sidebar_position: 1 +title: Ecosystem +description: Access essential tools, knowledge, and community connections for the Flow Blockchain ecosystem. +--- + + + + + + + !isSamePath(item.href, useLocation().pathname)), + { + type: 'link', + label: 'Flow Forum', + href: 'https://forum.onflow.org/', + description: 'Engage with the Flow community, discuss ideas, and seek support on the Flow Blockchain Forum.', + customProps: { + icon: "🏛️" + }, + }, + { + type: 'link', + label: 'FLIPs', + href: 'https://github.com/onflow/flips', + description: 'Flow Improvement Proposals (FLIPs) serve as a platform for engaging the Flow community in development, harnessing the collective ideas, insights, and expertise of contributors and experts while ensuring widespread communication of design changes.', + customProps: { + icon: "📜" + }, + }, + ] +}/> \ No newline at end of file diff --git a/static/markdown/ecosystem/projects.md b/static/markdown/ecosystem/projects.md new file mode 100644 index 0000000000..700818039c --- /dev/null +++ b/static/markdown/ecosystem/projects.md @@ -0,0 +1,253 @@ +--- +title: Community Projects +description: Explore the diverse projects and contributions within the Flow Blockchain community. +sidebar_position: 7 +sidebar_custom_props: + icon: 🏟️ +--- + + + +Explore an array of exciting, grassroots initiatives, and projects that thrive within the Flow Blockchain community, each contributing to the platform's growth and innovation. + + \ No newline at end of file diff --git a/static/markdown/ecosystem/vcs-and-funds.md b/static/markdown/ecosystem/vcs-and-funds.md new file mode 100644 index 0000000000..53bc6736a0 --- /dev/null +++ b/static/markdown/ecosystem/vcs-and-funds.md @@ -0,0 +1,28 @@ +--- +title: VCs & Funds +description: Connect with venture capital firms and investment funds supporting Flow projects +sidebar_position: 8 +sidebar_custom_props: + icon: 💼 +--- + +# VCs & Funds + +Building a successful Web3 project requires more than just great technology - having the right investors and partners can make all the difference. The Flow ecosystem is supported by some of the world's leading venture capital firms and crypto-native funds. + +Research shows that warm introductions can increase your chances of securing funding by up to 500% more liley compared to cold outreach. The Flow Foundation can help facilitate introductions to our network of trusted investors who have a deep understanding of the Flow ecosystem and web3. Reach out to your local dev-rel in [office hours](https://calendar.google.com/calendar/u/0/embed?src=c_47978f5cd9da636cadc6b8473102b5092c1a865dd010558393ecb7f9fd0c9ad0@group.calendar.google.com) or [discord](https://discord.gg/flow) to get a warm introduction. + +
    + + +## Generating a Non-Custodial Account + +A non-custodial account will make sure you are the only one holding the keys to your account. + +You can follow the following steps to add a non-custodial account: + +First, generate a new key pair with the [Flow CLI](https://github.com/onflow/flow-cli): + +```sh +> flow keys generate --network=mainnet + +🔴️ Store private key safely and don't share with anyone! +Private Key 5b438... +Public Key 1bdc5... +``` + +> **Note**: By default, this command generates an ECDSA key pair on the P-256 curve. Keep in mind the CLI is intended for development purposes only and is not recommended for production use. Handling keys using a Key Management Service is the best practice. + +Take a note of the public key and go back to Flow Port. Open the ["Create a new account" page](https://port.onflow.org/transaction?hash=a0a78aa7821144efd5ebb974bb52ba04609ce76c3863af9d45348db93937cf98&showcode=false&weight=1000&halg=3). + +On the page, enter your public key from the CLI, ensure the hash algorithm is set to `SHA3_256` and the weight is set to `1000`. Finally, check the box confirming correctness and hit 'Submit'. + +> **Important**: Your account needs to have at least 0.002 FLOW for the account creation. More details can be found [in this guide](../../build/basics/fees.md#storage). + +Once the transaction is sealed, you should scroll down to the events section and locate the `flow.AccountCreated` event with the newly generated address. + +![flow-port-sealed](port-sealed-tx.png) + +Make sure to take a note of the address. If you want to verify the public key for this address, you can visit [flow-view-source](https://flow-view-source.com/). + +## Important Mainnet Smart Contract Addresses + +You can review [all available core contracts](../../build/core-contracts/index.md) deployed to the mainnet to identify which ones you want to import. \ No newline at end of file diff --git a/static/markdown/networks/flow-networks/accessing-testnet.md b/static/markdown/networks/flow-networks/accessing-testnet.md new file mode 100644 index 0000000000..1a05653940 --- /dev/null +++ b/static/markdown/networks/flow-networks/accessing-testnet.md @@ -0,0 +1,60 @@ +--- +title: Flow Testnet +sidebar_label: Testnet +sidebar_position: 3 +description: Guide to Testnet access +--- + +## About Flow Testnet + +Flow Testnet is Flow's official testing and development network. It is intended to provide a staging and testing environment for dApp developers. +It aims to balance similarity with Mainnet with being a productive development environment, resulting in the following key differences: + +- Testnet has significantly fewer validator nodes, resulting in a faster block rate compared to Mainnet +- Testnet is configured with shorter epochs (about 12 hours, compared to 7 days on Mainnet) +- Testnet receives software upgrades up to 2 weeks before Mainnet + +## Accessing Flow Testnet + +Flow Testnet is available for access at this URL: + +``` +access.devnet.nodes.onflow.org:9000 +``` + +For example, to access the network using the [Flow Go SDK](https://github.com/onflow/flow-go-sdk): + +```go +import "github.com/onflow/flow-go-sdk/client" + +func main() { + flowAccessAddress := "access.devnet.nodes.onflow.org:9000" + flowClient, _ := client.New(flowAccessAddress, grpc.WithInsecure()) + // ... +} +``` + +### Generating Testnet Key Pair + +You can generate a new key pair with the [Flow CLI](https://github.com/onflow/flow-cli) as follows: + +```sh +> flow keys generate + +🙏 If you want to create an account on Testnet with the generated keys use this link: +https://testnet-faucet.onflow.org/?key= cc1c3d72... + +🔴️ Store private key safely and don't share with anyone! +Private Key 246256f3... +Public Key cc1c3d72... +``` + +**Note: By default, this command generates an ECDSA key pair on the P-256 curve. Keep in mind, the CLI is intended for development purposes only and is not recommended for production use. Handling keys using a Key Management Service is the best practice.** + +## Account Creation and Token Funding Requests + +Accounts and tokens for testing can be obtained through the [testnet faucet](https://testnet-faucet.onflow.org/). If you generated the keypair through the CLI, you can click on the URL provided to create an account and request testnet FLOW tokens. + +## Important Smart Contract Addresses + +You can review [all available core contracts](../../build/core-contracts/index.md) deployed to the Testnet to identify which ones you want to import. \ No newline at end of file diff --git a/static/markdown/networks/flow-networks/index.md b/static/markdown/networks/flow-networks/index.md new file mode 100644 index 0000000000..89b6d1d388 --- /dev/null +++ b/static/markdown/networks/flow-networks/index.md @@ -0,0 +1,50 @@ +--- +title: Flow Networks +sidebar_position: 1 +--- + +## About Flow Networks + +:::note + +This page provides information on Flow network RPCs. Flow EVM network RPCs can be found [here](../evm/networks) + +::: + +In addition to Mainnet, developers have access to the Testnet environment, which serves as an essential testing ground for applications and smart contracts prior to their deployment on Mainnet. This ensures that any potential issues can be identified and resolved in a controlled setting, mitigating risks associated with live deployment. + +Furthermore, during network upgrades, Testnet receives updates ahead of Mainnet. This preemptive update process allows developers to comprehensively test their apps against the latest versions of the nodes, enhancements to the Cadence programming language, and core contract upgrades. This strategy guarantees that when these updates are eventually applied to Mainnet, applications and smart contracts will operate seamlessly, enhancing overall network stability and user experience. + +### How To Access These Networks? + +| Network | GRPC | Web GRPC | REST | +| ------- | -------------------------------------- | -------------------- | ------------------------- | +| Mainnet | `access.mainnet.nodes.onflow.org:9000` | `mainnet.onflow.org` | `rest-mainnet.onflow.org` | +| Testnet | `access.devnet.nodes.onflow.org:9000` | `testnet.onflow.org` | `rest-testnet.onflow.org` | + +For more information on how to access these networks, refer to the following guides: + +- [Flow Testnet](./accessing-testnet.md) +- [Flow Mainnet](./accessing-mainnet.md) + +### Network + +There are two primary ways to access on-chain data within the Flow network; Access Nodes and Light nodes. Access Nodes are the node type that are most useful for developers, as they provide access to the Flow network via the following API endpoints: + +- [Flow Access API](../access-onchain-data/index.md) + - [Mainnet](./accessing-mainnet.md): `access.mainnet.nodes.onflow.org:9000` + - [Testnet](./accessing-testnet.md): `access.devnet.nodes.onflow.org:9000` +- [Status Page](https://status.onflow.org/) - Network status page + +### Rate limits + +Rate limits for Flow Public Access nodes hosted by QuickNode are detailed [here](https://www.quicknode.com/docs/flow#endpoint-rate-limits). + +### Running Your Own Node + +If you’re getting started you don’t need to run your own node and you can use the above public nodes. The public access nodes are rate-limited, so as your product matures you might want to run your own node. There are multiple options available: + +- Start with a [Light (Observer) Node](../node-ops/light-nodes/observer-node.md). +- You can also use a third-party provider like [Quicknode](https://www.quicknode.com/docs/flow). + +Check out [Running a Node](../node-ops/light-nodes/observer-node.md) for more information. \ No newline at end of file diff --git a/static/markdown/networks/flow-port/index.md b/static/markdown/networks/flow-port/index.md new file mode 100644 index 0000000000..519ab54808 --- /dev/null +++ b/static/markdown/networks/flow-port/index.md @@ -0,0 +1,150 @@ +--- +title: Flow Port +description: How to use Flow Port +--- + +Flow Port is an account management tool for Flow. Flow Port allows you to create an account using a wallet provider, manage your account and assets across Flow's VMs and perform staking and delegating actions on Flow. + +Typically, your wallet provider will support most of these features. However, should your wallet provider not do so, or should you wish to use this tool for any other reason, Flow Foundation makes it available for you. + +## Creating an Account +In order to access Flow Port, you must have a valid Flow address. If you do not have a Flow address you can create one by installing a [Flow compatible wallet](../../ecosystem/wallets). + +### Flow Wallet + +#### Creating Account Through Flow Port: Navigate To Flow Port + + 1. Using Google Chrome, Navigate to [Flow Port](https://port.onflow.org/). + + 2. Click on 'Sign Up' + + 3. Click on Flow Wallet and choose Chrome extension or Mobile + + 4. You should be logged into Flow Port! You can now see your account address in Flow Port and access Flow features for your account + +### Ledger +#### Before You Start + + 1. Ensure you have: + + - a.) [Ledger Live](https://www.ledger.com/ledger-live) installed on your computer + + - b.) [Initialized](https://support.ledger.com/hc/en-us/articles/360017362160-Flow-FLOW-?support=true) your Ledger Device. + +#### Install the Flow App + + 1. Connect your Ledger Device to your computer and open Ledger Live. + + 2. Make sure your Ledger device firmware is up to date. You can check this by clicking on **‘Manager’** from the side navigation bar. Choose to install the update if one is available + + - a.) NOTE: Sometimes the install option doesn't show up, or it is not clickable. If this is the case, wait for a little bit of time to see if it appears, or restart the ledger live app if necessary. + + 3. On the Manager screen in Ledger Live and search for ‘Flow’. + + 4. You should see the Flow App. Install it and follow the instructions on the device. + + - a.) NOTE: If the Flow App does not appear, it may be because you are on an outdated version. Please ensure you are on the most updated version. + +#### Navigate to Flow Port to Create an Address + + 1. Navigate to [Flow Port](https://port.onflow.org/). + + 2. Click on 'Sign Up' if you need to create a new Flow Account. + + 3. Click on Ledger. + + 4. Follow the prompts on the screen. Plug in your Ledger device and open the Flow App. + + 5. Click on Create an account. Follow the prompts on your Ledger device. + + 6. Once your account address is created, you will be automatically logged into Flow Port. + +## Staking & Delegating + +For a detailed walkthrough on how to use Flow Port for staking and delegating, please read the [Flow Port staking walkthrough](./staking-guide.md) +### How Do I Stake or Delegate? + +So you have decided you want to be a part of the Flow Network. Welcome! You are joining a group of people from all around the world that are a part of a movement centered around bringing decentralization, user empowerment, and transparency into the world. Below is a step-by-step guide that will assist you in the staking & delegation process. + +### Staking via a Custody Provider + +If you are using a custody provider who controls your account and private keys for you, such as Kraken, Finoa, or Coinlist, they all have different policies and processes for what you need to do to stake your tokens, the rewards you receive, and the fees that they take from your staking rewards. + +### Starting a Manual Staking Transaction + 1. You need to have FLOW in order to stake. Please see the [FLOW Token](../../build//core-contracts//03-flow-token.md) reference for information on how to become a FLOW holder. + + 2. Once you have FLOW tokens in your account, you can start staking through [Flow Port](https://port.onflow.org/) or, if applicable, with your [custody provider](#staking-via-a-custody-provider). + + 3. If you are using Flow Port, log-in with your Flow account address and navigate to the Stake/Delegate page. See the Manual Staking/Delegating section below for more information about what to do next. + +### Manual Staking/Delegating +If you are not using a custody provider, there is more responsibility that you have to accept, because you have complete control of your tokens. You need to ensure that you are well informed about the staking process and potentially node operation process because you will have to manage those on your own. Please read the [staking documentation](../../networks/staking/index.md) before continuing with this guide. + +Below are the various options you can choose. Please be aware, that at this time you can only have 1 stake or 1 delegate per account. This means that if you want to do multiple stakes, multiple delegates, or a mixture of stakes and delegates, you will need to create multiple accounts to do so. Please read them carefully as it will help you understand which route is best for your situation: +- Staking your own Node: You are responsible for running and maintaining a Flow Node. You are also solely responsible for providing the minimum stake for your selected node (minimum 135,000 FLOW) and you have the technical know-how and bandwidth to run and operate a node in the Flow protocol. +- Delegating: You have FLOW tokens and you want to stake, without having to run your own node and/or have the full minimum stake required to run your own node. You can ‘delegate’ any amount of your FLOW tokens to an existing node operator and you will earn rewards. + +Please see a list [here](https://github.com/onflow/flow/blob/master/nodeoperators/NodeOperatorList.md) for all node operators that you can delegate to. This list will be updated as new node operators are onboarded onto the network.' + +### Staking Your Own Node + 1. Once you have navigated to the staking/delegating page in Flow Port, click on the 'Stake a Node' option. + + 2. Next, select the type of node you will be running. + + 3. Input the amount of Flow you wish to stake with that node. You must stake at least the minimum in order for your stake request to be successfully processed. You are able to provide the minimum stake across multiple transactions. Meaning, you could execute your stake transaction with half of the minumum required. Then, before the next epoch, you can choose to 'Add Flow' to that pending stake to get it to the minimum stake required. + + 4. Run the [bootstrapping instructions](../../networks/node-ops/node-operation/node-bootstrap.md) and provide the remaining technical details needed to stake a node. + +### Delegating + 1. Once you have navigated to the staking/delegating page in Flow Port, click on the Delegate option. + + 2. Next, you will specify which node operator you would like to delegate to and how many tokens you want to delegate to them. + + 3. Execute the transaction. You will now see your pending delegation that will be processed during the next epoch. + + 4. At this point, you can also cancel the pending delegation. On the pending delegation, you will see an `X` that you can click to initiate the cancelation transaction. + +## I Have Successfully Executed a Stake Transaction, Now What? + - Now that you have executed a stake transaction in either Flow Port or your custody provider’s portal, that transaction will sit in a pending status until it is processed, which will be at the next [Epoch](../../networks/staking/index.md#epochs) Date (which is currently weekly). + - During the next [Epoch](../../networks/staking/index.md#epochs), the transaction will be processed. If successful, the provided FLOW will be staked and the associated Node would be either **a)** included in the network protocol if it is a new node or **b)** continue to operate as is in the network protocol. + - You are now a part of Flow, and will begin to earn rewards for being a valued member of the network! + +## What Else Can I Do? + - Add additional stake to your existing stake. Any added FLOW will again sit in a pending status and be processed at the next epoch. + - Withdraw/re-stake your earned rewards. If you decide to withdraw your rewards, this action will happen instantly. If you decide to re-stake your rewards, the request will again sit in a pending status and will be processed at the next [Epoch](../../networks/staking/index.md#epochs). + - Withdraw Rewards and send your earnings to other accounts. If you decide that you want to withdraw your rewards and send those earnings to other accounts via the 'Send FLOW' function, you should first withdraw your rewards. Once in your account, you can send these funds to any other account via the 'Send FLOW' option. + - Request to be unstaked from the network. The unstake request will sit in a pending status for two epochs. Once it is processed, the amount that has been unstaked will sit in your unstaked FLOW amount and can now be withdrawn or re-staked. + - Change the node you are staked/delegated to. If your staked/delegated node has no FLOW actively staked and you have completely withdrawn all unstaked amounts and rewards associated with the node, then you can move your stake to a different node. Click on the `Change Node` button to initiate this process. Please note that this feature is only visible once you get your active stake/delegate into the appropriate status. + +## FAQs + 1. Why do I have multiple 'Keys' on my account? + + If you created your account with Blocto, you will see that you have multiple keys that exist on your account in the 'Dashboard': + + 1 with weight 1 (device key): This is generated on Blocto and sent to users' device when they login with email. + 1 with weight 999 (Blocto service key): This is kept in Blocto's secure key management service and is used to sign transaction. + 1 with weight 1000 (recovery key): This is kept in Blocto's secure key management service and is only used when user wants to switch to non-custodial mode. + + Normally if a user wants to send a Flow transaction, it requires signature from both the key on users' device and a key from Blocto service. Making it harder for hackers to steal your assets. + + 2. Where can I find a list of node operators to delegate to? + + - a.) Please see a list [here](https://github.com/onflow/flow/blob/master/nodeoperators/NodeOperatorList.md) for all node operators that you can delegate to. This list will be updated as new node operators are onboarded onto the network. + + 3. I am currently running a node on the network already and have already gone through the staking process once. Do I need to execute a new stake every time there is a new epoch? + + - a.) Once you successfully stake your node and become part of the network, you do not need to submit a new staking request each and every epoch. Your node will be automatically staked from epoch to epoch. This also means that your Node ID will remain the same from epoch to epoch. If you want to unstake your node from the network, then you will follow the process of unstaking your node. + + 4. I have a Blocto account and I see that I can stake both in Flow Port and in Blocto's mobile app. What is the difference? + + - a.) If you go through Flow Port, you can choose any node operator within the Flow network to delegate any amount of your Flow Tokens to. If you go through Blocto's mobile site, you will only be able to stake to Blocto run nodes. You can read more about Blocto's staking process by referencing [here](https://guide.blocto.app/article/stake-flow-tokens-step-by-step-with-blocto). + + 5. Do I need to use my Ledger device to view information about my account (e.g. my balance and current staked or delegated FLOW)? + + - a.) No you do not! You only need your Ledger device to sign transactions. If you want to view your account, you can do so without your Ledger. You can do this by navigating directly to the appropriate desired page URL, while inputting your address into the URL itself. For quick reference, below is a list of these URLs and where you would input your address: + - Dashboard: https://port.onflow.org/account/[AccountAddress] + - Stake & Delegate: https://port.onflow.org/stake-delegate/[AccountAddress] + + 6. I am clicking 'submit' to execute a transaction, but nothing is happening. How can I unblock myself? + + - a.) Please disable any pop-up blockers and ad blockers you have and refresh the page. If you are still experiencing issues, please reach out via [Discord](https://discord.gg/flow) in the appropriate channel. \ No newline at end of file diff --git a/static/markdown/networks/flow-port/staking-guide.md b/static/markdown/networks/flow-port/staking-guide.md new file mode 100644 index 0000000000..63f893aa96 --- /dev/null +++ b/static/markdown/networks/flow-port/staking-guide.md @@ -0,0 +1,135 @@ +--- +title: Flow Port Staking Guide +--- + +This guide provides step-by-step instructions for using the Flow Port to stake your FLOW tokens and start earning rewards. +Currently, Flow Port only supports staking or delegating using tokens held in Blocto or Ledger wallets. +If you're new to the concepts of staking and delegating you can [read this guide](../../networks/staking/index.md) to learn more. + +## First Step + +When you arrive in Port, select **Stake & Delegate** from the left-hand menu. You should be taken to this page. + +![Flow Port Staking pt. 0](port-stake-0-00.png) + +From here you can decide whether to stake or delegate. + +- Select **Stake** if you plan to stake a node you're running. +- Select **Delegate** to delegate your stake to another Node Operator. You don't need to know which Node Operator, you'll be provided with a list to choose from. If you are not running your own node you scan skip directly to the [delegation section](#delegating) + +## Stake a Node + +Users who will be running their own nodes can stake them using the Flow Port. + +#### Prerequisites + +In order to stake your node, you'll need to have the required amount of FLOW for your node type. +You'll also need the following information about your node: + +- Node ID +- Network Address +- Networking Key +- Staking Key +- Machine Account Public Key (for collection/consensus nodes only) + +If you don't have this information, go [here](../../networks/node-ops/node-operation/node-bootstrap.md#step-1---run-genesis-bootstrap) for instructions on how to acquire it. + +### Begin Staking + +First, select the type of node you'll be running by choosing from the list. You must have the required amount of locked FLOW in your account. + +![Flow Port Staking](port-stake-0-02.png) + +Once you selected your node type, click next and specify how much you'd like to stake. The minimum amount for your node type is required, +but you may stake as much as you like beyond that. Here's the screen you should see: + +![Flow Port Staking](port-stake-0-03.png) + +Clicking next will take you to the final screen, where you'll need to enter information about your node you previously obtained. +If you don't have this information, go [here](../../networks/node-ops/node-operation/node-bootstrap.md#step-1---run-genesis-bootstrap) for instructions on how to acquire it. +Here's the screen you should see: + +![Flow Port Staking](port-stake-0-04.png) + +Clicking next will take you to a confirmation screen. This is your chance to double-check that you've entered your information correctly. If you're ready, check the +box confirming your information and click submit to send the transaction that will stake your node! You should see a transaction status screen like this: + +![Flow Port Staking](port-stake-0-05.png) + +**Note:** If your transaction fails, double-check the information you provided.

    + +If you return to the home screen, you'll be able to see your staking request in progress! + +![Flow Port Staking](port-stake-4.png) + +## Delegating + +Delegating is the process of staking your locked FLOW to nodes which are being run by another party. + +#### Prerequisites + +In order to delegate your stake to another node, you'll need to know the **node operator ID** of the operator who is running the nodes you wish to stake. +Here is a list of node operator IDs you can delegate to: [List of Available Node Operators](https://github.com/onflow/flow/blob/master/nodeoperators/NodeOperatorList.md) + +### Enter a Node Operator ID + +Simply enter the ID of the node operator of your choice and click next. + +![Flow Port Staking](port-delegate-1.png) + +### Enter an amount + +Next you'll enter an amount of FLOW you would like to delegate. When delegating you may send any amount to the node operator. + +![Flow Port Staking](port-delegate-2.png) + +Click next to reach the confirmation screen. Confirm the details of your delegation request and click submit! + +![Flow Port Staking](port-delegate-3.png) + +Once your transaction is submitted, you can monitor its status from this screen, or return to the Flow Port home screen. + +![Flow Port Staking](port-delegate-4.png) + +**Note:** If you transaction fails, double-check the information you provided.

    + +That's it! You've successfully delegated stake to your chosen node operator! + +## Returning to Port + +Within Flow Port, navigate to the ‘Stake & Delegate’ page to see details about your existing staked and/or delegated tokens. +This will also show you the rewards you have earned for your staked/delegated tokens. + +![Flow Port Staking pt. 1](port-stake-1.png) + +From here, you can do a few different things with your rewards: + +- You can choose to **re-stake** them to the associated node. +- You can choose to **withdraw** them to your wallet. + +## Re-staking + +Flow Port will not automatically re-stake your rewards. +To re-stake your rewards, simply hover your cursor over the 3 dots next to the rewards field: + +![Flow Port Re-Staking](port-stake-2.png) + +Click on the Restake option. This will take you to a screen that looks like the below. Input the amount of rewards you want to re-stake, acknowledge the transaction inputs and click submit: + +![Flow Port Re-Staking](port-stake-3.png) + +Once the transition is processed, you can reference the Stake & Delegate page again to see the pending stake now: + +![Flow Port Re-Staking](port-stake-4.png) + +## Withdraw your Rewards + +To withdraw your rewards, simply hover your cursor over the 3 dots next to the rewards field, and click on ‘Withdraw’. + +![Flow Port Re-Staking](port-stake-5.png) + +Input the amount that you want to withdraw to your wallet, acknowledge the transaction inputs and click submit: + +![Flow Port Re-Staking](port-stake-6.png) + +Once the transition is processed, you can now see the withdrawn rewards in your balance and you are now free to do other actions with them (send them to other accounts, delegate to a node, etc). \ No newline at end of file diff --git a/static/markdown/networks/governance.md b/static/markdown/networks/governance.md new file mode 100644 index 0000000000..a0e00f8f92 --- /dev/null +++ b/static/markdown/networks/governance.md @@ -0,0 +1,56 @@ +--- +title: Governance +description: Learn about Flow's governance model and how it's empowering our community of users and builders. +sidebar_position: 5 +sidebar_custom_props: + icon: 🏛️ +--- + +## Participation + +Participating in the governance process can take three forms: + +- Being elected as a council member on the governing committee +- Putting forth a proposal for the community to vote on +- Staking to receive voting rights + +Votes will be weighted based on locked tokens. All tokens staked by node operators will be eligible for voting, but other users can lock up their tokens to be given voting power. Anyone will be able to stake a Flow token to vote on issues (even if they aren’t participating as a staked node). + +## Token Holder Rights + +Tokens may be staked for operation or governance rights which gives holders the right to participate in running a node and/or to participate in public votes. + +## Process + +Proposals can be brought forward on a public forum where they will be evaluated by the governing committee. All decisions are made publicly and any stakeholder has the opportunity to organize grassroots action to veto specific decisions or to vote in or remove council members. + +To ensure the progress of the network, the elected council first assesses the proposal and selects an answer they agree to be the "default choice". Voters can freely vote how they choose, but having a well-considered default allows forward progress without being blocked by passive participants. All decisions are voted on by all participants and decisions made by the council must be ratified by a public vote on the network. + +### Timing + +Vote outcomes and upcoming votes will be published every Friday by 7am PT. All upcoming votes are available for review and voting for at least two weeks following their publication. + +## Protocol Set Parameters + +The following parameters will be set on the network on day 1 and will not be candidates for a public vote when the network first launches. + +- The staking ratio preserved between each node type +- The maximum inflation rate +- The role of FLOW as the main reserve asset for collateralized secondary tokens (e.g. stablecoins) +- The mechanism through which transaction inclusion, computation, and storage fees are determined and paid for + +## Early Governance of the Protocol + +Once governance is enabled, the community can participate in the following: + +- Protocol upgrades, including things like: - the consensus algorithm - the low-level network communication structure - the execution environment - the number of seats available for each node type +- Management of Ecosystem Development Fund, including: - issuance of grants - bug & feature bounties +- Selecting council members +- Committee budgets for each of the operational arms of the Foundation, including the executive, technical, operational, legal, pricing, financial, and marketing branches. +- Management of legal affairs, including: - enforcing license and patent infringements - issuing takedown notices and copyright infringement - freezing accounts if illegal activity occurs - updating the community, security, contribution policies + +During the Bootstrapping Phase, anyone may apply online to be set as a Validator by the Company. Approved Validators must then Stake a fixed minimum of FLOWs based on Validator type. Other FLOW holders may become “Delegators” when they dedicate or “Delegate” their FLOWs to approved Node Operators as a signal that they believe that Validator to be an effective and honest participant of the network. Staking and Delegation features are already enabled as of the Effective Date. + +Each Validator makes an individual decision of which Protocol Version they choose to use. Since the value of blockchain networks is primarily due to the collectively verified execution state, there is a strong incentive for Validators to choose a Protocol Version that is compatible with the Protocol Version selected by the majority of other Validators. As a practical matter, the Protocol Version chosen by the overwhelming majority of Validators is likely to be the most recent Protocol Version produced and recommended by the Core Team, provided the proposed changes are not contentious. However, if a significant fraction of the community disagrees with any aspect of the most recent Protocol Version, they can band together to use a previous Protocol Version, or some other Protocol Version defined independently from the Core Team. This process of a “contentious forking” is rare, but does have several precedents in other networks (REF: Ethereum Classic, Bitcoin Cash). + +The process by which the Core Team chooses the updates for each new Protocol Version follows the open process described above, using GitHub as an open discussion platform to gauge the priorities and needs of the entire Flow ecosystem. The proposed changes by the Core Team will be announced and discussed well before they are implemented, and any community member can propose their own changes or contribute code updates to implement any proposed changes. The details of a new Protocol Version are publicly available no less than 14 days before that version is formally recommended for use by Validators (a “Release”), with the complete implementation source code visible for no less than 7 days before a Release. \ No newline at end of file diff --git a/static/markdown/networks/index.md b/static/markdown/networks/index.md new file mode 100644 index 0000000000..c16b0ccd8e --- /dev/null +++ b/static/markdown/networks/index.md @@ -0,0 +1,12 @@ +--- +sidebar_position: 1 +--- + + + + + + +# Networks + + !isSamePath(item.href, useLocation().pathname))}/> \ No newline at end of file diff --git a/static/markdown/networks/network-architecture/index.md b/static/markdown/networks/network-architecture/index.md new file mode 100644 index 0000000000..552f5f2228 --- /dev/null +++ b/static/markdown/networks/network-architecture/index.md @@ -0,0 +1,71 @@ +--- +title: Flow's Network Architecture +sidebar_position: 1 +--- + +Flow has pioneered a new paradigm of multi-role architecture that solves the core problem of today’s blockchains. +The result is a scalable, decentralized, and secure network which ensures user safety and long-term sustainability. + +
    + +![flow_gif](images/flow_node_types_1.gif) + +
    + +To better understand the architecture, lets first understand the problems with the current blockchain. Then lets look at how Flow multi-role architecture solves these problems. + +# What are the biggest problems solved by Flow's Multi-role Architecture? + +## 1. The blockchain trilemma + +A blockchain should be fully decentralized, highly scalable and extremely secure. However a well-known problem with all blockchain is the blockchain trilemma - optimizing for any one edge comes at the cost of the other two. + +You can have a chain that is decentralized and secure but not scalable e.g. Bitcoin and Ethereum or you can have a chain that is scalable and secure but not as decentralized e.g. Solana, Aptos and Sui. +While multi-chain systems like Cosmos, Layer 2 solutions (L2s) like Polygon, and cross-chain bridges offer innovative approaches to address these challenges, they divide the trust into separate and independent security zones and such zones with fewer validators can be more vulnerable to attacks and therefore less secure. + +![scenario_1](images/trilemma.png) + +## 2. Disadvantaging end-users +Most blockchains, regardless of the number of participating nodes, inherently disadvantage individual end-users. This is because (colluding) nodes can censor user transactions or unfairly extract value from users in a phenomenon commonly known as Miner Extractable Value [MEV]. As a result, individual end users can end up paying an “invisible tax” or otherwise seeing their transactions fail due to MEV. + +## 3. Energy inefficient and unsustainable +It is well established that Proof-of-Work chains like Bitcoin consume massive amounts of energy, require perpetual hardware upgrades for the miners to stay competitive, and are therefore extremely harmful to the environment. A Proof-of-Stake chain’s environmental impact is less severe, but as web3 applications achieve mainstream adoption, every node in these chains will have to provide more and more hardware resources to meet the increasing throughput demand and the ever growing on-chain state. Vertically scaling the nodes implies higher energy consumption and environmental footprint. + +## Multi-role Architecture on Flow + +![banner](./images/banner.png) + +In first-generation smart contract blockchains like Ethereum and Bitcoin, every node in the network performs all of the work associated with processing every transaction (including the entire network’s history, account balances, smart contract code, etc.). While highly secure, it’s also incredibly inefficient, and does not scale throughput (transaction per second, transaction latency) and capacity (on-chain data storage). + +Most second-generation blockchain networks focus on improving performance in one of two ways: + +1. They compromise decentralization by requiring that participating nodes run on powerful servers (e.g. Solana); or +2. They dramatically increase smart developer complexity by breaking up the network through mechanisms such as sharding (e.g. L2s such as Polygon). + +The first approach is vulnerable to platform risk and cartel-like behavior. The second approach outsources the challenges of scaling the platform, effectively handing off the complexities of bridging the different strongly-federated ecosystems to application developers. + +Flow offers a new path: pipelining applied to blockchain networks. + +Pipelining is a well-established technique across various fields, from manufacturing to CPU design, for significantly increasing productivity. +Flow leverages this concept by distributing the tasks typically handled by a full node in a monolithic blockchain architecture across four specialized roles: Collection, Consensus, Execution, and Verification. +This division of labor between nodes occurs within the different validation stages for each transaction, rather than distributing transactions across different nodes as is done with sharding. +In other words, every Flow node still participates in the validation of every transaction, but they do so only at one of the stages of validation. +They can therefore specialize—and greatly increase the efficiency—for their particular stage of focus. + +### Flow node roles and what they do + +| | Node type | Responsibility | What do the nodes of this role do? | +|------------------------------------------|:--------------:|:--------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------| +| ![collection](images/collection.png) | Collection | Collection nodes act as a censorship-resistant data availability layer, which caches transactions for subsequent execution. | Collection nodes order transactions into batches known as collection. | +| ![consensus](images/consensus.png) | Consensus | The consensus committee serves as the security authority in the network and orchestrates Flow's transaction processing pipeline. | Consensus nodes order collections into blocks and commit execution results after verification. | +| ![execution](images/execution.png) | Execution | Execution nodes provide the computational resources for executing transactions and maintaining the state. | Execution nodes execute the transaction and record state changes. | +| ![verification](images/verification.png) | Verification | Verification nodes ensure that transactions are truthfully executed. | Verification nodes verify the work of the execution nodes. They either approve or disagree with their results, reporting their findings to the consensus nodes. | +| ![access](images/access.png) | Access | Access Nodes route transactions into the network and replicate (parts of) the state and transaction results for external clients to query. | Access node serve the API calls to send and read data from the chain. | + +### Further reading +1. [Primer on multi-role architecture](https://flow.com/primer#primer-multinode) +2. [Technical papers](https://flow.com/technical-paper) +3. [Core protocol vision](https://flow.com/core-protocol-vision) +4. [Medium article from Jan which deep dives into the Flow architecture](https://jan-bernatik.medium.com/introduction-to-flow-blockchain-7532977c8af8) + +In the next section, lets look at how Flow multi-role architecture solves those three big problems with blockchains. \ No newline at end of file diff --git a/static/markdown/networks/network-architecture/solving-blockchain-trilemma.md b/static/markdown/networks/network-architecture/solving-blockchain-trilemma.md new file mode 100644 index 0000000000..8155ac6e4b --- /dev/null +++ b/static/markdown/networks/network-architecture/solving-blockchain-trilemma.md @@ -0,0 +1,50 @@ +--- +title: Solving the blockchain trilemma +sidebar_label: Solving the blockchain trilemma +sidebar_position: 2 +--- + +# Solving the blockchain trilemma + +In a monolithic architecture, all nodes perform every task. As network usage grows, the transaction processing capacity of the individual nodes becomes a limiting factor, restricting the network’s throughput and latency. The amount of data that can be stored on-chain is limited since nodes have a finite storage capacity. The only way to scale monolithic blockchains is by increasing the capacity of each node by adding more CPU, memory, and storage (i.e. vertical scaling, an approach taken by Solana). However, this solution comes at the cost of decentralization. As nodes scale vertically, they become more expensive to run, and eventually, only a few operators can afford to run such high-performance, high-capacity nodes. Worse, energy consumption for every node in the network increases over time, making the chain environmentally unsustainable. + +Through its multi-role architecture, Flow implements a modular pipeline for processing transactions. This design allows the network to scale by tuning the level of decentralization at each specific step without sharding the state and fragmenting the network into smaller security zones. + +The modular pipeline is composed of Collection, Consensus, Execution and Verification Nodes. + +![pipeline](images/pipeline.png) + +## Separating Consensus from Compute + +At a high level, the pipeline essentially separates consensus from transaction computation. Non-deterministic (or “subjective”) processes such as determining the inclusion and order of transactions are decided by the broadly decentralized consensus committee. The deterministic (or “objective”) task of computing the result of those ordered transactions is done independently by a small number of specialized execution nodes. + +Collection and consensus are highly decentralized and achieve high levels of redundancy through a large number of lightweight, cost-effective nodes, numbering in the thousands, operated by several hundred different operators. These steps guarantee resilient transaction ordering (assuming that a malicious actor can only compromise a limited number of nodes). + +In comparison, transaction execution has low decentralization and redundancy (10 or less) with more powerful and expensive nodes. To accommodate for the anticipated growth of on-chain state without sharding, only the execution nodes have to be scaled vertically. All other node types can continue to run low-cost hardware. The execution nodes may eventually be scaled up to small data centers. + +![scaling_flow](images/scaling_flow.png) + +Low decentralization for transaction execution might appear to compromise decentralization of the whole network, as it is conceivable that a malicious actor might compromise a dominant fraction of nodes participating in execution. However, correctness of the transaction results is still guaranteed by the verification step, which also requires reasonably high redundancy, again with a large number of lighter and less expensive verification nodes to withstand compromisation attempts. + +Every node in Flow makes the protocol stronger, and the network can grow as needed to achieve different objectives: +- More censorship resistance? Add more collection nodes +- More decentralized block production? Add more consensus nodes +- Need to accommodate higher transaction throughput and state storage? Scale up execution nodes +- Do node operators want to reinforce network security with modest node hardware and low stake? Add more verification nodes. +- Need access to chain data locally? Add access nodes. + +In contrast, when traditional Layer 1 blockchains add more nodes to increase decentralization, they do so without providing any additional benefits. + +![verying_redundancy](images/varying_redudancy.png) + +> Flow’s architectural goals are to provide a throughput of at least 1M TPS, ingest at least ½ GB of transaction data per second and store and serve a very large state of one Patebyte and beyond. + +Thus, Flow’s multi-role architecture solves the blockchain trilemma: + +1. **Scalability**: Scale to thousands of times higher throughput and on-chain storage capacity. + +2. **Decentralization**: Except for the execution nodes, all nodes are light weight and low cost, lowering the barrier to entry and ensuring participation from a diverse set of node operators—big and small + +3. **Security**: Maintain a shared non-sharded execution environment for all operations on the network and use a secure in-built platform to build on. + +![trilemma_solved](images/flow_trillema_solved.png) \ No newline at end of file diff --git a/static/markdown/networks/network-architecture/sustainability.md b/static/markdown/networks/network-architecture/sustainability.md new file mode 100644 index 0000000000..999f6ae3cf --- /dev/null +++ b/static/markdown/networks/network-architecture/sustainability.md @@ -0,0 +1,19 @@ +--- +title: Sustainability +sidebar_label: Sustainability +sidebar_position: 3 +--- + +# Sustainability with Flow + +It's no secret that Proof of Stake blockchains are better for the environment. +As Web3 becomes more widely adopted, we engaged with Deloitte Canada to validate how much energy it uses. +And the results are astounding: Flow uses just 0.18 GWh annually, based on 2021 usage – or in simpler terms, minting an NFT on Flow takes less energy than a Google search or Instagram post. + +In addition to operating on a Proof of Stake consensus system, Flow’s multi-role node architecture securely divides the processing between specialized node types, making the network significantly more efficient than other blockchain architectures. +As network usage grows, vertical scaling is only needed for the execution nodes (as they execute transactions and persist all the chain state). +Because the increase in energy and hardware consumption over time is restricted to a small subset of the nodes in the network, this drastically limits the environmental footprint of the chain. + +The overall energy use of the network won’t increase significantly even if the activity increases by 100x or more, making the per-transaction energy footprint decrease over time. + +Read more about it [here](https://flow.com/post/flow-blockchain-sustainability-energy-deloitte-report-nft). \ No newline at end of file diff --git a/static/markdown/networks/network-architecture/user-safety.md b/static/markdown/networks/network-architecture/user-safety.md new file mode 100644 index 0000000000..857bf557e4 --- /dev/null +++ b/static/markdown/networks/network-architecture/user-safety.md @@ -0,0 +1,19 @@ +--- +title: User safety +sidebar_label: User safety +sidebar_position: 4 +--- + +# User Safety with Flow + +The monolithic node design of common L1s such as Bitcoin and Ethereum overly privileges operator control over block production. +This makes the chain vulnerable to censorship and MEV attacks. This problem is exacerbated by L2s with centralized sequencers. ERC-4337 is also susceptible to MEV on the user operations via bundlers. + +![mev](images/mev_attack.png) + +Flow’s multi-role architecture provides censorship & MEV resistance by design: +- Transactions are randomly assigned to collection nodes for inclusion in collections and eventually in blocks. Each collection node only sees a subset of transactions. + +- There is already a distinct separation between the proposers (represented by the collection nodes) and the builders (represented by the consensus nodes). This separation essentially provides an inherent implementation of "proposer-builder separation," a concept currently being explored by Ethereum. With this separation, even if the collection nodes were to reorder the transactions, there is no incentive for the consensus nodes to prefer one collection node’s proposal over another. + +![mev_protection](images/mev_protection_in_flow.png) \ No newline at end of file diff --git a/static/markdown/networks/node-ops/access-nodes/access-node-configuration-options.md b/static/markdown/networks/node-ops/access-nodes/access-node-configuration-options.md new file mode 100644 index 0000000000..237ea17360 --- /dev/null +++ b/static/markdown/networks/node-ops/access-nodes/access-node-configuration-options.md @@ -0,0 +1,276 @@ +--- +title: Serving execution data +sidebar_label: Execution Data +sidebar_position: 2 +--- + +Flow chain data comprises of two parts, +1. Protocol state data - This refers to the blocks, collection, transaction that are being continuously added to the chain. +2. Execution state data - This refers to what makes up the execution state and includes transaction events and account balances. + +The access node by default syncs the protocol state data and has been now updated to also sync the execution state data. +This guide provides an overview of how to use the execution data sync feature of the Access node. + + + +## Setup node’s directory + +The access node typically has the following directory structure: + +```bash +$ tree flow_access + flow_access/ + ├── bootstrap + │ ├── private-root-information (with corresponding AN data) + │ └── execution-state + │ └── public-root-information + │ ├── node-id + │ └── node-info.pub.NODE_ID.json + │ └── root-protocol-state-snapshot.json (the genesis data) + └── data (directory used by the node to store block data) + │ └── execution-data + │ └── execution-state + +``` + +## Setup execution data indexing + +First, your node needs to download and index the execution data. There are 3 steps: + +1. Enable Execution Data Sync +2. Download the root checkpoint file +3. Configure the node to run the indexer +4. Use the indexed data in the Access API. + +As of **`mainnet24`** / **`devnet49`**, Access nodes can be configured to index execution data to support local script execution, and serving all of the Access API endpoints using local data. There are different setup procedures depending on if you are enabling indexing immediately after a network upgrade, or at some point between upgrades. + +# Enable Execution Data Sync + +This is enabled by default, so as long as you didn’t explicitly disable it, the data should already be available. + +1. Make sure that either `--execution-data-sync-enabled` is not set, or is set to `true` +2. Make sure that you have a path configured for `--execution-data-dir`, otherwise the data will be written to the running user’s home directory, which is most likely inside the container’s volume. For example, you can create a folder within the node’s data directory `/data/execution-data/`. + +There are some additional flags available, but you most likely do not need to change them. + +## **Option 1: Enabling Indexing at the Beginning of a Spork** + +### Download the root protocol state snapshot + +The `root-protocol-state-snapshot.json` is generated for each [spork](https://developers.flow.com/networks/node-ops/node-operation/spork) and contains the genesis data for that spork. It is published and made available after each spork. The download location is specified [here](https://github.com/onflow/flow/blob/master/sporks.json) under [rootProtocolStateSnapshot](https://github.com/onflow/flow/blob/master/sporks.json#L16). + +Store the **`root-protocol-state-snapshot.json`** into the **`/bootstrap/public-root-information/`** folder. + +### Download the root checkpoint + +The root checkpoint for the network is used by Execution nodes and Access nodes to bootstrap their local execution state database with a known trusted snapshot. The checkpoint contains 18 files that make up the merkle trie used to store the blockchain’s state. + +The root checkpoint for each spork is hosted in GCP. You can find the link for the specific network in the [`sporks.json`](https://github.com/onflow/flow/blob/master/sporks.json) file. Here’s the URL for `mainnet24`: + +[https://github.com/onflow/flow/blob/52ee94b830c2d413f0e86c1e346154f84c2643a4/sporks.json#L15](https://github.com/onflow/flow/blob/52ee94b830c2d413f0e86c1e346154f84c2643a4/sporks.json#L15) + +The URL in that file will point to a file named `root.checkpoint`. This is the base file and is fairly small. There are 17 additional files that make up the actual data, named `root.checkpoint.000`, `root.checkpoint.001`, …, `root.checkpoint.016`. If you have `gsutil` installed, you can download them all easily with the following command. + +```bash +gsutil -m cp "gs://flow-genesis-bootstrap/[network]-execution/public-root-information/root.checkpoint*" . +``` + +Where `[network]` is the network you are downloading for. For example, `mainnet-24` or `testnet-49`. + +Once the files are downloaded, you can either move them to `/bootstrap/execution-state/` within the node’s bootstrap directory or put them in any mounted directory and reference the location with this cli flag: `--execution-state-checkpoint=/path/to/root.checkpoint`. The naming of files should be `root.checkpoint.*`. + +## **Option 2: Enabling Indexing Mid-Spork** + +### Identify the root checkpoint + +The root checkpoint for the network is used by Execution and Access nodes to bootstrap their local execution state database with a known trusted snapshot. The checkpoint contains 18 files that make up the merkle trie used to store the blockchain’s state. + +Root checkpoints are periodically generated on Flow Foundation execution nodes and uploaded to a GCP bucket. You can see +a list of available checkpoints [here](https://console.cloud.google.com/storage/browser/flow-genesis-bootstrap/checkpoints), +or list them using the [gsutil](https://cloud.google.com/storage/docs/gsutil) command + +```bash +gsutil ls "gs://flow-genesis-bootstrap/checkpoints/" +``` + +The checkpoint paths are in the format `flow-genesis-bootstrap/checkpoints/[network]/[epoch number]-[block height]/`. +Where +* `[network]` is the network the checkpoint is from. For example, `mainnet` or `testnet`. +* `[epoch number]` is the epoch number when the checkpoint was taken. You can find the current epoch number on the [flowscan.io](https://flowscan.io/) home page. +* `[block height]` is the block height at which the checkpoint was taken. +Make sure that the checkpoint you select is from an epoch when your node was part of the network. + +### Download the root checkpoint + +Once you have selected the checkpoint to download, you can download the files. If you have `gsutil` installed, you can download them all easily with the following command. + +```bash +gsutil -m cp "gs://flow-genesis-bootstrap/checkpoints/[network]/[epoch number]-[block height]/root.checkpoint*" . +``` + +Once the files are downloaded, you can either move them to `/bootstrap/execution-state/` within the node’s bootstrap directory or put them in any mounted directory and reference the location with this cli flag: `--execution-state-checkpoint=/path/to/root.checkpoint`. The naming of files should be `root.checkpoint*`. + +### Download the root protocol state snapshot + +Access nodes require that the data in the root checkpoint corresponds to the root block in the `root-protocol-state-snapshot.json` file. +It's important to download the snapshot for the correct height, otherwise bootstrapping will fail with an error described in the Troubleshooting section. + +You can download the `root-protocol-state-snapshot.json` file generated by the Execution from the same GCP bucket. + +```bash +gsutil cp "gs://flow-genesis-bootstrap/checkpoints/[network]/[epoch number]-[block height]/root-protocol-state-snapshot.json" . +``` + +Alternatively, you can download it directly from a trusted Access node using the `GetProtocolStateSnapshotByHeight` gRPC endpoint +with the corresponding height. You will get a `base64` encoded snapshot which decodes into a json object. At this time, this endpoint is only support using the grpc API. + +Store the **`root-protocol-state-snapshot.json`** into the **`/bootstrap/public-root-information/`** folder. + +# Configure the node to run the indexer + +Now you have the execution sync setup and the root checkpoint in place, it’s time to configure the node to index all of the data so it can be used for script execution. + +There are 2 cli flags that you will need to add: + +- `--execution-data-indexing-enabled=true` This will enable the indexer. +- `--execution-state-dir` This defines the path where the registers db will be stored. A good default is on the same drive as the protocol db. e.g. `/data/execution-state` + +# Start your node + +Now that all of the settings to enable indexing are in place, you can start your node. + +At a minimum, you will need the following flags: + +``` +--execution-data-indexing-enabled=true +--execution-state-dir=/data/execution-state +--execution-data-sync-enabled=true +--execution-data-dir=/data/execution-data +``` + +For better visibility of the process, you can also add + +`-p 8080:8080` - export port 8080 from your docker container, so you could inspect the metrics + +`--loglevel=info` - for checking logs. + +Notes on what to expect: + +- On startup, the node will load the checkpoint into the `execution-state` db. For `devnet48`, this takes 20-30 min depending on the node’s specs. For `mainnet24`, it takes >45 min. The loading time will increase over time. You can follow along with the process by grepping your logs for `register_bootstrap`. +- After the checkpoint is loaded, the indexer will begin ingesting the downloaded execution data. This will take several hours to days depending on if the data was already downloaded and the hardware specs of the node. +- If your node already had all the data, it will index all of it as quickly as possible. This will likely cause the node to run with a high CPU. + +When you restart the node for the first time with syncing enabled, it will sync execution data for all blocks from the network. + +# Use the indexed data in the Access API + +### Setup Local Script Execution + +Local execution is controlled with the `--script-execution-mode` flag, which can have one of the following values: + +- `execution-nodes-only` (default): Requests are executed using an upstream execution node. +- `failover` (recommended): Requests are executed locally first. If the execution fails for any reason besides a script error, it is retried on an upstream execution node. If data for the block is not available yet locally, the script is also retried on the EN. +- `compare`: Requests are executed both locally and on an execution node, and a comparison of the results and errors are logged. +- `local-only`: Requests are executed locally and the result is returned directly. + +There are a few other flags available to configure some limits used while executing scripts: + +- `--script-execution-computation-limit`: Controls the maximum computation that can be used by a script. The default is `100,000` which is the same as used on ENs. +- `--script-execution-timeout`: Controls the maximum runtime for a script before it times out. Default is `10s`. +- `--script-execution-max-error-length`: Controls the maximum number of characters to include in script error messages. Default is `1000`. +- `--script-execution-log-time-threshold`: Controls the run time after which a log message is emitted about the script. Default is `1s`. +- `--script-execution-min-height`: Controls the lowest block height to allow for script execution. Default: `no limit`. +- `--script-execution-max-height`: Controls the highest block height to allow for script execution. Default: `no limit`. +- `--register-cache-size`: Controls the number of registers to cache for script execution. Default: `0 (no cache)`. + +### Setup Using Local Data with Transaction Results and Events + +Local data usage for transaction results and events are controlled with the `--tx-result-query-mode` and `--event-query-mode` corresponding flags, which can have one of the following values: + +- `execution-nodes-only` (default): Requests are forwarded to an upstream execution node. +- `failover` (recommended): - `failover` (recommended): Requests are handled locally first. If the processing fails for any reason, it is retried on an upstream execution node. If data for the block is not available yet locally, the script is also retried on the EN. +- `local-only`: Requests are handled locally and the result is returned directly. + +# Troubleshooting + +- If the root checkpoint file is missing or invalid, the node will crash. It must be taken from the same block as the `root-protocol-state-snapshot.json` used to start your node. +- If you don’t set one the `--execution-data-dir` and `--execution-state-dir` flags, the data will be written to the home directory inside the container (likely `/root`). This may cause your container to run out of disk space and crash, or lose all data each time the container is restarted. +- If your node crashes or restarts before the checkpoint finishes loading, you will need to stop the node, delete the `execution-state` directory, and start it again. Resuming is currently not supported. +- If you see the following message then your `checkpoint` and `root-protocol-state-snapshot` are not for the same height. + +```json +{ + "level":"error", + ... + "module":"execution_indexer", + "sub_module":"job_queue", + "error":"could not query processable jobs: could not read job at index 75792641, failed to get execution data for height 75792641: blob QmSZRu2SHN32d9SCkz9KXEtX3M3PozhzksMuYgNdMgmBwH not found", + "message":"failed to check processables" +} +``` + +- You can check if the execution sync and index heights are increasing by querying the metrics endpoint: + ``` + curl localhost:8080/metrics | grep highest_download_height + curl -s localhost:8080/metrics | grep highest_indexed_height + ``` + +# Execution Data Sync + +The Execution Sync protocol is enabled by default on Access nodes, and uses the bitswap protocol developed by Protocol Labs to share data trustlessly over a peer-to-peer network. When enabled, nodes will download execution data for each block as it is sealed, and contribute to sharing the data with its peers. The data is also made available to systems within the node, such as the `ExecutionDataAPI`. + +Below is a list of the available CLI flags to control the behavior of Execution Sync requester engine. + +| Flag | Type | Description | +| --- | --- | --- | +| execution-data-sync-enabled | bool | Whether to enable the execution data sync protocol. Default is true | +| execution-data-dir | string | Directory to use for Execution Data database. Default is in the user’s home directory. | +| execution-data-start-height | uint64 | Height of first block to sync execution data from when starting with an empty Execution Data database. Default is the node’s root block. | +| execution-data-max-search-ahead | uint64 | Max number of heights to search ahead of the lowest outstanding execution data height. This limits the number non-consecutive objects that will be downloaded if an earlier block is unavailable. Default is 5000. | +| execution-data-fetch-timeout | duration | Initial timeout to use when fetching execution data from the network. timeout increases using an incremental backoff until execution-data-max-fetch-timeout. Default is 10m. | +| execution-data-max-fetch-timeout | duration | Maximum timeout to use when fetching execution data from the network. Default is 10s | +| execution-data-retry-delay | duration | Initial delay for exponential backoff when fetching execution data fails. Default is 1s | +| execution-data-max-retry-delay | duration | Maximum delay for exponential backoff when fetching execution data fails. Default is 5m | + + + +# Execution Data Indexer + +Below is a list of the available CLI flags to control the behavior of Execution Data Indexer. + +| Flag | Type | Description | +| --- | --- | --- | +| execution-data-indexing-enabled | bool | Whether to enable the execution data indexing. Default is false | +| execution-state-dir | string | Directory to use for execution-state database. Default is in the user’s home directory. | +| execution-state-checkpoint | string | Location of execution-state checkpoint (root.checkpoint.*) files. | +| event-query-mode | string | Mode to use when querying events. one of [local-only, execution-nodes-only(default), failover] | +| tx-result-query-mode | string | Mode to use when querying transaction results. one of [local-only, execution-nodes-only(default), failover] | + +Below is a list of the available CLI flags to control the behavior of Script Execution. + +| Flag | Type | Description | +| --- | --- | --- | +| script-execution-mode | string | Mode to use when executing scripts. one of [local-only, execution-nodes-only, failover, compare ] | +| script-execution-computation-limit | uint64 | Maximum number of computation units a locally executed script can use. Default: 100000 | +| script-execution-max-error-length | int | Maximum number characters to include in error message strings. additional characters are truncated. Default: 1000 | +| script-execution-log-time-threshold | duration | Emit a log for any scripts that take over this threshold. Default: 1s | +| script-execution-timeout | duration | The timeout value for locally executed scripts. Default: 10s | +| script-execution-min-height | uint64 | Lowest block height to allow for script execution. Default: no limit | +| script-execution-max-height | uint64 | Highest block height to allow for script execution. default: no limit | +| register-cache-type | string | Type of backend cache to use for registers [lru, arc, 2q] | +| register-cache-size | uint | Number of registers to cache for script execution. Default: 0 (no cache) | +| program-cache-size | uint | [experimental] number of blocks to cache for cadence programs. use 0 to disable cache. Default: 0. Note: this is an experimental feature and may cause nodes to become unstable under certain workloads. Use with caution. | + +# Resources + +FLIP: [https://github.com/onflow/flips/blob/main/protocol/20230309-accessnode-event-streaming-api.md](https://github.com/onflow/flips/blob/main/protocol/20230309-accessnode-event-streaming-api.md) + +Protobuf: [https://github.com/onflow/flow/blob/master/protobuf/flow/executiondata/executiondata.proto](https://github.com/onflow/flow/blob/master/protobuf/flow/executiondata/executiondata.proto) \ No newline at end of file diff --git a/static/markdown/networks/node-ops/access-nodes/access-node-setup.md b/static/markdown/networks/node-ops/access-nodes/access-node-setup.md new file mode 100644 index 0000000000..ce3f61dad8 --- /dev/null +++ b/static/markdown/networks/node-ops/access-nodes/access-node-setup.md @@ -0,0 +1,464 @@ +--- +title: Setting Up a Flow Access Node +sidebar_label: Access Node Setup +sidebar_position: 1 +--- + + + + +This guide is for running a permissonless Access node on Flow. If you are planning to run a different type of staked node then see [node bootstrap](../node-operation/node-bootstrap.md). + +Permissionless Access nodes allow any operator to run a Flow Access node. +Unlike the other staked nodes, a permissionless access node does not have to be approved by the service account before it can join the network, hence the term "permissionless". The goal is to make all node types permissionless and this is the first step towards achieving that goal. + +## Who Should Run a Permissionless Access Node? +dApp developers can choose to run their own private permissionless access node and move away from using the community access nodes. This will also allow them to not be subjected to the API rate limits of the public access nodes. + +Node operators can also run their own permissionless access node and provide access to that node as a service. + +Chain analytics, audit and exploration applications can run such an access node and do not have to rely on third parties for the state of the network. + +## Timing + +New nodes are able to join the network each time a new epoch begins. +An epoch is a period of time (approximately one week) when the node operators in the network are constant. +At epoch boundaries, newly staked node operators are able to join the network and existing node operators which have unstaked may exit the network. +You can read more about epochs [here](../../staking/03-schedule.md). + +In order to join the network at epoch N+1, the access node **must** be registered with at least 100 FLOW staked prior to the end of epoch N's Staking Auction Phase. + +Currently on mainnet, the staking auction starts every Wednesday at around 20:00 UTC and ends on the next Wednesday at around 12:00 UTC. +Since this deadline may shift slightly from epoch to epoch, we recommend the node be staked by _Wednesday, 8:00 UTC_ to be able to join the network in the next epoch. + +Confirmation of a new node's inclusion in epoch N+1 is included in the [`EpochSetup` event](../../staking/05-epoch-scripts-events.md#flowepochepochsetup). + +![Flow Epoch Schedule](../node-operation/epoch-startup-order.png) + +## Limitations + +There are five open slots for access nodes every epoch. +You can view the exact epoch phase transition time [here](https://dashboard.flow.com/) under `Epoch Phase`. + +To summarize, + +| **Epoch** | **Epoch Phase** | | +|:----------:|:----------------------:|:---------------------------------------------------:| +| N | Staking auction starts | Three new access node slots are opened. Anyone can register their access nodes | +| N | Staking auction ends | Three of the nodes registered during this epoch are randomly selected to be a part of the network in the next epoch. No more nodes can register until the next epoch starts. | +| N+1 | Epoch N+1 starts | The newly selected nodes can now participate in the network. Three new slots are opened. | + +## How To Run a Permissionless Access Node? + +:::note + +To run an access node you will need to provision a machine or virtual machine to run your node software. Please follow the [node-provisioning](../node-operation/node-provisioning.md) guide for it. +You can provision the machine before or after your node has been chosen. + +::: + +At a high level, to run a permissionless Access node, you will have to do the following steps: +1. Generate the node identity (private and public keys, node ID etc.). +2. Stake the node with 100 FLOW by the end of the staking phase of the current epoch (see [timing](#timing)) by providing the node information generated in step 1. +3. You can verify if your node ID was selected by the on-chain random selection process on Wednesday at around 20:00 UTC when the next epoch starts. +4. If your node ID was selected, you can provision and start running the node. If your node wasn't selected, your tokens will have been refunded to your unstaked bucket in the staking smart contract. When the next epoch begins, you can try committing tokens again in a future epoch to get a new spot. + +Following is a detail explanation of these four steps. +If you want to run multiple access nodes, you will have to run through these steps for each node. + +## Step 1 - Generate Node Information + +### Download the Bootstrapping Kit + +```shell +curl -sL -O storage.googleapis.com/flow-genesis-bootstrap/boot-tools.tar +tar -xvf boot-tools.tar +``` + +```shell CheckSHA256 +sha256sum ./boot-tools/bootstrap +460cfcfeb52b40d8b8b0c4641bc4e423bcc90f82068e95f4267803ed32c26d60 ./boot-tools/bootstrap +``` + +> If you have downloaded the bootstrapping kit previously, ensure the SHA256 hash for it still matches. If not, re-download to ensure you are using the most up-to-date version. + +### Generate Your Node Identity + +```shell +######################################################### +# Generate Keys +$ mkdir ./bootstrap +# YOUR_NODE_ADDRESS: FQDN associated to your instance +$ ./boot-tools/bootstrap key --address ":3569" --role access -o ./bootstrap +``` + +```shell Example +$./boot-tools/bootstrap key --address "flowaccess.mycompany.com:3569" --role access -o ./bootstrap + DBG will generate networking key + INF generated networking key + DBG will generate staking key + INF generated staking key + DBG will generate db encryption key + INF generated db encryption key + DBG assembling node information address=flowaccess.mycompany.com:3569 + DBG encoded public staking and network keys networkPubKey=f493a74704f6961ae7903e062ecd58d990672858eff99aece7bfbccf3aa02de8f1a624ecbf21a01e8b2f4a5854c231fbe218edd7762a34fea881f3958a215305 stakingPubKey=ae8dcf81f3a70d72036b7ba2c586ed37ed0eb82b9c0a4aab998a8420f98894f94c14f84fa716e93654d3940fc0c8ff4d19b504c90a5b4918b28f421e9d3659dc2b7e246025ebeffea0d83cceefe315d7ed346dbe412fdac51b64997d97d29f7e + INF wrote file bootstrap/public-root-information/node-id + INF wrote file bootstrap/private-root-information/private-node-info_e737ec6efbd26ef43bf676911cdc5a11ba15fc6562d05413e6589fccdd6c06d5/node-info.priv.json + INF wrote file bootstrap/private-root-information/private-node-info_e737ec6efbd26ef43bf676911cdc5a11ba15fc6562d05413e6589fccdd6c06d5/secretsdb-key + INF wrote file bootstrap/public-root-information/node-info.pub.e737ec6efbd26ef43bf676911cdc5a11ba15fc6562d05413e6589fccdd6c06d5.json + +$tree ./bootstrap/ +./bootstrap/ +├── private-root-information +│ └── private-node-info_e737ec6efbd26ef43bf676911cdc5a11ba15fc6562d05413e6589fccdd6c06d5 +│ ├── node-info.priv.json +│ └── secretsdb-key +└── public-root-information + ├── node-id + └── node-info.pub.e737ec6efbd26ef43bf676911cdc5a11ba15fc6562d05413e6589fccdd6c06d5.json + +3 directories, 4 files +``` + +:::warning + +_Use a fully qualified domain name for the network address. Please also include the port number in the network address e.g. `flowaccess.mycompany.com:3569`_ + +::: + +:::warning + +_Do not include the prefix `http://` in the network address._ + +::: + +:::tip + +If you would like to stake multiple access nodes, please ensure you generate a unique identity for each node. + +::: + +Your node identity has now been generated. Your node ID can be found in the file `./bootstrap/public-root-information/node-id`. + +```shell Example +$cat ./bootstrap/public-root-information/node-id +e737ec6efbd26ef43bf676911cdc5a11ba15fc6562d05413e6589fccdd6c06d5 +``` + +:::info + +All your private keys should be in the `bootstrap` folder created earlier. Please take a back up of the entire folder. + +::: + +## Step 2 - Stake the Node + +You need to now register the node on chain by staking the node via [Flow Port](https://port.onflow.org/). + +[Here](../../flow-port/staking-guide.md) is a guide on how to use Flow port if you are not familiar with it. +If you are staking via a custody provider or would like to directly submit a staking transaction instead follow this [guide](../../staking/index.md#how-do-i-stake). + +Fund you Flow account with at least 100.01 FLOW tokens, which covers the required stake plus the storage deposit. + +On Flow port, choose `Stake and Delegate` -> `Start Staking` or `Stake Again` and then choose Access node as the option. + +![choose_access_flowport](../node-operation/choose_access_flowport.png) + +On the next screen, provide the node details of you node. + +Those node details (`Node ID`, `Network Address`, `Networking Key` and `Staking Key`) can be found in the file: `./bootstrap/public-root-information/node-info.pub..json`. + +```shell Example +$cat ./bootstrap/public-root-information/node-info.pub. e737ec6efbd26ef43bf676911cdc5a11ba15fc6562d05413e6589fccdd6c06d5.json +{ + "Role": "access", + "Address": "flowaccess.mycompany.com:3569", + "NodeID": "e737ec6efbd26ef43bf676911cdc5a11ba15fc6562d05413e6589fccdd6c06d5", + "Weight": 0, + "NetworkPubKey": "f493a74704f6961ae7903e062ecd58d990672858eff99aece7bfbccf3aa02de8f1a624ecbf21a01e8b2f4a5854c231fbe218edd7762a34fea881f3958a215305", + "StakingPubKey": "ae8dcf81f3a70d72036b7ba2c586ed37ed0eb82b9c0a4aab998a8420f98894f94c14f84fa716e93654d3940fc0c8ff4d19b504c90a5b4918b28f421e9d3659dc2b7e246025ebeffea0d83cceefe315d7ed346dbe412fdac51b64997d97d29f7e" +} +``` + +#### Example + +![node_details_permissionless_an](../node-operation/node_details_permissionless_an.png) + +On the next screen, ensure that you stake 100 FLOW token. + +#### Example + +![transaction_register_node_permissionless_an](../node-operation/transaction_register_node_permissionless_an.png) + +Submit the Transaction. + +## Step 3 - Verify That Your Node ID Was Selected + +On Wednesday at around 12:00 UTC, the staking auction for the current epoch will end and five nodes from candidate list of nodes will be chosen at random by the staking contract to be part of the next epoch. + +:::note + +If all 5 slots have been taken from the previous epoch, then no new access nodes will be chosen (see #limitations) + +::: + +There are several ways to verify whether your node was chosen as explained below. + +When you stake the node, the tokens will show up under the `tokensCommitted` bucket. After the staking auction ends, if the node is selected, the tokens remain in the `tokensCommitted` bucket and are moved to the `tokensStaked` bucket at the end of the epoch. +If the node is not selected, the tokens are moved to the `tokensUnstaked` bucket. + +### Check Using Flow Port +You can check these balances on Flow Port before and after the epoch transition that will occur on Wednesday (see [timing](#timing)). + +When you stake the node, you should see the following on Flow Port under `Stake & Delegate` + +![Staked_node](../node-operation/Staked_FlowPort.png) + +After the epoch transition, if you see you token balance under the Staked Amount then your node got chosen. + +![Staked_node](../node-operation/Selected_FlowPort.png) + +Instead, if you see that your token balance is under the Unstaked Amount, then your node did not get chosen. + +![Unstaked_node](../node-operation/Unstaked_FlowPort.png) + +### Check Using Flow CLI + +You can also check these balance using [Flow Cli](https://github.com/onflow/flow-cli). Once you have downloaded and installed Flow Cli, you can query the account balance using the command, +```shell +flow accounts staking-info -n mainnet +``` + +For Example, the following node was chosen as Tokens staked is 100. + +```shell Example +$ flow accounts staking-info 0xefdfb20806315bfa -n testnet + +Account staking info: + ID: "e737ec6efbd26ef43bf676911cdc5a11ba15fc6562d05413e6589fccdd6c06d5" + Initial Weight: 100 + Networking Address: "flowaccess.mycompany.com:3569" + Networking Key: "f493a74704f6961ae7903e062ecd58d990672858eff99aece7bfbccf3aa02de8f1a624ecbf21a01e8b2f4a5854c231fbe218edd7762a34fea881f3958a215305" + Role: 5 + Staking Key: "ae8dcf81f3a70d72036b7ba2c586ed37ed0eb82b9c0a4aab998a8420f98894f94c14f84fa716e93654d3940fc0c8ff4d19b504c90a5b4918b28f421e9d3659dc2b7e246025ebeffea0d83cceefe315d7ed346dbe412fdac51b64997d97d29f7e" + Tokens Committed: 0.00000000 + Tokens To Unstake: 100.00000000 + Tokens Rewarded: 0.00000000 + Tokens Staked: 100.00000000 + Tokens Unstaked: 0.00000000 + Tokens Unstaking: 0.00000000 + Node Total Stake (including delegators): 0.00000000 +``` + +### Epoch Setup Event + +Alternatively, if you can monitor events, look for [the epoch setup event](../../staking/05-epoch-scripts-events.md#flowepochepochsetup) that gets emitted by the epoch contract. That event is emitted at the end of epoch N's staking auction and contains a list of node IDs that are confirmed for the next epoch. + +## Step 4 - Start Your Node + +If your node was selected as part of Step 3, you can now start your node. + +First you'll need to provision a machine or virtual machine to run your node software. Please see follow the [node-provisioning](../node-operation/node-provisioning.md) guide for it. + +The access node can be run as a Docker container with the following command. + +Be sure to set `$VERSION` below to the version tag (e.g. `v1.2.3`) corresponding to the latest **released** version [here](https://github.com/onflow/flow-go/releases) for version releases). Set `$NODEID` to your node's ID (see [Generate Your Node Identity](#generate-your-node-identity) section above). + + + + +```shell +docker run --rm \ +-v $PWD/bootstrap:/bootstrap:ro \ +-v $PWD/data:/data:rw \ +--name flow-go \ +--network host \ +gcr.io/flow-container-registry/access:$VERSION \ +--nodeid=$NODEID \ +--bootstrapdir=/bootstrap \ +--datadir=/data/protocol \ +--secretsdir=/data/secrets \ +--rpc-addr=0.0.0.0:9000 \ +--http-addr=0.0.0.0:8000 \ +--rest-addr=0.0.0.0:80 \ +--rpc-metrics-enabled=true \ +--bind 0.0.0.0:3569 \ +--dynamic-startup-access-address=secure.mainnet.nodes.onflow.org:9001 \ +--dynamic-startup-access-publickey=28a0d9edd0de3f15866dfe4aea1560c4504fe313fc6ca3f63a63e4f98d0e295144692a58ebe7f7894349198613f65b2d960abf99ec2625e247b1c78ba5bf2eae \ +--dynamic-startup-epoch-phase=EpochPhaseStaking \ +--loglevel=error +``` + + + + +```shell +docker run --rm \ +-v $PWD/bootstrap:/bootstrap:ro \ +-v $PWD/data:/data:rw \ +--name flow-go \ +--network host \ +gcr.io/flow-container-registry/access:$VERSION \ +--nodeid=$NODEID \ +--bootstrapdir=/bootstrap \ +--datadir=/data/protocol \ +--secretsdir=/data/secrets \ +--rpc-addr=0.0.0.0:9000 \ +--http-addr=0.0.0.0:8000 \ +--rest-addr=0.0.0.0:80 \ +--rpc-metrics-enabled=true \ +--bind 0.0.0.0:3569 \ +--dynamic-startup-access-address=secure.testnet.nodes.onflow.org:9001 \ +--dynamic-startup-access-publickey=ba69f7d2e82b9edf25b103c195cd371cf0cc047ef8884a9bbe331e62982d46daeebf836f7445a2ac16741013b192959d8ad26998aff12f2adc67a99e1eb2988d \ +--dynamic-startup-epoch-phase=EpochPhaseStaking \ +--loglevel=error +``` + + + + +For example, if your Node ID is `e737ec6efbd26ef43bf676911cdc5a11ba15fc6562d05413e6589fccdd6c06d5` and the software version is `v1.2.3`, the Docker command would be the following: +```shell Example +docker run --rm \ + -v $PWD/bootstrap:/bootstrap:ro \ + -v $PWD/data:/data:rw \ + --name flow-go \ + --network host \ + gcr.io/flow-container-registry/access:v1.2.3 \ + --nodeid=e737ec6efbd26ef43bf676911cdc5a11ba15fc6562d05413e6589fccdd6c06d5 \ + --bootstrapdir=/bootstrap \ + --datadir=/data/protocol \ + --secretsdir=/data/secrets \ + --rpc-addr=0.0.0.0:9000 \ + --http-addr=0.0.0.0:8000 \ + --rest-addr=0.0.0.0:80 \ + --rpc-metrics-enabled=true \ + --bind 0.0.0.0:3569 \ + --dynamic-startup-access-address=secure.mainnet.nodes.onflow.org:9001 \ + --dynamic-startup-access-publickey=28a0d9edd0de3f15866dfe4aea1560c4504fe313fc6ca3f63a63e4f98d0e295144692a58ebe7f7894349198613f65b2d960abf99ec2625e247b1c78ba5bf2eae \ + --dynamic-startup-epoch-phase=EpochPhaseStaking \ + --loglevel=error +``` + +> If you would like your node to sync from the start of the last network upgrade, then please see the instructions [here](https://developers.flow.com/networks/node-ops/node-operation/spork) + +Alternatively, you can build a binary for the access node to run it without using Docker. +To build the access node binary, see the instructions [here](https://github.com/onflow/flow-go?tab=readme-ov-file#building-a-binary-for-the-access-node). +Please make sure to git checkout the latest release tag before building the binary. + + + + +```shell +$PWD/flow-go/flow_access_node \ +--nodeid=e1a8b231156ab6f2a5c6f862c933baf5e5c2e7cf019b509c7c91f4ddb0a13398 \ +--bootstrapdir=$PWD/bootstrap \ +--datadir=$PWD/data/protocol \ +--secretsdir=$PWD/data/secrets \ +--execution-data-dir=$PWD/data/execution_data \ +--rpc-addr=0.0.0.0:9000 \ +--secure-rpc-addr=0.0.0.0:9001 \ +--http-addr=0.0.0.0:8000 \ +--rest-addr=0.0.0.0:8070 \ +--admin-addr=localhost:9002 \ +--bind=0.0.0.0:3569 \ +--dht-enabled=false \ +--grpc-compressor=gzip \ +--profiler-dir=$PWD/data/profiler \ +--dynamic-startup-access-address=secure.mainnet.nodes.onflow.org:9001 \ +--dynamic-startup-access-publickey=28a0d9edd0de3f15866dfe4aea1560c4504fe313fc6ca3f63a63e4f98d0e295144692a58ebe7f7894349198613f65b2d960abf99ec2625e247b1c78ba5bf2eae \ +--dynamic-startup-epoch-phase=EpochPhaseStaking +``` + + + + +```shell +$PWD/flow-go/flow_access_node \ +--nodeid=e1a8b231156ab6f2a5c6f862c933baf5e5c2e7cf019b509c7c91f4ddb0a13398 \ +--bootstrapdir=$PWD/bootstrap \ +--datadir=$PWD/data/protocol \ +--secretsdir=$PWD/data/secrets \ +--execution-data-dir=$PWD/data/execution_data \ +--rpc-addr=0.0.0.0:9000 \ +--secure-rpc-addr=0.0.0.0:9001 \ +--http-addr=0.0.0.0:8000 \ +--rest-addr=0.0.0.0:8070 \ +--admin-addr=localhost:9002 \ +--bind=0.0.0.0:3569 \ +--dht-enabled=false \ +--grpc-compressor=gzip \ +--profiler-dir=$PWD/data/profiler \ +--dynamic-startup-access-address=secure.testnet.nodes.onflow.org:9001 \ +--dynamic-startup-access-publickey=ba69f7d2e82b9edf25b103c195cd371cf0cc047ef8884a9bbe331e62982d46daeebf836f7445a2ac16741013b192959d8ad26998aff12f2adc67a99e1eb2988d \ +--dynamic-startup-epoch-phase=EpochPhaseStaking +``` + + + + +For a more mature setup, it is recommended that you run the container using systemd as described [here](../node-operation/node-setup.md#systemd) + +> 🚀 The access node should now be up and running, and you should be able to query the node using Flow CLI or curl, + +```shell Example +flow blocks get latest --host localhost:9000 +``` + +```shell Example +curl http://localhost/v1/blocks?height=sealed +``` + +## Monitoring and Metrics + +The node publishes several Prometheus metrics. See [Monitoring Node Health](../node-operation/monitoring-nodes.md) to setup node monitoring. + +### Node Status + +The metrics for the node should be able to provide a good overview of the status of the node. If we want to get a quick snapshot of the status of the node, and if it's properly participating in the network, you can check the `consensus_compliance_finalized_height` or `consensus_compliance_sealed_height` metric, and ensure that it is not zero and strictly increasing. + +```shell +curl localhost:8080/metrics | grep consensus_compliance_sealed_height + +# HELP consensus_compliance_sealed_height the last sealed height +# TYPE consensus_compliance_sealed_height gauge +consensus_compliance_sealed_height 1.132054e+06 +``` + +## FAQs + +### Will the access node receive rewards? + +No, the access nodes do not receive any rewards. + +### Why is there a 100 FLOW token minimum? + +As mentioned in the [FLIP](https://github.com/onflow/flips/blob/main/protocol/20220719-automated-slot-assignment.md), the minimum is required to prevent certain vulnerabilities +in the smart contract that are a result of having a zero minimum stake requirement. + +### Can the Access node be unstaked? + +Yes, like any other staked node, the Access node can be unstaked. The staked tokens will be moved to the unstaked bucket in the subsequent epoch. + +### How to see all the access nodes that have staked? + +When the nodes are initially staked, they are all added to the candidate list of nodes before the end of the epoch staking phase. +The list can be retrieved from the chain by executing the [get_candidate_nodes](https://github.com/onflow/flow-core-contracts/blob/48ba17d3386023d70817197a20effbc5d16339b3/transactions/idTableStaking/scripts/get_candidate_nodes.cdc) script which returns the candidate list for the current epoch. + +```shell +$ flow scripts execute ./transactions/idTableStaking/scripts/get_candidate_nodes.cdc -n mainnet +``` + +### How to check the availability of open access nodes slots for the next epoch? + +The limits for the open slots are defined in the staking contract and can be queried from the chain by executing the [get_slot_limits](https://github.com/onflow/flow-core-contracts/blob/master/transactions/idTableStaking/scripts/get_slot_limits.cdc) script. + +Node types are defined [here](https://github.com/onflow/flow-core-contracts/blob/5696ec5e3e6aa5fc10762cbfeb42b9c5c0b8ddbe/contracts/FlowIDTableStaking.cdc#L114-L119) + +```shell + +$ flow scripts execute ./transactions/idTableStaking/scripts/get_slot_limits.cdc --args-json '[{ "type":"UInt8", "value":"5"}]' -n mainnet +Result: 118 +``` + +Example: there are 115 access nodes already part of the network. Hence, the total number of new nodes that can join are 118 - 115 = 3. \ No newline at end of file diff --git a/static/markdown/networks/node-ops/evm-gateway/evm-gateway-setup.md b/static/markdown/networks/node-ops/evm-gateway/evm-gateway-setup.md new file mode 100644 index 0000000000..cd0b2894fc --- /dev/null +++ b/static/markdown/networks/node-ops/evm-gateway/evm-gateway-setup.md @@ -0,0 +1,440 @@ +--- +title: Setting up an EVM Gateway node +sidebar_label: EVM Gateway Setup +sidebar_position: 2 +--- + + + + +This guide is for running the [EVM Gateway](https://github.com/onflow/flow-evm-gateway) node on Flow. The EVM Gateway implements the +[Ethereum JSON-RPC specification](https://ethereum.org/en/developers/docs/apis/json-rpc/) and is the only node type which accepts EVM +client connections. + +The EVM Gateway consumes Flow protocol state from the configured Flow Access Node and persists the indexed EVM state locally to +service EVM client requests. It submits EVM transactions it receives into the Flow network, wrapped in a Cadence transaction, and +mutating EVM state when executed. Non-mutating RPC methods only query the local state index of the gateway and are never forwarded +to Access Nodes. It does not participate in the block production process and requires no stake. + +## Anyone can run EVM Gateway + +The EVM Gateway can serve as a dedicated private RPC, a performance scaling solution, and a free gas provider offering similar capabilities +to centralized middleware providers like Infura, Alchemy, etc. at a fraction of the cost. EVM Gateway nodes connect directly to the Flow network +with no middleware, giving you full control. + +If you are just getting started building your application, you can use the [public EVM Gateway](https://developers.flow.com/evm/networks). +Applications generating high call volumes to the JSON-RPC may have hit rate limits on Flow public EVM Gateway and may benefit from running their +own gateway to remove rate limits. Self-hosted gateways connect directly to public Flow Access Nodes, which may also optionally be [run](../access-nodes/access-node-setup.md). + +:::info + +Apps can use EVM gateway to subsidize user transaction fees for smoother onboarding + +::: + +Alternatively, you can also choose from any of the following providers who provide the EVM Gateway as a managed service along with other value added services on top. + +1. [Alchemy](https://www.alchemy.com/flow) +2. [ThirdWeb](https://thirdweb.com/flow) +3. [Moralis](https://docs.moralis.com/web3-data-api/evm/chains/flow) +4. [QuickNode](https://www.quicknode.com/chains/flow) + +## Hardware specifications + +The EVM Gateway is a lightweight node which runs on commodity hardware and cloud VMs. It can be run on GCP **standard** and AWS **large** +VM types for low to moderate volume app co-location use-cases. However, higher volume use cases may require larger instance types and more +testing. An inactive node requires less than 200MB memory when run in Docker and data storage growth corresponds with Flow EVM transaction +growth. Listed below are theoretical RPS maximums based on Flow mainnet CPU and memory resource utilization metrics and linear scaling assumptions. + +### Google Cloud Platform (GCP) VM Types + +| VM Type | vCPUs | Memory (GB) | Estimated Max Requests/s | +| --------- |-------|-------------|--------------------------| +| n2-standard-2 | 2 | 8 | ~2,950 | +| c4a-standard-1 | 1 | 4 | ~1,475 | +| c4a-standard-2 | 2 | 8 | ~2,950 | +| n2-highmem-4 | 4 | 32 | ~11,800 | +| c3-standard-8 | 8 | 32 | ~29,500 | + +### Amazon Web Services (AWS) EC2 Instance Types +| Instance Type | vCPUs | Memory (GB) | Estimated Max Requests/s | +| --------- |--------|-------------|--------------------------| +| m6i.large | 2 | 8 | ~2,950 | +| c6i.large | 2 | 4 | ~3,687 | +| m6i.xlarge | 4 | 16 | ~11,800 | +| c6i.2xlarge | 8 | 16| ~29,500 | +| t3.2xlarge | 8 | 32 | ~17,700 | + +# How To Run EVM Gateway + +## Step 1 - Account Creation + +The EVM Gateway's role in mediating EVM transactions over to Cadence is how it accrues fees from handling client transactions. Since +the gateway submits Cadence transactions wrapping EVM transaction payloads to the Flow Access Node the transaction fee for that must +be paid by the EVM Gateway. + +The account used for funding gateway Cadence transactions must be a COA, not an EOA. `--coa-address` is configured with the Cadence address +of the COA account and the `--coa-key` must belong to the same account. The `--coinbase` account accrues EVM Gateway fees from EVM client +transactions and can be either an EVM EOA or COA address. + +It is acceptable to create a single Cadence account for the COA and use the EVM address associated with that for the COINBASE address. + +### Create Flow account to use for COA + +If you don't already have a Flow account you will need to create one. + + + + + 1. Install [Flow Wallet](https://wallet.flow.com/) + 2. Once installed you will be able to copy the wallet address, similar to _0x1844efeb3fef2242_ + 3. Obtain account private key from +
    Settings -> Account List -> Choose Main account -> Private Key -> [Password prompt]
    + 4. Ensure the wallet is funded from a CEX or other wallet + +
    + + +Install [Flow CLI](https://developers.flow.com/tools/flow-cli/install) if not already installed. + +```bash +flow keys generate +``` +This will output something similar to: +` +```bash +🔴️ Store private key safely and don't share with anyone! +Private Key 3cf8334d.....95c3c54a28e4ad1 +Public Key 33a13ade6....85f1b49a197747 +Mnemonic often scare peanut ... boil corn change +Derivation Path m/44'/539'/0'/0/0 +Signature Algorithm ECDSA_P256 +``` + +Visit https://faucet.flow.com/, and use the generated `Public Key`, to create and fund your Flow testnet account. + + +
    + +## Step 2 - Build the gateway + +To run EVM Gateway on bare metal or in a VM without the use of docker, select the '_Build from source_' tab otherwise refer to the +'_Build using Docker_' tab. + + + + +This will build the EVM gateway binary from source. + +```bash +git clone https://github.com/onflow/flow-evm-gateway.git + +cd flow-evm-gateway +git checkout $(curl -s https://api.github.com/repos/onflow/flow-evm-gateway/releases/latest | jq -r .tag_name) +CGO_ENABLED=1 go build -o evm-gateway cmd/main/main.go +chmod a+x evm-gateway +mv evm-gateway /usr/bin +``` + + + + +```bash +git clone https://github.com/onflow/flow-evm-gateway.git + +cd flow-evm-gateway +git checkout $(curl -s https://api.github.com/repos/onflow/flow-evm-gateway/releases/latest | jq -r .tag_name) +make docker-build +``` + + + + +Registry versions available for download can be found [here](https://console.cloud.google.com/artifacts/docker/dl-flow-devex-production/us-west1/development/flow-evm-gateway). +```bash +docker pull us-west1-docker.pkg.dev/dl-flow-devex-production/development/flow-evm-gateway:${VERSION} +``` + + + + +## Step 3 - Start Your Node + +Operators will need to refer to the gateway [configuration flags](https://github.com/onflow/flow-evm-gateway?tab=readme-ov-file#configuration-flags) and make adjustments that align with the desired +deployment topology. + +### EVM Coinbase address + +If this is your first time setting up the gateway we need to ensure that an EVM COA or EOA address is available to configure the `COINBASE`. This account +can be an account created using Metamask or other web3.js wallet, or otherwise can be the EVM address corresponding to the Flow Wallet COA account created above. + +If you haven't already got an EVM address and you have the COA account created by Flow Wallet above then follow the steps below: + +* Click top left burger icon to show current profile +* Click 'Enable the path to Flow EVM' button +* Your EVM account will now be available to use in the left nav account view +* When you switch to that account you can obtain its EVM address + +### COA Address and Key + +COA address and private key is configured for `--coa-address` & `--coa-key` configuration flags. If running multiple EVM Gateway hosts it is standard to +share the same COA address and key across _n_ hosts. + +### Run the gateway + +Ensure that the following ENV variables have been set. Add/update as required if your configuration differs from those listed. + +```bash +# Set required environment variables +export ACCESS_NODE_GRPC_HOST="access.mainnet.nodes.onflow.org:9000" # or access.devnet.nodes.onflow.org:9000 for testnet +export FLOW_NETWORK_ID="flow-mainnet" # or flow-testnet +export INIT_CADENCE_HEIGHT="85981135" # 211176670 for testnet +export COINBASE="${EVM_ADDRESS_WITHOUT_0x}" +export COA_ADDRESS="${CADENCE_ACCOUNT_ADDRESS_WITHOUT_0x}" +export COA_KEY="${CADENCE_ACCOUNT_PRIVATE_KEY_WITHOUT_0x}" +export GAS_PRICE="100" # operators can set this to 0 for zero cost transactions. The linked COA account will pay for transactions on users behalf + +# $\{ACCESS_NODE_SPORK_HOSTS\} are comma separated +# testnet: access-001.devnet51.nodes.onflow.org:9000 +# mainnet: access-001.mainnet25.nodes.onflow.org:9000 +``` +ACCESS_NODE_SPORK_HOSTS is used by the gateway to track state across Flow sporks. These are generally infrequent with only one planned +spork per year. A canonical list of required hosts can be found in the EVM Gateway [Makefile](https://github.com/onflow/flow-evm-gateway/blob/main/Makefile#L9). + + + + +**Create EVM Gateway service** + +```bash +sudo tee </dev/null /etc/systemd/system/gateway.service +[Unit] +Description=Gateway daemon +After=network-online.target + +[Service] +User=$USER +ExecStart=/usr/bin/evm-gateway \ +--access-node-grpc-host=$ACCESS_NODE_GRPC_HOST \ +--access-node-spork-hosts=$ACCESS_NODE_SPORK_HOSTS \ +--flow-network-id=$FLOW_NETWORK_ID \ +--init-cadence-height=$INIT_CADENCE_HEIGHT \ +--ws-enabled=true \ +--coinbase=$COINBASE \ +--coa-address=$COA_ADDRESS \ +--coa-key=$COA_KEY \ +--rate-limit=9999999 \ +--rpc-host=0.0.0.0 \ +--gas-price=$GAS_PRICE \ +--tx-state-validation=local-index +Restart=always +RestartSec=3 +LimitNOFILE=4096 + +[Install] +WantedBy=multi-user.target +EOF + +cat /etc/systemd/system/gateway.service +sudo systemctl enable gateway +``` + +**Start all services** + +```bash +sudo systemctl daemon-reload +sudo systemctl restart access-node +sudo systemctl restart gateway +``` + +**Check logs** + +```bash +# change log settings to persistent if not already +sed -i 's/#Storage=auto/Storage=persistent/g' /etc/systemd/journald.conf +sudo systemctl restart systemd-journald + +journalctl -u gateway.service -f -n 100 +``` + + + + +It may be necessary to make local changes to the `docker-run` target to add params which are needed for your requirements. If you pulled a +specific image from the gateway container registry ensure that the `$VERSION` environment variable is set to the same as the image version +you pulled. + +```bash +cd flow-evm-gateway +make docker-run +``` +Additional options are available as follows + +```bash +DOCKER_RUN_DETACHED=true +DOCKER_HOST_MOUNT=[host mount directory] +DOCKER_HOST_PORT=[desired port to expose on host] +DOCKER_HOST_METRICS_PORT=[desired port to expose on host for metrics] + +# Example usage + +make DOCKER_RUN_DETACHED=true DOCKER_HOST_PORT=1234 DOCKER_HOST_MOUNT=/my/host/dir docker-run +``` + + + + +### Startup bootstrap indexing + +Once your EVM Gateway is up and running you will see it indexing the Flow network which was configured. At the present time this +is a lengthy process (possibly 1-3 days, depending on CPU core count) during which time the gateway will not respond to queries. +Once the data is fully indexed the gateway can serve requests to clients. + +To speed up gateway setup we recommend backing up the `/${GATEWAY_HOME_DIR}/data` directory to use when creating additional nodes +using the same release version. We are currently working on an export/import feature that will enable gateway operators to +store state snapshots to bootstrap newly created nodes without the delay. + +:::note + +If you are upgrading the gateway from pre-v1.0.0 release versions the indexed data directory will need to be reindexed from genesis. +You will not be able to re-use the DB data dir from the previous versions. + +::: + +### Account and Key Management + +When operating an EVM Gateway it is important to understand how keys are configured and used. Each gateway instance +must be configured with a Flow account address, which is sufficiently funded and which it uses to pay to wrap EVM transactions into a +Cadence transaction when submitting to the Flow Access Node. This can be configured with a standalone private key file for +the `--coa-key` config flag. Alternatively, you may also use cloud KMS providers per the guidance below. + +#### COA Account signing key rotation + +The gateway implements a signing key rotation scheme to scale the use of the `COA_KEY` and enable it to be used across many +EVM client transactions. This is configured by reusing the COA public key to create new on-chain signing keys. Although it may seem +counter-intuitive to use the same COA public key when creating new signing keys, the newly added keys all occupy different +key slots on the account which enables the gateway to support concurrent transaction signing without causing [nonce collisions](https://developers.flow.com/build/advanced-concepts/scaling#problem) +for EVM clients. + +Assuming there is already one key on the account, the following example transaction adds 100 copies of that key: +```swift +transaction { + prepare(signer: auth(AddKey) &Account) { + let firstKey = signer.keys.get(keyIndex: 0)! + let range: InclusiveRange = InclusiveRange(1, 100, step: 1) + for element in range { + signer.keys.add( + publicKey: firstKey.publicKey, + hashAlgorithm: HashAlgorithm.SHA2_256, + weight: 1000.0 + ) + } + } +} +``` +Signing keys which are added to the COA account are required to use the same hashing algorithm as the key being copied. + +If keys are added while the gateway is running it will need to be restarted to make use of the new keys. + +:::note + +If you are operating your EVM Gateway(s) to relay traffic for Flow EVM, or if you otherwise anticipate high volumes of +transactions we recommend configuring 2000 signing keys or more. Signing key utilization increases proportionately +with transaction throughput growth. + +A large number of keys are recommended for live networks because keys have a lengthy cool down period of 600 blocks (approx 10 minutes) +before they are re-used. This is to avoid nonce collisions from re-using the key too soon. + +::: + +You can track signing key utilization as a metric, see `evm_gateway_available_signing_keys` below. + +#### KMS Configuration + +EVM Gateway allows for Google and AWS Key Management Service (KMS) integration, which is the recommended way of setting up the gateway +for live networks. It is only required to configure a single KMS key for the Flow account configured as the gateway `COA_ACCOUNT`. + +``` +--coa-cloud-kms-project-id=your-project-kms-id \ +--coa-cloud-kms-location-id=global \ +--coa-cloud-kms-key-ring-id=your-project-kms-key-ring-id \ +--coa-cloud-kms-key=example-gcp-kms@1 \ +``` + +### Monitoring and Metrics + +The EVM Gateway reports Prometheus metrics which are a way to monitor the gateway's availability and progress. The database folder +size may also need to be monitored to prevent disk full issues. + +**Metric labels** +```bash +evm_gateway_api_errors_total # Total count of API errors for period +evm_gateway_api_request_duration_seconds_bucket # Histogram metric buckets for API request durations +evm_gateway_api_request_duration_seconds_count # Histogram metric API request count for period +evm_gateway_api_request_duration_seconds_sum # Histogram metric API request sum of values for period +evm_gateway_api_server_panics_total # Total count of server panics for period +evm_gateway_blocks_indexed_total # Total count of EVM blocks indexed +evm_gateway_cadence_block_height # Cadence block height +evm_gateway_evm_account_interactions_total # Count of unique accounts observed for period +evm_gateway_evm_block_height # EVM block height +evm_gateway_operator_balance # Gateway node COA operator account balance +evm_gateway_trace_download_errors_total # Total count of trace download errors +evm_gateway_txs_indexed_total # Total count of indexed transactions +evm_gateway_available_signing_keys # Total count of available COA signing keys +``` + +Alerts are recommended to be configured on server panics, low operator balance, available signing keys and disk usage metrics. + +**Metrics port** + +``` +--metrics-port 8080 \ +``` +### Node Status + +For basic node status or keepalive monitoring we recommend automated checks on the following monotonically increasing counter: +``` +curl -s -XPOST 'your-evm-gw-host:8545' --header 'Content-Type: application/json' --data-raw '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' | jq -r '.result' | xargs printf "%d\n" +10020239 +``` + +## Troubleshooting + +Join our [Discord](https://discord.com/invite/J6fFnh2xx6) and use the `#flow-evm` channel to ask any questions you may have about +EVM Gateway. + +### No signing keys available + +```bash +Failed to send transaction: no signing keys available +``` +This message indicates that the GW has used all its available signing keys. Please refer to the [Account and Key Management](./evm-gateway-setup#account-and-key-management) documentation to add more signing keys to your COA. + +### Database version inconsistency/corruption + +If you see a similar message to this from an aborted startup the gateway database directory is not compatible with the schema versions of the runtime, or there may be corruption. In this instance we recommend that you delete the contents of the EVM GW data directory. + +```bash +Jan 16 17:00:57 nodename docker[6552]: {"level":"error","error":"failed to open db for dir: /flow-evm-gateway/db, with: pebble: manifest file \"MANIFEST-018340\" for DB \"/flow-evm-gateway/db\": comparer name from file \"leveldb.BytewiseComparator\" != comparer name from Options \"flow.MVCCComparer\"","time":"2025-01-16T17:00:57Z","message":"Gateway runtime error"} +``` + +### State stream configuration + +If you are running an Access Node on the same logical host as the EVM Gateway you may see the following log entries. + +```bash +failure in event subscription at height ${INIT-CADENCE-HEIGHT}, with: recoverable: disconnected: error receiving event: rpc error: code = Unimplemented desc = unknown service flow.executiondata.ExecutionDataAPI” +``` +```bash +component execution data indexer initialization failed: could not verify checkpoint file: could not find expected root hash e6d4f4c755666c21d7456441b4d33d3521e5e030b3eae391295577e9130fd715 in checkpoint file which contains: [e10d3c53608a1f195b7969fbc06763285281f64595be491630a1e1bdfbe69161] +``` + +To resolve this configure `--state-stream-addr` to use the same address/port combination which is set for Access Node `--rpc-addr`. +This is required by the gateway to allow both the streaming and non-streaming APIs to query using the same connection. + +### Access Node not fully synced + +The following log entry will occur when the EVM Gateway attempts to sync with the Access Node but it has not yet synced up to latest block +```bash +failure in event subscription at height ${INIT-CADENCE-HEIGHT}, with: recoverable: disconnected: error receiving event: rpc error: code = FailedPrecondition desc = could not get start height: failed to get lowest indexed height: index not initialized +``` \ No newline at end of file diff --git a/static/markdown/networks/node-ops/index.md b/static/markdown/networks/node-ops/index.md new file mode 100644 index 0000000000..4487ddfb05 --- /dev/null +++ b/static/markdown/networks/node-ops/index.md @@ -0,0 +1,113 @@ +--- +title: Node Operations +sidebar_position: 1 +--- + +# Hello Node Operator! + +Flow nodes are vital components of the Flow blockchain. These nodes are responsible for a variety of network operations to maintain the distributed ledger. + +## Why Run a Node? + +--- + +By running your own node, you have direct access to the evolving state of the network, without having to rely on third parties. +This increases privacy and security, reduces reliance on external servers, and helps balance load distribution. +By running a node, you also directly contribute to the security and decentralization of the whole network. + +Flow multirole architecture makes it more scalable and provides several node types that you as a node operator can pick and choose from. + +## Which Node Should You Run? + +--- + +The different types of nodes are described [here](./node-operation/node-roles.md). As node operator, you can choose to run any of the different types of node that best fits your needs. + +The nodes are classified as follows, + +![Flownodesdiagram.png](./node-operation/Flownodesdiagram.png) + +## Light Node A.K.A. Observer Node + +--- + +The light node is one of the easiest nodes to spin up and can be run by Dapp developers who need the latest block data available locally, e.g. a wallet application that needs to track the latest block ID and height. +In addition to supporting dapps, an observer node can also be run by access node operators who want to scale their access nodes' endpoints. Access node operators can spin up geographically dispersed observer nodes which can talk to their staked access nodes and to each other. + +The observer node is not staked but still provides the same API as the access node. + +:::info + +To run a light node, follow this [guide](./light-nodes/observer-node.md) + +::: + +## Full Node + +--- + +In a nutshell, Full Nodes are staked network participants that drive network progress, e.g. by creating and executing new blocks. They are the primary contributors to network safety (all of them validate the correctness of the consensus process and secure the network additionally through their role-specific tasks). In comparison, Light Nodes don't contribute to the networks progress. Though, they help to secure the network by also validating the integrity of the consensus process. +- The Access node is a full node that serves as an RPC node and acts as a gateway node for the network. +- The Validator node (Collection, Consensus, Verification and Execution) is a full node that plays a role in block generation. + +### Access Node + +--- + +If you want local access to the protocol state data (blocks, collections, transactions) and do not want to use one of the community access nodes you can run an access node. +Dapp developers, chain explorers, chain analytics and others who want exclusive access to chain data and not be subject to the rate-limits on the community access node can choose to run an access node. + +An access node is minimally staked for network security. +The central goal for Access Nodes is to provide RPC functionality to its node operator. +In comparison, contributing to protocol progress (e.g. routing transactions to collector clusters, relaying blocks to the unstaked peer-to-peer network, etc.) should only take up a marginal fraction an Access Node's computational resources. +Furthermore, Access Node operators can freely rate-limit the amount of resources their Access Node dedicates to supporting the broader ecosystem. Therefore, Access Nodes do not receive staking rewards. + +:::info + +Launch an access node using QuickNode + +[https://www.quicknode.com/chains/flow](https://www.quicknode.com/chains/flow) + +::: + +:::info + +To run a self-hosted access node, follow this [guide](./access-nodes/access-node-setup.md) + +::: + +:::tip + +Alternately, instead of running an access node, you can use the [Flow community](../access-onchain-data/index.md) access nodes or the ones run by any of the other node operators. + +::: + +### Validator Node + +--- + +You can also be a core participant in running the Flow network and contribute to securing it. Depending on your preference, you could run one or any combination of the following node roles: +- Collection Nodes collaboratively create batches of transactions (in Flow terminology collections). +- Consensus Nodes create blocks, schedule them for asynchronous execution, and commit execution results once they are verified (so called sealing). In addition, they orchestrate the Flow protocol and enforce protocol compliance. +- Execution Nodes asynchronously execute blocks. They are the power-houses in the protocol, providing the vast computational resources available to Flow transactions. +- Verification Nodes check the execution results in a distributed manner. + +Nodes with these roles are staked and also receive staking rewards. + +### Running a Staked Node + +--- + +To run a staked node (node type access, collection, consensus, verification or execution) the node must: +* be registered with sufficient stake +* be authorized by the governance working group + +Before proceeding, ensure you have the stake required for your new node and that your node will be authorized by the governance working group (apply [here](https://github.com/onflow/flow-validator)). + +To set up a new staked node after it has been authorized by the Flow governance working group, you will need to complete the following steps: + +1. [Provision](./node-operation/node-setup.md) the machine on which your node will run. + +2. [Generate and register](./node-operation/node-bootstrap.md) your node identity. + +3. [Start](./node-operation/node-bootstrap.md#step-3---start-your-flow-node) your node! \ No newline at end of file diff --git a/static/markdown/networks/node-ops/light-nodes/observer-node.md b/static/markdown/networks/node-ops/light-nodes/observer-node.md new file mode 100644 index 0000000000..1d3d646cbb --- /dev/null +++ b/static/markdown/networks/node-ops/light-nodes/observer-node.md @@ -0,0 +1,261 @@ +--- +title: Light Node a.k.a Observer Node +sidebar_label: Light Node Setup +sidebar_position: 1 +--- + +A light node also known as the observer node is similar to an access node and provides a locally accessible, continuously updated, verified copy of the block data. It serves the [gRPC Access API](../../access-onchain-data/index.md) but unlike an access node, an light node does not need to be staked, and **anyone** can run it without being added to the approved list of nodes. + +The light node bootstraps by connecting to an access node and becoming part of the public network comprised of access nodes and other light nodes. It then continuously receives blocks, which the consensus nodes are adding to the chain, either directly from access nodes or from other light nodes that are part of the public network. However, it makes no trust assumption of the upstream access node or the light node which is providing the block and locally verifies that the blocks that are received are the correct extension of the chain e.g. after receiving valid blocks A, B and C when it receives block D, it verifies that block D is indeed signed by the consensus nodes and is a valid next block. The received block data is indexed and made available via the Access API. For Collection, Transactions and Account queries, it delegates those requests to the upstream access node. Similarly, transactions and scripts sent to a light node are also forwarded to the upstream access node. Future versions of the light node will be able to serve this data locally as well. + +Since the light node is not staked, it does not produce or execute blocks but instead serves as an _unstaked access node_ that can be easily run on any consumer-grade computer which has enough disk space. + +![Observer nodes](../node-operation/observer.png) + +## Who should run a light node? + +The light node provides an alternative to running an access node. Hence, it is ideal for Dapps that need access to the latest block data locally on a machine they control. Examples include a wallet application that needs to track the latest block ID and height. Alternatively, access node operators that want to scale their access node endpoints geographically can spin up light nodes in different regions, which can talk to their staked access node and to each other. + +## Running an light node + +### Hardware + +In general, any consumer-grade computer with a decent network connection and sufficient disk space should be able to run a light node. + +Minimum requirements + +- CPU with 2+ cores +- 4 GB RAM minimum +- 300 GB SSD disk +- 10Mbps network connection + +### Steps to run a light node + +> [Here](https://www.loom.com/share/990a725531754106b91d8ccec6244219) is video walk-though of these 👇 steps. + +#### Step 1 - Generate the node directory structure +The light node requires the following directory structure, +```shell +$ tree flow_observer +flow_observer/ +├── bootstrap +│ ├── network.key (file containing the node private network key) +│ └── public-root-information +│ └── root-protocol-state-snapshot.json (the genesis data of the current spork) +└── data (directory used by the light node to store block data) +``` + +Create the parent and the sub-directories +e.g. +```shell +mkdir -p flow_observer/bootstrap/public-root-information +mkdir flow_observer/data +``` + +#### Step 2 - Generate the network key + +Like any other Flow node, the light node also needs a networking [ECDSA key](https://github.com/onflow/flow-go/blob/master/cmd/bootstrap/utils/key_generation.go#L52-L54) to talk to the network. +Download the Bootstrapping kit, and generate the networking key. + +```shell +curl -sL -O storage.googleapis.com/flow-genesis-bootstrap/boot-tools.tar +tar -xvf boot-tools.tar +./boot-tools/bootstrap observer-network-key --output-file ./flow_observer/bootstrap/network.key +``` + +_If you are running on a mac, download the boot-tools for mac to generate the key_ +```shell +# For M1 +curl -sL -O storage.googleapis.com/flow-genesis-bootstrap/boot-tools-m1.tar +# For Intel Mac +curl -sL -O storage.googleapis.com/flow-genesis-bootstrap/boot-tools-intel-mac.tar +``` + +#### Step 3 - Download the root-protocol-state-snapshot.json file for the current spork + +The `root-protocol-state-snapshot.json` is generated for each [spork](../node-operation/spork.md) and contains the genesis data for that spork. +It is published and made available after each spork. The download location is specified [here](https://github.com/onflow/flow/blob/master/sporks.json) under [rootProtocolStateSnapshot](https://github.com/onflow/flow/blob/master/sporks.json#L16) and can be downloaded as follows, + +For mainnet find the latest spork version from [sporks.json](https://github.com/onflow/flow/blob/master/sporks.json) and then download the `root-protocol-state-snapshot.json` and the signature file for it. + +```shell +wget -P ./flow_observer/bootstrap/public-root-information https://storage.googleapis.com/flow-genesis-bootstrap/mainnet--execution/public-root-information/root-protocol-state-snapshot.json +wget -P ./flow_observer/bootstrap/public-root-information https://storage.googleapis.com/flow-genesis-bootstrap/mainnet--execution/public-root-information/root-protocol-state-snapshot.json.asc +``` + +Similarly, for testnet find the latest spork version from [sporks.json](https://github.com/onflow/flow/blob/master/sporks.json) and then download the `root-protocol-state-snapshot.json` and the signature file for it. +```shell +wget -P ./flow_observer/bootstrap/public-root-information https://storage.googleapis.com/flow-genesis-bootstrap/testnet-/public-root-information/root-protocol-state-snapshot.json +wget -P ./flow_observer/bootstrap/public-root-information https://storage.googleapis.com/flow-genesis-bootstrap/testnet-/public-root-information/root-protocol-state-snapshot.json.asc +``` + +##### Verify the PGP signature + +Add the `flow-signer@onflow.org` public key +```shell +gpg --keyserver keys.openpgp.org --search-keys flow-signer@onflow.org + +gpg: data source: http://keys.openpgp.org:11371 +(1) Flow Team (Flow Full Observer node snapshot verification master key) < + 256 bit ECDSA key CB5264F7FD4CDD27, created: 2021-09-15 +Keys 1-1 of 1 for "flow-signer@onflow.org". Enter number(s), N)ext, or Q)uit > 1 +``` + +Verify the root-snapshot file +```shell +gpg --verify ./flow_observer/bootstrap/public-root-information/root-protocol-state-snapshot.json.asc + +gpg: assuming signed data in 'bootstrap/public-root-information/root-protocol-state-snapshot.json' +gpg: Signature made Wed Sep 15 11:34:33 2021 PDT +gpg: using ECDSA key 40CD95717AC463E61EE3B285B718CA310EDB542F +gpg: Good signature from "Flow Team (Flow Full Observer node snapshot verification master key) " [unknown] +gpg: WARNING: This key is not certified with a trusted signature! +gpg: There is no indication that the signature belongs to the owner. +Primary key fingerprint: 7D23 8D1A E6D3 2A71 8ECD 8611 CB52 64F7 FD4C DD27 + Subkey fingerprint: 40CD 9571 7AC4 63E6 1EE3 B285 B718 CA31 0EDB 542F +``` + +Alternately, if you don't care about the blocks before the current block, you can request the current root-snapshot file via the [Flow CLI](../../../tools/flow-cli/index.md). + +For mainnet +```shell + flow snapshot save ./flow_observer/bootstrap/public-root-information/root-protocol-state-snapshot.json --host secure.mainnet.nodes.onflow.org:9001 --network-key 28a0d9edd0de3f15866dfe4aea1560c4504fe313fc6ca3f63a63e4f98d0e295144692a58ebe7f7894349198613f65b2d960abf99ec2625e247b1c78ba5bf2eae +``` + +For testnet +```shell +flow snapshot save ./flow_observer/bootstrap/public-root-information/root-protocol-state-snapshot.json --host secure.testnet.nodes.onflow.org:9001 --network-key ba69f7d2e82b9edf25b103c195cd371cf0cc047ef8884a9bbe331e62982d46daeebf836f7445a2ac16741013b192959d8ad26998aff12f2adc67a99e1eb2988d +``` + +#### Step 4 - Start the node + +The light node can be run as a docker container + +##### Observer for Flow Mainnet + +```shell +docker run --rm \ + -v $PWD/flow_observer/bootstrap:/bootstrap:ro \ + -v $PWD/flow_observer/data:/data:rw \ + --name flow_observer \ + -p 80:80 \ + -p 3569:3569 \ + -p 9000:9000 \ + -p 9001:9001 \ + gcr.io/flow-container-registry/observer:v0.27.2 \ + --bootstrapdir=/bootstrap \ + --datadir=/data/protocol \ + --bind 0.0.0.0:3569 \ + --rest-addr=:80 \ + --loglevel=error \ + --secretsdir=/data/secrets \ + --upstream-node-addresses=secure.mainnet.nodes.onflow.org:9001 \ + --upstream-node-public-keys=28a0d9edd0de3f15866dfe4aea1560c4504fe313fc6ca3f63a63e4f98d0e295144692a58ebe7f7894349198613f65b2d960abf99ec2625e247b1c78ba5bf2eae \ + --bootstrap-node-addresses=secure.mainnet.nodes.onflow.org:3570 \ + --bootstrap-node-public-keys=28a0d9edd0de3f15866dfe4aea1560c4504fe313fc6ca3f63a63e4f98d0e295144692a58ebe7f7894349198613f65b2d960abf99ec2625e247b1c78ba5bf2eae \ + --observer-networking-key-path=/bootstrap/network.key +``` + +##### Observer for Flow Testnet + +```shell +docker run --rm \ + -v $PWD/flow_observer/bootstrap:/bootstrap:ro \ + -v $PWD/flow_observer/data:/data:rw \ + --name flow_observer \ + -p 80:80 \ + -p 3569:3569 \ + -p 9000:9000 \ + -p 9001:9001 \ + gcr.io/flow-container-registry/observer:v0.27.2 \ + --bootstrapdir=/bootstrap \ + --datadir=/data/protocol \ + --bind 0.0.0.0:3569 \ + --rest-addr=:80 \ + --loglevel=error \ + --secretsdir=/data/secrets \ + --upstream-node-addresses=secure.devnet.nodes.onflow.org:9001 \ + --upstream-node-public-keys=ba69f7d2e82b9edf25b103c195cd371cf0cc047ef8884a9bbe331e62982d46daeebf836f7445a2ac16741013b192959d8ad26998aff12f2adc67a99e1eb2988d \ + --bootstrap-node-addresses=secure.devnet.nodes.onflow.org:3570 \ + --bootstrap-node-public-keys=ba69f7d2e82b9edf25b103c195cd371cf0cc047ef8884a9bbe331e62982d46daeebf836f7445a2ac16741013b192959d8ad26998aff12f2adc67a99e1eb2988d \ + --observer-networking-key-path=/bootstrap/network.key +``` + +The light node acts as a DHT client and bootstraps from upstream access nodes which run the DHT server. +The upstream bootstrap server is specified using the `bootstrap-node-addresses` which is the comma-separated list of hostnames of the access nodes. +The `bootstrap-node-public-keys` is the list of the corresponding networking public key of those nodes. + +The light node delegates many of the API calls to the upstream access nodes. +The `upstream-node-addresses` is the list of access node hostnames to which this light node can delegate to. The list can be different from the bootstrap node list. +The `bootstrap-node-public-key` is the list of the corresponding networking public key of those nodes. + +> In the above docker commands, the Flow community access nodes are being used as the upstream access nodes. However, any other Flow access node that supports a light node can be used + +_All parameters and their explanation can be found [here](https://github.com/onflow/flow-go/blob/82da35141ff095fbf75ce2c950efec240ad38565/cmd/access/node_builder/access_node_builder.go#L523-L558)_ + +🚀 **The node should now be up and running** + +You can now query the node for blocks, transaction etc. similar to how you would query an access node. + +e.g. querying the gRPC API endpoint using Flow CLI +```shell +flow blocks get latest --host localhost:9000 +``` + +e.g. querying the REST API endpoint using curl +```shell +curl "http://localhost/v1/blocks?height=sealed" +``` + +The light node, like the other type of Flow nodes, also produces Prometheus metrics that can be used to monitor node health. More on that [here](../node-operation/node-setup.md#monitoring-and-metrics) + +## FAQs + +### Does the light node need to be staked? + +No, the light node is not a staked node. + +### Can any access node be used to bootstrap a light node? + +No, only Access nodes which have explicitly turned ON support for light nodes can be used to bootstrap a light node. + +The public access nodes that support light nodes are listed below. Apart from these, other public access nodes run by node operators other than the Flow foundation team may choose to support light nodes. + +### How can an access node turn ON support for light node? + +An access node can support a light node by passing in the following two parameters when starting the access node +```shell + --supports-observer=true --public-network-address=0.0.0.0:3570 +``` +`public-network-address` is the address the light nodes will connect to. + +### Are light nodes subject to rate limits? + +The light node serves all the [Block related queries](https://github.com/onflow/flow/blob/master/protobuf/flow/access/access.proto#L24-L42) from is local database. These are not subjected to any rate limits. + +However, it proxies all the other requests to the access node and those will be rate limited as per the rate limits defined on that access node. + +### Flow community access nodes that support connections from light nodes + +#### For mainnet + +Access-007: +* Host: `access-007.[current mainnet spork].nodes.onflow.org` +* Public Key: `28a0d9edd0de3f15866dfe4aea1560c4504fe313fc6ca3f63a63e4f98d0e295144692a58ebe7f7894349198613f65b2d960abf99ec2625e247b1c78ba5bf2eae` + +Access-008: +* Host: `access-008.[current mainnet spork].nodes.onflow.org` +* Public Key: `11742552d21ac93da37ccda09661792977e2ca548a3b26d05f22a51ae1d99b9b75c8a9b3b40b38206b38951e98e4d145f0010f8942fd82ddf0fb1d670202264a` + +#### For testnet + +Access-001: +* Host: `access-001.[current devnet spork].nodes.onflow.org` +* Public Key: `ba69f7d2e82b9edf25b103c195cd371cf0cc047ef8884a9bbe331e62982d46daeebf836f7445a2ac16741013b192959d8ad26998aff12f2adc67a99e1eb2988d` + +Access-003: +* Host: `access-003.[current devnet spork].nodes.onflow.org` +* Public Key: `b662102f4184fc1caeb2933cf87bba75cdd37758926584c0ce8a90549bb12ee0f9115111bbbb6acc2b889461208533369a91e8321eaf6bcb871a788ddd6bfbf7` + +While the public keys remain the same, the hostnames change each spork to include the spork name. Substitute `[current mainnet spork]` and `[current devnet spork]` with the appropriate spork name (e.g. `mainnet20`). +See [Past Sporks](../node-operation/past-upgrades) for the current spork for each network. \ No newline at end of file diff --git a/static/markdown/networks/node-ops/node-operation/byzantine-node-attack-response.md b/static/markdown/networks/node-ops/node-operation/byzantine-node-attack-response.md new file mode 100644 index 0000000000..66c5ae7b1c --- /dev/null +++ b/static/markdown/networks/node-ops/node-operation/byzantine-node-attack-response.md @@ -0,0 +1,178 @@ +--- +title: Byzantine Node Attack Response +sidebar_label: Byzantine Attack Response +description: How to respond to a byzantine node attack on the network +sidebar_position: 3 +--- + +Flow, like most blockchains, forms an open decentralized peer-to-peer network between all of the nodes +on the network. Due to its decentralized nature, there is a potential for nodes to behave maliciously +(byzantine) and intentionally try to harm the network. There are a variety of protections within the +node software to deal with invalid messages - message signatures, sender authorization, payload +validation, etc. These protections guard the network against many types of attacks. However, there +could still be a byzantine node that spams other nodes in the network with invalid messages at volumes +that are intended to impact node performance. While this will not compromise the security of the +network it could impact network liveness. + +This guide explains how to detect such a node and what actions you should take as a node operator +to deal with such byzantine nodes. + +Responding to an attack from a byzantine node requires the following: + +1. Immediate action to block network traffic originating from the byzantine node to your node. +2. Raising a governance FLIP to remove the node from the network as described in this [FLIP](https://github.com/onflow/flips/blob/main/governance/20230105-identify-errant-node.md). +3. A service account transaction to set the node weight to 0. + +This guide focuses on the first action. + +## Admin Server + +Flow nodes have an admin server which exposes a simple REST API for interacting with the node. +See the [README](https://github.com/onflow/flow-go/blob/master/admin/README.md) for some useful examples. +It is disabled by default. + +### Enable the Admin Server + +To enable to admin server, + +1. Add the following option to the node's CLI flags. +``` +--admin-addr=localhost:9002 +``` + +> Note: The port does not have to be 9002. You can choose any free port. + +> ⚠️ Do NOT expose the port outside the machine and always use localhost:port + +2. Reboot the node to apply the new setting. You can then verify it’s working by logging into +the machine via ssh and running, + +``` +curl localhost:9002 +``` + +This should return a json response message as below. +``` +{"code":5,"message":"Not Found","details":[]} +``` + +If you instead get a connection rejected message then it’s not configured correctly. + +## Detecting a Byzantine Node + +There are 2 general categories of byzantine attacks: +1. Safety attacks - are attacks where a node attempts to corrupt or modify the state of the +blockchain outside of normal protocol rules. +2. Liveness attacks - sometimes called spamming attacks, are when a node attempts to disrupt the +network by abusing their access to waste network and node resources. This generally results in +degraded performance. + +Flow nodes are protected against safety attacks, but liveness attacks are extremely difficult to +completely prevent. To close the gap, we rely on coordination between node operators to detect +and block abusive nodes. + +### Metrics + +Flow nodes generate a variety of metrics that can be used to measure the node's performance and +identify abnormal behavior. Most metrics are only useful in the context of "normal" operation, +so it is a good idea to regularly review them to build an understanding of what is "normal". + +Metrics to watch: +* CPU, memory, network connections, network I/O, file descriptors +* `network_authorization_*` - counts the number of unauthorized/invalid messages received +* `network_queue_message_queue_size` - measures the number of incoming messages waiting to be processed +* `network_engine_messages_received_total` - measures the number of messages received from the network + +There are many other metrics, but these are a good starting point. If you notice any anomalous trends, +review the logs for additional context. + +### Logs + +Log events related to suspicious activity are logged with the label `"suspicious":true`. This is +helpful to identify the most relevant logs, but there are legitimate cases when these logs are +emitted, so they cannot be used as a definitive indicator of malicious activity. Two examples of +expected log messages are: +* `rejected inbound connection` - You may see this error if an operator unstaked their node between +sporks, but never shut it down. The node will continue to operate as usual, but peers will not have +it in their identity table and will (correctly) reject incoming connections. +* `middleware does not have subscription for the channel ID indicated in the unicast message received` - +This is commonly logged during node startup when receiving messages before all of the components +have finished registering their channels with the network layer. It is NOT expected after startup. + +The following is an example of a log message indicating an Access node attempted to send a message it +is not authorized to send: +``` +{ + "level": "error", + "node_role": "collection", + "node_id": "4a6f7264616e20536368616c6d00a875801849f2b5bea9e9d2c9603f00e5d533", + "module": "network_slashing_consumer", + "peer_id": "QmY2kby3xt3ugu2QqJP5w24rP4HSakYgDFpAJy1ifSRkF7", + "networking_offense": "unauthorized_sender", + "message_type": "messages.BlockProposal", + "channel": "sync-committee", + "protocol": "publish", + "suspicious": true, + "role": "access", + "sender_id": "f9237c896507b8d654165c36b61c9a3080e6dd042dea562a4a494fbd73133634", + "time": "2023-01-24T21:10:32.74684667Z", + "message": "potential slashable offense: sender role not authorized to send message on channel" +} +``` + +### Identifying the Source of Malicious Traffic + +Most log messages include either the node ID or peer ID. Peer ID is the ID used to identify nodes on +by the libp2p library. Peer IDs are derived from the node's networking public key, so there is a 1:1 +mapping between node ID and peer ID. + +The two simplest ways to match a node ID to a peer ID: +1. `inbound connection established` and `outbound connection established` log messages contain both +the node and peer IDs +2. The following admin command will return the node info for a given peer ID: +``` +curl localhost:9002/admin/run_command \ + -H 'Content-Type: application/json' \ + -d '{"commandName": "get-latest-identity", "data": { "peer_id": "QmY2kby3xt3ugu2QqJP5w24rP4HSakYgDFpAJy1ifSRkF7" }}' +``` + +If you cannot find any log messages at the current log level, you may need to enable debug logging. +See the admin server's [README](https://github.com/onflow/flow-go/blob/master/admin/README.md) for +an example. + +## Reporting the Byzantine Node + +Report the suspicious node on Discord in the `#flow-validators-alerts` channel along with all the +evidence you have collected (log messages, other networking related metrics, etc). +This will alert other node operators who can review their nodes to corroborate the report. Using +evidence from multiple operators, a consensus can be reached about the suspicious node, and +appropriate action can be taken. + +## Blocking a Byzantine Node + +Once a consensus is reached about the suspicious node on Discord among the node operators, the +suspicious node can be blocked using the admin command. + +``` +curl localhost: 9002/admin/run_command \ + -H 'Content-Type: application/json' \ + -d '{"commandName": "set-config","data": {"network-id-provider-blocklist": [""]}} +``` + +After blocking the node, all traffic coming from the node will be rejected and you should only see +logs about reject messages and connections for that node ID. + +## Unblocking a Node + +If you need to unblock a node, you can use the same command to remove the node ID from the blocklist. +Simply run it again with an empty list to remove all blocked nodes, or an existing list with the +specific node ID you want to unblock removed. + +The following command returns a list of the currently blocked nodes. +``` +curl localhost: 9002/admin/run_command \ + -H 'Content-Type: application/json' \ + -d '{"commandName": "get-config", "data": "network-id-provider-blocklist"} +``` + +After unblocking the node, connections and traffic coming from the node should resume. \ No newline at end of file diff --git a/static/markdown/networks/node-ops/node-operation/db-encryption-existing-operator.md b/static/markdown/networks/node-ops/node-operation/db-encryption-existing-operator.md new file mode 100644 index 0000000000..e011aa9abe --- /dev/null +++ b/static/markdown/networks/node-ops/node-operation/db-encryption-existing-operator.md @@ -0,0 +1,56 @@ +--- +title: Database Encryption for Existing Node Operators +sidebar_label: Database Encryption for Existing Node Operators +description: Instructions for existing Node Operators to follow to create a machine account for their collection or consensus nodes. +sidebar_position: 4 +--- + +In Mainnet14, the DKG (distributed key generation) is turned on, requiring storage of +dynamically generated confidential data (random beacon keys). These are stored in a +separate database which is new with the Mainnet14 release. + +All node operators joining after Mainnet14 will generate encryption keys for this database +through the node bootstrapping and staking process. We strongly recommend all node operators +(especially consensus node operators) generate an encryption key for this database. This +guide demonstrates how to enable encryption for this database for existing operators. + +## Downloading Bootstrap Utility + + + If you have downloaded the bootstrapping kit previously, ensure that you do + this step again to get the latest copy of the bootstrapping kit since there + have been significant changes to it. + + +Follow the instructions [here](./node-bootstrap.md#download-the-bootstrapping-kit) +to download the latest version of the bootstrapping kit, then return to this page. + +## Generate Database Encryption Key + +You will need to generate an encryption key for the database using the `bootstrap` utility. + + + + Ensure you run the following commands on the machine you use to run your node software. + The bootstrap directory passed to the `-o` flag must be the same bootstrap directory used by your node. + The default location is `/var/flow/bootstrap`, but double-check your setup before continuing. + + + +```shell GenerateEncryptionKey +$./boot-tools/bootstrap db-encryption-key -o ./bootstrap + INF generated db encryption key + INF wrote file bootstrap/private-root-information/private-node-info_ab6e0b15837de7e5261777cb65665b318cf3f94492dde27c1ea13830e989bbf9secretsdb-key + +$tree ./bootstrap/ +./bootstrap +├── private-root-information +│ └── private-node-info_ab6e0b15837de7e5261777cb65665b318cf3f94492dde27c1ea13830e989bbf9 +│ ├── node-info.priv.json +│ └── secretsdb-key +└── public-root-information + ├── node-id + └── node-info.pub.ab6e0b15837de7e5261777cb65665b318cf3f94492dde27c1ea13830e989bbf9.json + +3 directories, 4 files +``` \ No newline at end of file diff --git a/static/markdown/networks/node-ops/node-operation/faq.md b/static/markdown/networks/node-ops/node-operation/faq.md new file mode 100644 index 0000000000..81b2698fd3 --- /dev/null +++ b/static/markdown/networks/node-ops/node-operation/faq.md @@ -0,0 +1,65 @@ +--- +title: Operator FAQ +sidebar_position: 1 +--- + +# Operator FAQ + +### Can anybody run a node? What is the approval process? + +Anyone can run an [observer node](../light-nodes/observer-node.md). + +Anyone can run an Access Node after registering and staking. See [Access Node Setup](../access-nodes/access-node-setup.md) for detailed instructions. + +For the other node roles, individuals can go through an application process that involves asking about their background and experience contributing to decentralized projects. To pursue an application, please visit [the Flow website here to apply](https://www.onflow.org/node-validators). + +Pending approval, new node operators will be onboarded and invited to join a webinar to meet the team and share more about how they’ll grow the community. Node Operators are invited to join and participate in Flow's Node Validator Discord channel for setup questions and network announcements. + +In the long-term, anyone can run a node validator on Flow. + +### How do I generate keys? + +Please follow the instructions provided here: [Generate Your Node Keys](./node-bootstrap.md#generate-your-node-keys) + +### How do I check on the status of my node? + +Please follow the instructions provided here: [Monitoring nodes](./monitoring-nodes.md) + +### Can I bootstrap and run a node at any time? + +Flow allows nodes to join/leave the network each time a new epoch begins (roughly once per week). +See [Staking & Epochs](../../staking/index.md#epochs) for general information and [Node Setup](./node-bootstrap.md#timing) for a guide to running a new node. + +### Would it hurt the network to have a node that constantly spins up and down? + +All staked nodes except access nodes, have to be online at all time. A staked node, other than an access node, which is not online can cause severe degradation of network performance and will be subjected to slashing of rewards. +A way to prevent this is to check your equipment meets Flow's [recommended requirements](./node-provisioning.md#hardware-requirements), periodically checking for updates and announcements in Discord but also using a node monitoring system for when your node does go offline. + +### Does Flow has a regular schedule for Sporks? + +Yes, see [Upcoming Sporks](./upcoming-sporks.md) for the latest schedule. Currently, Flow has a Mainnet Spork and a Testnet Spork roughly every two months. + +### How do I update the Node Software? + +One of the reasons for a [spork](./spork.md) is to make sure all nodes update to the latest software version. Hence, you should have the latest software update as long as you are participating in each spork. +However, if we do release any software update in between a Spork (e.g. an emergency patch) we will announce it on Discord. + +### Is there any way to know if a node is currently online? + +To verify if a node is online, please [setup metrics](./faq.md#how-do-i-check-on-the-status-of-my-node) for the node. + +### Can I migrate a node to a new machine? + +Yes, as long as you retain the `boostrap` information which includes the node staking key, networking key, IP address and port from the old node to the new. +More on this [here](./node-migration.md) + +### Where can I find how many nodes are currently running Flow? + +If you are running a node, then you most definitely have this information on your node in the file `/public-root-information/node-infos.pub.json`. If you are not running a node, you can find this information by using a Cadence script to query the [Staking Smart Contract](../../../build/core-contracts/06-staking-contract-reference.md) (or check [Flowdiver](https://flowdiver.io/staking/overview)) + +### Why do I need to update my node's ulimit? + +Flow nodes create network connections to other nodes on the network to participate in the protocol. The node's operating system represents +these connections as file descriptors, and uses soft and hard limits to control the number of open files. The node software uses these limits +to manage how many connections it will open and accept from other nodes. If the limit is too low, the node will not be able to communicate +with its peers, preventing it from functioning properly. \ No newline at end of file diff --git a/static/markdown/networks/node-ops/node-operation/guides/genesis-bootstrap.md b/static/markdown/networks/node-ops/node-operation/guides/genesis-bootstrap.md new file mode 100644 index 0000000000..ea7c1f396e --- /dev/null +++ b/static/markdown/networks/node-ops/node-operation/guides/genesis-bootstrap.md @@ -0,0 +1,173 @@ +--- +title: Genesis Bootstrapping +--- + + + All nodes joining the network in May are required to go through this process as part of the Genesis Bootstrapping. + + +## Overview + +To kickstart the Flow network and build the first block, all the nodes that will participate in the first round of consensus need to be known and have exchanged some metadata in advance. + +This guide will take you through setting up your nodes, running the initial metadata and key generation, exchanging data back and forth with the Flow team, and then finally starting your nodes to join the network. + +## Before You Begin + +The Flow consensus algorithm depends on there always being a previous block, which means your nodes cannot start until _after_ the Genesis block has been signed. The process of signing that block will be done by the Flow team, and can only be done after every node has completed the first half of the bootstrapping process, which assures that all the identities are included. Since the Flow team needs to wait for metadata from all participants, it will take hours to even days until the Flow network can start. + +The bootstrapping process will be in 2 phases, with the Flow team signing the Genesis block between the two. + + + The bootstrapping process deals with a number of different keys. Make sure you understand their usage and terminology by reviewing the [Node Keys Guide](../node-bootstrap.md#generate-your-node-keys). + + +## Download the Bootstrapping Toolkit + +Both phases of the bootstrapping are automated with scripts. Pull a copy onto each of your nodes and extract it. + +```shell Pull-boot-tools +~ $ curl -sL -O storage.googleapis.com/flow-genesis-bootstrap/boot-tools.tar +~ $ tar -xvf boot-tools.tar +``` + +## Generate Your Node Keys + +Start the bootstrapping process by generating your Staking Key and Networking Key. Use your Node Address that you generated in [Setting Up a Node](../node-setup.md) in the `--address` flag, and the node role. + +Your Node Address must be a publicly routable IPv4 address or valid DNS name that points to your node. This is how other nodes in the network will communicate with you. + +```shell Generate-bootstrap-keys" +~ $ mkdir ./bootstrap +~ $ ./boot-tools/bootstrap key --address \"${YOUR_NODE_ADDRESS}:3569\" --role ${YOUR_NODE_ROLE} -o ./bootstrap +``` + + + By default, the bootstrap script uses the kernel entropy source, either via a `getrandom` syscall or `/dev/urandom`. If you have a more secure source of entropy, like a hardware device, you can specify `--staking-seed` and `--networking-seed`, to provide your own seeds. + + Run the `bootstrap` command with no flags to print usage information." + + + + The key pairs generated in the bootstrapping process are extremely sensitive and must be managed securely. This guide does not deal with storing the keys in a secure backup or controlling access, as the right approach to this will vary from user to user, but it is something you must consider. + + Private keys are suffixed with `.priv.json`, their public counterparts are not sensitive and can be shared freely. + + +This command generates two keys, a Staking Key and a Network Key, and stores them both in a `.node-info` file. Both these keys are needed during runtime and must be present as a file to start your flow node. + +For more details around all the keys that are needed to run nodes and their usage, see the [Node Keys](../node-bootstrap.md#generate-your-node-keys) overview. + +The bootstrapping process will create a file structure similar to the following + +```text bootstrap-directory +~ +└──bootstrap + ├──{id}.node-info.priv.json + └──{id}.node-info.pub.json", +``` + +## Upload Public Keys + +To mint the Genesis Block, the Flow team will need the public Staking and Network keys from all your nodes. + +**If you have previously joined our networks, and you are generating your keys again. Ensure that you take a backup of your keys before generating it again** + +To facilitate this, the boot-tools directory comes with a script `push-keys` that will bundle your `*.pub.json` files and send it to the flow team. You can inspect this script to make sure no private key material is being bundled or uploaded. The data not encrypted before being sent as the public keys involved are not sensitive. + +In phase 2 of the bootstrapping process, the Flow team will need to securely issue each node a Random Beacon key. This key is again sensitive and unique to your node. To enable this, the `push-keys` script also generates another key pair called the Transit Key. The public key of this pair will be uploaded along with the Staking and Network keys, and your Random Beacon key will be encrypted with it before being sent to you. You must keep your Transit Key until you have received and decrypted your Random Beacon key from the Flow team. + + + The transit script here need a `-t` token parameter flag. This token will have been provided to you by the Flow team out of band. Reach out to your contact if you don't have your token. + + +```shell Upload-public-keys +# If you joined our network previously, make sure to take a backup! +cp /path/to/bootstrap /path/to/bootstrap.bak +$ ./boot-tools/transit push -d ./bootstrap -t ${TOKEN} -role ${YOUR_NODE_ROLE} +Running push +Generating keypair +Uploading ... +Uploaded 400 bytes + +``` + + + Once you've run the bootstrap and are confident in your setup, run the transit push command only once. If you bootstrap again and transit push again with a new node ID, it will count against your quota of Nodes. Exceeding your quota will result in a long back and forth with the Flow team to see which node is the extra one. + + +## Update Node Config + +As flow node requires a `--nodeid` flag to start. You will need to pass in the contents of the `node-id` into either your container, `runtime-config.env` file, or hard coded into the `systemd` unit file which the flow team provides. + +You can get the `node-id` from the metadata that you pulled. It will be at: `/path/to/bootstrap/public-genesis-information/node-id` + +### Wait + +Now the ball is in the Flow team's court. As soon as all nodes have completed the above steps, the Genesis block will be created and distributed to you. + +Join the [Flow discord server](https://chat.onflow.org) if you haven't already and stay tuned for updates. Your nodes need not be online during this waiting period if you want to suspend them to reduce cost, but you must not lose your key material. + + + For the Genesis Block, your nodes will start pre-staked, which means no action on your part is needed to get your nodes staked. + + For more details on staking check the guide on [Staking and Rewards](../../../staking/08-staking-rewards.md). + + +## Receive Your Random Beacon Keys + +When the Flow team gives the go-ahead, your Random Beacon keys will be available for retrieval. Each Node will need to pull their own keys down individually. + +```shell Pull-beacon-keys +~ $ ./boot-tools/transit pull -d ./bootstrap -t ${TOKEN} -role ${YOUR_NODE_ROLE} +Fetching keys for node ID FEF5CCFD-DC66-4EF6-8ADB-C93D9B6AE5A4 +Decrypting Keys +Keys available +``` + +Pulling your keys will also pull a bunch of additional metadata needed for the bootstrapping process. +In the end, your bootstrap directory should look like this: + +```text bootstrap-directory +~ +bootstrap/ +├── private-genesis-information +│ └── private-node-info_{node id} +│ ├── node-info.priv.json +│ └── random-beacon.priv.json +├── public-genesis-information +│ ├── dkg-data.pub.json +│ ├── genesis-block.json +│ ├── genesis-cluster-block.{cid}.json +│ ├── genesis-cluster-block.{cid}.json +│ ├── genesis-cluster-qc.{cid}.json +│ ├── genesis-cluster-qc.{cid}.json +│ ├── genesis-commit.json +│ ├── genesis-qc.json +│ ├── node-id +│ ├── node-info.pub.{node id}.json +│ └── node-infos.pub.json +├── +``` + + + Unlike staking and account keys, the beacon keys are not randomly generated, and depend on inputs from all consensus nodes on the network. In typical Flow network operation, these keys will be dynamically generated on demand by the consensus nodes communicating. However for genesis, as the consensus nodes aren't communicating yet, the Flow team will generate and distribute them to kickstart the process. + + +## Move Genesis Data + +This bootstrapping data is needed by your node at each startup, so it must be present on disk. + +Where in the filesystem you store this data is up to you, but you may not change the folder structure generated by the bootstrapping process. By default, flow stores this data under `/var/flow/bootstrap`. + +## New Images + +Once the Genesis block has been minted, it will be included into the official container images so that it's available to all nodes. Pull the new images, which should now be version `v1.0.0`. + +## Start Your Nodes + +Once every node has puled its keys and fetched the new images, the network is ready to start. + +Make sure you're part of the [Discord Chat](https://chat.onflow.org). Once all nodes are ready, updates will be provided to everyone. + +Start your systems, let's make some blocks! \ No newline at end of file diff --git a/static/markdown/networks/node-ops/node-operation/guides/spork-practice.md b/static/markdown/networks/node-ops/node-operation/guides/spork-practice.md new file mode 100644 index 0000000000..785b9dacad --- /dev/null +++ b/static/markdown/networks/node-ops/node-operation/guides/spork-practice.md @@ -0,0 +1,69 @@ +--- +title: Spork Practice +--- + +## Sporking + +The actual process of Sporking will mostly be covered by the Node Operators Quick Guide, and will not be covered here. + +[Spork](../spork.md) + +Instead, we'll aim to give some instructions for those that want to Practice the process themselves, before joining the Mainnet Spork. + +This guide assumes you have access to the Flow-Go repo, which you'll need to build up-to-date containers and run code snippets. + +[](https://github.com/onflow/flow-go) + +## Local Testnet + +One way to get a good feel of the network without too much interaction with infrastructure is to play with the local testnet, which we've named the Flow Local Instrumented Test Environment (FLITE). + +[https://github.com/onflow/flow-go/blob/master/integration/localnet/README.md](https://github.com/onflow/flow-go/blob/master/integration/localnet/README.md) + +FLITE will allow you to start a full flow network locally, which means starting all 5 roles required for a functioning network. Instructions for initializing and starting the local network are provided in the README above. + +When Starting FLITE, it will build all the docker images required for the network. This can also be done manually ahead of time, using `make docker-build-flow` from the root directory of `flow-go` + +## Remote Testnet + +If you would like more control over the nodes, beyond what docker compose can provide, or you wish to deploy the docker images to separate VMs, to more closely imitate Mainnet, you will have to manually run bootstrapping for a specific configuration of nodes that you would like to test. + +[](https://github.com/onflow/flow-go/blob/master/cmd/bootstrap/README.md) + +Example files are available in the `cmd/bootstrap/example_files` folder. + +Where the `node-config.json` will usually store all flow's nodes, whereas partner node info usually goes into a separate folder. The last file, which will need to be manually populated, is the partner stakes file, which takes the IDs of all the partner nodes and associates a stake. For now, this can be arbitrary. + +Once you have all the information, you can make use of the `finalize` command: + +[](https://github.com/onflow/flow-go/tree/master/cmd/bootstrap#example-1) + +And generate the bootstrapping folder required to start up your nodes. + +Once you have the bootstrapping folder, you'll be able to start up all the nodes that were included in the bootstrapping process. + +[Node Setup Docker](../node-setup.md#docker) + +The startup command will look very similar to what is provided in the quick guide. One such example, assuming we named our bootstrap folder `bootstrap`: + +```shell +docker run --rm \ + -v /path/to/bootstrap:/bootstrap:ro \ + -v /path/to/data:/data:rw \ + --name flow-go \ + --network host \ + gcr.io/flow-container-registry/execution:latest \ + --nodeid=${FLOW_GO_NODE_ID} \ + --bootstrapdir=/bootstrap \ + --datadir=/data/protocol \ + --rpc-addr=0.0.0.0:9000 \ + --nclusters=${FLOW_NETWORK_COLLECTION_CLUSTER_COUNT} \ + --bind 0.0.0.0:3569 \ + --loglevel=error +``` + +The two missing pieces of info here are `FLOW_GO_NODE_ID` which will have been generated from the bootstrap process, and will depend on which node you're trying to run, and `FLOW_NETWORK_COLLECTION_CLUSTER_COUNT` which we've been defaulting to `2` + +## Practice Testnet + +Lastly, if the goal is to practice the entire Sporking procedure, including `transit` of staking and networking keys, and joining a network, we can help spin up a Testnet temporarily for this purpose. This will require quite a bit of coordination, and will basically be the same steps as the Mainnet spork, so please let us know if this is something you'd like to do and we’ll connect to plan accordingly. \ No newline at end of file diff --git a/static/markdown/networks/node-ops/node-operation/guides/starting-nodes.md b/static/markdown/networks/node-ops/node-operation/guides/starting-nodes.md new file mode 100644 index 0000000000..de3eda6380 --- /dev/null +++ b/static/markdown/networks/node-ops/node-operation/guides/starting-nodes.md @@ -0,0 +1,117 @@ +--- +title: Starting Your Nodes +--- + +Prior to starting up your nodes make sure you have the following items completed: + +1. Bootstrap process completed with the bootstrap directory handy (default: `/var/flow/bootstrap`) +2. Flow `data` directory created (default: `/var/flow/data`) +3. [node config](../node-bootstrap.md) ready +4. Firewall exposes TCP/3569, and if you are running `access` node also the GRPC port (default: TCP/9000) + +For more details head back to [Setting up your node](../node-setup.md#prepare-your-node-to-start) + +When you have all the above completed, you can start your Flow node via `systemd` or `docker`. + +## systemd + +Ensure that you downloaded the systemd unit file. If you haven't, follow the [Set your node to start](../node-setup.md#prepare-your-node-to-start) guide to get your unit file and enabled. + +Once you have your Flow service enabled you can now start your service: `systemctl start flow` + +## Docker + +If you don't have have systemd on your system, or prefer not to use systemd, you can run the following `docker` commands for your respective Flow role to start your node! + +### Access + +``` +docker run --rm \ + -v /path/to/bootstrap:/bootstrap:ro \ + -v /path/to/data:/data:rw \ + --name flow-go \ + --network host \ + gcr.io/flow-container-registry/access:v0.0.6-alpha \ + --nodeid=${FLOW_GO_NODE_ID} \ + --bootstrapdir=/bootstrap \ + --datadir=/data/protocol \ + --rpc-addr=0.0.0.0:9000 \ + --ingress-addr=${FLOW_NETWORK_COLLECTION_NODE} \ + --script-addr=${FLOW_NETWORK_EXECUTION_NODE} \ + --bind 0.0.0.0:3569 \ + --loglevel=error +``` + +### Collection + +``` +docker run --rm \ + -v /path/to/bootstrap:/bootstrap:ro \ + -v /path/to/data:/data:rw \ + --name flow-go \ + --network host \ + gcr.io/flow-container-registry/collection:v0.0.6-alpha \ + --nodeid=${FLOW_GO_NODE_ID} \ + --bootstrapdir=/bootstrap \ + --datadir=/data/protocol \ + --rpc-addr=0.0.0.0:9000 \ + --nclusters=${FLOW_NETWORK_COLLECTION_CLUSTER_COUNT} \ + --bind 0.0.0.0:3569 \ + --loglevel=error +``` + +### Consensus + +``` +docker run --rm \ + -v /path/to/bootstrap:/bootstrap:ro \ + -v /path/to/data:/data:rw \ + --name flow-go \ + --network host \ + gcr.io/flow-container-registry/consensus:v0.0.6-alpha \ + --nodeid=${FLOW_GO_NODE_ID} \ + --bootstrapdir=/bootstrap \ + --datadir=/data/protocol \ + --nclusters=${FLOW_NETWORK_COLLECTION_CLUSTER_COUNT} \ + --bind 0.0.0.0:3569 \ + --loglevel=error +``` + +### Execution + +``` +docker run --rm \ + -v /path/to/bootstrap:/bootstrap:ro \ + -v /path/to/data:/data:rw \ + --name flow-go \ + --network host \ + gcr.io/flow-container-registry/execution:v0.0.6-alpha \ + --nodeid=${FLOW_GO_NODE_ID} \ + --bootstrapdir=/bootstrap \ + --datadir=/data/protocol \ + --ingress-addr=0.0.0.0:9000 \ + --nclusters=${FLOW_NETWORK_COLLECTION_CLUSTER_COUNT} \ + --bind 0.0.0.0:3569 \ + --loglevel=error +``` + +### Verification + +``` +docker run --rm \ + -v /path/to/bootstrap:/bootstrap:ro \ + -v /path/to/data:/data:rw \ + --name flow-go \ + --network host \ + gcr.io/flow-container-registry/verification:v0.0.6-alpha \ + --nodeid=${FLOW_GO_NODE_ID} \ + --bootstrapdir=/bootstrap \ + --datadir=/data/protocol \ + --nclusters=${FLOW_NETWORK_COLLECTION_CLUSTER_COUNT} \ + --bind 0.0.0.0:3569 \ + --loglevel=error +``` + +### Additional Flags +#### Networking Layer +All networking layer settings are initialized to default values from the [config/default-config.yml](https://github.com/onflow/flow-go/blob/master/config/default-config.yml) file when the Flow node starts up. Each attribute in this YAML file matches a flag name, allowing you to override the default setting by specifying the corresponding flag in the `docker run` command. For instance, to change the `networking-connection-pruning` setting, use its matching flag name (`networking-connection-pruning`) and desired value in the `docker run` command. \ No newline at end of file diff --git a/static/markdown/networks/node-ops/node-operation/hcu.md b/static/markdown/networks/node-ops/node-operation/hcu.md new file mode 100644 index 0000000000..25adb1a03e --- /dev/null +++ b/static/markdown/networks/node-ops/node-operation/hcu.md @@ -0,0 +1,39 @@ +--- +title: Height coordinated upgrade (HCU) +sidebar_label: Height coordinated upgrade +--- + +## Overview + +To enables rapid development of the Flow Protocol, the height coordinated upgrade method is used to roll out non-breaking changes such as bug fixes, +feature implementations and security fixes. + +## HCU versus Spork + +A [spork](./spork.md) requires a coordinated network upgrade process where node operators upgrade their node software and +re-initialize with a consolidated representation of the previous spork's state. +It is used to roll out changes which may be non-backward compatible with respect to the protocol and the execution state. +Spork entails a network downtime as all nodes in the system are upgraded and brought back online. +Sporks are only executed once every quarter. + +A height coordinated upgrade (HCU) on the other hand allows the execution and the verification nodes to be upgraded without stopping the network. +There is no network downtime during an HCU but the transaction execution will stop for few minutes while the execution nodes restart. +Currently, an HCU is only used to update the execution and the verification nodes. +For other node types, a simple rolling upgrade is used where operators are asked to upgrade their nodes async. + +## HCU process + +The HCU is executed in two parts. + +The first part is executed by the service committee. In this, the version boundary at which the execution nodes and verification nodes should stop is set on chain by submitting the [set_version_boundary](https://github.com/onflow/flow-core-contracts/blob/master/transactions/nodeVersionBeacon/admin/set_version_boundary.cdc) transaction. +The version boundary includes the block height at which the two node types should stop and the new node software version that the nodes should compare after a restart. + +The second part is executed by the node operator. In this the node operator, monitors the execution and verification node that they are running. When the nodes reach the height set on chain, they stop if their version is lower then the version specified in the version boundary. +At this point, the operator should update the node version to the new node software version and start the node again. The node will continue from where it left off. + +The block height and the node version will be announced by the Flow team on Discord as well as the [forum page](https://forum.onflow.org/c/mainnet-sporks/36). +It can also be directly queried from the chain using the following script. + +``` +TODO: insert flow cli command here to query the block version details. +``` \ No newline at end of file diff --git a/static/markdown/networks/node-ops/node-operation/machine-existing-operator.md b/static/markdown/networks/node-ops/node-operation/machine-existing-operator.md new file mode 100644 index 0000000000..5bd9d163e6 --- /dev/null +++ b/static/markdown/networks/node-ops/node-operation/machine-existing-operator.md @@ -0,0 +1,125 @@ +--- +title: Machine Accounts for Existing Node Operators +sidebar_label: Machine Accounts for Existing Node Operators +description: Instructions for existing Node Operators to follow to create a machine account for their collection or consensus nodes. +sidebar_position: 6 +--- + +The [Flow Epoch Preparation Protocol](../../staking/04-epoch-preparation.md) requires that +`collection` and `consensus` nodes use an automated [machine account](../../staking/09-qc-dkg.md#machine-accounts) +to participate in important processes required to start the next epoch. (QC and DKG, respectively) + +Starting on Thursday, August 26th 2021, all collector and consensus nodes who register with Flow Port will +automatically create and initialize this machine account as part of their node registration. + +If you have an existing `consensus` or `collection` node that you registered with Flow Port before Thursday August 26th, +you will need to create this Machine Account manually in order to participate in epochs. +You will need to create one Machine Account for each `consensus` or `collection` node that you operate. + +This guide will walk you through creating a Machine Account and getting it set up. + + + During this process you will generate a new private key which will have sole control over your machine account. + This private key will be stored on the machine you use to run your node, alongside your staking and networking keys. + Loss of any of these keys (staking, networking, or machine account) will require you to un-stake your tokens, start a completely new node, and register the new node to continue participating in the Flow network, which takes multiple weeks. + + +## Downloading Bootstrap Utility + + + If you have downloaded the bootstrapping kit previously, ensure that you do + this step again to get the latest copy of the bootstrapping kit since there + have been significant changes to it. + + +Follow the instructions [here](./node-bootstrap.md#download-the-bootstrapping-kit) +to download the latest version of the bootstrapping kit, then return to this page. + +## Generate Machine Account key + +You will need to generate a Machine account private key using the `bootstrap` utility. + + + + Ensure you run the following commands on the machine you use to run your node software. + The bootstrap directory passed to the `-o` flag must be the same bootstrap directory used by your node. + The default location is `/var/flow/bootstrap`, but double-check your setup before continuing. + + + +```shell GenerateMachineAccountKey +$./boot-tools/bootstrap machine-account-key -o ./bootstrap + INF generated machine account private key + INF encoded machine account public key for entry to Flow Port machineAccountPubKey=f847b84031d9f47b88435e4ea828310529d2c60e806395da50d3dd0dd2f32e2de336fb44eb06488645673850897d7cc017701d7e6272a1ab7f2f125aede46363e973444a02038203e8 + INF wrote file bootstrap/private-root-information/private-node-info_6f6e98c983dbd9aa69320452949b81abeab2ac591a247f55f19f4dbf0b477d26/node-machine-account-key.priv.json + +$tree ./bootstrap/ +./bootstrap +├── private-root-information +│ └── private-node-info_ab6e0b15837de7e5261777cb65665b318cf3f94492dde27c1ea13830e989bbf9 +│ ├── node-info.priv.json +│ └── node-machine-account-key.priv.json +│ └── secretsdb-key +└── public-root-information + ├── node-id + └── node-info.pub.ab6e0b15837de7e5261777cb65665b318cf3f94492dde27c1ea13830e989bbf9.json + +3 directories, 4 files +``` + +## Create Machine Account + +You will now need to copy the Machine account public key displayed in the terminal output and +head over to [Flow Port](../../../networks/flow-port/staking-guide.md#stake-a-node) to submit a transaction to create a Machine Account. +For example, from the example above, we would copy `f847...` from this line: + +```shell Example + INF encoded machine account public key for entry to Flow Port machineAccountPubKey=f847b84031d9f47b88435e4ea828310529d2c60e806395da50d3dd0dd2f32e2de336fb44eb06488645673850897d7cc017701d7e6272a1ab7f2f125aede46363e973444a02038203e8 +``` + +This process will create your machine account for you and show you your machine account's address, which you will need to save for the next step. + +## Finalize Machine Account setup + +You will now need to use the `bootstrap` utility to run `machine-account` with the created address to finalize the set up of your Machine account. + +```shell +$ ./boot-tools/bootstrap machine-account --address ${YOUR_MACHINE_ACCOUNT_ADDRESS} -o ./bootstrap +``` + +```shell Example +$./boot-tools/bootstrap machine-account --address 0x1de23de44985c7e7 -o ./bootstrap + INF read machine account private key json + DBG encoded public machine account key machineAccountPubKey=2743786d1ff1bf7d7026d693a774210eaa54728343859baab62e2df7f71a370651f4c7fd239d07af170e484eedd4f3c2df47103f6c39baf2eb2a50f67bbcba6a + INF wrote file bootstrap/private-root-information/private-node-info_6f6e98c983dbd9aa69320452949b81abeab2ac591a247f55f19f4dbf0b477d26/node-machine-account-info.priv.json + +$tree ./bootstrap/ +./bootstrap +├── private-root-information +│ └── private-node-info_d60bd55ee616c5c297cae1d5cfb7f65e7e04014d9c4abe595af2fd83f3cfe160 +│ ├── node-info.priv.json +│ ├── node-machine-account-info.priv.json +│ └── node-machine-account-key.priv.json +│ └── secretsdb-key +└── public-root-information + ├── node-id + └── node-info.pub.d60bd55ee616c5c297cae1d5cfb7f65e7e04014d9c4abe595af2fd83f3cfe160.json + +3 directories, 5 files +``` + +After running this step, you should see the `node-machine-account-info.priv.json` file in your `bootstrap` directory as shown above. + +### Verify Machine Account Setup + +After finalizing your machine account setup, you should verify its correctness with the `check-machine-account` command: + +```shell CheckMachineAccount +$ ./boot-tools/bootstrap check-machine-account --access-address access.mainnet.nodes.onflow.org:9000 -o ./bootstrap + DBG read machine account info from disk hash_algo=SHA3_256 key_index=0 machine_account_address=0x284463aa6e25877c machine_account_pub_key=f847b84051bad4512101640772bf5e05e8a49868d92eaf9ebed41030881d95485769afd28653c5c53216cdcda4554384bb3ff6396a2ac04842422d55f0562496ad8d952802038203e8 signing_algo=ECDSA_P256 + DBG checking machine account configuration... machine_account_address=0x284463aa6e25877c role=consensus + DBG machine account balance: 0.10000000 + INF 🤖 machine account is configured correctly +``` + +This command will detect and provide information about common misconfigurations, or confirm that the machine account is configured correctly. \ No newline at end of file diff --git a/static/markdown/networks/node-ops/node-operation/monitoring-nodes.md b/static/markdown/networks/node-ops/node-operation/monitoring-nodes.md new file mode 100644 index 0000000000..ed6ae7908a --- /dev/null +++ b/static/markdown/networks/node-ops/node-operation/monitoring-nodes.md @@ -0,0 +1,92 @@ +--- +title: Monitoring Node Health +sidebar_label: Node Monitoring +sidebar_position: 7 +--- + +A Flow node generates logs and publishes metrics as it runs. These logs and metrics can be used to gain insights into the health of the node. + +## Logs + +Logs are emitted to `stdout` as JSON formed strings. Where these logs are available on your system depends on how you launch your containers. On `systemd` systems for example, the logs will be sent to the system journal daemon `journald`. Other systems may log to `/var/log`. + +## Metrics + +Flow nodes produce health metrics in the form of [Prometheus](https://prometheus.io) metrics, exposed from the node software on `/metrics`. + +If you wish to make use of these metrics, you'll need to set up a Prometheus server to scrape your Nodes. Alternatively, you can deploy the Prometheus Server on top of your current Flow node to see the metrics without creating an additional server. + +> The flow-go application doesn't expose any metrics from the underlying host such as CPU, network, or disk usages. It is recommended you collect these metrics in addition to the ones provided by flow using a tool like node exporter (https://github.com/prometheus/node_exporter) + +1. Copy the following Prometheus configuration into your current flow node + + ```yaml + global: + scrape_interval: 15s # By default, scrape targets every 15 seconds. + + scrape_configs: + # The job name is added as a label `job=` to any timeseries scraped from this config. + - job_name: 'prometheus' + + # Override the global default and scrape targets from this job every 5 seconds. + scrape_interval: 5s + + static_configs: + - targets: ['localhost:8080'] + ``` + +2. Start Prometheus server + ```shell + docker run \ + --network=host \ + -p 9090:9090 \ + -v /path/to/prometheus.yml:/etc/prometheus/prometheus.yml \ + prom/prometheus" + ``` +3. (optional) Port forward to the node if you are not able to access port 9090 directly via the browser + `ssh -L 9090:127.0.0.1:9090 YOUR_NODE` + +4. Open your browser and go to the URL `http://localhost:9090/graph` to load the Prometheus Dashboard + +### Key Metric Overview + +The following are some important metrics produced by the node. + +| Metric Name | Description | +| ------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | +| go\_\* | Go runtime metrics | +| consensus_compliance_finalized_height | Latest height finalized by this node; should increase at a constant rate. | +| consensus_compliance_sealed_height | Latest height sealed by this node; should increase at a constant rate. | +| consensus_hotstuff_cur_view | Current view of the HotStuff consensus algorith; Consensus/Collection only; should increase at a constant rate. | +| consensus_hotstuff_timeout_seconds | How long it takes to timeout failed rounds; Consensus/Collection only; values consistently larger than 5s are abnormal. | + +### Machine Account + +Collection and consensus nodes use a machine account that must be kept funded. See [here](../../staking/11-machine-account.md) for details. + +Nodes check their machine account's configuration and funding and produce metrics. + +| Metric Name | Description | +| ------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | +| machine_account_balance | The current balance (FLOW) | +| machine_account_recommended_min_balance | The recommended minimum balance (FLOW) | +| machine_account_is_misconfigured | 0 if the node is configured correctly; 1 if the node is misconfigured | + +To be notified when your node's machine account needs to be refilled or has a configuration error, you can set up alerts. + +When the machine account balance needs to be refilled: +``` +machine_account_balance < machine_account_recommended_min_balance +``` + +When the machine account has a configuration error: +``` +machine_account_is_misconfigured > 0 +``` + +The metrics include the account address of the machine account (`acct_address` label) for convenience: +``` +# HELP machine_account_balance the last observed balance of this node's machine account, in units of FLOW +# TYPE machine_account_balance gauge +machine_account_balance{acct_address="7b16b57ae0a3c6aa"} 9.99464935 +``` \ No newline at end of file diff --git a/static/markdown/networks/node-ops/node-operation/node-bootstrap.md b/static/markdown/networks/node-ops/node-operation/node-bootstrap.md new file mode 100644 index 0000000000..5f5ad74420 --- /dev/null +++ b/static/markdown/networks/node-ops/node-operation/node-bootstrap.md @@ -0,0 +1,323 @@ +--- +title: Node Bootstrap +sidebar_label: Node Bootstrapping +description: How to get started running a node on Flow +sidebar_position: 8 +--- + +This guide is for getting a new node staked and running on Flow other than a permissionless Access node. For running a permissionless Access node see [Access node setup](../access-nodes/access-node-setup.md). For sporking documentation for existing node operators, see [Spork Process](./spork.md). + +## Timing + +New nodes are able to join the network each time a new epoch begins. +In order to join the network at epoch N+1, the node must be registered with sufficient stake and +authorized by the service account prior to the end of epoch N's Staking Auction Phase. +Confirmation of a new node's inclusion in epoch N+1 is included in the [`EpochSetup` event](../../staking/05-epoch-scripts-events.md#flowepochepochsetup). + +Nodes registered for epoch N+1 are able to participate in network communication on a limited basis starting in the `Epoch Setup Phase` of epoch N. + +![Flow Epoch Schedule](https://storage.googleapis.com/flow-resources/documentation-assets/epoch-startup-order.png) + +Once registered and confirmed to join the network at epoch N+1, the node must start up **before** epoch N+1 begins. +* Verification & Access nodes may start up any time during the `Epoch Setup Phase`. +* Consensus & Collection nodes must start up within the first **1000 views (~30mins)** +of the `Epoch Setup Phase` to participate in the [Epoch Preparation Protocol](../../staking/04-epoch-preparation.md#phase-1-epoch-setup). + +## Step 1 - Run Genesis Bootstrap + +:::info + + You will need to run this process for each node that you are operating + +::: + +### Download the Bootstrapping Kit + +:::warning + +If you have downloaded the bootstrapping kit previously, ensure you check the hash below still matches. If not, re-download to ensure you are using the most up-to-date version. + +::: + +```shell +curl -sL -O storage.googleapis.com/flow-genesis-bootstrap/boot-tools.tar +tar -xvf boot-tools.tar +chmod +x ./boot-tools/bootstrap +chmod +x ./boot-tools/transit +``` + +```shell CheckSHA256 +sha256sum ./boot-tools/bootstrapcmd +460cfcfeb52b40d8b8b0c4641bc4e423bcc90f82068e95f4267803ed32c26d60 ./boot-tools/bootstrap + +sha256sum ./boot-tools/transit +f146bdc82ce0cce73c0fb9de284b2e2639e851120f8b89a1dd9368e8442123b4 ./boot-tools/transit +``` + +### Generate Your Node Keys + +#### Network Address + +:::info + +Use a fully qualified domain name for the network address. Please also include the port number in the network address e.g. `example.com:3569` + +::: + +:::warning + +Do not include in `http://` format. + +::: + +:::info + +If you are running multiple nodes, please +ensure you have different addresses for each node. + +::: + +:::warning + +All your current keys and Flow genesis files should be in the `bootstrap` +folder created earlier. Please take a back up of the entire folder. + +::: + +```shell +## Skip this section if this is your first time ## +# If you joined our network previously, make sure to take a backup of your previously generated keys! +cp -r /path/to/bootstrap /path/to/bootstrap.bak +######################################################### +# Generate Keys +$ mkdir ./bootstrap +# YOUR_NODE_ADDRESS: FQDN associated to your instance (do NOT use an IP address, use a hostname) +# YOUR_NODE_ROLE: The Flow nodes that you wish to run, it should be ONE of the following - [ access, collection, consensus, execution, verification ] +$ ./boot-tools/bootstrap key --address \"YOUR_NODE_ADDRESS_GOES_HERE:3569\" --role YOUR_NODE_ROLE_GOES_HERE -o ./bootstrap + +``` + +```shell Example +$./boot-tools/bootstrap key --address "consensus-001.nodes.flow.com:3569" --role consensus -o ./bootstrap + DBG will generate networking key + INF generated networking key + DBG will generate staking key + INF generated staking key + DBG will generate db encryption key + INF generated db encryption key + DBG assembling node information address=consensus-001.nodes.flow.com:3569 + DBG encoded public staking and network keys networkPubKey=7f31ae79017a2a58a5e59af9184f440d08885a16614b2c4e361019fa72a9a1a42bf85b4e3f9674782f12ca06afd9782e9ccf19496baed069139385b82f8f40f6 stakingPubKey=829d086b292d84de8e7938fd2fafa8f51a6e025f429291835c20e59d9e25665febf24fa59de12a4df08be7e82c5413180cc7b1c73e01f26e05344506aaca4fa9cc009dc1c33f8ba3d7c7509e86d3d3e7341b43b9bf80bb9fba56ae0b3135dd72 + INF wrote file bootstrap/public-root-information/node-id + INF wrote file bootstrap/private-root-information/private-node-info_ab6e0b15837de7e5261777cb65665b318cf3f94492dde27c1ea13830e989bbf9/node-info.priv.json + INF wrote file bootstrap/private-root-information/private-node-info_5e44ad5598bb0acb44784f629e84000ffea34d5552427247d9008ccf147fb87f/secretsdb-key + INF wrote file bootstrap/public-root-information/node-info.pub.ab6e0b15837de7e5261777cb65665b318cf3f94492dde27c1ea13830e989bbf9.json + DBG will generate machine account key + INF generated machine account key + DBG assembling machine account information address=consensus-001.nodes.flow.com:3569 + INF encoded machine account public key for entry to Flow Port machineAccountPubKey=f847b8406e8969b869014cd1684770a8db02d01621dd1846cdf42fc2bca3444d2d55fe7abf740c548639cc8451bcae0cd6a489e6ff59bb6b38c2cfb83e095e81035e507b02038203e8 + INF wrote file bootstrap/private-root-information/private-node-info_ab6e0b15837de7e5261777cb65665b318cf3f94492dde27c1ea13830e989bbf9/node-machine-account-key.priv.json + +$tree ./bootstrap/ +./bootstrap +├── private-root-information +│ └── private-node-info_ab6e0b15837de7e5261777cb65665b318cf3f94492dde27c1ea13830e989bbf9 +│ ├── node-info.priv.json +│ ├── node-machine-account-key.priv.json +│ └── secretsdb-key +└── public-root-information + ├── node-id + └── node-info.pub.ab6e0b15837de7e5261777cb65665b318cf3f94492dde27c1ea13830e989bbf9.json + +3 directories, 4 files +``` + +:::info + +For `consensus` and `collection` node types an additional key will be created for the Machine Account. +For all other node types this will not be needed. + +::: + +#### Machine Account Creation + +If you are running a collection and consensus node, you will have an additional private key file (`node-machine-account-key.priv.json`) +which contains the private key for your node's machine account. You can learn more about machine +accounts [here](../../staking/11-machine-account.md). + +In Step 2 of this guide, when you submit a transaction to stake your node, you will need to provide the +machine account public key, which can be found in the output of the previous `bootstrap key` command. + +```shell MachineAccountPublicKey +$./boot-tools/bootstrap key --address YOUR_NODE_ADDRESS_GOES_HERE --role YOUR_NODE_ROLE_GOES_HERE -o ./bootstrap +... + DBG encoded public machine account key machineAccountPubKey=1b9c00e6f0930792c5738d3397169f8a592416f334cf11e84e6327b98691f2b72158b40886a4c3663696f96cd15bfb5a08730e529f62a00c78e2405013a6016d + INF wrote file bootstrap/private-root-information/private-node-info_ab6e0b15837de7e5261777cb65665b318cf3f94492dde27c1ea13830e989bbf9/node-machine-account-key.priv.json +``` + +:::warning + +Copy the machine account public key somewhere safe. You will need it in a later step. + +::: + +## Step 2 - Stake Your Node + +Stake your node via [Flow Port](https://port.onflow.org/) + +The `node details` (`Node ID`, `Network Address`, `Networking Key` and `Staking Key`) that need to be submitted when staking the node on Flow Port, can be found in the file: `./bootstrap/public-root-information/node-info.pub..json`. + +```shell Example +$cat ./bootstrap/public-root-information/node-info.pub.39fa54984b8eaa463e129919464f61c8cec3a4389478df79c44eb9bfbf30799a.json +{ + "Role": "consensus", + "Address": "consensus-001.nodes.flow.com:3569", + "NodeID": "39fa54984b8eaa463e129919464f61c8cec3a4389478df79c44eb9bfbf30799a", + "Weight": 0, + "NetworkPubKey": "d92e3d5880abe233cf9fe9104db34bbb31251468a541454722b3870c04156a1b0504aef443bcaad124b997384b8fe7052847ce1e6189af1392d865e6be69835b", + "StakingPubKey": "917826e018f056a00b778a58ae83054906957ffd4b6f1b7da083551f7a9f35e02b76ace50424ed7d2c9fc69207a59f0f08a031048f5641db94e77d0648b24d150dedd54bab7cd44b4aa60cfd54be418647b0b3965f8ae54c0bcb48ae9d705162" +} +``` + +If you are running a collection or consensus node, you will need to provide an additional field `Machine Account Public Key`. +This value is found in the output of the `bootstrap key` command from Step 1. + +Staking a collection or consensus node will also create a machine account for the node. The machine account will be mentioned in the output of the staking transaction displayed by Flow Port. Please save the machine account for the next step. + +:::info + +Please let us know your node id via discord or email. + +::: + +### Finalize Machine Account Setup + +:::warning + +If you are not running a collection or consensus node, you can skip this step. + +::: + +You will now need to use the `bootstrap` utility to run `machine-account` with the created address to finalize the set up of your Machine account. + +```shell +$ ./boot-tools/bootstrap machine-account --address YOUR_MACHINE_ACCOUNT_ADDRESS_GOES_HERE -o ./bootstrap +``` + +```shell Example +$ ./boot-tools/bootstrap machine-account --address 0x1de23de44985c7e7 -o ./bootstrap + INF read machine account private key json + DBG encoded public machine account key machineAccountPubKey=2743786d1ff1bf7d7026d693a774210eaa54728343859baab62e2df7f71a370651f4c7fd239d07af170e484eedd4f3c2df47103f6c39baf2eb2a50f67bbcba6a + INF wrote file bootstrap/private-root-information/private-node-info_6f6e98c983dbd9aa69320452949b81abeab2ac591a247f55f19f4dbf0b477d26/node-machine-account-info.priv.json + +$tree ./bootstrap/ +./bootstrap +├── private-root-information +│ └── private-node-info_d60bd55ee616c5c297cae1d5cfb7f65e7e04014d9c4abe595af2fd83f3cfe160 +│ ├── node-info.priv.json +│ ├── node-machine-account-info.priv.json +│ ├── node-machine-account-key.priv.json +│ └── secretsdb-key +└── public-root-information + ├── node-id + └── node-info.pub.d60bd55ee616c5c297cae1d5cfb7f65e7e04014d9c4abe595af2fd83f3cfe160.json + +3 directories, 5 files +``` + +After running this step, you should see the `node-machine-account-info.priv.json` file in your `bootstrap` directory as shown above. + +### Verify Machine Account Setup + +After finalizing your machine account setup, you should verify its correctness with the `check-machine-account` command: + +```shell CheckMachineAccount +$ ./boot-tools/bootstrap check-machine-account --access-address access.mainnet.nodes.onflow.org:9000 -o ./bootstrap + DBG read machine account info from disk hash_algo=SHA3_256 key_index=0 machine_account_address=0x284463aa6e25877c machine_account_pub_key=f847b84051bad4512101640772bf5e05e8a49868d92eaf9ebed41030881d95485769afd28653c5c53216cdcda4554384bb3ff6396a2ac04842422d55f0562496ad8d952802038203e8 signing_algo=ECDSA_P256 + DBG checking machine account configuration... machine_account_address=0x284463aa6e25877c role=consensus + DBG machine account balance: 0.10000000 + INF 🤖 machine account is configured correctly +``` + +This command will detect and provide information about common misconfigurations, or confirm that the machine account is configured correctly. + +### Push transit keys (consensus node only) + +If you are running a consensus node, run the following command to generate the transit keys. + +```shell transit +$ ./boot-tools/transit prepare -b ./bootstrap -r consensus + INF running prepare + INF generating key pair + INF completed preparation role=consensus +``` + +This will generate the public and private transit keys under the bootstrap folder. +The transit keys are used to transfer the DKG keys after a network upgrade. + +Please share the **public** transit key with the Flow Foundation via [discord](https://discord.gg/flow) or [email](mailto::governance@flow.com). + +## Step 3 - Start Your Flow Node + +Ensure you have configured your node using the [Node Setup guide](./node-setup.md). + +### Confirming authorization + +You can confirm your node's successful registration and authorization by executing a Cadence script to query the [Staking Contract](../../../build/core-contracts/06-staking-contract-reference.md#contract). +At the end of the `Staking Auction Phase`, the members of the Proposed Identity Table are confirmed as authorized participants in the next epoch. +Therefore, if your node ID appears in the Proposed Identity Table during the `Staking Auction Phase`, your node will be a participant in the next epoch. + +You can read the current Proposed Identity Table using the [getProposedTable script](https://github.com/onflow/flow-core-contracts/blob/master/transactions/idTableStaking/scripts/get_proposed_table.cdc). + +You can read the current epoch phase using the [getEpochPhase script](https://github.com/onflow/flow-core-contracts/blob/master/transactions/epoch/scripts/get_epoch_phase.cdc). (A return value of `0` indicates the `Staking Auction Phase`.) + +### Trusted Root Snapshot + +Once your node has been registered and authorized by the service account, it will be able to participate in the next epoch. + +![Flow Epoch Schedule](https://storage.googleapis.com/flow-resources/documentation-assets/epoch-startup-order.png) + +A new node must bootstrap with a trusted root snapshot of the protocol state, where the node is a confirmed participant. +Since new nodes are confirmed at the end of the `Staking Auction Phase`, this means that, if the node is registered to join at epoch `N+1`, it must use a root snapshot from within the `Epoch Setup Phase` of epoch `N`. + +### Dynamic Startup + +Flow provides a mechanism called Dynamic Startup to simplify the process of obtaining the root snapshot. +When using Dynamic Startup, the node can be started **at any time during the `Staking Auction Phase`**. +The node will wait for the `Epoch Setup Phase` to begin, retrieve a valid root snapshot from a trusted Access Node, then bootstrap its state and join the network. +This is the recommended way to start your node for the first time. + +1. Remove any `root-protocol-state-snapshot.json` file from your `bootstrap` folder. (If this file is present the node will attempt to bootstrap with it rather than Dynamic Startup.) +2. Select a trusted Access Node to provide the root snapshot. You will need this node's **secure GRPC server address** and **Networking Public Key**. +3. Configure Dynamic Startup by adding flags: +```shell ExampleDynamicStartupFlags + ... \ + --dynamic-startup-access-address=secure.mainnet.nodes.onflow.org:9001 \ + --dynamic-startup-access-publickey=28a0d9edd0de3f15866dfe4aea1560c4504fe313fc6ca3f63a63e4f98d0e295144692a58ebe7f7894349198613f65b2d960abf99ec2625e247b1c78ba5bf2eae +``` +4. Start your node (see [guide](./node-setup#start-the-node)) + +:::info + +Once the node has bootstrapped, these flags will be ignored and may be removed. + +::: + +### Manually Provisioned Root Snapshot + +You can also provision the root snapshot file manually, then start the node without configuring Dynamic Startup. +See [here](./protocol-state-bootstrap.md) for the available options to provision a Root Snapshot. + +:::warning + +The snapshot must be within the `Epoch Setup Phase`. + +::: + +:::warning + +Since Collection and Consensus Nodes must start up in the first ~30mins of the `Epoch Setup Phase` (see [Timing](./node-bootstrap.md#timing)), +the snapshot must be provisioned within this time window. + +::: + +Once a valid root snapshot file is downloaded to the node's bootstrap folder, it can be started (see [guide](./node-setup.md#start-the-node)) \ No newline at end of file diff --git a/static/markdown/networks/node-ops/node-operation/node-economics.md b/static/markdown/networks/node-ops/node-operation/node-economics.md new file mode 100644 index 0000000000..e57a505845 --- /dev/null +++ b/static/markdown/networks/node-ops/node-operation/node-economics.md @@ -0,0 +1,35 @@ +--- +title: Node Economics +sidebar_label: Node Economics +description: Node Operator Economics - An illustration +sidebar_position: 8 +--- + +Node operators play a crucial role in securing the Flow network. Here’s a simple example to illustrate what node operators can expect in terms of node economics. + +## Node Operator Economics: An illustration + +:::warning + +This illustration is strictly to serve as an example. Actual numbers will vary based on several factors. + +For real-time numbers, please refer to the [block explorer](https://www.flowscan.io/tokenomics). + +::: + +| # | Parameter | Value | Explanation | +| -------- | ------------- | ------------- | ------------- | +| A| Node Operator’s Stake | 500,000 FLOW | Assuming minimum staking requirements for a consensus node. Remember there’s no upper cap on how much FLOW can be staked to a Flow node. | +| B| Delegation to node | 1,000,000 FLOW | Funds that individual/ institutional delegators delegate to your node. Assuming 1M FLOW for this example. | +| C | APY | 10% | Subject to change based on total ecosystem stake in each epoch. Remember APY = R / S, where S = Total FLOW Staked / Total FLOW Supply and R = 5% (”reward rate”) | +| D | Delegation Rate | 8% | Fee taken by the node operator from delegator rewards to cover their operating expenses, currently set at 8% of the rewards received by delegators. Note that the 8% fee is only applied to the staking reward, not to the tokens delegated. | +| E | Annual Staking Rewards | 50,000 FLOW | Product of A x C; the number shown is annualized but is paid each epoch (week). | +| F | Annual Delegator Fee | 8,000 FLOW | Product of B x C x D; ; the number shown is annualized but is paid each epoch (week). | +| G | Annual (Gross) Rewards | 58,000 FLOW | Sum of E and F | +| H | COGS | 4,190 FLOW | Assumed costs of running a consensus node in FLOW assuming 1US$/FLOW. The actual cost will vary depending on several factors such as self-hosted vs cloud, bare metal vs VM, the type of node, the FLOW exchange rate. | +| J | Net Annual Rewards | 53,810 FLOW | G less H | + +## Note + +1. Each year, 5% of the total Flow supply is distributed as rewards to incentivize validators and delegators. While the total rewards for each epoch are fixed, the rewards for individual stakers vary depending on the amount they stake and the total funds delegated to their node. +2. All Flow node types follow the same economic principles, with the only difference being their minimum staking requirements. For details on the minimum stakes needed for each node type, see [here](https://flow.com/flow-tokenomics/technical-overview). \ No newline at end of file diff --git a/static/markdown/networks/node-ops/node-operation/node-migration.md b/static/markdown/networks/node-ops/node-operation/node-migration.md new file mode 100644 index 0000000000..bea9fdca1a --- /dev/null +++ b/static/markdown/networks/node-ops/node-operation/node-migration.md @@ -0,0 +1,55 @@ +--- +title: Node Migration +description: How to migrate a Flow node from one machine to another +sidebar_position: 9 +--- + +There are a few different methods to migrate a running Flow node from one machine to the other. + +Choose the method depending upon what part of the staking data of the node is changing. + +### Method 1 - No change to the node staking data + +If there is no change to the network address or the staking and networking keys and only the hardware the node is running needs to be changed then do the following: +1. Stop the Flow node. +2. Copy over the bootstrap data (typically under `/var/flow/bootstrap`) which contains the node private key to the new machine. +3. Copy over the data folder (typically under `/var/flow/data`) which contains the state data. +4. Start the new node on the same network address as the old one. + +:::warning + +Please ensure that there is minimal downtime during this migration. + +::: + +:::warning + +The network address is currently part of the staking data that was submitted for the node. It is how other nodes in the network discover this node. +Hence, the network address of the node must stay the same between epochs otherwise the node will become unreachable for the other nodes and stop functioning. + +::: + +### Method 2 - Network address change + +A change to the node network address (IP or a hostname) can only be done during the spork process. + +To change the networking address: +1. A day before the [upcoming mainnet spork](./upcoming-sporks.md), change the network address for the nodes in Flow Port (using the update network address feature). +The change will not take effect till an epoch transition happens. +2. Change the addresses in the `/var/flow/bootstrap/private-root-information/private-node-info_/node-info.priv.json` json file on the node. +3. A spork also causes an epoch transition, and the new addresses will take effect after the spork immediately. + +### Method 3 - Staking or networking key change + +If the node after migration will be using new staking or networking keys then it needs to be unstaked and then re-staked with the new keys. + +1. Unstake the node via Flow Port. +2. Register the new node via Flow Port with the new staking information. +3. Run the new node with the new keys and network address. It should be able to join the network at the next epoch (see [timing](./node-bootstrap.md#timing)) + +:::warning + +Unstaking a node will result in the node [not earning rewards](../../staking/06-technical-overview.md#staking-operations-available-to-all-stakers) for the next epoch. +Delegators to the old node will have their tokens unstaked automatically. They will also stop earning rewards unless they withdraw their unstaked tokens and delegate them to a different node. + +::: \ No newline at end of file diff --git a/static/markdown/networks/node-ops/node-operation/node-providers.md b/static/markdown/networks/node-ops/node-operation/node-providers.md new file mode 100644 index 0000000000..c2163b030d --- /dev/null +++ b/static/markdown/networks/node-ops/node-operation/node-providers.md @@ -0,0 +1,27 @@ +--- +sidebar_position: 18 +description: | + Easy access to Flow's blockchain. Providers handle the technical work, letting you use Flow's features without managing nodes yourself. +sidebar_custom_props: + icon: 📚 +--- + +# Node Providers + +## Quick Node + +[QuickNode](https://www.quicknode.com/chains/flow) offers convenient access to Flow's blockchain infrastructure, allowing developers and businesses to utilize Flow's capabilities without the complexities of managing nodes themselves. It offers reliable and fast connectivity to blockchain networks, sparing users from the resource-intensive task of running their own full nodes. + +### Supported Networks + +- Testnet +- Mainnet + +## Tatum + +[Tatum](https://tatum.io/) provides a comprehensive platform that simplifies the process of building, testing, and deploying blockchain applications. With Tatum, users can access infrastructure, an SDK, and a unified API to develop blockchain apps without the need to handle individual blockchain node configuration or maintenance. + +### Supported Networks + +- Testnet +- Mainnet \ No newline at end of file diff --git a/static/markdown/networks/node-ops/node-operation/node-provisioning.md b/static/markdown/networks/node-ops/node-operation/node-provisioning.md new file mode 100644 index 0000000000..06c9e5f866 --- /dev/null +++ b/static/markdown/networks/node-ops/node-operation/node-provisioning.md @@ -0,0 +1,101 @@ +--- +title: Provisioning a Flow node +sidebar_label: Node Provisioning +description: Hardware, networking and Operating system setup for a Flow node +sidebar_position: 10 +--- + +## Hardware Requirements + +The hardware your Node will need varies depending on the role your Node will play in the Flow network. For an overview of the differences see the [Node Roles Overview](./node-roles.md). + +| Node Type | CPU | Memory | Disk | Example GCP Instance | Example AWS Instance | +|:----------------:| ---------:| ------:| ------:|:--------------:|:--------------:| +| **Collection** | 4 cores | 32 GB | 200 GB | n2-highmem-4 | r6i.xlarge | +| **Consensus** | 2 cores | 16 GB | 200 GB | n2-standard-4 | m6a.xlarge | +| **Execution** | 128 cores | 864 GB | 9 TB (with maintenance see: [pruning chunk data pack](https://forum.flow.com/t/execution-node-upgrade-to-v0-31-15-and-managing-disk-space-usage/5167) or 30 TB without maintenance) | n2-highmem-128 | | +| **Verification** | 2 cores | 16 GB | 200 GB | n2-highmem-2 | r6a.large | +| **Access** | 16 cores | 64 GB | 750 GB | n2-standard-16 | m6i.4xlarge | +| **Observer** | 2 cores | 4 GB | 300 GB | n2-standard-4 | m6i.xlarge | +| **EVM Gateway** | 2 cores | 32 GB | 30 GB | n2-highmem-4 | r6i.xlarge | + +_Note: The above numbers represent our current best estimate for the state of the network. These will be actively updated as we continue benchmarking the network's performance._ + +## Networking Requirements + +Most of the load on your nodes will be messages sent back and forth between other nodes on the network. Make sure you have a sufficiently fast connection; we recommend at _least_ 1Gbps, and 5Gbps is better. + +Each node will require a fixed DNS name and we will refer to this more generally as your 'Node Address' from here on out. + + + Your Node Address must be a publicly routable valid DNS name + that points to your node. This is how other nodes in the network will + communicate with you. + + +Your firewalls must expose **TCP/3569** for both, ingress and egress. + +If you are running an Access Node, you must also expose the GRPC port **9000** to your internal network traffic. Port 9000 is not required for external ingress/egress. + +![Flow Architecture](flow-architecture.png) + +## Operating System Requirements + +The Flow node code is distributed as a Linux container image, so your node must be running an OS with a container runtime like [docker](https://docker.com) or [containerd](https://containerd.io). + +The bootstrapping scripts we'll use later are compiled binaries targeting an `amd64` architecture, so your system must be 64-bit. Some of these scripts are bash based hence a shell interpreter that is bash compatible will also be needed. + +Flow also provides `systemd` service and unit files as a template for installation, though `systemd` is not required to run Flow. + + + Flow is distributed in such a way that makes it very system agnostic. You are + free to build your own orchestration around how you run your nodes and manage + your keys. + + For the remainder of this guide, we cover the most simple case, a single node being + hand deployed. This should give you a good sense of what's needed, and you can + modify to suit your needs from there. + + The Flow team has tested running nodes on Ubuntu 18.04 and GCP's Container + Optimized OS, which is based on Chromium OS. If you are unsure where to start, + those are good choices. + + +## Time synchronization + +You should also ensure you run **time synchronization** on the machine hosting the container, to avoid clock drift. In practice, this means configuring a client for the NTP protocol, and making sure it runs as a daemon. `ntpd` is one recommended example. To configure it, you just have to point it to an NTP server to query periodically. A default from your Linux distribution or cloud operator may already be set, and in the interest of decentralization, our recommendation would be to use it unless you have a specific reason to do otherwise. + + + + - **Leap-smearing**: Leap-smearing time servers and non-leap-smearing time servers are both acceptable for the magnitude of our time precision requirements - though considering very few providers offer leap smearing time servers, a "regular" time server helps ensure our pool of time providers is more diverse. + + - **Why not do it in the container itself? Why do we need to do this?**: Without special privileges and in all major container runtimes, a container will not run with the `CAP_SYS_TIME` capability. For Flow, this means that the node software itself cannot change the time of the host machine, making the in-container use of standard time synchronization protocols ineffective. + + - **Why does time matter in Flow?**: Time information comes up in consensus and in smart contracts. The consensus algorithm of Flow allows nodes to exit the influence of a corrupt or ineffective "leader" node by collectively deciding to switch to the next "phase" of the protocol at the right time. The smart contract language also allows developer access to block time stamps, which provide an approximation of time. To resist manipulation in each case, honest nodes must compute timing values from an aggregate of the information provided by all nodes. That approach, though resilient, is still sensitive to inaccurate time information. In other words, a node subject to clock drift but otherwise honest will not stop the consensus, but might make it slower. + + + +## Setup Data Directories & Disks + +Flow stores protocol state on disk, as well as execution state in the case of execution nodes. + +Where the data is stored is up to you. By default, the `systemd` files that ship with Flow use `/var/flow/data`. +This is where the vast majority of Flow's disk usage comes from, so you may wish to mount this directory on a separate disk from the OS. +The performance of this disk IO is also a major bottleneck for certain node types. +While all nodes need to make use of this disk, if you are running an execution node, you should make sure this is a high performing SSD. + +As a rough benchmark for planning storage capacity, each Flow block will grow the data directory by 3-5KiB. + +### Confidential Data & Files + +Flow stores dynamically generated confidential data in a separate database. We strongly recommend enabling encryption +for this database - see [this guide](./db-encryption-existing-operator.md) for instructions. + +Confidential information used by Flow is stored in the `private-root-information` subtree of the `bootstrap` folder. +In particular: +* the staking private key (`node-info.priv.json`) +* the networking private key (`node-info.priv.json`) +* the encryption key for the secrets database (`secretsdb-key`) +* (if applicable) the initial random beacon private key (`random-beacon.priv.json`) + +These files contain confidential data, and must be stored and accessed securely. \ No newline at end of file diff --git a/static/markdown/networks/node-ops/node-operation/node-roles.md b/static/markdown/networks/node-ops/node-operation/node-roles.md new file mode 100644 index 0000000000..ab9883bcce --- /dev/null +++ b/static/markdown/networks/node-ops/node-operation/node-roles.md @@ -0,0 +1,68 @@ +--- +title: Node Roles +sidebar_position: 11 +--- + +Unlike most blockchains, not all Flow nodes are equal. Flow nodes all specialize and fulfill a specific role in the operation of the network. +Collection, consensus, execution, verification and access nodes are all staked nodes while the observer node is not staked. + +## Collection + +Collection nodes are bandwidth-optimized nodes divided by the protocol into several cooperating Clusters. Their first task is managing the transaction pool and collecting well-formed transactions to propose to Consensus nodes. Transactions are assigned to a cluster pseudorandomly by transaction hash. A well-formed transaction must include credentials from the guarantor of the transaction. When a Collection Node sees a well-formed transaction, it hashes the text of that transaction and signs the transaction to indicate two things: first, that it is well-formed; and second, that it will commit to storing the transaction text until the Execution nodes have finished processing it. Each cluster collects transactions, assembles them into Collections and submits a Collection Guarantee signed by a super-majority of the cluster to the Consensus nodes. + +Collection nodes are required to stake a minimum of 250,000 FLOW to be a confirmed node operator. + +## Consensus + +Consensus nodes form and propose blocks in a manner similar to traditionally-structured proof-of-stake blockchains, using the HotStuff consensus algorithm to create a globally consistent chain of blocks. Consensus nodes validate that the signed collection hashes submitted to them by Collection nodes were, in fact, signed by the required majority of Collection nodes. Thereafter, the Consensus nodes assemble the transactions into blocks and finalize them through voting. +The more participants there are in this process, the more decentralized the network. However, consensus algorithms typically bottleneck the limit to the number of participants. The Flow protocol chose the HotStuff algorithm because it is flexible enough to add participants and currently supports about 100 operators. Adding more than 100 participants to the protocol by adapting HotStuff will continue to be an area of active development. + +Consensus nodes act as checkpoints against other Collection nodes. They are responsible for checking that a critical number of Collection nodes reviewed and signed for the transaction. Collection nodes are held accountable by Consensus nodes. A common concern with proof-of-work- and proof-of-stake based systems is that a small subset of the population of nodes can control important resources such as the mining or stake needed to produce and vote on blocks, which is a degradation of the security of the system. By lowering the requirements to participate, Flow makes it extremely difficult and expensive to coordinate a Byzantine majority of Consensus nodes. + +Consensus nodes have minimal bandwidth and computation requirements, allowing even a modest computing device (any consumer-grade hardware) to participate in the voting process and ensure the safety of the network. Many networks claim open participation, yet substantial resources — stake, computation, or otherwise — are needed to partake. Maintaining such barriers to entry undermines the security of the network. Lowering the participation requirements preserves the security of the network by providing a high degree of byzantine fault tolerance since it becomes exceedingly difficult for a subset of bad actors to subvert the network. + +Consensus nodes are required to stake a minimum of 500,000 FLOW to be a confirmed node operator. + +## Execution + +Execution nodes are the most resource-intensive nodes on the Flow network, responsible for executing transactions and maintaining the Execution State — a cryptographically-verifiable data store for all user accounts and smart contract states — as well as responding to queries related to it. Execution nodes compute the outputs of the blocks they are provided. They then ask the Collection nodes for the collections which contain transactions waiting to be executed. With this data they are able to compute the output, which is later verified by Verification nodes to ensure honesty (allocation of Verification nodes is via a sortition algorithm). The Execution nodes are primarily responsible for Flow's improvements in scale and efficiency because only a very small number of these powerful compute resources are required to compute and store the historical state. + +Execution nodes give the Flow network its performance characteristics: highly scalable within a single shared state environment (i.e., no sharding). However, the significant hardware requirements make them the least accessible option for participation as a Validator. Because the revenue pool splits between relatively few nodes, the revenue per-node should more than compensate for the high capital costs of operating this node. + +An Execution Node presents a hashed commitment once it has computed the output. The output is only revealed once its co-executors have also submitted their outputs. This is important to ensure nodes aren't spoofing each other's work. Once they've all submitted their answers, the output is revealed and subjected to random queries and checks run by Verification nodes. The Execution nodes have relatively low byzantine fault tolerance. However, this does not compromise the overall security of the system because the process they perform is deterministic -- any bad actor will easily be detected and punished by Verification nodes. + +This relatively small group of nodes has the most substantial technical requirements for processor speed and bandwidth because they are tasked with all the computations necessary to determine the output of the network. Allowing for this degree of specialization can reduce computation costs by at least one thousand times, and possibly much more, when compared to Ethereum. + +Execution nodes are required to stake a minimum of 1,250,000 FLOW to be a confirmed node operator. + +## Verification + +Verification nodes are responsible for confirming the correctness of the work done by Execution nodes. Individual Verification nodes only check a small amount of the total computation, but collectively they check every computation many times in parallel. Verification nodes verify Execution Receipts provided by Execution nodes and issue Result Approvals. A sortition algorithm determines which chunks of the Execution Receipt from the Execution nodes the Verification Node must query to check they were computed correctly. Ultimately, these nodes keep the Execution nodes honest; this balance of power maintains the access, security, and verifiability criteria of decentralization. It is highly byzantine fault tolerant because even if there is a substantial number of byzantine errors in the Verification Node +pool, the Consensus nodes are still required to approve that transactions they signed were reviewed by a critical amount of the network. + +Verification nodes are required to stake a minimum of 135,000 FLOW to be a confirmed node operator. + +## Access + +Access nodes act as a proxy to the Flow network. The Access node routes transactions to the correct collection node and routes state queries to execution nodes (while likely caching state to answer queries in a timely manner in the future). Clients submit their transactions to any Access node or run their own if they can't find a service provider they're happy with. + +Access nodes are required to stake 100 FLOW to be a confirmed node operator. However, since an access node does not participate in block production, it does not receive any staking rewards. + +## Observer + +An observer node provides locally accessible, continuously updated, verified copy of the block data. It serves the Access API but unlike an access node, an observer node does not need to be staked, and **anyone** can run it without being added to the approved list of nodes. + +[Get started running an observer node](../light-nodes/observer-node.md) + +## + +Here is a comparison of the different node roles, + +| Role | Staked | Recives Rewards | Permissioned | +| :---------------|:---------------:| :---------------:|:---------------:| +| Collection | Yes | Yes | Yes | +| Consensus | Yes | Yes | Yes | +| Execution | Yes | Yes | Yes | +| Verification | Yes | Yes | Yes | +| Access | Yes | No | No 🆕 | +| Observer | No | No | No | \ No newline at end of file diff --git a/static/markdown/networks/node-ops/node-operation/node-setup.md b/static/markdown/networks/node-ops/node-operation/node-setup.md new file mode 100644 index 0000000000..63f8f42560 --- /dev/null +++ b/static/markdown/networks/node-ops/node-operation/node-setup.md @@ -0,0 +1,300 @@ +--- +title: Setting Up a Flow Node +sidebar_label: Node Setup +description: How to run a Collection, Consensus, Verification and Execution node +sidebar_position: 12 +--- + +This guide is for running a Collection, Consensus, Verification and Execution node. +If you are planning to run an Access node then refer to [access node setup](../access-nodes/access-node-setup.md). + +First you'll need to provision a machine or virtual machine to run your node software. Please see follow the [node-provisioning](./node-provisioning.md) guide for it. + +## Pull the Flow Images + +The `flow-go` binaries are distributed as container images, and need to be pulled down to your host with your image management tool of choice. + +Replace `$ROLE` with the node type you are planning to run. Valid options are: + +- collection +- consensus +- execution +- verification +- access + +```shell + # Docker + docker pull gcr.io/flow-container-registry/${ROLE}:alpha-v0.0.1 + + # Containerd + ctr images pull gcr.io/flow-container-registry/${ROLE}:alpha-v0.0.1", +``` + +## Prepare Your Node to Start + +Your nodes will need to boot at startup, and restart if they crash. + +If you are running `systemd` you can use the service files provided by `flow-go`. +Find them in the [Flow Go](https://github.com/onflow/flow-go/tree/master/deploy). + +If you are using some other system besides Systemd, you need to ensure that the Flow container is started, +the appropriate key directories are mounted into the container, and that the container will +automatically restart following a crash. + +The `systemd` files pull runtime settings from `/etc/flow/runtime-config.env` and any `.env` +files under `/etc/flow/conf.d`. Examples of these files are also available in the github repo. +You will need to modify the runtime config file later. + +### Systemd + + +If you are not using Systemd, you can skip this step + + +1. Ensure that you pulled the latest changes from [flow-go repository](https://github.com/onflow/flow-go) via `git` + +```shell +## Clone the repo if you haven't already done so +git clone https://github.com/onflow/flow-go + +## Get latest changes +cd flow-go +git pull origin master +``` + +2. Copy your respective [systemd unit file](https://github.com/onflow/flow-go/tree/master/deploy/systemd-docker) to: `/etc/systemd/system` +3. Create directory `sudo mkdir /etc/flow` +4. Copy the [runtime-conf.env](https://github.com/onflow/flow-go/blob/master/deploy/systemd-docker/runtime-conf.env) file to: `/etc/flow/` +5. Enable your service `sudo systemctl enable flow-$ROLE.service` (replace `$ROLE` with your node role - eg. `collection`) + +### Docker Configuration + +If you are not using Systemd, sample commands for running each Docker container are below. +Be sure to replace `/path/to/data` and `/path/to/bootstrap` with the appropriate paths you are using. + +:::warning + +Do not run your node using `docker run` command directly without a mechanism for the node +to automatically restart following a crash. + +::: + +:::info + +The actual Docker image tag can be found [here](./past-upgrades) for appropriate spork. + +::: + +### System Configuration + +Flow nodes create connections to other nodes on the network, which are represented as file descriptors by the OS. Depending on the default +limits for your machine, you may need to increase the soft limit available to the node software. + +Make sure the soft limit is at least `8192`. + +You can configure the ulimit for the node's docker container. See the [Docker documentation](https://docs.docker.com/engine/networks/commandline/run/#ulimit) for more details. + +### Admin Server + +Each node can be configured with an admin server, which allows you to control some of the node's configuration, as well as view some of its internal state. You can find +a few of the commands in the Admin Server [README](https://github.com/onflow/flow-go/blob/master/admin/README.md). Two commands to highlight are: + +* `list-commands`: which returns a list of all of the available commands for your node +* `set-log-level`: which allows you to change the log level of your node at runtime + +You can enable the admin server by passing the `--admin-addr` flag with an interface and port. + +> ⚠️ _IMPORANT: The admin server can modify your node's configuration. DO NOT allow access to untrusted clients._ + +### Access + +```shell +docker run --rm \ + -v /path/to/bootstrap:/bootstrap:ro \ + -v /path/to/data:/data:rw \ + --name flow-go \ + --network host \ + --ulimit nofile=8192 \ + gcr.io/flow-container-registry/access: \ + --nodeid=${FLOW_GO_NODE_ID} \ + --bootstrapdir=/bootstrap \ + --datadir=/data/protocol \ + --secretsdir=/data/secrets \ + --execution-data-dir=/data/execution_data \ + --rpc-addr=0.0.0.0:9000 \ + --http-addr=0.0.0.0:8000 \ + --admin-addr=0.0.0.0:9002 \ + --collection-ingress-port=9000 \ + --script-addr=${FLOW_NETWORK_EXECUTION_NODE} \ + --bind 0.0.0.0:3569 \ + --loglevel=error +``` + +### Collection + +```shell +docker run --rm \ + -v /path/to/bootstrap:/bootstrap:ro \ + -v /path/to/data:/data:rw \ + --name flow-go \ + --network host \ + --ulimit nofile=8192 \ + gcr.io/flow-container-registry/collection: \ + --nodeid=${FLOW_GO_NODE_ID} \ + --bootstrapdir=/bootstrap \ + --datadir=/data/protocol \ + --secretsdir=/data/secrets \ + --ingress-addr=0.0.0.0:9000 \ + --admin-addr=0.0.0.0:9002 \ + --bind 0.0.0.0:3569 \ + --access-node-ids=4e17496619df8bb4dcd579c252d9fb026e54995db0dc6825bdcd27bd3288a990,7e3fe64ccc119f578a7795df8b8c512e05409bdc7de4f74259c6f48351fecb26,416c65782048656e74736368656c009530ef3ab4b8bf83b24df54fe5f81853de,416e647265772042757269616e00d219355d62b9adad8ebd3fab223a1cf84c22 \ + --gossipsub-peer-scoring-enabled=false \ + --gossipsub-peer-gater-enabled=true \ + --loglevel=error +``` + +### Consensus + +```shell +docker run --rm \ + -v /path/to/bootstrap:/bootstrap:ro \ + -v /path/to/data:/data:rw \ + --name flow-go \ + --network host \ + --ulimit nofile=8192 \ + gcr.io/flow-container-registry/consensus: \ + --nodeid=${FLOW_GO_NODE_ID} \ + --bootstrapdir=/bootstrap \ + --datadir=/data/protocol \ + --secretsdir=/data/secrets \ + --admin-addr=0.0.0.0:9002 \ + --bind 0.0.0.0:3569 \ + --access-node-ids=4e17496619df8bb4dcd579c252d9fb026e54995db0dc6825bdcd27bd3288a990,7e3fe64ccc119f578a7795df8b8c512e05409bdc7de4f74259c6f48351fecb26,416c65782048656e74736368656c009530ef3ab4b8bf83b24df54fe5f81853de,416e647265772042757269616e00d219355d62b9adad8ebd3fab223a1cf84c22 \ + --gossipsub-peer-scoring-enabled=false \ + --gossipsub-peer-gater-enabled=true \ + --loglevel=error +``` + +### Execution + +```shell +docker run --rm \ + -v /path/to/bootstrap:/bootstrap:ro \ + -v /path/to/data:/data:rw \ + --name flow-go \ + --network host \ + --ulimit nofile=500000 \ + gcr.io/flow-container-registry/execution: \ + --nodeid=${FLOW_GO_NODE_ID} \ + --bootstrapdir=/bootstrap \ + --datadir=/data/protocol \ + --secretsdir=/data/secrets \ + --triedir=/data/execution \ + --execution-data-dir=/data/execution_data \ + --rpc-addr=0.0.0.0:9000 \ + --admin-addr=0.0.0.0:9002 \ + --bind 0.0.0.0:3569 \ + --loglevel=error +``` + +For execution nodes, it is recommend to increase the open files limit in your operating system. To do that, add the following to your `/etc/security/limits.conf` or the equivalent `limits.conf` for your distribution: + +``` +* hard nofile 500000 +* soft nofile 500000 +root hard nofile 500000 +root soft nofile 500000 +``` + +Restart your machine to apply these changes. To verify that the new limits have been applied, run: + +``` +ulimit -n +``` + +### Verification + +```shell +docker run --rm \ + -v /path/to/bootstrap:/bootstrap:ro \ + -v /path/to/data:/data:rw \ + --name flow-go \ + --network host \ + --ulimit nofile=8192 \ + gcr.io/flow-container-registry/verification: \ + --nodeid=${FLOW_GO_NODE_ID} \ + --bootstrapdir=/bootstrap \ + --datadir=/data/protocol \ + --secretsdir=/data/secrets \ + --admin-addr=0.0.0.0:9002 \ + --bind 0.0.0.0:3569 \ + --loglevel=error +``` + +## Start the Node + +Now that your node is provisioned and configured, it can be started. + + + +Before starting your node, ensure it is [registered](./node-bootstrap.md#step-2---stake-your-node) and [authorized](./node-bootstrap.md#confirming-authorization). + + + +Ensure you start your node at the appropriate time. +See [Spork Process](./spork.md) for when to start up a node following a spork. +See [Node Bootstrap](./node-bootstrap.md#timing) for when to start up a newly registered node. + +### Systemd + +1. Check that your `runtime-conf.env` is at `/etc/flow/runtime-conf.env` +2. Update your environment variables: `source /etc/flow/runtime-conf.env` +3. Start your service: `sudo systemctl start flow` + +## Verify your Node is Running + +Here are a few handy commands that you can use to check if your Flow node is up and running + +### Systemd + +- To get Flow logs: `sudo journalctl -u flow-YOUR_ROLE` +- To get the status: `sudo systemctl status flow` + +```shell +● flow-verification.service - Flow Access Node running with Docker +Loaded: loaded (/etc/systemd/system/flow-verification.service; enabled; vendor preset: enabled) +Active: active (running) since Wed 2020-05-20 18:18:13 UTC; 1 day 6h ago +Process: 3207 ExecStartPre=/usr/bin/docker pull gcr.io/flow-container-registry/verification:${FLOW_GO_NODE_VERSION} (code=exited, status=0/SUCCESS) +Main PID: 3228 (docker) +Tasks: 10 (limit: 4915) +Memory: 33.0M +CGroup: /system.slice/flow-verification.service + └─3228 /usr/bin/docker run --rm -v /var/flow/bootstrap:/bootstrap:ro -v /var/flow/data:/data:rw --rm --name flow-go --network host gcr.io/flow-container-registry/verification:candidate8 --nodeid=489f8a4513d5bd8b8b093108fec00327b683db545b37b4ea9153f61b2c0c49dc --bootstrapdir=/bootstrap --datadir=/data/protocol --alpha=1 --bind 0.0.0.0:3569 --loglevel=error +``` + +### Docker + +- To get Flow logs: `sudo docker logs flow-go` +- To get the status: `sudo docker ps` + +```shell +$ sudo docker ps +CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES +1dc5d43385b6 gcr.io/flow-container-registry/verification:candidate8 \"/bin/app --nodeid=4…\" 30 hours ago Up 30 hours flow-go +``` + +## Monitoring and Metrics + +This is intended for operators who would like to see what their Flow nodes are currently doing. Head over to [Monitoring Node Health](./monitoring-nodes.md) to get setup. + +### Node Status + +The metrics for the node should be able to provide a good overview of the status of the node. If we want to get a quick snapshot of the status of the node, and if it's properly participating in the network, you can check the `consensus_compliance_finalized_height` or `consensus_compliance_sealed_height` metric, and ensure that it is not zero and strictly increasing. + +```shell +curl localhost:8080/metrics | grep consensus_compliance_sealed_height + +# HELP consensus_compliance_sealed_height the last sealed height +# TYPE consensus_compliance_sealed_height gauge +consensus_compliance_sealed_height 1.132054e+06 +``` \ No newline at end of file diff --git a/static/markdown/networks/node-ops/node-operation/past-upgrades.md b/static/markdown/networks/node-ops/node-operation/past-upgrades.md new file mode 100644 index 0000000000..7e4b027787 --- /dev/null +++ b/static/markdown/networks/node-ops/node-operation/past-upgrades.md @@ -0,0 +1,1029 @@ +--- +title: Past Network Upgrades +description: Information about Flow Mainnet and Testnet network upgrades. +sidebar_position: 14 +--- + +A JSON version of the information below can be found in [onflow/flow/sporks.json](https://github.com/onflow/flow/blob/master/sporks.json) + +## Mainnet Upgrades + +> Currently only includes HCUs from 2025. + +## Height Coordinated Upgrade 7 + +| HCU Info | +|:--------------------------------------------------------------------------------------| +| **Date**: April 10, 2025 | +| **Block Height**: 109384800 | +| **Git Commit**: 86c40b1ff20b3b7f17c4017bde083d26303c508d | +| **Branch/Tag**: v0.40.0 | +| **Docker Image Tag**: v0.40.0 | +| **Release Notes**: [v0.40.0](https://github.com/onflow/flow-go/releases/tag/v0.40.0) | + +## Rolling Upgrade 1 + +| RU Info | +|:-------------------------------------------------------------------------------------| +| **Date**: April 3, 2025 | +| **Block Height**: 108630638 | +| **Block View **: 20504725 | +| **Git Commit**: ad1076f0a36bb2d20cc36295d3573989edc15c6c | +| **Branch/Tag**: v0.39.0 | +| **Docker Image Tag**: v0.39.0 | +| **Release Notes**: [v0.39.0](https://github.com/onflow/flow-go/releases/tag/v0.39.0) | + +## Height Coordinated Upgrade 6 + +| HCU Info | +|:-------------------------------------------------------------------------------------| +| **Date**: Feb 18, 2025 | +| **Block Height**: 103983000 | +| **Git Commit**: 4e7e56b3a92e5772279f1304d88dd445c0ea5016 | +| **Branch/Tag**: v0.38.3 | +| **Docker Image Tag**: v0.38.3 | +| **Release Notes**: [v0.38.3](https://github.com/onflow/flow-go/releases/tag/v0.38.3) | + +## Height Coordinated Upgrade 5 + +| HCU Info | +|:-------------------------------------------------------------------------------------| +| **Date**: Feb 18, 2025 | +| **Block Height**: 103957477 | +| **Git Commit**: bcb8a2264fcde9dcd4c997f6b28d8184af19160b | +| **Branch/Tag**: v0.38.2 | +| **Docker Image Tag**: v0.38.2 | +| **Release Notes**: [v0.38.2](https://github.com/onflow/flow-go/releases/tag/v0.38.2) | + +## Height Coordinated Upgrade 4 + +| HCU Info | +|:---------------------------------------------------------------------------------------| +| **Date**: Jan 27, 2025 | +| **Block Height**: 101584244 | +| **Git Commit**: 5f6b25bd02257e3239341c4be0134b007f3deb49 | +| **Branch/Tag**: v0.37.26 | +| **Docker Image Tag**: v0.37.26 | +| **Release Notes**: [v0.37.26](https://github.com/onflow/flow-go/releases/tag/v0.37.26) | + +## Mainnet 26 + +| Spork Info | +|:----------------------------------------------------------------------------------------| +| **Access Node**: access.mainnet.nodes.onflow.org:9000 | +| **Date**: Sep 25, 2024 | +| **Root Height**: 88226267 | +| **Root Parent ID**: 71052eb6e774ae5065b31c604a85af47fa16d5c53e54b9a992581c1ecf0ecfac | +| **Root State Commit**: 3bba639062a723af1b44b1dfe07e795d158482f02f807f1df0b7c39edd6a8cca | +| **Git Commit**: 25d9c2a9b89bac8fa003ca67928eb79b1427ea17 | +| **Branch/Tag**: v0.37.16-patch.1 | +| **Docker Image Tag**: v0.37.16-patch.1 | + +## Mainnet 25 + +| Spork Info | +|:----------------------------------------------------------------------------------------| +| **Access Node**: access-001.mainnet25.nodes.onflow.org:9000 | +| **Date**: Sep 4, 2024 | +| **Root Height**: 85981135 | +| **Root Parent ID**: bc16d37060cb408163a04afe406b9c9398a31663c839de35b92e3c3b10bcf834 | +| **Root State Commit**: dead79e8f86d20ea3214735d4247b7fac1b4408e93e9b092fe0566cf40cecb9e | +| **Git Commit**: feabd3a4f9baaa5d7770a312e5b8dc1bd94b1edb | +| **Branch/Tag**: [v0.37.10](https://github.com/onflow/flow-go/releases/tag/v0.37.10) | +| **Docker Image Tag**: v0.37.10 | + +## Mainnet 24 + +| Spork Info | +|:----------------------------------------------------------------------------------------| +| **Access Node**: access-001.mainnet24.nodes.onflow.org:9000 | +| **Date**: Nov 8, 2023 | +| **Root Height**: 65264619 | +| **Root Parent ID**: aace2d9b6e66067989d0f71c2efff38fe30d88da61e3d80946c7e7b4ee2bbc2f | +| **Root State Commit**: 709530929e4968daff19c303ef1fc5f0a7649b3a1ce7d5ee5202056969524c94 | +| **Git Commit**: e63117642e34b215993d14d36622d45df249016c | +| **Branch/Tag**: [v0.32.7](https://github.com/onflow/flow-go/releases/tag/v0.32.7) | +| **Docker Image Tag**: v0.32.7 | + +## Mainnet 23 + +| Spork Info | +| :-------------------------------------------------------------------------------------- | +| **Access Node**: access-001.mainnet23.nodes.onflow.org:9000 | +| **Date**: Jun 20, 2023 | +| **Root Height**: 55114467 | +| **Root Parent ID**: dcaa1469c6cd67154942c70b594bdff407ea28eda1fc9c4a81a814f02dc2efc9 | +| **Root State Commit**: 5586f6b9af7c0d8efa7b403dbd3a894d71a18faad5a1abda48d3dfb7dcd4b017 | +| **Git Commit**: 0f6ea38efc91b7d27736b8b2c94091076c624796 | +| **Branch/Tag**: [v0.31.9](https://github.com/onflow/flow-go/releases/tag/v0.31.9) | +| **Docker Image Tag**: v0.31.9 | + +## Mainnet 22 + +| Spork Info | +| :-------------------------------------------------------------------------------------- | +| **Access Node**: access-001.mainnet22.nodes.onflow.org:9000 | +| **Date**: Feb 22, 2023 | +| **Root Height**: 47169687 | +| **Root Parent ID**: 60a976d4cc36d0a5150d3f81ede85809916d4af9eb791d9190af0a12c1fd8a17 | +| **Root State Commit**: c9c9d3da3fe059a616b13768da2374275bd1a35f94d753ee8e41c538a3cc92d8 | +| **Git Commit**: e644427a8e83e8cd2a307c40e4c8fd3066008cae | +| **Branch/Tag**: [v0.29.13](https://github.com/onflow/flow-go/releases/tag/v0.29.13) | +| **Docker Image Tag**: v0.29.13 | + +## Mainnet 21 + +| Spork Info | +| :-------------------------------------------------------------------------------------- | +| **Access Node**: access-001.mainnet21.nodes.onflow.org:9000 | +| **Date**: Jan 18, 2023 | +| **Root Height**: 44950207 | +| **Root Parent ID**: 52004adfa7854b1a515d0d905dd5317dc7f77a8dbb56058e04dde01e53e80a92 | +| **Root State Commit**: 905c5e9a576ba2cbe49b5fe5f64ae84c2dee1bc26a3e81932e573e06a722d08a | +| **Git Commit**: 7f02a642bb437b45326c4ace54a7f033b32832f8 | +| **Branch/Tag**: [v0.29.6](https://github.com/onflow/flow-go/releases/tag/v0.29.6) | +| **Docker Image Tag**: v0.29.6 | + +## Mainnet 20 + +| Spork Info | +| :-------------------------------------------------------------------------------------- | +| **Access Node**: access-001.mainnet20.nodes.onflow.org:9000 | +| **Date**: Nov 2, 2022 | +| **Root Height**: 40171634 | +| **Root Parent ID**: f66302ac43623a87d29dfdeb08fce5d19e3af7be2e4283d468f74ee10468f248 | +| **Root State Commit**: ec1e1cd34bb05b5abb3c4701a7f365d1dde46d9d908dc57420bde8b4a53d940a | +| **Git Commit**: b9b941db9a3949db0e299a40264d852980d35ddd | +| **Branch/Tag**: [v0.28.6](https://github.com/onflow/flow-go/releases/tag/v0.28.6) | +| **Docker Image Tag**: v0.28.6 | + +## Mainnet 19 + +| Spork Info | +| :-------------------------------------------------------------------------------------- | +| **Access Node**: access-001.mainnet19.nodes.onflow.org:9000 | +| **Date**: Aug 24, 2022 | +| **Root Height**: 35858811 | +| **Root Parent ID**: 5c030d4125f8ace0e0ab8255880143190d58aca4ddb7c4720c28eaf497adcae1 | +| **Root State Commit**: 96ff0d9a2b7d8264ea8727d4a104d7372efcfe18dc0c9111aff5c46b688eff04 | +| **Git Commit**: b6e9a988514d13e1e1ecd0802d7e02f9e9b1415b | +| **Branch/Tag**: [v0.27.4](https://github.com/onflow/flow-go/releases/tag/v0.27.4) | +| **Docker Image Tag**: v0.27.4 | + +## Mainnet 18 + +| Spork Info | +| :-------------------------------------------------------------------------------------- | +| **Access Node**: access-001.mainnet18.nodes.onflow.org:9000 | +| **Date**: Jun 15, 2022 | +| **Root Height**: 31735955 | +| **Root Parent ID**: 716d54edbb3d9b2ad290709a516f1ffe4290c7b7b33a49bd0480e0b193a45884 | +| **Root State Commit**: 5bdae9f5fb4cc5d63075547df5502e2bc3cb20707452389fb89ebbe71ecf7b68 | +| **Git Commit**: fdc732183233f1c577a9e529da6b453364431301 | +| **Branch/Tag**: [v0.26.9](https://github.com/onflow/flow-go/releases/tag/v0.26.9) | +| **Docker Image Tag**: v0.26.9 | + +## Mainnet 17 + +| Spork Info | +| :-------------------------------------------------------------------------------------- | +| **Access Node**: access-001.mainnet17.nodes.onflow.org:9000 | +| **Date**: Apr 6, 2022 | +| **Root Height**: 27341470 | +| **Root Parent ID**: dd7ed04e14559ed47ecc92896a5cb3dbb6b234065d9be7f816d99602238762aa | +| **Root State Commit**: 113e752ec0619b63187630b4fae308ec5405a00f56f25c2de0b139e283a95b14 | +| **Git Commit**: 5226c35eb14890db024b9193793b0c49d1b5ad04 | +| **Branch/Tag**: [v0.25.7](https://github.com/onflow/flow-go/releases/tag/v0.25.7) | +| **Docker Image Tag**: v0.25.7 | + +## Mainnet 16 + +| Spork Info | +| :-------------------------------------------------------------------------------------- | +| **Access Node**: access-001.mainnet16.nodes.onflow.org:9000 | +| **Date**: Feb 9, 2022 | +| **Root Height**: 23830813 | +| **Root Parent ID**: b0e7a891682dce277a41e87e2cef52af344ac614bf70c82a5a3a801e63960e88 | +| **Root State Commit**: 8964d1f74c2bed2d0fbb4a366fff1fd3c39b71653e9de4d4512090798631e5f8 | +| **Git Commit**: c78cac3573e0548611f29df7cfa2db92203554c1 | +| **Branch/Tag**: [v0.24.4](https://github.com/onflow/flow-go/releases/tag/v0.24.4) | +| **Docker Image Tag**: v0.24.4 | + +## Mainnet 15 + +| Spork Info | +| :-------------------------------------------------------------------------------------- | +| **Access Node**: access-001.mainnet15.nodes.onflow.org:9000 | +| **Date**: Dec 8, 2021 | +| **Root Height**: 21291692 | +| **Root Parent ID**: 8a28ddc6653a8991435dfbc95103d6be1a3b653cda3d664681215ee93112a203 | +| **Root State Commit**: 84d9b325d3f48f7f075eea0db6c246cb5adc759a2dd8561e461477a7ca1f7f22 | +| **Git Commit**: bfde54ae3324db5d18ebeaa22c70b5574a114f2e | +| **Branch/Tag**: [v0.23.4](https://github.com/onflow/flow-go/releases/tag/v0.23.4) | +| **Docker Image Tag**: v0.23.4 | + +## Mainnet 14 + +| Spork Info | +| :-------------------------------------------------------------------------------------- | +| **Access Node**: access-001.mainnet14.nodes.onflow.org:9000 | +| **Date**: Oct 6, 2021 | +| **Root Height**: 19050753 | +| **Root Parent ID**: ac4dbf344ce96e39e15081f1dc3fbbf6dc80532e402de9a57af847d3b35df596 | +| **Root State Commit**: 641eb088e3ce1a01ff56df2d3a14372c65a7fef44c08799eb92cd7759d1d1d2a | +| **Git Commit**: f019c1dbd778ce9f92dea61349ca36003678a9ad | +| **Branch/Tag**: [v0.22.9-patch-1-epoch-view-check-hotfix](https://github.com/onflow/flow-go/releases/tag/v0.22.9-patch-1-epoch-view-check-hotfix) | +| **Docker Image Tag**: v0.22.9-patch-1-epoch-view-check-hotfix | + +## Mainnet 13 + +| Spork Info | +| :-------------------------------------------------------------------------------------- | +| **Access Node**: access-001.mainnet13.nodes.onflow.org:9000 | +| **Date**: Sept 15, 2021 | +| **Root Height**: 18587478 | +| **Root Parent ID**: 2f708745fff4f66db88fac8f2f41d496edd341a2837d3e990e87679266e9bdb8 | +| **Root State Commit**: 51e3098d327df22fd005d960cb73167c83cb438c53e6c4363c07d8611ae44528 | +| **Git Commit**: 9535540110a4452231d044aceabab0e60f67708c | +| **Branch/Tag**: [v0.21.3](https://github.com/onflow/flow-go/releases/tag/v0.21.3) | +| **Docker Image Tag**: v0.21.3 | + +## Mainnet 12 + +| Spork Info | +| :-------------------------------------------------------------------------------------- | +| **Access Node**: access-001.mainnet12.nodes.onflow.org:9000 | +| **Date**: Aug 18, 2021 | +| **Root Height**: 17544523 | +| **Root Parent ID**: f6ca04ba5c6fa6ba690a77202a9fad8d3ec30c67762ae065f0f0f53e8fed84d0 | +| **Root State Commit**: b5cf1977b12de699d0e777af5be25095653735a153d1993f97ff07804b070917 | +| **Git Commit**: 4a0c10d74f1bcaadfdfec8c325efa411acd1a084 | +| **Branch/Tag**: [v0.20.5](https://github.com/onflow/flow-go/releases/tag/v0.20.5) | +| **Docker Image Tag**: v0.20.5 | + +## Mainnet 11 + +| Spork Info | +| :-------------------------------------------------------------------------------------- | +| **Access Node**: access-001.mainnet11.nodes.onflow.org:9000 | +| **Date**: July 21, 2021 | +| **Root Height**: 16755602 | +| **Root Parent ID**: de15461988000eddc6e507dc7b159dcd192ee3aa72f3bd3b0e31ae9c6538399f | +| **Root State Commit**: 4eb91bf34cb65b7537a6a95806f444f409308b2eaaa0ad28d1924b6cb8afa140 | +| **Git Commit**: 2644560c0562412a3c2209820be07f8f3f8b1846 | +| **Branch/Tag**: [v0.19.2](https://github.com/onflow/flow-go/releases/tag/v0.19.2) | +| **Docker Image Tag**: v0.19.2 | + +## Mainnet 10 + +| Spork Info | +| :-------------------------------------------------------------------------------------- | +| **Access Node**: access-001.mainnet10.nodes.onflow.org:9000 | +| **Date**: June 23, 2021 | +| **Root Height**: 15791891 | +| **Root Parent ID**: 1d4109bbb364d5cdd94640546dd1c423d792d962284665233d541e4ade921726 | +| **Root State Commit**: 9b6a1a5ab52fd3d5a19ea22f09cb607bba63671311f157b3e604dd265efb851a | +| **Git Commit**: 01f53ebd7df3101e337d9212736cff6ab1e0056d | +| **Branch/Tag**: [v0.18.4](https://github.com/onflow/flow-go/releases/tag/v0.18.4) | +| **Docker Image Tag**: v0.18.4 | + +## Mainnet 9 + +| Spork Info | +| :-------------------------------------------------------------------------------------- | +| **Access Node**: access-001.mainnet9.nodes.onflow.org:9000 | +| **Date**: May 26, 2021 | +| **Root Height**: 14892104 | +| **Root Parent ID**: 265d10ba3e36ed6539fd4d7f4322735aad4997c0378d75783e471437dd83ef33 | +| **Root State Commit**: fcc30a6664337ef534ad544ad7b17c5cc3b5470a8ef0d93f18573fddf6b25c4a | +| **Git Commit**: 2d81520c49a8865fa686c32c508d2261155c86bc | +| **Branch/Tag**: [v0.17.4](https://github.com/onflow/flow-go/releases/tag/v0.17.4) | +| **Docker Image Tag**: v0.17.4 | + +## Mainnet 8 + +| Spork Info | +| :-------------------------------------------------------------------------------------- | +| **Access Node**: access-001.mainnet8.nodes.onflow.org:9000 | +| **Date**: April 28, 2021 | +| **Root Height**: 13950742 | +| **Root Parent ID**: faa2a3a996c6efcc3ef562fe03d797e4b19dbe00f6beab082d6d37a447044abd | +| **Root State Commit**: 259836c7f74e6bbb803c9cfb516044bc701d99c2840e9b9f89609464867e7f0f | +| **Git Commit**: 4e733ba2038512e9d80bcd955e67e88ba6e3ecf2 | +| **Branch/Tag**: v0.16.2 | +| **Docker Image Tag**: v0.16.2 | + +## Mainnet 7 + +| Spork Info | +| :-------------------------------------------------------------------------------------- | +| **Access Node**: access-001.mainnet7.nodes.onflow.org:9000 | +| **Date**: April 7, 2021 | +| **Root Height**: 13404174 | +| **Root Parent ID**: 8b969d0babbb7d2043957b3d55a811f2c13344faa76565096d4ad901a466ecaa | +| **Root State Commit**: 1247d74449a0252ccfe4fd0f8c6dd98e049417b3bffc3554646d92f810e11542 | +| **Git Commit**: b6f47fd23ffe31e2fe714c6bff0b17d901e210b4 | +| **Branch/Tag**: v0.15.3-patch.4 | +| **Docker Image Tag**: v0.15.3-patch.4 | + +Releases compatible with Mainnet 7: No change from Mainnet 6 + +## Mainnet 6 + +| Spork Info | +| :-------------------------------------------------------------------------------------- | +| **Access Node**: access-001.mainnet6.nodes.onflow.org:9000 | +| **Date**: Mar 10, 2021 | +| **Root Height**: 12609237 | +| **Root Parent ID**: c68e63ca5b6f7ff61ef2b28d7da528c5b677b0f81f2782f067679c108d77932b | +| **Root State Commit**: ddfedbfaa2d858e6a8e3b142381a91b289f50e45622f5b5a86ac5c00ce61bf11 | +| **Git Commit**: c887bd343ca7db6351690007b87bec40d39d7b86 | +| **Branch/Tag**: v0.14.9 | +| **Docker Image Tag**: v0.14.9 | + +Releases compatible with Mainnet 6: + +### Network Implementations + +Flow Go: https://github.com/onflow/flow-go/releases/tag/v0.14.9
    +Emulator: https://github.com/onflow/flow-emulator/releases/tag/v0.16.1
    + +Emulator v0.16.1 is distributed in Flow CLI v0.15.0: https://github.com/onflow/flow-cli/releases/tag/v0.15.0 + +### SDK Compatibility + +#### Flow Go SDK + +Minimum version: https://github.com/onflow/flow-go-sdk/releases/tag/v0.16.1
    +Recommended version: https://github.com/onflow/flow-go-sdk/releases/tag/v0.16.1
    + +#### FCL (Flow Client Library) + +Minimum version: [v0.0.66](https://github.com/onflow/fcl-js/blob/master/packages/fcl/CHANGELOG.md#0066---2020-11-09)
    +Recommended version: [v0.0.67](https://github.com/onflow/fcl-js/blob/master/packages/fcl/CHANGELOG.md#0067-alpha0---2020-11-17) + +While FCL v0.0.67 is not strictly necessary to use Mainnet 6, we strongly recommend upgrading in order to adapt to wallet improvements that were introduced in v0.0.67. + +--- + +## Mainnet 5 + +| Spork Info | +| :--------------------------------------------------------------------------------------------------- | +| **Access Node**: access-001.mainnet5.nodes.onflow.org:9000 | +| **Date**: Feb 17, 2021 | +| **Root Height**: 12020337 | +| **Root Parent ID**: 9131733835702b0d6321088bddb4642a4964bb5c630440ccb0de47bdbc371d1a | +| **Root State Commit**: 54bef048a6c5574ef4eb452dd2698aeb2fe5eca6edd536aca6d0bc631c2daaa9 | +| **Git Commit**: 027569a9d76e41b1140b189fa1b9187c711ab241 | +| **Branch/Tag**: v0.14.1 for Access, Verification, Collection and v0.14.2 for Consensus and Execution | +| **Docker Image Tag**: v0.14.1 / v0.14.2 | + +--- + +## Mainnet 4 + +| Spork Info | +| :------------------------------------------------------------------------------------- | +| **Access Node**: access-001.mainnet4.nodes.onflow.org:9000 | +| **Date**: Dec 16, 2020 | +| **Root Height**: 9992020 | +| **Root Parent ID**: 691e35a4ac4d0d47e1be1ec81512ac9f6cdd04545b908fad1d6ceea58c76b560 | +| **Root State Commit**: 0011fda57f2f3aaa8e6bcc1e1deea9778a9543252f8b65bbd4ebca3687789420 | +| **Git Commit**: f4a73c7f20109209e9e2e999cf50fcf1ec41241b | +| **Branch/Tag**: v0.13.1 | +| **Docker Image Tag**: v0.13.1 | + +--- + +## Mainnet 3 + +| Spork Info | +| :------------------------------------------------------------------------------------- | +| **Access Node**: access-001.mainnet3.nodes.onflow.org:9000 | +| **Date**: Dec 9, 2020 | +| **Root Height**: 9737133 | +| **Root Parent ID**: 116751c904a7f868cd6e8c90522fdbd70fe826db6886b830338c68c6339df3e7 | +| **Root State Commit**: 1d2c91e801d0560024848a0c981e03120efc372436ada5f7909c4d44d4600f04 | +| **Git Commit**: badd5887512b955e7aa18b4e73dae980ca72fa22 | +| **Branch/Tag**: v0.12.6 | +| **Docker Image Tag**: v0.12.6 | + +--- + +## Mainnet 2 + +| Spork Info | +| :------------------------------------------------------------------------------------- | +| **Access Node**: access-001.mainnet2.nodes.onflow.org:9000 | +| **Date**: Nov 13, 2020 | +| **Root Height**: 8742959 | +| **Root Parent ID**: b35fdb189d21a95df7f19f941786f748d9854a8b93b1e555b51cda7d9f53a6e1 | +| **Root State Commit**: d6a25be552ed93213df0ffc2e8c7f39f6401c04cbf22bac7a4b84d3c9493f005 | +| **Git Commit**: 4ef68efb935c0e3393ae3966752ece5e7739bab4 | +| **Branch/Tag**: v0.11.1 | +| **Docker Image Tag**: v0.11.1 | + +--- + +## Mainnet 1 + +| Spork Info | +| :------------------------------------------------------------------------------------- | +| **Access Node**: access-001.mainnet1.nodes.onflow.org:9000 | +| **Date**: Oct 13, 2020 | +| **Root Height**: 7601063 | +| **Root Parent ID**: ab1ee18b6e1c0ee11cc021c26a17c694c627699a576e85f7013cd743bdbc7877 | +| **Root State Commit**: 6e1adf15689eaf5ea6859bcdd0b510f5eb4c34dac878d8577b3f65bc20c3f312 | +| **Git Commit**: 114d45436e7d9052e910c98a1e40f730e3fd12d7 | +| **Branch/Tag**: v0.10.1 | +| **Docker Image Tag**: v0.10.1 | + +--- + +## Candidate 9 + +| Spork Info | +| :------------------------------------------------------------------------------------- | +| **Access Node**: access-001.candidate9.nodes.onflow.org:9000 | +| **Date**: Sep 25, 2020 | +| **Root Height**: 6483246 | +| **Root Parent ID**: 9131733835702b0d6321088bddb4642a4964bb5c630440ccb0de47bdbc371d1a | +| **Root State Commit**: 90c6f406f5d21880d525ad4702cb249509b85e7f745db2de67e9fe541a56da4c | +| **Git Commit**: v0.9.3 | +| **Branch/Tag**: v0.9.3 | +| **Docker Image Tag**: | + +--- + +## Candidate 8 + +| Spork Info | +| :------------------------------------------------------------------------------------- | +| **Access Node**: access-001.candidate8.nodes.onflow.org:9000 | +| **Date**: Sep 9, 2020 | +| **Root Height**: 4972987 | +| **Root Parent ID**: 5bc2b0900a5138e39d9209a8fe32e14b3e5c884bd36d2a645620f746b7c8bd47 | +| **Root State Commit**: 6b9161a225b087a461ec95e710fdf4e73f6d6c9401ebf066207a021dced4ce5e | +| **Git Commit**: | +| **Branch/Tag**: | +| **Docker Image Tag**: | + +--- + +## Candidate 7 + +| Spork Info | +| :------------------------------------------------------------------------------------- | +| **Access Node**: access-001.candidate7.nodes.onflow.org:9000 | +| **Date**: Aug 24, 2020 | +| **Root Height**: 4132133 | +| **Root Parent ID**: 28f4f495aad016b519acf27fc9d9a328f6a4009807480e36e2df780eeccd99bc | +| **Root State Commit**: 001d173bfcf9c7f71684da89bff72b3ee582b39a69c7929360230faf73735c17| +| **Git Commit**: f811f8cd49369ae2bc559e0fbb781aff129484f5 | +| **Branch/Tag**: candidate7 | +| **Docker Image Tag**: v0.7.2 | + +--- + +## Candidate 6 + +| Spork Info | +| :------------------------------------------------------------------------------------- | +| **Access Node**: access-001.candidate6.nodes.onflow.org:9000 | +| **Date**: Aug 18, 2020 | +| **Root Height**: 3187931 | +| **Root Parent ID**: 2ff5f7424a448943a153001d2f0869d4fac330906ecb8e17b7ef7fe50e4c7b36 | +| **Root State Commit**: bd7f16dc5ef5eced849ab5f437547c14c1907059e1ecf89a942d0521166c5cbb | +| **Git Commit**: b30c48008c0ec1cc8ecb750aeb9ff9f3d712681d | +| **Branch/Tag**: | +| **Docker Image Tag**: | + +--- + +## Candidate 5 + +| Spork Info | +| :------------------------------------------------------------------------------------- | +| **Access Node**: access-001.candidate5.nodes.onflow.org:9000 | +| **Date**: Jul 28, 2020 | +| **Root Height**: 2033592 | +| **Root Parent ID**: a0efffb2beb1500419ae4f7c6e49bfbbe3a4d1d1c201bf925ccaec467ea30e91 | +| **Root State Commit**: 0190d417a26b9870f5bb2cf408ad31985b3aa7e57f6ababa6e543f0f90b99dcd | +| **Git Commit**: cd876653d20b398952af4002701a0ae2800fd5f2 | +| **Branch/Tag**: | +| **Docker Image Tag**: | + +--- + +## Candidate 4 + +| Spork Info | +|:----------------------------------------------------------------------------------------| +| **Access Node**: access-001.candidate4.nodes.onflow.org:9000 | +| **Date**: Jul 14, 2020 | +| **Root Height**: 1065711 | +| **Root Parent ID**: 68c2bbe68524b50f5d689bc2ac7ad2dd70e88ed7dd15ad6c3cdf6ea314cb1aa3 | +| **Root State Commit**: c05086e4d1d428d3b9af5bd8b81d8780054f783ef4eec3ca28b491202e9ac696 | +| **Git Commit**: b9b197280d6590576f1ef183bc3d04d41d6be587 | +| **Branch/Tag**: | +| **Docker Image Tag**: | + +--- + +## Testnet Upgrades + +> Currently only includes HCUs from 2025. + +## Height Coordinated Upgrade 9 + +| HCU Info | +|:-------------------------------------------------------------------------------------| +| **Date**: April 9, 2025 | +| **Block Height**: 252457666 | +| **Git Commit**: 86c40b1ff20b3b7f17c4017bde083d26303c508d | +| **Branch/Tag**: v0.40.0 | +| **Docker Image Tag**: v0.40.0 | +| **Release Notes**: [v0.40.0](https://github.com/onflow/flow-go/releases/tag/v0.40.0) | + +## Height Coordinated Upgrade 8 + +| HCU Info | +|:-------------------------------------------------------------------------------------| +| **Date**: Feb 18, 2025 | +| **Block Height**: 243615144 | +| **Git Commit**: 4e7e56b3a92e5772279f1304d88dd445c0ea5016 | +| **Branch/Tag**: v0.38.3 | +| **Docker Image Tag**: v0.38.3 | +| **Release Notes**: [v0.38.3](https://github.com/onflow/flow-go/releases/tag/v0.38.3) | + +## Height Coordinated Upgrade 7 + +| HCU Info | +|:-------------------------------------------------------------------------------------| +| **Date**: Feb 14, 2025 | +| **Block Height**: 242883902 | +| **Git Commit**: bcb8a2264fcde9dcd4c997f6b28d8184af19160b | +| **Branch/Tag**: v0.38.2 | +| **Docker Image Tag**: v0.38.2 | +| **Release Notes**: [v0.38.2](https://github.com/onflow/flow-go/releases/tag/v0.38.2) | + +## Height Coordinated Upgrade 6 + +| HCU Info | +|:---------------------------------------------------------| +| **Date**: Feb 11, 2025 | +| **Block Height**: 242365900 | +| **Git Commit**: bcb8a2264fcde9dcd4c997f6b28d8184af19160b | +| **Branch/Tag**: v0.38.1 | +| **Docker Image Tag**: v0.38.1 | +| **Release Notes**: N/A | + +## Height Coordinated Upgrade 5 + +| HCU Info | +|:---------------------------------------------------------------------------------------| +| **Date**: Jan 24, 2025 | +| **Block Height**: 239255500 | +| **Git Commit**: 5f6b25bd02257e3239341c4be0134b007f3deb49 | +| **Branch/Tag**: v0.37.26 | +| **Docker Image Tag**: v0.37.26 | +| **Release Notes**: [v0.37.26](https://github.com/onflow/flow-go/releases/tag/v0.37.26) | + +## Devnet 52 + +| Spork Info | +|:----------------------------------------------------------------------------------------| +| **Date**: Sept 24th, 2024 | +| **Root Height**: 218215349 | +| **Root Parent ID**: 20dd925a750399493cf7455f199c32c952e8010a6c0b4424dba00a193fa18e44 | +| **Root State Commit**: b0498700398cdc8c0c9368cc2f82fde62e8fe4b06e9c8af6c9bb619ab499e6c3 | +| **Git Commit**: 25d9c2a9b89bac8fa003ca67928eb79b1427ea17 | +| **Branch/Tag**: v0.37.16-patch.1 | +| **Docker Image Tag**: v0.37.16-patch.1 | + +## Devnet 51 + +| Spork Info | +|:----------------------------------------------------------------------------------------| +| **Date**: Aug 14th, 2024 | +| **Root Height**: 211176670 | +| **Root Parent ID**: c92e07e5d4fbb3a64e0091085a190a4a1119bfc628c71efe513e373dc0482f5a | +| **Root State Commit**: c3af77992f253f4dcfeac808912ff68e6f10923aa3fc4541a2e39eb9786c9eb3 | +| **Git Commit**: eeac47931cd6837ec6e29c4c0480609238959ccd | +| **Branch/Tag**: v0.37.1 | +| **Docker Image Tag**: v0.37.1 | + +## Devnet 50 + +| Spork Info | +|:----------------------------------------------------------------------------------------------------------------------------| +| **Date**: May 20th, 2024 | +| **Root Height**: 185185854 | +| **Root Parent ID**: cc4800bf44bc07864d156f829cfda2ae1964b5e103de7b9fa1bd879f9e92c10d | +| **Root State Commit**: 6a0ae7bf43660e813ee9c2d654f00476ac1bdc357ff47ad11f0e52fc1700d62f | +| **Git Commit**: 0585789483c4f5ea423bb11afcfe862c9a99711e | +| **Branch/Tag**: v0.33.23-failure-mode-revert-patch | +| **Docker Image Tag**: v0.33.23-failure-mode-revert-patch | + +## Devnet 49 + +| Spork Info | +|:----------------------------------------------------------------------------------------| +| **Date**: Nov 2nd, 2023 | +| **Root Height**: 129578013 | +| **Root Parent ID**: 91b039c1a5caf25776948270a6355017b8841bfb329c87460bfc3cf5189eba6f | +| **Root State Commit**: e10d3c53608a1f195b7969fbc06763285281f64595be491630a1e1bdfbe69161 | +| **Git Commit**: fce4ae31c8c90c6a21de9856a319c379bb797fc5 | +| **Branch/Tag**: v0.32.6-patch.1 | +| **Docker Image Tag**: v0.32.6-patch.1 | + +## Devnet 48 + +| Spork Info | +|:----------------------------------------------------------------------------------------| +| **Date**: Aug 4th, 2023 | +| **Root Height**: 127720466 | +| **Root Parent ID**: 2b30e75bd857f898456dcb296bea4b8bc8001cab7062eeee9e47876411b36d76 | +| **Root State Commit**: f2e5ebfca2fd519e49f7bd85bea81e92eeaa85a705b3376d8534e9c9649da710 | +| **Git Commit**: 692969b1718b3d21f95ee7f66e5061623d99e599 | +| **Branch/Tag**: v0.32.3 | +| **Docker Image Tag**: v0.32.3 | + +## Devnet 47 + +| Spork Info | +|:----------------------------------------------------------------------------------------| +| **Date**: Aug 4th, 2023 | +| **Root Height**: 113167876 | +| **Root Parent ID**: dbd59a00503707c8bc3c5fb3bcc7bd243da4bf8e24c86b6a496505e275b85311 | +| **Root State Commit**: 42006aedbfbfa9fcd949de8347b55166df77d8742bf5f273266a8dfcdf2b836b | +| **Git Commit**: db1c2584d6d8359b7ccf733c16bd5e1b9385c9bc | +| **Branch/Tag**: v0.31.13 | +| **Docker Image Tag**: v0.31.13 | + +## Devnet 46 + +| Spork Info | +|:----------------------------------------------------------------------------------------| +| **Date**: Jun 8th, 2023 | +| **Root Height**: 105155067 | +| **Root Parent ID**: daced0cdeed95cf143320db50ac904ed17dabe04898e988264af2a71e0d1ca48 | +| **Root State Commit**: e8c39b7a1672cb3f5f70da6f1d71a3a0322d3d6c3d7ebf8092ae2ae40d12c30b | +| **Git Commit**: 3d4159e93c92cc6331e69708b8c3270d40c09c5f | +| **Branch/Tag**: v0.31.4 | +| **Docker Image Tag**: v0.31.4 | + +## Devnet 45 + +| Spork Info | +|:----------------------------------------------------------------------------------------| +| **Date**: Jun 7th, 2023 | +| **Root Height**: 105032150 | +| **Root Parent ID**: 71df56106ee1492c055a60e2d951a6a8d1b7d1483b903f10146cec912e793e82 | +| **Root State Commit**: 0e2e053ca4436a4881f65acc031e12820b5260ef616446950650a1bc8fc9be2f | +| **Git Commit**: 8d32e5ea087fcceb0d1aa923c56be1d5a2d6538a | +| **Branch/Tag**: v0.31.2 | +| **Docker Image Tag**: v0.31.2 | + +## Devnet 44 + +| Spork Info | +|:----------------------------------------------------------------------------------------| +| **Date**: Apr 24th, 2023 | +| **Root Height**: 100675451 | +| **Root Parent ID**: 298854580771edc6ec2e2bbc8da3990ff7f746e2fc5cfe16e550d577bdd4bc5b | +| **Root State Commit**: 2a062531331b8214de4e900a26ff0f76c578481b4ce22b4b5d8e55bd9535abda | +| **Git Commit**: b5b65c9d43bf6bd12766eef06e870990c3963b7c | +| **Branch/Tag**: v0.30.6 | +| **Docker Image Tag**: v0.30.6 | + +## Devnet 43 + +| Spork Info | +|:----------------------------------------------------------------------------------------| +| **Date**: Apr 12th, 2023 | +| **Root Height**: 99452067 | +| **Root Parent ID**: 0e6bae31b2f34ffb0d64d4e1a33c2fbcebd80c936d77d70d2f5dd9321dc92393 | +| **Root State Commit**: 7cd69bb0a4448566dce42808efa8b1d03f322135f0bfce6f18037fca1294984c | +| **Git Commit**: d55ca8f48167e9669bdb1dc3173253936863e31e | +| **Branch/Tag**: v0.30.3 | +| **Docker Image Tag**: v0.30.3 | + +## Devnet 42 + +| Spork Info | +|:----------------------------------------------------------------------------------------| +| **Date**: Apr 12th, 2023 | +| **Root Height**: 99444465 | +| **Root Parent ID**: a3788d5c0ff1c45db38bca2625bf18bfc562e1bfdc9ebb7dc83ef080be31e697 | +| **Root State Commit**: a6e5bfc16a39109ef86caad4dab77ec3752680ef3813c3449f239d84fddc5aa1 | +| **Git Commit**: d55ca8f48167e9669bdb1dc3173253936863e31e | +| **Branch/Tag**: v0.30.3 | +| **Docker Image Tag**: v0.30.3 | + +## Devnet 41 + +| Spork Info | +|:----------------------------------------------------------------------------------------| +| **Date**: Jan 30th, 2023 | +| **Root Height**: 93156994 | +| **Root Parent ID**: 26ff2f7f2948a05c63e723eb42946565809b47dbef87079a8f0bae0cc36a0478 | +| **Root State Commit**: 08d712b4f7ed838d53b8699e2fd94d0ad010c4b1fa45735b6e80083ff8ef08ff | +| **Git Commit**: a7f2cd0ddd9fc7e1e56187327a84fec9efdc3c9d | +| **Branch/Tag**: v0.29.8 | +| **Docker Image Tag**: v0.29.8 | + +## Devnet 40 + +| Spork Info | +|:----------------------------------------------------------------------------------------| +| **Date**: Jan 23rd, 2023 | +| **Root Height**: 92473965 | +| **Root Parent ID**: 7c9812f414d9e9795c1cd7dbd27fc45baf880391452e0e948aaa80ba86dfc77d | +| **Root State Commit**: 0068a04843d2c8e007086abaaee90c8c8cae8aa78f240048cd4d43aeb0376d0b | +| **Git Commit**: 7f02a642bb437b45326c4ace54a7f033b32832f8 | +| **Branch/Tag**: v0.29.6 | +| **Docker Image Tag**: v0.29.6 | + +## Devnet 39 + +| Spork Info | +|:----------------------------------------------------------------------------------------| +| **Date**: Jan 4th, 2023 | +| **Root Height**: 90595736 | +| **Root Parent ID**: 3d09b9703019b40a065787fff3dd62e28eafa5efcfb69efbc2d713d73034cf38 | +| **Root State Commit**: afd47ff2a8e73efd51f0cbe7f572eefda25a66e77f1e6b9c4f3f4e7cdc46568f | +| **Git Commit**: e1c172aaee7da9e33828429757b44f51e59368a2 | +| **Branch/Tag**: v0.29.3 | +| **Docker Image Tag**: v0.29.3 | + +## Devnet 38 + +| Spork Info | +|:----------------------------------------------------------------------------------------| +| **Date**: Oct 19th, 2022 | +| **Root Height**: 83007730 | +| **Root Parent ID**: 1b914363c9a34c46b93974adeefb10c546578d7f3f4ac9291e01d746d2c84226 | +| **Root State Commit**: 79df428bc27f22d38c233777610d93d33e180f23cfbc640a95d144a508e0f080 | +| **Git Commit**: 3aae289f8f390f58ac481fd694254ea0e48960a8 | +| **Branch/Tag**: v0.28.4 | +| **Docker Image Tag**: v0.28.4 | + +## Devnet 37 + +| Spork Info | +|:----------------------------------------------------------------------------------------| +| **Date**: Aug 10th, 2022 | +| **Root Height**: 76159167 | +| **Root Parent ID**: 8f379a8a86f28c7adef276890874b17786cecf5efb9e71734b0a780bd38660a0 | +| **Root State Commit**: 7d1fe692ea2f857568dec54ddece094a68a9ba8ff8dd0de0664e6f73abb90dd8 | +| **Git Commit**: 959911cabd50e1a11be45e89726952a90f1a9c22 | +| **Branch/Tag**: v0.27.2 | +| **Docker Image Tag**: v0.27.2 | + +## Devnet 36 + +| Spork Info | +|:----------------------------------------------------------------------------------------| +| **Date**: July 27th, 2022 | +| **Root Height**: 74786360 | +| **Root Parent ID**: 9d9113ca8daa4f3be72e949ea9ead2d4b11db222b2ccd0dc897186ee5f8703ab | +| **Root State Commit**: aa2e12033129f27b5320fb973cf109f562db3ad7ddaf50dbfe9d8cc195a7ac0f | +| **Git Commit**: 13970fcae812bc04487422922f73eab39f53935c | +| **Branch/Tag**: v0.26.17 | +| **Docker Image Tag**: v0.26.17 | + +## Devnet 35 + +| Spork Info | +| :-------------------------------------------------------------------------------------- | +| **Date**: June 9th, 2022 | +| **Root Height**: 70072575 | +| **Root Parent ID**: cd76fd9d5ceb1b98b5f30b0108f40836593c533ffe32eef0c6f3ed6d50bf645b | +| **Root State Commit**: d933d73f48c9371f0a00ab7ffc1ed0daf5ba9e520d2d539e6b9494920c5ffd91 | +| **Git Commit**: 07057c8d5fe2f09bbe5a9a3f8de6209346d910d0 | +| **Branch/Tag**: v0.26.6 | +| **Docker Image Tag**: v0.26.6 | + +## Devnet 34 + +| Spork Info | +| :-------------------------------------------------------------------------------------- | +| **Date**: Apr 4th, 2022 | +| **Root Height**: 64904846 | +| **Root Parent ID**: 0cbb13d9e7ed7092b5f20d0a20a79d1cae96fd796fb2bc569b27ce49cc97d97e | +| **Root State Commit**: f2e77e16628543e285be8bac677db06e17b37f49e53a107af1e6bf99fbc17b30 | +| **Git Commit**: 5226c35eb14890db024b9193793b0c49d1b5ad04 | +| **Branch/Tag**: v0.25.7 | +| **Docker Image Tag**: v0.25.7 | + +## Devnet 33 + +| Spork Info | +| :-------------------------------------------------------------------------------------- | +| **Date**: Feb 7th, 2022 | +| **Root Height**: 59558934 | +| **Root Parent ID**: 099fbb7b645c3441ea830746ed67059bcc1091c88ff3fd78b331137cf917d15f | +| **Root State Commit**: 5b5578cb4ef6c34818ce2cfd9969720c7f17681f41dffa3a9e361935140d7c8e | +| **Git Commit**: bd3dca7bf20914f5c019a325b6939bbb662aa131 | +| **Branch/Tag**: v0.24.3 | +| **Docker Image Tag**: v0.24.3 | + +## Devnet 32 + +| Spork Info | +| :-------------------------------------------------------------------------------------- | +| **Date**: Dec 6th, 2021 | +| **Root Height**: 53376277 | +| **Root Parent ID**: f900db2ccff33f3bf353c8bf28ece0a9d2650f2805b23ddb7893e296774a5457 | +| **Root State Commit**: 843ea0b5498342dcf960376585eeafee8ebe008df3b03325351408a100cb830c | +| **Git Commit**: be20371fa8c5044a4e25e5629bbca91f1ed19731 | +| **Branch/Tag**: v0.23.3 | +| **Docker Image Tag**: v0.23.3 | + +## Devnet 31 + +| Spork Info | +| :-------------------------------------------------------------------------------------- | +| **Date**: Nov 5th, 2021 | +| **Root Height**: 50540412 | +| **Root Parent ID**: cfebaa6b8c19ec48a27eaa84c3469b23255350532b5ea4c7e4c42313386c07b6 | +| **Root State Commit**: 31a2b1eb05a6acb91560970e46b8f3f3171747245eae1ad2bf40290ce773806e | +| **Git Commit**: 3d060b90264d59ccd38b4500ae0cd6d72036cfe4 | +| **Branch/Tag**: v0.23-testnet | +| **Docker Image Tag**: v0.23.1 | + +## Devnet 30 + +| Spork Info | +| :-------------------------------------------------------------------------------------- | +| **Date**: Oct 6th, 2021 | +| **Root Height**: 47330085 | +| **Root Parent ID**: 0ec9172a21f84cbae15761ae4d59ab4a701f9d4fd15cd0632715befc8cf205cf | +| **Root State Commit**: e280f972c72c6b379ec3d4a7173953e596704d8d72f384ef1637d2f4f01ff901 | +| **Git Commit**: f019c1dbd778ce9f92dea61349ca36003678a9ad | +| **Branch/Tag**: v0.22.8-patch-1-scripts-and-errors | +| **Docker Image Tag**: v0.22.8-patch-1-scripts-and-errors | + +## Devnet 29 + +| Spork Info | +| :-------------------------------------------------------------------------------------- | +| **Date**: Oct 5th, 2021 | +| **Root Height**: 47242826 | +| **Root Parent ID**: 00f745576222a1e7e15ee79974b4b3eaddd760fb4f56e846cfaef3cb5ea59d50 | +| **Root State Commit**: 3c5bfb88a3fa184c9981e7677d1f2a2cd0a4eaa581bb2a7867b7b023ae015f38 | +| **Git Commit**: e1659aebc39b4a15c68112227fc8c32788a798b6 | +| **Branch/Tag**: v0.22.8 | +| **Docker Image Tag**: v0.22.8 | + +## Devnet 28 + +| Spork Info | +| :-------------------------------------------------------------------------------------- | +| **Date**: Sept 22, 2021 | +| **Root Height**: 45889254 | +| **Root Parent ID**: 1518c15f7078cb8fd4c636b9fc15ee847ac231a8631ed59a0b8c9d4a182fb5b2 | +| **Root State Commit**: 296001ee05ce3e6c6616ad9bcdc20e6d93d02c91354e57fff6054cff44c5afa3 | +| **Git Commit**: a979f4d25a79630581f6b350ad26730d4012cad4 | +| **Branch/Tag**: v0.21.6 | +| **Docker Image Tag**: v0.21.6 | + +## Devnet 27 + +| Spork Info | +| :-------------------------------------------------------------------------------------- | +| **Date**: Sept 14, 2021 | +| **Root Height**: 45051578 | +| **Root Parent ID**: 8525ac24717b5f42e29172f881e9a7439235e4cd443a8a59494dbecf07b9376a | +| **Root State Commit**: b3ef3b039f722130009b658e3f5faee43b3b9202fec2e976907012994a8fc9be | +| **Git Commit**: 4f903f1d45e6f8c997a60de47de62a74ede3c2e4 | +| **Branch/Tag**: v0.21.3 | +| **Docker Image Tag**: v0.21.3 | + +## Devnet 26 + +| Spork Info | +| :-------------------------------------------------------------------------------------- | +| **Date**: Aug 11, 2021 | +| **Root Height**: 41567027 | +| **Root Parent ID**: ea465f33266be26b21c82ec728c75cc0dcbb022405d83c44ed0082b0df9aa81d | +| **Root State Commit**: 9459485a2a640b1bdc3066916a9a46dc20bf2528a03f06ddc541d34444c3264c | +| **Git Commit**: 781ec414b892e2ccf7034aa263b5b19d97f82031 | +| **Branch/Tag**: v0.20.4 | +| **Docker Image Tag**: v0.20.4 | + +## Devnet 25 + +| Spork Info | +| :-------------------------------------------------------------------------------------- | +| **Date**: July 20, 2021 | +| **Root Height**: 39272449 | +| **Root Parent ID**: 2824828e7c87e1a89bc94daca9497625f1a35c8f9fc555f52d1f8b475179e125 | +| **Root State Commit**: bd50708e7808be0d43725a9eae6039558b32b679c5a584a2e6103bb027dad7eb | +| **Git Commit**: 2644560c0562412a3c2209820be07f8f3f8b1846 | +| **Branch/Tag**: v0.19.2 | +| **Docker Image Tag**: v0.19.2 | + +## Devnet 24 + +| Spork Info | +| :-------------------------------------------------------------------------------------- | +| **Date**: June 22, 2021 | +| **Root Height**: 36290422 | +| **Root Parent ID**: 8d6fad91536ec750d1bb44ebb59e030af2dca49d41c104e45f4f82433184e663 | +| **Root State Commit**: fdfd7a9fff481256972095ffc2c6cba300128f41d8c6aa971985de29427eb39d | +| **Git Commit**: 37d9ae7a309bf7d21063f57fce008d04828d4840 | +| **Branch/Tag**: v0.18.3 | +| **Docker Image Tag**: v0.18.3 | + +## Devnet 23 + +| Spork Info | +| :-------------------------------------------------------------------------------------- | +| **Date**: May 25, 2021 | +| **Root Height**: 33257098 | +| **Root Parent ID**: dafa3e7a9a93de8ceb0a3acd09b2cce4ad0e5d7ea8fe4237f27c4503e5ad416c | +| **Root State Commit**: decf340a722ba136c94ece029e9333d9fbcf216482cd1c81a274365e2abd6688 | +| **Git Commit**: fef838147fa70c94a254183e23e7e79f0d412ef6 | +| **Branch/Tag**: v0.17.3 | +| **Docker Image Tag**: v0.17.3 | + +## Devnet 22 + +| Spork Info | +| :-------------------------------------------------------------------------------------- | +| **Date**: Apr 27, 2021 | +| **Root Height**: 30171528 | +| **Root Parent ID**: 46c7c675f2ed413532009a6a6ecaa566d360a806e033693520d7add147ca89ea | +| **Root State Commit**: d88edf1b2a07dba9ef48214dbffb743c0b2e01f7c74e3e14d828ac076d30f1a6 | +| **Git Commit**: 8331b78d99eddea405076e3b6a7839ec5f6ea209 | +| **Branch/Tag**: v0.16.2 | +| **Docker Image Tag**: v0.16.2 | + +## Devnet 21 + +| Spork Info | +| :-------------------------------------------------------------------------------------- | +| **Date**: Mar 30, 2021 | +| **Root Height**: 26935025 | +| **Root Parent ID**: 3f92949a68c577b6d7d17267f00fc47304d1c44052f0c9a078b63fd344f636dd | +| **Root State Commit**: 21f48748d35178bd6ad89f6324321fa9d123ee7a07b07826acbce887260b2c70 | +| **Git Commit**: 8331b78d99eddea405076e3b6a7839ec5f6ea209 | +| **Branch/Tag**: v0.15.3-patch.1 | +| **Docker Image Tag**: v0.15.3-patch.1 | + +## Devnet 20 + +| Spork Info | +| :------------------------------------------------------------------------------------- | +| **Date**: Mar 9, 2021 | +| **Root Height**: 25450390 | +| **Root Parent ID**: febe212117a83f7f70ed6a5af285ff03332f81a1120ab2c306560c4cb42672f7 | +| **Root State Commit**: 828259e9cb895f7f8a7306debbe6de524500db65cb6b80e27b2db9040513b04e | +| **Git Commit**: b9b197280d6590576f1ef183bc3d04d41d6be587 | +| **Branch/Tag**: v0.14.19 | +| **Docker Image Tag**: v0.14.19 | + +--- + +## Devnet 19 + +| Spork Info | +| :------------------------------------------------------------------------------------- | +| **Date**: Feb 3, 2021 | +| **Root Height**: 16483518 | +| **Root Parent ID**: 4220911048404bd3a7733ab6219531a5945dc20020f86869bcd6422c3a6e3f76 | +| **Root State Commit**: f6eea9b652a7df433b80d8d647ba414aabcfa03153dd1cba33048c27ce888097 | +| **Git Commit**: eb11ae095df6db6e856b1a8e824f03ce4c713b19 | +| **Branch/Tag**: v0.14.0 | +| **Docker Image Tag**: v0.14.0 | + +--- + +## Devnet 18 + +| Spork Info | +| :------------------------------------------------------------------------------------- | +| **Date**: Dec 11, 2020 | +| **Root Height**: 17756122 | +| **Root Parent ID**: 52ace0d0c8d4e574213fe98e19a5043f215bee992659bd1ef35c5758acf54d1b | +| **Root State Commit**: b1412c9d453b1c10d3ace6111e00ac804d564ba3d3295002bedb077685c7da73 | +| **Git Commit**: 115ccee9cae920ee5bc309537cf43a9b152a1cf9 | +| **Branch/Tag**: v0.13.0 | +| **Docker Image Tag**: v0.13.0 | + +--- + +## Devnet 17 + +| Spork Info | +| :------------------------------------------------------------------------------------- | +| **Date**: Nov 27, 2020 | +| **Root Height**: 16483518 | +| **Root Parent ID**: 96d452f9d2a15fafab720f1809fc490b019b23e42c885590e62085e48b8c2b6b | +| **Root State Commit**: 0b45f6055a1f09b413d098997cc0e7c9a0ef19eac8b4d294085b0e2f436c6bff | +| **Git Commit**: ef54713595d0fe1e0bb4b14e9469c4a64dfaf6e7 | +| **Branch/Tag**: v0.12.1 | +| **Docker Image Tag**: v0.12.1 | \ No newline at end of file diff --git a/static/markdown/networks/node-ops/node-operation/protocol-state-bootstrap.md b/static/markdown/networks/node-ops/node-operation/protocol-state-bootstrap.md new file mode 100644 index 0000000000..52021cc072 --- /dev/null +++ b/static/markdown/networks/node-ops/node-operation/protocol-state-bootstrap.md @@ -0,0 +1,152 @@ +--- +title: Protocol State Bootstrapping +description: How to bootstrap a new or existing node +--- + +When a node joins the network, it bootstraps its local database using a trusted initialization file, called a Root Snapshot. +Most node operators will use the `Spork Root Snapshot` file distributed during the [spork process](./spork.md). +This page will explain how the bootstrapping process works and how to use it in general. + +For guides covering specific bootstrapping workflows, see: +- [Node Bootstrap](./node-bootstrap.md) for bootstrapping a newly joined node. +- [Reclaim Disk](./reclaim-disk.md) for bootstrapping from a recent snapshot to recover disk space. + + + This page covers only Protocol State bootstrapping and applies to Access, Collection, Consensus, & Verification Nodes. + Execution Nodes also need to bootstrap an Execution State database, which is not covered here. + + +## Node Startup + +When a node starts up, it will first check its database status. +If its local database is already bootstrapped, it will start up and begin operating. +If its local database is not already bootstrapped, it will attempt to bootstrap using a Root Snapshot. + +There are two sources for a non-bootstrapped node to obtain a Root Snapshot: +1. Root Snapshot file in the `bootstrap` folder +2. Dynamic Startup flags, which will cause the node to download a Root Snapshot from a specified Access Node + +The node software requires that only one of the above options is provided. + +## Using a Root Snapshot File + + + If your node already has a bootstrapped database, the Root Snapshot file will be ignored. If both a Root Snapshot and Dynamic Startup flags are present, the node will not startup. + + +Using a Root Snapshot file is more flexible but more involved for operators compared to Dynamic Startup. + +A file in `$BOOTDIR/public-root-information` named `root-protocol-state-snapshot.json` will be read and used as the Root Snapshot for bootstrapping the database. + +### Instructions + +1. Obtain a Root Snapshot file (see below for options) +2. Ensure your node is stopped and does not already have a bootstrapped database. +3. Move the Root Snapshot file to `$BOOTDIR/public-root-information/root-protocol-state-snapshot.json`, where `$BOOTDIR` is the value passed to the `--bootstrapdir` flag. +4. Start your node. + +### Obtain Root Snapshot File using Flow CLI + +[Flow CLI](../../../tools/flow-cli/index.md) supports downloading the most recently sealed Root Snapshot from an Access Node using the [`flow snapshot save`](../../../tools/flow-cli/utils/snapshot-save.md) command. + +When using this method: +- ensure you connect to an Access Node you operate or trust +- ensure you use the [`--network-key`](../../../tools/flow-cli/utils/snapshot-save#network-key) flag so the connection is encrypted + +### Obtain Root Snapshot File from Protocol database + +If you have an existing node actively participating in the network, you can obtain a Root Snapshot using its database. + +1. Obtain a copy of the Flow `util` tool and ensure it is in your `$PATH`. This tool is distributed during sporks, or you can build a copy from [here](https://github.com/onflow/flow-go/tree/master/cmd/util). +2. Stop the existing node. +3. Construct a Root Snapshot using the `util` tool. The tool will print the JSON representation to STDOUT, so you can redirect the output to a file. + +Replace `$DATADIR` with the value passed to the `--datadir` flag. You can specify the desired reference block for the snapshot. + +Retrieve the snapshot for the latest finalized block: +```sh +util read-protocol-state snapshot -d $DATADIR --final > latest-finalized-snapshot.json +``` + +Retrieve the snapshot for a specific finalized block height: +```sh +util read-protocol-state snapshot -d $DATADIR --height 12345 > specific-height-snapshot.json +``` + +## Using Dynamic Startup + +Dynamic Startup is a startup configuration where your node will download a Root Snapshot and use it to bootstrap its local database. +Dynamic Startup is designed for nodes which are newly joining the network and need to [bootstrap from within a specific epoch phase](./node-bootstrap#timing), but can be used for other use-cases. + + + If your node already has a bootstrapped database, Dynamic Startup flags will be ignored. If both a Root Snapshot and Dynamic Startup flags are present, the node will not startup. + + +When using Dynamic Startup, we specify: +1. An Access Node to retrieve the snapshot from. +2. A target epoch counter and phase to wait for. + +After startup, your node will periodically download a candidate Root Snapshot from the specified Access Node. +If the Root Snapshot's reference block is either **within or after** the specified epoch phase, the node will bootstrap using that snapshot. +Otherwise the node will continue polling until it receives a valid Root Snapshot. + +See the [Epochs Schedule](./../../staking/03-schedule.md) for additional context on epoch phases. + +### Specifying an Access Node + +Two flags are used to specify which Access Node to connect to: +- `--dynamic-startup-access-address` - the Access Node's secure GRPC server address +- `--dynamic-startup-access-publickey` - the Access Node's networking public key + +Select an Access Node you operate or trust to provide the Root Snapshot, and populate these two flags. + +For example, to use the Access Node maintained by the Flow Foundation for Dynamic Startup, specify the following flags: +```shell ExampleDynamicStartupFlags + ... \ + --dynamic-startup-access-address=secure.mainnet.nodes.onflow.org:9001 \ + --dynamic-startup-access-publickey=28a0d9edd0de3f15866dfe4aea1560c4504fe313fc6ca3f63a63e4f98d0e295144692a58ebe7f7894349198613f65b2d960abf99ec2625e247b1c78ba5bf2eae +``` + +### Specifying an Epoch Phase + +Two flags are used to specify when to bootstrap: +- `--dynamic-startup-epoch-phase` - the epoch phase to start up in (default `EpochPhaseSetup`) +- `--dynamic-startup-epoch` - the epoch counter to start up in (default `current`) + +> You can check the current epoch phase of the network by running [this](https://github.com/onflow/flow-core-contracts/blob/master/transactions/epoch/scripts/get_epoch_phase.cdc) script. Alternatively, you can also check the current epoch phase [here](https://dashboard.flow.com/) under Epoch Phase. + +#### Bootstrapping Immediately + +If you would like to bootstrap immediately, using the first Root Snapshot you receive, then specify a past epoch counter: +```shell ExampleDynamicStartupFlags + ... \ + --dynamic-startup-epoch-phase=1 +``` +You may omit the `--dynamic-startup-epoch-phase` flag. + +### Instructions + +#### Example 1 +Use Dynamic Startup to bootstrap your node at the `Epoch Setup Phase` of the current epoch (desired behaviour for newly joining nodes): +1. Ensure your database is not already bootstrapped, and no Root Snapshot file is present in the `$BOOTSTRAPDIR` folder. +2. Add necessary flags to node startup command. +For example, using the Flow Foundation Access Node: +```sh + ... \ + --dynamic-startup-access-address=secure.mainnet.nodes.onflow.org:9001 \ + --dynamic-startup-access-publickey=28a0d9edd0de3f15866dfe4aea1560c4504fe313fc6ca3f63a63e4f98d0e295144692a58ebe7f7894349198613f65b2d960abf99ec2625e247b1c78ba5bf2eae +``` +3. Start your node. + +#### Example 2 +Use Dynamic Startup to bootstrap your node immediately, using the most recent Root Snapshot: +1. Ensure your database is not already bootstrapped, and no Root Snapshot file is present in the `$BOOTSTRAPDIR` folder. +2. Add necessary flags to node startup command. +For example, using the Flow Foundation Access Node: +```sh + ... \ + --dynamic-startup-access-address=secure.mainnet.nodes.onflow.org:9001 \ + --dynamic-startup-access-publickey=28a0d9edd0de3f15866dfe4aea1560c4504fe313fc6ca3f63a63e4f98d0e295144692a58ebe7f7894349198613f65b2d960abf99ec2625e247b1c78ba5bf2eae \ + --dynamic-startup-epoch=1 +``` +3. Start your node. \ No newline at end of file diff --git a/static/markdown/networks/node-ops/node-operation/reclaim-disk.md b/static/markdown/networks/node-ops/node-operation/reclaim-disk.md new file mode 100644 index 0000000000..46800505a4 --- /dev/null +++ b/static/markdown/networks/node-ops/node-operation/reclaim-disk.md @@ -0,0 +1,69 @@ +--- +title: Managing disk space +description: How to manage the node disk space +--- + +As the chain advances, nodes receive chain data and store it on disk. +Hence, the disk usage of a node keeps increasing gradually over time. + +In addition to this, currently nodes also experience an intermittent 30-35% spike in disk usage caused by the compaction process of the Badger database used by the node software. + +> The spikes will be eliminated once the Badger database is replaced by the Pebble database in the future. + +Hence, as a node operator, please make sure to do the following: + +1. Provision enough disk space as per the node role (see: [node-provisioning](./node-provisioning.md)) + +2. Setup disk usage monitoring and ensure that the node has enough room to grow and to also accommodate those intermittent spikes. + +3. If needed, please add more disk space to the node from time to time. + +> It highly recommended to setup alerting around disk usage to facilitate timely action and avoid any downtime and subsequent reward slashing for the node. + +## Reclaiming disk space + +### Access, Collection, Consensus and Verification node + +If you are running any node other than an execution node and the node is close to running out of disk space or has already exhausted all of its disk, you can re-bootstrap the node's database. This frees up disk space by discarding historical data past a certain threshold. + +1. Stop the node. + +2. Back up the data folder to a tmp folder in case it is required to revert this change. The default location of the data folder is `/var/flow/data` unless overridden by the `--datadir` flag. +```sh +mv /var/flow/data /var/flow/data_backup +``` + +3. Configure the node to bootstrap from a new, more recent Root Snapshot. You may use either of the two methods described [here](./protocol-state-bootstrap.md) to configure your node. + +4. Start the node. The node should now recreate the data folder and start fetching blocks. + +5. If the node is up and running OK, delete the `data_backup` folder created in step 2. +```sh +rm -rf /var/flow/data_backup +``` + +#### Limitation for Access Node + +Re-bootstrapping allows the node to be restarted at a particular block height by deleting all the previous state. + +For an **Access Node**, this results in the node not being able to serve any API request before the height at which the node was re-bootstrapped. + +_Hence, if you require the access node to serve data from the start of the last network upgrade (spork), do not use this method of reclaiming disk space. Instead provision more disk for the node._ + +### Execution node + +For an execution node, the chunk data directory is the one that takes up most of the space. To reclaim space on an execution, do the following: + +1. Stop the Execution Node. + +2. Remove the Chunk Data Pack Directory. The default is `/var/flow/data/chunk_data_pack` unless overridden by the `chunk-data-pack-dir` parameter. + + Do **not** delete the bootstrap folder. + + ``` rm -rf /var/flow/data/chunk_data_pack``` + +3. Start the Execution Node. + +Upon restart, the chunk data pack directory will be automatically recreated. + +> Note: Always exercise caution when performing system operations, and make sure you have a backup of important data before making any changes. \ No newline at end of file diff --git a/static/markdown/networks/node-ops/node-operation/slashing.md b/static/markdown/networks/node-ops/node-operation/slashing.md new file mode 100644 index 0000000000..dd62d42850 --- /dev/null +++ b/static/markdown/networks/node-ops/node-operation/slashing.md @@ -0,0 +1,324 @@ +--- +title: Slashing Conditions +sidebar_position: 17 +--- + +## Introduction + +Flow is a proof-of-stake system, which means holders of FLOW can earn inflationary rewards +by staking their FLOW tokens to secure and operate the network. +A node can participate in the Flow network by depositing a specific amount of stake +(based on role types) thereby making a bonded pledge to participate +in the Flow protocol during the upcoming epoch. +(An epoch is a finite amount of time defined by the protocol, approximately one week, +during which the nodes participate to run the protocol and are responsible for their operations.) + +See the [Staking and Epochs section of the documentation](../../staking/index.md) to learn more +about the design and functionality of this part of the protocol. + +Flow nodes follow the procedures defined in the protocol (based on their role) +in order to receive rewards. Any deviation (see Slashing Challenges below) +from the protocol can result in decreased reward payments or punishments. +Severe infractions, which undermine the safety of the network, +can lead to “slashing”, where some or all of the staked tokens are confiscated from the offending node(s). + +This reward and punishment structure is designed to guarantee the security +of the protocol and optimize performance over time. +This document outlines the most severe infractions against the protocol +which result in some portion of a node’s stake being taken from them (“slashing conditions”). +Enforcing these slashing conditions is critical to ensure the cryptoeconomic security of the protocol. +Future documents will describe an incentive structure that encourages system-wide efficiency and speed, +by providing bonuses to the most performant nodes and withholding payments to nodes that are unresponsive. + +This document assumes a working understanding of the high-level architecture of the Flow blockchain. +Readers who are new to Flow or those looking for a refresher are encouraged +to read the Protocol Summary [here](../node-operation/node-roles.md) and the staking documentation. + +## Slashing Conditions + +Any violation of the Flow protocol that could result in staked tokens being seized +from the offending nodes is called **Slashable Behaviour.** +In order for the tokens to be seized, the data necessary to prove the occurrence of Slashable Behaviour +must be combined with the data necessary to attribute the behaviour +to the node(s) responsible into a **Slashing Witness**. +(A reduction of rewards, e.g. due to lack of active participation, +is not formally included in our definition of slashing.) +The Flow protocol considers only server threats to safety and liveness +to be slashable conditions and as such, there are no performance related slashing penalties. +The one exception is in the case of missing Collections (see the section on MCC below), +where a widespread failure to respond by a large number of nodes is presumed +to be coordinated and therefore punishable with slashing. + +Most Slashable Behaviour in Flow can be detected and attributed to the offender +by a single honest node observing that behaviour. +(In other words, one node can generate a Slashing Witness without coordinating with other nodes.) +However, some Slashable Behaviour can only be detected and attributed +by combining information from multiple nodes. In those situations, +the node that first detects the potential infraction raises a **Slashing Challenge**. +When a challenge is raised, other nodes are expected to provide additional information +which can be combined with the original challenge into a definitive Slashing Witness +that is used to adjudicate the challenge. Each type of Slashing Challenge depends +on different information provided from a different subset of nodes, +the details of which are provided below. + +Flow adheres to a number of principles in the design of its slashing rules: + +- Only Consensus Nodes can perform slashing, and only by following the BFT consensus mechanism +defined in the protocol. As such, a super-majority of Consensus Nodes must inspect +and confirm a Slashing Witness before any punishment is levied. + +- All Slashing Witnesses are objectively decidable. +Given the current protocol state (maintained by the Consensus Nodes) +and a well-formed Slashing Witness, all non-Byzantine Consensus Nodes will deterministically come +to the same conclusion as to which node or nodes should be slashed (if any) +and the amount of stake to be seized. + +- All Slashing Behaviour in Flow requires active malfeasance on the part of the offending node. +In other words, a node will only be slashed if it takes an action against the rules of the protocol, +and it will not be slashed if it fails to take an action prescribed by the protocol. +(“If your machine is crashed, you won’t get slashed.”) The one exception +is in the case of missing Collections (see the section on MCC below), +where a widespread failure to respond by a large number of nodes is presumed +to be coordinated and therefore punishable with slashing. + +- Flow makes no attempt to detect and punish liveness failures within the protocol. +A liveness failure across the network functionally slashes the stake of any participants +excluded from participating in the reboot (since their stake is locked in a non-functional network). +Community analysis can determine which nodes were responsible for the failure +and exclude those Byzantine actors from the new instance. + +- Any staked node of Flow can submit a Slashing Witness for any Slashable Behaviour, +regardless of its role. (For example, a Collection Node could submit a Slashing Witness +for an invalid execution receipt, even though the protocol doesn’t require Collection Nodes +to verify execution receipts.) + +- Submitting an invalid Slashing Witness is Slashable Behaviour. +We treat the invalid Slashing Witness itself as the Slashing Witness for that case. + +## Stages of Slashing + +Transitioning to a rigorous staking protocol in which all slashable conditions are checked, +enforced, and punished will take place over three phases. +The Slashing Challenges section below outlines the various challenges +which may be submitted against an offending node but these challenges +will not be fully enforced until Phase 3 of the network. + +### Phase 1: Beta + +- In the beta phase of the network, the expectation is that nodes are running error detection +and logging but not submitting formal challenges. Any errors found may be submitted +to the Flow team for additional testing and security improvements. + +### Phase 2: Testing Slashing Mechanics + +- At this time the slashing mechanisms will be implemented and require testing. +Formal challenges should be raised and the protocol will follow the complete, +formal mechanics for arbitrating challenges and slashing perpetrators, +but no real slashing will take place. + +### Phase 3: BFT + +- By now, the network has been security-hardened and tested and valid challenges +result in real slashing of the offending node. + +## Slashing Challenges + +### 0. All Nodes + +**Invalid Report Witness (IRW): **if any nodes report an invalid/inaccurate witness, +an invalid report witness will be reported by the Consensus Nodes, +and the node(s) reporting the witness get slashed. + +### 1. Collection Nodes + +**1.1 Missing Collection Challenge (MCC): ** Collection nodes are responsible +for storing collection content (all transactions) for any collection which they guarantee +during the current epoch and the first 1000 blocks of the next epoch. +During this time they have to respond to any collection request from staked execution, +verification and Consensus Nodes and should respond in a timely manner (specific timeout). +If an Execution Node or a Verification Node doesn't receive the response from any +of the collection guarantors (Collection Nodes who signed a collection), +they can raise a Missing Collection Challenge and broadcast it to the Consensus Nodes to evaluate. + +**Adjudication: **Consensus nodes randomly contact some of the guarantors. +If Collection Nodes don't respond, a portion of their stakes will be seized. +If the amount of their stake goes to less than half, they will be fully slashed. +Then the Consensus Nodes notify all the Execution Nodes to skip that collection. +If any of the Collection Nodes respond, Consensus Nodes redirect the collection content +to the Execution Nodes but will also set small penalties both +for all the guarantors and that Execution Node (according to their revenue ratio). + +**1.2 Invalid Collection Witness (ICW):** Collection nodes are responsible for responding +to collection content queries by collection hash from any staked nodes. +The collection hash is the hash of an ordered list of transaction hashes. +If a collection content sent by the Collection Node turns out to be invalid, +any staked node can report an Invalid Collection Witness. This includes cases where: + +- the content is malformed or incomplete, +- there exists an invalid transaction inside the collection, or +- the collection hash doesn't match (inside collection guarantee). + +**Adjudication:** Consensus nodes evaluate the content of the collection, +if the collection is found invalid, the Collection Node who signed the content is slashed. + +**1.3 Double Collection Proposal Witness (DCPW):** Collection nodes of a cluster run a mini consensus +inside the cluster to decide on a collection, which requires Collection nodes to propose +the collection and aggregate votes from others. During the collection consensus, +if a Collection Node proposes more than one proposal, any other Collection Node +inside the cluster can report a Double Collection Proposal Witness (including both proposals). + +**Adjudication: **Consensus nodes evaluate the content and signatures of these two proposals, +and if the witness turns out to be valid, the Collection Node who proposed two collections will get slashed. + +**1.4 Double Collection Voting Witness (DCVW):** Collection nodes of a cluster +run a mini consensus inside the cluster to decide on a collection, +which requires Collection nodes to propose the collection and aggregate votes from others. +During the collection consensus, if a Collection Node votes for more than one collection proposal +with identical collection number and size, any other Collection Node inside the cluster +can report a Double Collection Voting Witness (including both votes). + +**Adjudication: **Consensus nodes evaluate the signatures of these two votes and evaluate them, +and if the witness turns out to be valid, the Collection Node who voted two times will get slashed. + +### 2. Consensus Nodes + +**2.1 Double Block Proposal Witness (DBPW):** Consensus nodes run the consensus (HotStuff algorithm) over blocks. +During these consensus steps, if a Consensus Node proposes more than one variation of a block proposal, +any other Consensus Node can report a Double Block Proposal Witness (including both proposals). +This report will be broadcasted to all other Consensus Nodes. + +**Adjudication: **Consensus nodes evaluate content and signatures of both proposals. +If the witness turns out to be valid, the Consensus Node who submitted both proposals will get slashed. + +**2.2 Double Block Voting Witness (DBVW): ** Consensus nodes run the consensus (HotStuff algorithm) +over blocks. During the consensus steps, if a Consensus Node votes for +more than one block proposal with the same height, any other Consensus Node can report +a Double Block Voting Witness (including both votes). +This report will be broadcasted to all other Consensus Nodes. + +**Adjudication: **Consensus nodes evaluate content and signatures of both votes +and If the witness turns out to be valid, the Consensus Node who submitted both votes will get slashed. + +**2.3 Invalid Block Vote Witness (IBVW):** If a Consensus Node votes for an invalid block +or the content of the vote itself is invalid (e.g. vote for non-existing block), +any other Consensus Nodes can report an Invalid Block Vote Witness. + +**Adjudication: **Consensus nodes evaluate the vote content and signature. +If the witness turns out to be valid, the Consensus Node who submitted the faulty vote will get slashed. + +**2.4 Invalid Block Proposal Witness (IBPW):** If a Consensus Node proposes +an invalid block proposal (e.g. quorum certificate without 2/3 vote), +any other Consensus Nodes can raise an Invalid Block Proposal Witness. + +**Adjudication: **Consensus nodes evaluate the proposal content and signature, +If the witness turns out to be valid, the Consensus Node who submitted the invalid proposal +will get slashed. + +**2.5 Invalid Block Witness (IBW):** If the block contents returned by any Consensus Node is invalid, +any node can raise the Invalid Block Witness: + +- It is malformed or incomplete +- It doesn't match the payload hash provided by the block header + +**Adjudication: **Consensus nodes evaluate the block content and signatures. +If the witness turns out to be valid, the Consensus Node who signed the block content will get slashed. + +**2.6 Invalid Random Beacon Signature Witness (IRBSW):** +If any participant of the random beacon returns an invalid signature, +an Invalid Random Beacon Signature Witness can be reported by other Consensus Nodes. + +**Adjudication:** Consensus nodes evaluate the random beacon signature. +If the witness turns out to be valid, the Consensus Node who signed the invalid random beacon part +will get slashed. + +### 3. Execution Nodes + +**3.1 Faulty Computation Challenge (FCC): ** If any of the Verification Nodes +find a fault in the execution of transactions by an Execution Node it can raise an FCC challenge. +An FCC challenge includes a faulty chunk and all the evidence. + +**Adjudication: **Consensus nodes evaluate the challenge, by sending requests +for collection contents and chunk data needed to run the faulty chunk and comparing +the results against the expected state commitment. If Consensus Nodes detect any fault +in the execution of that chunk, the Execution Node(s) who signed the faulty execution receipts +will get slashed. If no fault is found, the Verification Node who raised the challenge will get slashed. + +**3.2 Conflicting Execution Results Challenge (CERC): ** +If two or more variations of execution results are reported by Execution Nodes for a given block. +Since only one can be valid, Consensus Nodes raise a conflicting execution results challenge. + +**Adjudication: **As soon as this challenge is raised, all the Verification Nodes +go into full check mode (checks all the chunks). The first execution result +that receives result approval from at least 2/3 of Verification Nodes is the accurate one, +and the other execution results will be considered faulty and Execution Nodes generating those +will get slashed. If none of the execution results receive majority approval +from Verification Nodes after a very long timeout, +all the Consensus Nodes start executing chunks to determine the correct output. + +**3.3 Invalid Chunk Data Package Witness (ICDPW):** If the contents of a chunk data package +doesn't match the hash provided inside the execution result, or the contents is invalid, +the Verification Nodes can report an Invalid Chunk Data Package Witness. + +**Adjudication: **Consensus nodes evaluate the content of the chunk data package. +If the witness turns out to be valid, the Execution Node(s) +who signed the faulty chunk data package will get slashed. + +**3.4 Missing Chunk Data Package Challenge (MCDPC):** +If an Execution Node doesn't respond to the chunk data package request by any staked Verification Node, +a Missing Chunk Data Package Challenge can be raised by the Verification Node. + +**Adjudication: **When this challenge is received by the Consensus Nodes, +they contact Execution Nodes and ask for the chunk data package. +If none of the Execution Nodes respond after a long timeout, all of them get slashed. +If any of the Execution Nodes responds with a valid chunk data package, +Consensus Nodes redirect the chunk data package to the Verification Nodes +but will also set small penalties both for all the Execution Nodes and the challenge raiser +(Verification Node) according to their revenue ratio. + +**3.5 Execution Results Timeout Challenge (ERTC):** +If no execution receipt received in X number of blocks after the submission of each block, +the liveness of the system is compromised and Consensus Nodes can raise +an Execution Results Timeout Challenge for all the Execution Nodes. + +**Adjudication: **When this challenge is received by the Consensus Nodes, +they contact Execution Nodes and ask for an update. If none of the Execution Nodes respond +after a long timeout, all of them get slashed. +If any of the Execution Nodes return the execution receipt, the case is dismissed. + +**3.6 Invalid Execution Receipt Witness (IERW):** +If an Execution Node provides an execution receipt that is not valid, +the Consensus Nodes can report an Invalid Execution Receipt Witness. + +**Adjudication: **Consensus nodes evaluate the content of the execution receipt. +If the witness turns out to be valid, the Execution Node(s) +who signed the invalid execution receipt will get slashed. + +**3.7 Non-Matching SPoCKs Challenge (NMSC): ** +If the SPoCKs provided by the Execution Node don't match the ones provided by the Verification Node, +the Consensus Nodes can raise a Non-Matching SPoCKs challenge. + +**Adjudication: **Consensus nodes have to re-execute the chunk +to be able to compute the accurate SPoCKs secret to be able to adjudicate the challenge. +This requires requesting the collection and all other data needed for execution from other nodes. +Any node which provided invalid SPoCKs will be slashed. + +### 4. Verification Nodes + +**4.1 Non-Matching SPoCKs Challenge (NMSC):** +If the SPoCKs provided by the Execution Node don't match the ones provided by the Verification Node, +the Consensus Nodes can raise a Non-Matching SPoCKs challenge. + +**Adjudication: **Consensus nodes have to re-execute the chunk to determine the accurate SPoCKs secret +which is needed to adjudicate the challenge. This requires requesting the collection +and all other data needed for execution from the other nodes. +Any node which provided invalid SPoCKs will be slashed. + +**4.2 Invalid Result Approval Witness (IRAW):** +If a Verification Node provides an invalid result approval, +the Consensus Nodes can report this witness. +This includes cases that a Verification Node sends a result approval +for a chunk that was not assigned to the Verification Node (excluding full check mode) +or if the SPoCK’s signature doesn't match the public key of the Verification Node. + +**Adjudication: **Consensus nodes evaluate the content and signatures of the result approval. +If the witness turns out to be valid, the Verification Node who signed that result approval be slashed. \ No newline at end of file diff --git a/static/markdown/networks/node-ops/node-operation/spork.md b/static/markdown/networks/node-ops/node-operation/spork.md new file mode 100644 index 0000000000..51d70a87b2 --- /dev/null +++ b/static/markdown/networks/node-ops/node-operation/spork.md @@ -0,0 +1,93 @@ +--- +title: Network Upgrade (Spork) Process +description: Steps to be carried out by node operators during a network upgrade. +sidebar_position: 15 +--- + +## Overview + +A spork is a coordinated network upgrade process where node operators upgrade their node software and +re-initialize with a consolidated representation of the previous spork's state. This enables rapid development +on the Flow Protocol and minimizes the impact of breaking changes. + +The Flow network sporks approximately once every year. Upcoming sporks +are announced in advance on the `#flow-validators-announcements` **Discord** channel +and in [Upcoming Sporks](./upcoming-sporks.md). The `#flow-validators-announcements` channel is +also used to coordinate during the spork process. + +This guide is for existing operators participating in a spork. See [Node Bootstrap](./node-bootstrap.md) +for a guide to joining the network for the first time. + +## Step 1 - Cleaning Up Previous Spork State + +Once the spork start has been announced on, stop your node and clear your database. The node should stay stopped for the duration of the spork. + + + You can skip this step if it is your first time running a node on Flow. + + +1. Stop your Flow node +2. Clear the contents of your `data` directory that you have previously created. The default location is `/var/flow/data`. The `data` directory contains the Flow chain state. + +## Step 2 - Start Your Node + +Once you receive an announcement that the spork process is complete (via Discord), you will need to fetch the genesis info, update your runtime configuration and then boot your Flow node up! + + + +If you had set the [dynamic bootstrap arguments](https://developers.flow.com/networks/node-ops/node-operation/protocol-state-bootstrap) command line arguments (`--dynamic-startup-access-address`, `--dynamic-startup-access-publickey`, `--dynamic-startup-epoch-phase`) please remove them. + + + +1. Run the transit script to fetch the new genesis info: + `./boot-tools/transit pull -b ./bootstrap -t ${PULL_TOKEN} -r ${YOUR_NODE_TYPE} --concurrency 10 --timeout 15m` + +- `PULL_TOKEN` will be provided by the Flow team. + - For `collection`, `consensus`, `verification` node type it will generally be `testnet-x` or `mainnet-x` where x is the latest number of respective network upgrade. e.g. `testnet-52`, `mainnet-26`. + - For `execution` node type it will generally be `testnet-x-execution` or `mainnet-x-execution`. + - For `access` node: + - It will generally be `testnet-x` or `mainnet-x` if execution data indexing is not enabled. + - It will generally be `testnet-x-execution` or `mainnet-x-execution` if execution data indexing is enabled. + +- `YOUR_NODE_TYPE` should be one of `collection`, `consensus`, `execution`, `verification`, `access` based on the node(s) that you are running. + +```shell Example +$ ./boot-tools/transit pull -b ./bootstrap -t mainnet-16 -r consensus +Transit script Commit: a9f6522855e119ad832a97f8b7bce555a163e490 +2020/11/25 01:02:53 Running pull +2020/11/25 01:02:53 Downloading bootstrap/public-root-information/node-infos.pub.json +2020/11/25 01:02:54 Downloading bootstrap/public-root-information/root-protocol-snapshot.json +2020/11/25 01:02:54 Downloading bootstrap/random-beacon.priv.json.39fa54984b8eaa463e129919464f61c8cec3a4389478df79c44eb9bfbf30799a.enc +2020/11/25 01:02:54 SHA256 of the root block is: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 + +$ tree ./bootstrap/ + ./bootstrap/ + ├── private-root-information + │ └── private-node-info_39fa54984b8eaa463e129919464f61c8cec3a4389478df79c44eb9bfbf30799a + │ └── node-info.priv.json + ├── public-root-information + │ ├── node-id + │ ├── node-info.pub.39fa54984b8eaa463e129919464f61c8cec3a4389478df79c44eb9bfbf30799a.json + │ ├── node-infos.pub.json + │ └── root-protocol-snapshot.json + └── random-beacon.priv.json.39fa54984b8eaa463e129919464f61c8cec3a4389478df79c44eb9bfbf30799a +``` + +2. Pull the latest changes from [flow-go repository](https://github.com/onflow/flow-go) +3. Get your `node-id`, you can find it at `/path/to/bootstrap/public-genesis-information/node-id` +4. Update the `FLOW_GO_NODE_ID` inside [runtime-conf.env](https://github.com/onflow/flow-go/blob/master/deploy/systemd-docker/runtime-conf.env) to the `node-id` that you got from the previous step +5. Start your Flow node via `docker` or `systemd` + +See [Node Bootstrap](./node-bootstrap.md) for detailed information on Docker/Systemd configuration. + +## Common Issues + +### Error: cannot create connection + +```shell +20T18:34:21Z","message":"could not create connection"} +{"level":"error","node_role":"consensus","node_id":"6d3fac8675a1df96f4bb7a27305ae531b6f4d0d2bc13a233e37bb07ab6b852dc","target":"QmVcSQaCdhmk1CMeMN7HTgGiUY1i2KqgVE2vvEmQXK4gAA","error":"failed to dial : all dials failed + * [/ip4/155.138.151.101/tcp/3569] dial tcp4 155.138.151.101:3569: connect: connection refused","retry_attempt":2,"time":"2020-05-20T18:34:21Z","message":"could not create connection"} +``` + +This error is OK. Your fellow node operators have not turned on/joined the network yet. So no need to worry about it! \ No newline at end of file diff --git a/static/markdown/networks/node-ops/node-operation/upcoming-sporks.md b/static/markdown/networks/node-ops/node-operation/upcoming-sporks.md new file mode 100644 index 0000000000..6a9d98accf --- /dev/null +++ b/static/markdown/networks/node-ops/node-operation/upcoming-sporks.md @@ -0,0 +1,44 @@ +--- +title: Upcoming Sporks +description: Information about upcoming Mainnet & Testnet sporks +sidebar_position: 16 +--- + +The following are the upcoming Spork dates. These dates indicate the intention to Spork. Announcements will be made regarding any delays or changes to these dates in our developer [Discord server](https://discord.gg/flow). + +
    + +| Mainnet Spork Date | Spork Info | Testnet Spork Date | Spork Info | +|:----------------------------|:---------------------------------------|------------------------------------------|------------| +| ~Q3 2024 (exact date tbd) | | Q3 2024 (exact date tbd) | | + | | | May 20, 2024 | Devnet50 | +| Nov 8, 2023 | Mainnet 24 | Nov 2, 2023 | Devnet49 | +| | | Aug 4, 2023 | Devnet48 | +| | | Aug 4, 2023 | Devnet47 | +| June 21, 2023 | Mainnet 23 | Jun 8, 2023 | Devnet46 | +| | | Jun 7, 2023 | Devnet45 | +| | | Apr 24, 2023 | Devnet44 | +| | | Apr 12, 2023 | Devnet43 | +| | | Apr 12, 2023 | Devnet42 | +| Feb 22, 2023 | Mainnet 22 | Jan 30, 2023 —> Feb 22, 2023 | Devnet41 | +| | | Jan 23, 2023 | Devnet40 | +| Jan 18, 2023 | Mainnet 21 | Jan 4, 2023 —> Jan 18, 2023 | Devnet39 | +| Nov 2, 2022 | Mainnet 20 | Oct 19, 2022 —> Nov 2, 2022 | Devnet38 | +| Aug 24, 2022 | Mainnet 19 | Aug 10, 2022 —> Aug 24, 2022 | Devnet37 | +| | | Jul 27, 2022 | Devnet36 | +| June 15, 2022 | [Mainnet 18](./past-upgrades#mainnet-18) | June 9, 2022 —> June 15, 2022 | Devnet35 | +| April 6, 2022 | [Mainnet 17](./past-upgrades#mainnet-17) | April 4, 2022 —> April 6, 2022 | Devnet34 | +| February 9, 2022 | [Mainnet 16](./past-upgrades#mainnet-16) | February 7, 2022 —> February 9, 2022 | Devnet33 | +| December 8, 2021 | [Mainnet 15](./past-upgrades#mainnet-15) | December 7, 2021 —> December 8, 2021 | Devnet32 | +| November 10, 2021 | Cancelled | November 9, 2021 —> November 10, 2021 | Devnet31 | +| October 6, 2021 | [Mainnet 14](./past-upgrades#mainnet-14) | October 5, 2021 —> October 6, 2021 | Devnet30 | +| September 15, 2021 | [Mainnet 13](./past-upgrades#mainnet-13) | September 14, 2021 —> September 15, 2021 | Devnet27 | +| August 18, 2021 | [Mainnet 12](./past-upgrades#mainnet-12) | August 12, 2021 —> August 18, 2021 | Devnet26 | +| July 21, 2021 | [Mainnet 11](./past-upgrades#mainnet-11) | July 20, 2021 —> July 21, 2021 | Devnet25 | +| June 23, 2021 | [Mainnet 10](./past-upgrades#mainnet-10) | June 22, 2021 —> June 23, 2021 | Devnet24 | +| May 26, 2021 | [Mainnet 9](./past-upgrades#mainnet-9) | May 25, 2021 —> May 26, 2021 | Devnet23 | +| April 28, 2021 | [Mainnet 8](./past-upgrades#mainnet-8) | April 27, 2021 —> April 28, 2021 | Devnet22 | +| April 7, 2021 | [Mainnet 7](./past-upgrades#mainnet-7) | March 30, 2021 —> March 31, 2021 | Devnet21 | +| March 10, 2021 | [Mainnet 6](./past-upgrades#mainnet-6) | March 9, 2021 —> March 10, 2021 | Devnet20 | + +
    \ No newline at end of file diff --git a/static/markdown/networks/staking/02-epoch-terminology.md b/static/markdown/networks/staking/02-epoch-terminology.md new file mode 100644 index 0000000000..7a761fe408 --- /dev/null +++ b/static/markdown/networks/staking/02-epoch-terminology.md @@ -0,0 +1,135 @@ +--- +title: Epoch and Staking Terminology +sidebar_label: Epoch and Staking Terminology +description: Important Definitions for Epochs +--- + + + If you haven't read the staking introduction, please read that + first. That document provides a non-technical overview of staking on Flow for + all users and is a necessary prerequisite to this document. + + + This document assumes you have some technical knowledge about the Flow + blockchain and programming environment. + + +## Terminology + +If any of the definitions are confusing, you can find more detail in the other sections of the technical docs. + +**Staker:** Any user who has staked tokens for the Flow network. +A node operator is a staker, and a delegator is a staker as well. + +**Node Operator:** A user who operates a node on the Flow network. Each node operator has a unique node resource +object they store in their account to perform staking operations. + +**Node Operator Metadata:** This information is tracked for each node operator in the Flow network. + - **Node ID:** 32 byte identifier for the node. Usually a hash of the node public key. + - **Role:** Indicates what role the node operator is. (Collection, Consensus, Execution, Verification, Access) + - **Networking Address:** The address that the node operator uses for networking. Using a hostname is highly encouraged. + - **Networking Key:** The 64 byte ECDSA-P256 node operator public key for networking. + - **Staking Key:** The 96 byte BLS12-381 public key for the node. + Used to sign node messages and votes for Quorum Certificate generation. + - **Proof of Possession:** A 48 byte (96 hex characters) string that acts as cryptographic + proof of ownership of the node's staking key. + +**Delegator:** A user who delegates tokens to a node operator and receives rewards for their staked tokens, minus a fee +taken by the node operator. Each delegator stores a unique delegator resource object in their account +that allows them to perform staking operations. + +- **Delegator Metadata:** This information is tracked for all delegators in the network. + - **id:** The ID associated with a delegator. These IDs are assigned to delegators automatically + by the staking contract and are only unique within an individual node operators' record. + - **nodeID:** The ID of the node operator a user delegates to. + +**Node Identity Table:** The record of all the nodes in the network, and their delegators. +The identity table keeps separate lists for the info about node operators and delegators. + + + NOTE: The staking smart contract does not associate a node or delegator with + an account address. It associates it with the assigned resource object that + corresponds to that entry in the contract. There can be any number of these + objects stored in the same account, and they can be moved to different + accounts if the owner chooses. + + +**Epoch:** The period of time between changes in the identity table and reward payments. +(Initially a week, measured in consensus views) +At the end of every epoch, insufficiently staked node operators are refunded their stake, +rewards are paid to those who are currently staked, committed tokens are marked as staked, +unstaking tokens are marked as unstaked, and unstaking requests are changed from staked to unstaking. + +**Consensus View:** A internal detail that the Flow consensus algorithm, HotStuff, uses to measure time. +Views count the number of rounds in the consensus algorithm. +Each round/view the counter is incremented and a new block may be proposed. + +**Seat/Slot:** The right to participate in the network as a node of a certain type +for a specific Epoch. There are a limited number of seats/slots for each node type per epoch. +Current Slot Limits (may be slightly different than what is shown here): +- Access Nodes: 167 +- Collection Nodes: 156 +- Consensus Nodes: 149 +- Execution Nodes: 10 +- Verification Nodes: 105 + +**Candidate:** A node that has committed tokens for the next epoch but has not been accepted yet. +There is a limited number of node slots per epoch and candidate nodes are selected randomly, +so there is a chance that a candidate node will not be chosen to participate in the next epoch +because there aren't enough slots even if they meet all the other regular requirements + +**Staking Auction Phase:** The period of time when nodes and delegators are able to submit staking operations +in preparation for the upcoming epoch. This phase is expected to take over 90% of the time of an epoch. + +**Epoch Setup Phase:** The period of time after the staking auction, where nodes have to perform certain processes +to initialize the state and communication with other nodes for the next epoch. +These processes are called **Cluster Quorum Certificate Generation (QC)**, and **Distributed Key Generation (DKG)**. +If any node does not perform this initialization properly, it is not included in the next epoch's Identity Table. +This phase is expected to take less than 10% of the time of an epoch, near the end. + +**Cluster Quorum Certificate Generation (QC):** A process by which nodes using the HotStuff consensus algorithm +submit signed messages in order to generate a certificate for bootstrapping HotStuff. Each collector cluster runs +a mini-version of HotStuff, and since clusters are randomized each epoch, a new quorum certificate is required +for each cluster each epoch. + +**Distributed Key Generation (DKG):** Process for generating a shared public key to initialize the random beacon. +Consensus nodes use a shared whiteboard to communicate and submit final key vectors to generate a shared key. + +**Epoch Commit Phase:** The final phase of an epoch, after the Epoch Setup Phase. In this phase, the identity table +has been finalized for the next epoch, all setup has been completed, and the network +is simply waiting for the next epoch to start. + +**Service Event:** Special messages that are generated by the epoch smart contracts and included in execution results. +They enable communication between system smart contracts and the Flow protocol. +In other words, they serve as a communication mechanism between the execution state and the protocol state. +Service events are not any different that other Cadence events, except in the fact that +Flow nodes treat them differently because they are being emitted by the service account. + +**Node and Delegator Staked Token Tracking Terms:** + - **Tokens Committed:** The tokens that a user has committed to stake in the next epoch, but that aren't currently staked. + - **Tokens Staked:** The tokens that a user has staked in the current epoch. + - **Tokens Requested to Unstake:** The amount of tokens that a user has requested to be unstaked + at the end of the current epoch (to be removed from the **tokens staked** pool). + - **Tokens Unstaking:** The tokens that were unstaked at the beginning of the current epoch and + are being held for an additional epoch holding period before being released. + - **Tokens Unstaked:** Tokens that used to be committed or staked and have been unstaked. + - **Tokens Rewarded:** Tokens that the user has received via staking rewards. + +**Delegation Rewards Cut:** The percentage of a delegator's rewards that the node operators take. Initially set to 8%. + +**Epoch Payout:** The total amount of tokens paid in rewards at the end of an epoch. +This value will change as the supply of FLOW changes. See the [rewards page](./03-schedule.md) for more details. + +**Minimum Stake Requirement:** Each node type AND delegator has a requirement for the minimum number of FLOW +they have to commit to stake to be considered a valid staker and receive rewards. +If a node operator or delegator does not meet the minimum stake, +they will not be included in the next epoch and will not receive any rewards. + +- Access Nodes: 100 FLOW +- Collection Nodes: 250,000 FLOW +- Consensus Nodes: 500,000 FLOW +- Execution Nodes: 1,250,000 FLOW +- Verification Nodes: 135,000 FLOW +- Delegators: 50 FLOW + +There is no maximum stake limit. \ No newline at end of file diff --git a/static/markdown/networks/staking/03-schedule.md b/static/markdown/networks/staking/03-schedule.md new file mode 100644 index 0000000000..773d6ea171 --- /dev/null +++ b/static/markdown/networks/staking/03-schedule.md @@ -0,0 +1,144 @@ +--- +title: Epoch and Reward Schedule +sidebar_label: Epoch and Reward Schedule +description: How the Flow protocol manages the schedule of an epoch and rewards payments +--- + + + +This information covers the current state of how epoch phases are ran and how +rewards are calculated and distributed to node operators and delegators. +All of the information in the document is still being designed and is subject to change +based on research and discussion by the Flow core team and community. +If any changes are proposed, the Flow community will be notified in advance. + + +# Schedule + +![Flow Epoch Schedule](./epoch-phase-diagram.png) + +An Epoch is a period of time when the node operators in the network are constant. At epoch +boundaries, newly staked node operators are able to join the network and existing node operators +which have unstaked may exit the network. + +Each epoch lasts approximately a week, and the **Epoch Switchover** is defined as the point in time +when one epoch ends and the next epoch begins, marking a possible change in the list of valid nodes. + + + +The exact timing of each epoch end is influenced by the number of blocks proposed during the epoch. +Therefore, epoch phase timing can very and will likely drift over time. + +**All quoted epoch end times are estimates and subject to some variance (up to several hours)**. +See [Epoch Preparation Protocol](./04-epoch-preparation.md#epoch-length) for details. + + + +**Staking Operations are disabled for approximately the last 6-12 hours of an epoch**, +typically around 00:00 US Pacific Daylight Time (07:00 UTC) on Wednesday every week until around 12:00 US Pacific Daylight Time (19:00 UTC). +See [Epoch Setup](./04-epoch-preparation.md#phase-1-epoch-setup) for more information on this phase. + +**Epoch Switchovers will happen around 12:00 pm PT on Wednesday (7:00 pm UTC)** every week. +Please note exact epoch ending time vary based on the performance of the network +& all staking operations that interact with staked tokens will be processed +by the protocol at the start of each epoch. + +## Rewards + +**Rewards are usually paid around 12 pm PT on Wednesday (7:00 pm UTC)**, every week, +to all users that have tokens staked. +This is close to the same time as the Epoch Switchover. See the Rewards Distribution section below +for more information about rewards calculation and schedule. + +## Staking Auction + +The first, and longest phase of an epoch is the [staking auction](./04-epoch-preparation.md#phase-0-staking-auction). +This phase is when nodes and delegators can register to stake and perform other staking operations +such as staking more tokens or unstaking their existing tokens. +None of these operations are fully executed until the **Epoch Switchover** though. + +**The Staking Auction lasts for at least the first 90% of the length of an Epoch** + +## Epoch Setup and Epoch Commit + +The [Epoch Setup](./04-epoch-preparation.md#phase-1-epoch-setup) +and [Epoch Commit](./04-epoch-preparation.md#phase-2-epoch-committed) +phases are the final phases of the epoch, when node operators who have been included +in the next epoch perform important setup functionality to prepare for the next epoch. + +**The Epoch Setup and Epoch Committed phases usually last less than 10% of the time of an epoch.** + +**Staking Operations will be rejected during the Epoch Setup and Epoch Commit phases.** +This is because the staking information has been finalized in preparation for the next epoch +and cannot be changed because these final phases rely on the staking information being constant. + +**The Staking Auction Ends every Wednesday near 00:00 PDT (07:00 UTC).** +**This means that staking operations will be disabled for ALL users** +**in the period between the end of the staking auction and the beginning of the next epoch, currently 6-12hrs.** + +## Rewards Distribution + +The rewards distribution schedule has been designed to ensure +there is enough liquid supply of FLOW available in the ecosystem +to empower a wide variety of use cases and promote fair and diverse participation in the Flow ecosystem. + +The numbers in this table represent the total amount of tokens that are paid +as staking rewards at each epoch to the entire pool of participants in the Flow network. +While the total staking reward amount is known and fixed per epoch, +rewards that individual stakers receive are variable depending on many factors. + +The total rewards for each epoch are fixed for that epoch, but where those rewards come from can change. +When the protocol pays rewards, it first pulls from the central pool of all the transaction fees +that have been paid by every user in the network since the last rewards payment. +Once that pool has been depleted, the protocol mints new tokens that are used as rewards. + +Please see the next section on how to calculate an individual staking reward. + +| | Dec 22, 2020 | Dec 29, Jan 5, 12, 19, 26 (2021) | Feb 2, 2021 weekly on Wednesdays indefinitely | +| ----------------------------- | ------------------- | -------------------------------- | --------------------------------------------- | +| Total Rewards % (Annual) | 5% | 20% | 5% | +| Total Rewards Amount Per Week | ~1.2M FLOW | ~4.4M FLOW | ~1.3M FLOW | + +## Individual Calculation + +Each user gets a percentage of the total rewards during each epoch +that is proportional to their percentage of all the tokens that are staked by all participants. + +The full reward calculation on a per-user basis is equal to: + +``` +New Reward(user) = Tr * (Sn / St) +``` + +where: +- `Tr` = Total staking rewards to be paid out during the current epoch. (See table above) +- `Sn` = Amount of FLOW Staked by the target user for the current Epoch. (Different for each staker) +- `St` = Sum of all the FLOW staked by all the participants in the network. (Changes every epoch) + +Rewards for delegators are also calculated in the exact same way that rewards for node operators are calculated, +with one difference in that 8% of the calculated reward amount is given to the node operator being delegated to +(effected as a protocol layer fee, which is the same for all node operators). +The remaining 92% is awarded to the delegator. +Note: the 8% fee is only applied to the staking reward, not to the tokens delegated. + +With this calculation, the node you choose to run or delegate to +DOES NOT affect the amount of rewards you receive every week. +The only variable that you can control is the number of tokens you have staked. +The more tokens you stake, the more rewards you will receive. + +Because of the variable nature of the rewards calculation, we cannot provide an expected weekly/yearly return +for a single staker. You can plug your own numbers into the formula to see some sample calculations, +but you won't be able to know exactly what you will earn until the beginning +of the epoch in which you are participating in staking or delegation. + +## Rewards History + +For the first two years of its existence, the staking rewards payments +were handled with manual transactions. You can find the history of those transactions +including their arguments and IDs in the +[Pay Rewards Section](https://github.com/onflow/service-account/tree/main/transactions/pay-rewards) +of the Flow Service Account Repo. The dates correspond to the date when the +rewards were paid at the end of an epoch and the network transitioned to a new epoch. + +Future rewards payments and epoch switchovers happen automatically via a system chunk transaction, +which does not create regular transaction IDs. \ No newline at end of file diff --git a/static/markdown/networks/staking/04-epoch-preparation.md b/static/markdown/networks/staking/04-epoch-preparation.md new file mode 100644 index 0000000000..961c20dfaf --- /dev/null +++ b/static/markdown/networks/staking/04-epoch-preparation.md @@ -0,0 +1,266 @@ +--- +title: Epoch Preparation Protocol +sidebar_label: Epoch Preparation Protocol +description: Technical Overview of the Flow Epoch Protocol +--- + + + If you haven't read the staking introduction, please read that + first. That document provides a non-technical overview of staking on Flow for + all users and is a necessary prerequisite to this document. + + + This document assumes you have some technical knowledge about the Flow + blockchain and programming environment. + + +# Epochs + +The epoch preparation protocol defines how information about the next epoch +is determined and propagated to the protocol state. + +There are two primary actors in this protocol, the Epoch Smart Contracts, and the Consensus Committee: + +- [`Epoch Smart Contracts`](https://github.com/onflow/flow-core-contracts/blob/master/contracts/epochs) - the smart contracts that manage epochs: + - `FlowClusterQC` : Manages the quorum certificate generation for bootstrapping + the hotstuff consensus algorithm for each collector cluster. + - `FlowDKG` : Manages the Distributed Key Generation that consensus nodes participate + in to initialize the random beacon for each epoch. + - `FlowIDTableStaking` : Manages the source of truth for the identity table, + and enforces rules related to staking FLOW, delegating, paying rewards, and allocating token movements between epochs. + - `FlowEpoch` : Ties all of the previously mentioned contracts together to manage + the high level epoch lifecycle. `FlowEpoch` acts as a state machine that transitions + between different epoch phases when specific conditions from the other contracts are met and triggers important operations in the other smart contracts when phase changes happen. +- `Consensus Committee` - the committee of consensus nodes for the current epoch + +This document describes the communication protocol between these two actors and the impact on the protocol state. + +It gives an overview of the process of epochs, the staking auction, and the epoch setup and commit phases. +It is an important prerequisite to understand before proceeding with any other technical integration or interaction with the Flow Protocol, +but does not provide step-by-step instructions for how to perform specific actions. + +The transactions described in this document are contained in the [`flow-core-contracts/transactions/epoch/`](https://github.com/onflow/flow-core-contracts/tree/master/transactions/epoch) +directory. You can see the text of all the transactions used to interact with the smart contracts there. + +## Epochs Overview + +Only a pre-determined set of nodes is authorized to participate in the protocol at any given time. +The set of authorized nodes is a-priori known to all network participants. +This set is referred to as the **Identity Table**. An **Epoch** is defined as a period of time +where the set of authorized nodes is constant (or can only shrink due to ejection of malicious nodes). + +At an Epoch switchover, which is the time when the network transitions from one epoch to the next, +the set of authorized nodes can change. For each of Flow's node roles, the Flow protocol admits a protocol-determined number of nodes. + +For each Epoch, there is a [Staking Auction](./06-technical-overview.md) in which new potential node operators may submit Staking Commitments. +All this is completely smart-contract based and handled through conventional transactions. + +After the Staking Auction is over, the protocol determines which commitments to accept and which to reject. +The node operators whose staking commitments were accepted are added to the Identity Table for the next epoch, +and become authorized participants at the next epoch switchover. +Staked Nodes also can submit other operations to modify their existing stake, which are all carried out at the end of the current epoch. + +The smart contract that determines the nodes for the next Epoch has special privileges. +Specifically, it is allowed to emit [Service Events](./05-epoch-scripts-events.md#monitor-epoch-service-events), +which are how the execution state updates the consensus node-based protocol state. + +At the end of the staking auction, the epoch smart contracts conclude that they have now determined +the set of nodes which will be running the network for the next Epoch, and the amount of FLOW that all the nodes have staked. +The smart contract then emits a service event with this information. + +When processing the block with seat assignment, all network nodes (including future ones which are supposed to monitor the chain in anticipation) +are thereby informed about the upcoming change. + + +Note: At this point in the epoch (end of the staking auction), +there is no change in participating nodes. +The change in participating nodes happens at the end of the epoch. + + +After the staking auction, there is an interim period of time until the new Epoch starts for the following tasks to be completed: +- The epoch smart contract runs the cluster assignment algorithm for all the collector nodes +and each collector node will vote for the root block of their respective clusters +- The Random Beacon Committee for the next Epoch (currently all consensus nodes) +will run the Distributed Key Generation (DKG), +- When completing the QC generation and DKG, the smart contracts will emit a service event. +After consensus nodes have collected all relevant information (public keys for the random beacon and cluster quorum certificates), +they can update the identity table to include the information for the next Epoch. + +If preparation for the next Epoch is not completed before the current Epoch ends, +the network goes into epoch fallback mode (EFM) and a special transaction, sometimes including +a spork, is required to transition to the next Epoch. + +## Epoch Length + +The length of an Epoch is measured in terms of consensus views. +The number of views in an epoch and in the various epoch phases are determined before +the Epoch begins and stored as a field in the main epoch smart contract (`FlowEpoch`). + +Generally, there is not a block for every view, so the view number will not change at the same rate as the block height. + +Because the length of a consensus view can vary depending on many different factors, +the wall-clock time of an epoch is expected to vary from week to week. +Under typical network conditions we expect the variance in epoch length to be less than 2 hours for a 1-week epoch (~1%). +Under adverse network conditions the variance in epoch length will increase (typically this will result in longer epochs). + +As the average view rate changes over time, the Service Account can change the epoch length to +target a 1 week wall-clock epoch length. + +# Phases + +The preparation for the next epoch is separated into distinct phases. +Each phase occurs completely within the current epoch. + +![Flow Epoch Schedule](https://storage.googleapis.com/flow-resources/documentation-assets/epoch-phase-diagram.png) + +The Epoch Smart Contract acts as a state machine. The smart contract keeps a record of the current phase, +the number of views in the current phase, and the conditions that need to be met in order to advance to the next phase, or next epoch. +A special `Heartbeat` resource is used to call the `advanceBlock()` method during every single new block in Flow. +During these regular method calls, if all of the conditions are met to advance to the next phase, +the smart contract performs any relevant retrieval and storage of information, emits a Service Event, +and transitions to the next phase, which often involves setting certain metadata +or enabling one of the connected smart contracts to begin its work. + +From the perspective of the consensus committee, the phase transitions within epochs +occur as a result of including a service event in a block, +thus the phase transition only applies to the fork containing the block with the service event. + +At the end of Phase 0 and beginning of Phase 1, the `EpochSetup` service event is emitted +that contains the identity table and other initial metadata for the upcoming epoch. + +At the end of Phase 1 and beginning of Phase 2, the `EpochCommit` service event +is emitted that contains the results of the Epoch Setup phase. + +The start of a new epoch is the first block with its view > the last view of the previous epoch, +and its parent view ≤ the last view of the last epoch. + +## Phase Transitions + +The **Consensus Committee** triggers the **phase transition coinciding with the Epoch switchover** +by publishing the block of the next Epoch. +This block's execution state will also detect the the end view of an epoch has arrived +and trigger the start of the new epoch. +The transition to a new epoch is also marked by the emission of [an event](https://github.com/onflow/flow-core-contracts/blob/master/contracts/epochs/FlowEpoch.cdc#L62) (`EpochStart`) +from the epoch smart contract. + +- +The state of the smart contracts reflect the latest epoch's new identity table and metadata. + +For the **Epoch-*internal* Phase transitions**, meaning the phase transitions within an epoch, +the **Epoch Smart Contract** provides the trigger by emitting a respective service event: + +- The `EpochSetup` service event triggers the phase transition +`Staking Auction Phase` → `Epoch Setup Phase` +- The `EpochCommit` service event triggers the phase transition +`Epoch Setup Phase` → `Epoch Committed Phase` + +Only one of each service event may be emitted each epoch, for a given fork. +`EpochCommit` may only be emitted after `EpochSetup` has been generated in the respective given fork. + +The `FlowEpoch` contract manages all of these phases, the `FlowIDTableStaking` contract +manages the identity table and staking auction, the `FlowClusterQC` contract manages +the Quorum Certificate generation for collector clusters, and the `FlowDKG` contract manages +the Distributed Key Generation protocol for the consensus nodes. + +Initially, control of these phases and contracts will be managed manually by the Flow Token Admin, +but control will eventually be completely decentralized and managed by the node software, smart contracts, +and democratically by all the stakers in the network. + +## Phase 0: Staking Auction + +**Purpose:** During the staking auction phase, operators can put up stake +in exchange for being a part of the upcoming epoch. +All voluntary commitments to register a new node, increase, or decrease stake for the next epoch +must occur before the end of this phase. + +**Duration:** The staking auction phase begins with the first block of the current Epoch +Its last block is the block in which the `EpochSetup` service event is emitted. + +### **Protocol Directives:** + +Epoch Smart Contract + +- The `FlowEpoch` Smart Contract is responsible for ensuring that staking, un-staking, +and stake-modification transactions for the next epoch are +are only executed during the staking auction and fail otherwise. +The contract enforces this by setting a `stakingEnabled` field in the staking contract. +Every staking method checks to see if this is set before executing. + +- The `FlowEpoch` Smart Contract must ensure that the subsequent phases +are sufficiently long to perform all required tasks before the epoch ends. +- As part of the execution result for the last block of the staking auction, +the `Epoch Smart Contract` computes the seat assignment information for the next epoch, +and emits a specialized service event, the `EpochSetup` event, +with the timing and identity table information about the next epoch. +See the [Epoch Setup Event Documentation](./05-epoch-scripts-events.md#flowepochepochsetup) +for a detailed breakdown of the epoch setup event. + +## Phase 1: Epoch Setup + +**Purpose:** During the epoch setup phase, all nodes participating in the upcoming epoch +must perform setup tasks in preparation for the upcoming epoch. + +**Duration:** The epoch setup phase begins right after the `EpochSetup` service event is emitted. +It ends with the block where `EpochCommit` service event is emitted. + +### **Protocol Directives:** + +Consensus: + +- When a primary constructs a block that seals the `EpochSetup` service event, +the primary includes an update to the protocol state in the block. +Specifically, it adds the nodes for the `PendingEpoch` to the list of authorized nodes. +When this block is propagated, all staked nodes will know about the participants +in the next epoch and can communicate with them. + +- Based on the `RandSeed` field in the `EpochSetup` event, all nodes compute: + - The seed to initialize the consensus node's primary selection algorithm for the next epoch + - The seeds to initialize the collector clusters' primary selection algorithm for the next epoch + +- The collector nodes generate the root block for their respective clusters +in the next Epoch and submit a vote for the root block to a specialized smart contract, `FlowClusterQC`. +- The Random Beacon Committee for the next Epoch (currently all consensus nodes) +will run the DKG through a specialized smart contract, `FlowDKG`. + +Epoch Smart Contract: + +- The `FlowEpoch` Smart Contract is responsible for ensuring that Epoch Setup transactions +are only executed during the Epoch Setup phase and fail otherwise. +The contract enforces this by setting an `enabled` field in the `FlowClusterQC` and `FlowDKG` contracts. +Every state-changing method from these contracts checks to see if this is set before executing. + +- The `FlowEpoch` Smart Contract must ensure that the subsequent phase +is sufficiently long to perform all required tasks before the epoch ends. + +- As part of the execution of the last block of the Epoch Setup phase, +the `FlowEpoch` Smart Contract computes the public key shares generated by the DKG +and the `QC`s for the collector clusters and publishes these as `EpochCommit` service event. +The `FlowEpoch` Smart Contract should emit this event as soon as the artifacts are determined. + +See the [Epoch Commit Event Documentation](./05-epoch-scripts-events.md#flowepochepochcommit) +for a detailed breakdown of the epoch commit event. + +## Phase 2: Epoch Committed + +**Purpose:** When the epoch committed phase starts, the precise role of each node is fully specified. +From a protocol-perspective, all information is available for each node +to start its operation for the next Epoch. +This phase provides some time for nodes to establish the communication channels +and synchronize with the network to seamlessly switch over to the next epoch. + +**Duration:** The epoch committed phase begins right *after* the `EpochCommit` service event +has been emitted. It ends when the epoch ends. + +### **Protocol Directives:** + +Consensus + +- When a primary constructs a block that seals the `EpochCommit` service event, +the primary includes an update to the protocol state in the block. Specifically, it: + - adds the information generated in the setup phase to the Protocol State and + - marks the updated Protocol State as `committed` in this respective fork. + +# Query Information from the Epoch Contract + +See the [epoch scripts and events document](./05-epoch-scripts-events.md#introduction) for detailed documentation about +you can use scripts events to learn information about the state of the epoch contracts. \ No newline at end of file diff --git a/static/markdown/networks/staking/04-stake-slashing.md b/static/markdown/networks/staking/04-stake-slashing.md new file mode 100644 index 0000000000..2cdd933499 --- /dev/null +++ b/static/markdown/networks/staking/04-stake-slashing.md @@ -0,0 +1,34 @@ +--- +title: Stake Slashing +sidebar_position: 4 +description: How Flow enforces honest node behaviour +--- + +Flow slashes nodes only for acts that directly impact +the security and integrity of the network and its shared execution state. +Nodes are not slashed for liveness infractions. +The protocol reserves slashing for maintaining the security of the protocol rather than its liveness. + +You can find more details on the conditions under which a node is slashed +in the [Flow whitepapers](https://www.onflow.org/technical-paper). + +Direct stake slashing is not currently enforced by the protocol and staking contract. +It will be handled on a case-by-case basis for the foreseeable future +to ensure network participants have time to participate in the testing and rollout of slashing. + +There is a very basic form of slashing that is currently used, where +nodes who have liveness issues during an epoch may have their rewards +and their delegators' rewards reduced by a pre-determinded amount based on +the severity of the liveness infractions. This amount is often 50% +and is only taken from the stakers' rewards for a given epoch. +Their staked FLOW is not touched at all. + +When slashing is enforced, slashable protocol violations must be adjudicated by a supermajority +of more than 2/3 of the staked consensus nodes in order to take effect. +If a node is found guilty of committing a slashable protocol violation, +the consensus nodes directly deduct a fine from the node's stake. + +It is still TBD where the slashed tokens will be deposited. + +The remaining un-slashed stake is deposited back into node's unstaked pool +at the end of the unstaking period. \ No newline at end of file diff --git a/static/markdown/networks/staking/05-epoch-scripts-events.md b/static/markdown/networks/staking/05-epoch-scripts-events.md new file mode 100644 index 0000000000..a4fa4e84f3 --- /dev/null +++ b/static/markdown/networks/staking/05-epoch-scripts-events.md @@ -0,0 +1,273 @@ +--- +title: Query Epoch Info with Scripts or Events +sidebar_label: Epoch Scripts and Events +toc_max_heading_level: 4 +--- + +## Introduction + +The epoch contract stores a lot of different state, and the state is constantly changing. +As an external party, there are two ways to keep track of these state changes. +You can either use Cadence scripts to query the state of the contract at any given time, +or you can monitor events that are emitted by the epoch contract to be notified of any important occurrences. + +## Monitor Epoch Service Events + +These events can be queried using the Go or JavaScript SDKs to extract useful notifications and information about the +state of the epoch preparation protocol. + +### What is a Service Event? + +Service events are special messages that are generated by smart contracts and included in execution results. +They enable communication between system smart contracts and the Flow protocol. +In other words, they serve as a communication mechanism between the execution state and the protocol state. + +Concretely, service events are defined and emitted as events like any other in Cadence. An event is considered a service event when it is: + +- emitted within the service chunk +- emitted from a smart contract deployed to the service account +- conformant to an event allowlist + +Each block contains a system chunk. For each system chunk, +all service events emitted are included in the corresponding execution result. + +When verifying the system chunk, verifier nodes will only produce result approvals +when the system chunks included in the execution result are correct. +Thus, the security of this communication mechanism is enforced by the verification system. + +When sealing a block containing a service event, the consensus committee will update the protocol state accordingly, +depending on the semantics of the event. + +For example, a service event may indicate that a node's stake has diminished to the point where they should be ejected, +in which case the consensus committee would mark that node as ejected in the protocol state. + +Service events are fundamentally asynchronous, due the lag between block execution and sealing. +Consequently they are handled slightly differently than other protocol state updates. + +The diagram below illustrates the steps each service event goes through to be included in the protocol state. + +![Flow Service Event Diagram](./epoch-service-event-diagram.png) + +For conciseness, we say a service event is `sealed` when the block in which it was emitted is sealed, +and we say a service event is `finalized` when the block containing the seal is finalized. + +### Event Descriptions + +#### `FlowEpoch.EpochStart` + +The Epoch Start service event is emitted by `FlowEpoch.startNewEpoch()` +when the epoch commit phase ends and the Epoch Smart Contracts transition +to the staking auction phase. +It contains the relevant metadata for the new epoch that was generated during the last epoch: + +```cadence + access(all) event EpochStart ( + + /// The counter for the current epoch that is beginning + counter: UInt64, + + /// The first view (inclusive) of the current epoch. + firstView: UInt64, + + /// The last view (inclusive) of the current epoch's staking auction. + stakingAuctionEndView: UInt64, + + /// The last view (inclusive) of the current epoch. + finalView: UInt64, + + /// Total FLOW staked by all nodes and delegators for the current epoch. + totalStaked: UFix64, + + /// Total supply of all FLOW for the current epoch + /// Includes the rewards that will be paid for the previous epoch + totalFlowSupply: UFix64, + + /// The total rewards that will be paid out at the end of the current epoch. + totalRewards: UFix64, + ) +``` + +#### `FlowEpoch.EpochSetup` + +The Epoch Setup service event is emitted by `FlowEpoch.startEpochSetup()` +when the staking auction phase ends and the Epoch Smart Contracts transition to the Epoch Setup phase. +It contains the finalized identity table for the upcoming epoch, +as well as timing information for phase changes. + +```cadence +access(all) event EpochSetup ( + + /// The counter for the upcoming epoch. Must be one greater than the + /// counter for the current epoch. + counter: UInt64, + + /// Identity table for the upcoming epoch with all node information. + /// Includes: + /// nodeID, staking key, networking key, networking address, role, + /// staking information, weight, and more. + nodeInfo: [FlowIDTableStaking.NodeInfo], + + /// The first view (inclusive) of the upcoming epoch. + firstView: UInt64, + + /// The last view (inclusive) of the upcoming epoch. + finalView: UInt64, + + /// The cluster assignment for the upcoming epoch. Each element in the list + /// represents one cluster and contains all the node IDs assigned to that + /// cluster, with their weights and votes + collectorClusters: [FlowClusterQC.Cluster], + + /// The source of randomness to seed the leader selection algorithm with + /// for the upcoming epoch. + randomSource: String, + + /// The deadlines of each phase in the DKG protocol to be completed in the upcoming + /// EpochSetup phase. Deadlines are specified in terms of a consensus view number. + /// When a DKG participant observes a finalized and sealed block with view greater + /// than the given deadline, it can safely transition to the next phase. + DKGPhase1FinalView: UInt64, + DKGPhase2FinalView: UInt64, + DKGPhase3FinalView: UInt64 +) +``` + +#### `FlowEpoch.EpochCommit` + +The `EpochCommit` service event is emitted when the Epoch Smart Contracts transition +from the Epoch Setup phase to the Epoch Commit phase. +It is emitted only when all preparation for the upcoming epoch (QC and DKG) has been completed. + +```cadence +access(all) event EpochCommit ( + + /// The counter for the upcoming epoch. Must be equal to the counter in the + /// previous EpochSetup event. + counter: UInt64, + + /// The result of the QC aggregation process. Each element contains + /// all the nodes and votes received for a particular cluster + /// QC stands for quorum certificate that each cluster generates. + clusterQCs: [FlowClusterQC.ClusterQC], + + /// The resulting public keys from the DKG process, encoded as by the flow-go + /// crypto library, then hex-encoded. + /// Group public key is the first element, followed by the individual keys + dkgPubKeys: [String], +) +``` + +## Query Information with Scripts + +The `FlowEpoch` smart contract stores important metadata about the current, proposed, +and previous epochs. Metadata for all historical epochs is stored permanently +in the Epoch Smart Contract's storage. + +```cadence +access(all) struct EpochMetadata { + + /// The identifier for the epoch + access(all) let counter: UInt64 + + /// The seed used for generating the epoch setup + access(all) let seed: String + + /// The first view of this epoch + access(all) let startView: UInt64 + + /// The last view of this epoch + access(all) let endView: UInt64 + + /// The last view of the staking auction + access(all) let stakingEndView: UInt64 + + /// The total rewards that are paid out for the epoch + access(all) var totalRewards: UFix64 + + /// The reward amounts that are paid to each individual node and its delegators + access(all) var rewardAmounts: [FlowIDTableStaking.RewardsBreakdown] + + /// Tracks if rewards have been paid for this epoch + access(all) var rewardsPaid: Bool + + /// The organization of collector node IDs into clusters + /// determined by a round robin sorting algorithm + access(all) let collectorClusters: [FlowClusterQC.Cluster] + + /// The Quorum Certificates from the ClusterQC contract + access(all) var clusterQCs: [FlowClusterQC.ClusterQC] + + /// The public keys associated with the Distributed Key Generation + /// process that consensus nodes participate in + /// Group key is the last element at index: length - 1 + access(all) var dkgKeys: [String] +} +``` + +#### Get Epoch Metadata + +The `FlowEpoch` smart contract provides a public function, `FlowEpoch.getEpochMetadata()` +to query the metadata for a particular epoch. + +You can use the **Get Epoch Metadata**([EP.01](../../build/core-contracts/07-epoch-contract-reference.md#getting-epoch-info)) script +with the following arguments: + +| Argument | Type | Description | +| ---------------- | ---------| --------------------------------------------- | +| **epochCounter** | `UInt64` | The counter of the epoch to get metadata for. | + +#### Get Configurable Metadata + +The `FlowEpoch` smart contract also has a set of metadata that is configurable by the admin +for phase lengths, number of collector clusters, and inflation percentage. + +```cadence +access(all) struct Config { + /// The number of views in an entire epoch + access(all) var numViewsInEpoch: UInt64 + + /// The number of views in the staking auction + access(all) var numViewsInStakingAuction: UInt64 + + /// The number of views in each dkg phase + access(all) var numViewsInDKGPhase: UInt64 + + /// The number of collector clusters in each epoch + access(all) var numCollectorClusters: UInt16 + + /// Tracks the annualized percentage of FLOW total supply that is minted as rewards at the end of an epoch + /// Calculation for a single epoch would be (totalSupply * FLOWsupplyIncreasePercentage) / 52 + access(all) var FLOWsupplyIncreasePercentage: UFix64 +} +``` + +You can use the **Get Configurable Metadata**([EP.02](../../build/core-contracts/07-epoch-contract-reference.md#getting-epoch-info)) script +to get the list of configurable metadata: + +This script does not require any arguments. + +#### Get Epoch Counter + +The `FlowEpoch` smart contract always tracks the counter of the current epoch. + +You can use the **Get Epoch Counter**([EP.03](../../build/core-contracts/07-epoch-contract-reference.md#getting-epoch-info)) script +to get the current epoch counter. + +This script does not require any arguments. + +#### Get Epoch Phase + +The `FlowEpoch` smart contract always tracks the active phase of the current epoch. + +```cadence +access(all) enum EpochPhase: UInt8 { + access(all) case STAKINGAUCTION + access(all) case EPOCHSETUP + access(all) case EPOCHCOMMIT +} +``` + +You can use the **Get Epoch Phase**([EP.04](../../build/core-contracts/07-epoch-contract-reference.md#getting-epoch-info)) script +to get the current epoch phase. + +This script does not require any arguments. \ No newline at end of file diff --git a/static/markdown/networks/staking/06-technical-overview.md b/static/markdown/networks/staking/06-technical-overview.md new file mode 100644 index 0000000000..83bdfd9941 --- /dev/null +++ b/static/markdown/networks/staking/06-technical-overview.md @@ -0,0 +1,274 @@ +--- +title: Staking Technical Overview +sidebar_label: Staking Technical Overview +description: Technical Overview of the Flow Staking Auction Phase +--- + + + If you haven't read the Introduction, please read that first. That document + provides a non-technical overview of staking on Flow for all users and is a + necessary prerequisite to this document. + + + This document assumes you have some technical knowledge about the Flow + blockchain and programming environment. + + +# Staking + +This document describes the functionality of the +[core identity table and staking smart contract](https://github.com/onflow/flow-core-contracts/blob/master/contracts/FlowIDTableStaking.cdc). +It gives an overview of the process of epochs, staking as a node, and delegation. It is an important prerequisite +to understand before proceeding with any other technical integration or interaction with the Flow Protocol, +but does not provide step-by-step instructions for how to perform specific actions. See the +[Staking Collection Docs for instructions](./14-staking-collection.md) + +This document also describes how to read public staking data from the contract. +Anyone can read public data from the staking smart contract with these instructions. + +The transactions described in this document are contained in the +[`flow-core-contracts/transactions/idTableStaking/`](https://github.com/onflow/flow-core-contracts/tree/master/transactions/idTableStaking) +directory. You can see the text of all the transactions used to interact with the smart contract there. + +## Smart Contract Summary + +The Flow staking smart contract manages a record of stakers who have staked tokens for the network. +Users who want to stake can register with the staking contract at any time during the staking auction, +and their tokens will be locked for staking until they request to unstake them. + +You should already understand from reading the [epoch documentation](./04-epoch-preparation.md) +that an epoch lasts roughly a week. The `FlowIDTableStaking` contract focuses on the identity table +and staking part of the epoch schedule. + +Epoch Schedule from the perspective of the `FlowIDTableStaking` contract: + +1. **Start of Epoch:** Generic metadata about the current epoch is updated and shared + and the staking auction is enabled. +2. **Staking Auction:** Stakers can perform any action they want to manage their stake, like + initially registering, staking new tokens, unstaking tokens, or withdrawing rewards. + This phase takes up the vast majority of time in the epoch. +3. **End Staking Auction:** Stakers cannot perform any more staking actions + until the start of the next epoch/staking auction. +4. **Remove Insufficiently Staked Nodes:** All node operators who don't meet the minimum + or are not operating their node properly will be removed. +5. **Randomly Assign Nodes to New Slots:** Each node type has a configurable + number of nodes that can operate during any given epoch. + The contract will randomly select nodes from the list of newly staked and approved nodes + to add them to the ID table. Once all the slots have been filled, the remaining nodes are refunded + and can apply again for the next epoch if there are slots available. +6. **Rewards Calculation:** Calculate rewards for all the node operators staked in the current epoch. +7. **Move tokens between pools.** (See the token pools section for the order of movements) +8. **End Epoch:** Set the reward payout for the upcoming epoch and go to the top of this list. +9. **Rewards Payout:** Pay rewards to all the node operators staked + from the previous epoch using the calculation from earlier in the epoch. + +The `FlowIDTableStaking` contract manages the identity table, and all of these phases. +Control of these phases is controlled by the `FlowIDTableStaking.Admin` resource +object stored in the Flow Epoch account storage. +The `FlowEpoch` smart contract uses this resource to autonomously manage the functioning of the network. It is decentralized and managed by the node software, smart contracts, +and democratically by all the stakers in the network. + +## Staking as a Node Operator + +For a node to stake, node operators first need to generate their staking key, +staking key proof-of-possesion, networking address, and networking key. + +The [node operation guide](../node-ops/index.md) +describes how to run a node and generate node information. + +To generate a node ID, simply hash the staking key. + +Node operators need to determine the role of node they will be running +(Collection, Consensus, Execution, Verification, or Access). + + + NOTE: Access Nodes are eligible to stake and have a staking minimum of 100 FLOW, + but will not receive rewards for their stake. + Please register as a different node type if you would like to receive rewards. + + +Once the info has been determined: + +- Node role: `UInt8` (1 = Collection, 2 = Consensus, 3 = Execution, 4 = Verification, 5 = Access) +- Node ID: 32 byte `String` (64 hex characters) +- Networking Address: `String` (Length must be less than 510 characters and be a properly formatted IP address or hostname) +- Networking Key: 64 byte `String` (128 hex characters, must be a valid ECDSA-P256 Key) +- Staking Key: 96 byte `String` (192 hex characters, must be a valid BLS key) +- Staking Key Proof of Possesion: (48 byte (96 hex characters) string) + +The node operator is ready to register their node. + + + NOTE: The staking smart contract validates that the strings for the keys are + valid public keys. The staking admin and node software also checks the keys + and networking address to make sure they are valid and if they are not, the + registered node will not be eligible to stake. + + +To register a node, the node operator calls the +[`addNodeRecord` function](https://github.com/onflow/flow-core-contracts/blob/master/contracts/FlowIDTableStaking.cdc#L1552) +on the staking contract, providing all the node info and the tokens that they want to immediately stake, if any. + +This registers the node in the Flow node identity table +and commits the specified tokens to stake during the next epoch. +This also returns a special node operator object that is stored in the node operator's account. +This object is used for staking, unstaking, and withdrawing rewards. + +Consensus and Collection nodes also need to create a separate machine account +for use in the DKG and QC processes, respectively. This machine account creation +is handled automatically by the staking collection smart contract. +More information is in the [machine account documentation](./11-machine-account.md#creation). + + + The register node transaction only needs to be submitted once per node. A node + does not need to register every epoch. A registration cannot be used to manage + multiple nodes. Multiple nodes need to be registered separately (with the + Staking Collection). + + + + Once a node operator has registered their node and its metadata, the metadata + cannot be modified. The only exception is the networking address, which can me + modified with the Update Networking Address transaction. If a node operator + wants to update any of their other metadata such as ID, keys, or role, they + need to unstake, withdraw their tokens, and register a completely new node. + + +Once node operators have registered and have the special node object, they will be able +to perform any of the valid staking options with it, assuming that they have +the required amount of tokens to perform each operation. + +When the staking auction ends, if a node operator has committed less than the minimum stake required, +[or if their node information is invalid and they haven't been approved by the network,](https://github.com/onflow/flow-core-contracts/blob/master/contracts/FlowIDTableStaking.cdc#L788) +their committed tokens are moved to their unstaked pool, which they can withdraw from at any time. + +Nodes who did have enough tokens committed and are approved will have their +[committed tokens moved to the staked state](https://github.com/onflow/flow-core-contracts/blob/master/contracts/FlowIDTableStaking.cdc#L923-L927) +at the end of the epoch if they are selected as a node operator +by the random node slot filling algorithm. +There is a configurable cap on the number of nodes of each type, +so if the number of selected nodes equals the cap, than newly registered nodes +will not be added to the network until the cap is raised or other nodes unstake. + +If a node operator has users delegating to them, they cannot withdraw their own tokens +such that their own staked tokens would fall below the minimum requirement for that node type. +If they have delegators and try to submit [an unstaking transaction](https://github.com/onflow/flow-core-contracts/blob/master/contracts/FlowIDTableStaking.cdc#L510-L514) +that would put their stake below the minimum, it will fail. + +If they want to unstake below the minimum, they must unstake all of their tokens using the special +[`unstakeAll` method,](https://github.com/onflow/flow-core-contracts/blob/master/contracts/FlowIDTableStaking.cdc#L538) +which also unstakes all of the tokens that have been delegated to them. + +Consequently, a node operator cannot accept delegation unless [their own stake is above the minimum.](https://github.com/onflow/flow-core-contracts/blob/master/contracts/FlowIDTableStaking.cdc#L1066) + +## Staking as a Delegator + +Every staked non-access node in the Flow network is eligible for delegation by any other user. +The user only needs to know the node ID of the node they want to delegate to. + +To register as a delegator, the delegator submits a **Register Delegator** +transaction that calls the [`registerNewDelegator function`](https://github.com/onflow/flow-core-contracts/blob/master/contracts/FlowIDTableStaking.cdc#L1590), +providing the ID of the node operator they want to delegate to. +This transaction should store the `NodeDelegator` object +in the user's account, which is what they use to perform staking operations. + +Users are able to get a list of possible node IDs to delegate to via on-chain scripts. +This information will also be provided off-chain, directly from the node operators or via +third-party services. [Available node IDs are listed in a public repo.](https://github.com/onflow/flow/blob/master/nodeoperators/NodeOperatorList.md) + +The fee that node operators take from the rewards their delegators receive is 8%. +A node operator cannot be delegated to unless the total tokens they have committed to stake +are above the minimum requirement for their node types. + +The delegation logic keeps track of the amount of tokens each delegator has delegated for the node operator. +When rewards are paid, the protocol [automatically takes the 8% cut](https://github.com/onflow/flow-core-contracts/blob/master/contracts/FlowIDTableStaking.cdc#L888-L898) +of the delegator's rewards for the node operator +and the delegator's rewards are deposited in the delegator's reward pool. + +## Staking Operations Available to All Stakers + +Regardless of whether they are a node operator or delegator, a staker has access +to all the same staking operations, outlined below. +Specific implementations of these transactions are detailed in the [Staking Collection Docs](./14-staking-collection.md) + +### Stake More Tokens + +A staker can commit more tokens to stake for the next epoch at any time during the staking auction, +and there are three different ways to do it. + +1. They can commit new tokens to stake by submitting a **stake_new_tokens** transaction, + which withdraws tokens from their account's flow token vault and commits them. +2. They can commit tokens that are in their unstaked token pool, which holds the tokens + that they have unstaked. Submit a **stake_unstaked_tokens** + transaction to move the tokens from the unstaked pool to the committed pool. +3. They can commit tokens that are in their rewarded token pool, which holds the tokens + they have been awarded. They submit a **stake_rewarded_tokens** + transaction to move the tokens from the rewards pool to the committed pool. + +### Cancel Committed Stake / Unstake Tokens + +At any time during the staking auction, a staker can submit a request to unstake tokens with a **request_unstaking** transaction. +If there are tokens that have been committed but are not staked yet, +they are moved to the unstaked pool and are available to withdraw. + +If the requested tokens are in the staked pool, +it marks the specified amount of tokens to be unstaked at the end of the epoch. +At the end of the epoch, the tokens are moved to the unstaking pool. +They will sit in this pool for one (1) additional epoch, +at which point they will be moved to the unstaked tokens pool. + +### Cancel an Unstake Request + +Unstaking requests are not fulfilled until the end of the epoch where they are submitted, +so a staker can cancel the unstaking request before it is carried out. +A staker can do this by submitting a **stake_unstaked_tokens** transaction, specifying +the number of tokens of their unstake request they would like to cancel. +If the specified number of tokens have been requested to unstake, the request will be canceled. + +### Withdraw Unstaked Tokens + +At any time, stakers are able to freely withdraw from their unstaked tokens pool +with the **withdraw_unstaked** transaction. + +### Withdraw Rewarded Tokens + +Staking rewards are paid out at the end of every epoch based on how many tokens +are in a users `tokensStaked` pool. Every staker's rewards +are deposited into their rewarded tokens pool. Rewards can be withdrawn +at any time by submitting a **withdraw_reward_tokens** transaction. + +These tokens are unlocked and can be transferred on-chain if desired, or re-staked. + +The source code for the staking contract and more transactions +can be found in the [Flow Core Contracts GitHub Repository](https://github.com/onflow/flow-core-contracts). + +# Monitor Events from the Identity Table and Staking Contract + +See the [staking events document](./07-staking-scripts-events.md) +for information about the events that can be emitted by the staking contract. + +# Appendix + +## Token Pools + +Each node operator has five token pools allocated to them: + +- **Committed Tokens:** Tokens that are committed for the next epoch. + They are automatically moved to the staked pool when the next epoch starts. +- **Staked Tokens:** Tokens that are staked by the node operator for the current epoch. + They are only moved at the end of an epoch and if the staker + has submitted an unstaking request. +- **Unstaking Tokens:** Tokens that have been unstaked, + but are not free to withdraw until the following epoch. +- **Unstaked Tokens:** Tokens that are freely available to withdraw or re-stake. + Unstaked tokens go to this pool. +- **Rewarded Tokens:** Tokens that are freely available to withdraw or re-stake. + Rewards are paid and deposited to the rewarded Pool after each epoch. + +At the end of every epoch, tokens are moved between pools in this order: + +1. All committed tokens will get moved either to the staked tokens pool, + or to the unstaked tokens pool (depending on if the registered node has met the minimum stake requirements). +2. All committed tokens get moved to staked tokens pool. +3. All unstaking tokens get moved to the unstaked tokens pool. +4. All requested unstaking tokens get moved from the staked pool to the unstaking pool. \ No newline at end of file diff --git a/static/markdown/networks/staking/07-staking-scripts-events.md b/static/markdown/networks/staking/07-staking-scripts-events.md new file mode 100644 index 0000000000..0e22e7c31c --- /dev/null +++ b/static/markdown/networks/staking/07-staking-scripts-events.md @@ -0,0 +1,485 @@ +--- +title: Query Staking Info with Scripts or Events +sidebar_label: Staking Scripts and Events +--- + +# Introduction + +The staking contract stores a lot of different state, and the state is constantly changing. +As an external party, there are two ways to keep track of these state changes. +You can either use Cadence scripts to query the state of the contract at any given time, +or you can monitor events that are emitted by the staking contract to be notified of any important occurances. + +# Query Information with Scripts + +## Get the list of proposed nodes for the next epoch: + +`FlowIDTableStaking.getProposedNodeIDs()`: Returns an array of node IDs for proposed nodes. +Proposed nodes are nodes that have enough staked and committed for the next epoch +to be above the minimum requirement and have been selected to participate in the next epoch. +This means that new access nodes that have not been selected with the random slot selection algorithm +will not be included in this list. + +You can use the **Get Proposed Table**([SC.05](../../build/core-contracts/06-staking-contract-reference.md#getting-staking-info-with-scripts)) script for retrieving this info. + +This script requires no arguments. + +## Get the list of all nodes that are currently staked: + +`FlowIDTableStaking.getStakedNodeIDs()` and ``FlowIDTableStaking.getParticipantNodeList()`: +Returns an array of nodeIDs that are currently staked. +Staked nodes are nodes that are staked and participating in the current epoch. + +You can use the **Get Current Table**([SC.04](../../build/core-contracts/06-staking-contract-reference.md#getting-staking-info-with-scripts)) script for retrieving this info. + +This script requires no arguments. + +## Get the list of all Candidate Nodes + +`getCandidateNodeList(): {UInt8: {String: Bool}}`: +Returns a dictionary of nodes that are candidates to stake in the next epoch +but are not staked in the current epoch. + +You can use the [**Get Candidate Node List**](https://github.com/onflow/flow-core-contracts/blob/master/contracts/FlowIDTableStaking.cdc#L1762) script for retrieving this info. + +This script requires no arguments. + +## Get all of the info associated with a single node staker: + +`FlowIDTableStaking.NodeInfo(nodeID: String)`: Returns a `NodeInfo` struct with all of the metadata +associated with the specified node ID. You can see the `NodeInfo` definition in the [FlowIDTableStaking +smart contract.](https://github.com/onflow/flow-core-contracts/blob/master/contracts/FlowIDTableStaking.cdc#L254) + +You can use the **Get Node Info**([SC.08](../../build/core-contracts/06-staking-contract-reference.md#getting-staking-info-with-scripts)) script +with the following arguments: + +| Argument | Type | Description | +| ---------- | -------- | -------------------------------------- | +| **nodeID** | `String` | The node ID of the node to search for. | + +You can also query the info from an address that uses the staking collection by using the **Get Node Info From Address**([SCO.15](../../build/core-contracts/11-staking-collection.md#scripts)) script +with the following arguments: + +| Argument | Type | Description | +| ----------- | --------- | ------------------------------------------------- | +| **address** | `Address` | The address of the account that manages the nodes. | + +## Get the total committed balance of a node (with delegators): + +`FlowIDTableStaking.NodeInfo(_ nodeID: String).totalCommittedWithDelegators()`: Returns the total committed balance for a node, +which is their total tokens staked + committed, plus all of the staked + committed tokens of all their delegators. + +You can use the **Get Node Total Commitment**([SC.09](../../build/core-contracts/06-staking-contract-reference.md#getting-staking-info-with-scripts)) script +with the following argument: + +| Argument | Type | Description | +| ---------- | -------- | -------------------------------------- | +| **nodeID** | `String` | The node ID of the node to search for. | + +## Get the total committed balance of a node (without delegators): + +`FlowIDTableStaking.NodeInfo(_ nodeID: String).totalCommittedWithoutDelegators()`: Returns the total committed balance for a node, +which is their total tokens staked + committed, plus all of the staked + committed tokens of all their delegators. + +You can use the **Get Only Node Total Commitment**([SC.11](../../build/core-contracts/06-staking-contract-reference.md#getting-staking-info-with-scripts)) script +with the following argument: + +| Argument | Type | Description | +| ---------- | -------- | -------------------------------------- | +| **nodeID** | `String` | The node ID of the node to search for. | + +## Get all the info associated with a single delegator: + +`FlowIDTableStaking.DelegatorInfo(nodeID: String, delegatorID: UInt32)`: Returns a `DelegatorInfo` struct with all of the metadata +associated with the specified node ID and delegator ID. You can see the `DelegatorInfo` definition in the [FlowIDTableStaking +smart contract.](https://github.com/onflow/flow-core-contracts/blob/master/contracts/FlowIDTableStaking.cdc#L375) + +You can use the **Get Delegator Info**([SC.10](../../build/core-contracts/06-staking-contract-reference.md#getting-staking-info-with-scripts)) +script with the following arguments: + +| Argument | Type | Description | +| --------------- | -------- | -------------------------------------------- | +| **nodeID** | `String` | The node ID that the delegator delegates to. | +| **delegatorID** | `String` | The ID of the delegator to search for. | + +You can also query the info from an address by using the **Get Delegator Info From Address**([SCO.16](../../build/core-contracts/11-staking-collection.md#scripts)) script +with the following arguments: + +| Argument | Type | Description | +| ----------- | --------- | ------------------------------------------------------ | +| **address** | `Address` | The address of the account that manages the delegator. | + +## Get the delegation cut percentage: + +`FlowIDTableStaking.getRewardCutPercentage(): UFix64`: Returns a `UFix64` number for the cut of delegator rewards that each node operator takes. + +You can use the **Get Cut Percentage**([SC.01](../../build/core-contracts/06-staking-contract-reference.md#getting-staking-info-with-scripts)) script to retrieve this info. + +This script requires no arguments. + +## Get the minimum stake requirements: + +`FlowIDTableStaking.getMinimumStakeRequirements(): {UInt8: UFix64}`: Returns a mapping +for the stake requirements for each node type. + +You can use the **Get stake requirements**([SC.02](../../build/core-contracts/06-staking-contract-reference.md#getting-staking-info-with-scripts)) script to retrieve this info. + +This script requires no arguments. + +## Get the total weekly reward payout: + +`FlowIDTableStaking.getEpochTokenPayout(): UFix64`: Returns a `UFix64` value for the total number of FLOW paid out each epoch (week). + +You can use the **Get weekly payout**([SC.03](../../build/core-contracts/06-staking-contract-reference.md#getting-staking-info-with-scripts)) script to retrieve this info. + +This script requires no arguments. + +## Get the total FLOW staked: + +You can use the **Get total FLOW staked**([SC.06](../../build/core-contracts/06-staking-contract-reference.md#getting-staking-info-with-scripts)) script to retrieve this info. + +This script requires no arguments. + +## Get the total FLOW staked by all the nodes of a single node role: + +You can use the **Get total FLOW staked by node type**([SC.07](../../build/core-contracts/06-staking-contract-reference.md#getting-staking-info-with-scripts)) script +with the following arguments: + +| Argument | Type | Description | +| ------------ | ------- | ------------------------------- | +| **nodeType** | `UInt8` | The type of node to search for. | + +# Staking Events + +Staking events can be queried using the Go or JavaScript SDKs to extract useful notifications and information about the +state of the staking process. + +## Global Staking and Epoch Events + +### NewEpoch + +```cadence +access(all) event NewEpoch(totalStaked: UFix64, totalRewardPayout: UFix64, newEpochCounter: UInt64) +``` + +| Field | Type | Description | +| ---- | ---- | ----- | +| totalStaked | UFix64 | The total number of tokens staked for the new Epoch | +| totalRewardPayout | UFix64 | The total number of tokens that will be paid as rewards for this epoch | +| newEpochCounter | UInt64 | The epoch counter for this new epoch | + +Emitted by `FlowIDTableStaking.Admin.moveTokens()` when the tokens are moved between pools, which signals a new epoch. + +### NewWeeklyPayout + +```cadence +access(all) event NewWeeklyPayout(newPayout: UFix64) +``` + +| Field | Type | Description | +| --------- | ------ | ------------------------------------------------------------------ | +| newPayout | UFix64 | The new number of tokens that will be paid at the end of the epoch | + +Emitted by `FlowIDTableStaking.Admin.setEpochTokenPayout()` when the Admin changes the total tokens paid at the end of the epoch. + +After this event the `epochTokenPayout` is equal to the new value. + +## Node Events + +These are events that concern the operation of a node. + +### NewNodeCreated + +```cadence +access(all) event NewNodeCreated(nodeID: String, role: UInt8, amountCommitted: UFix64) +``` + +| Field | Type | Description | +| ---- | ------ | ------- | +| nodeID | String | The unique ID string for the node. 32 bytes. Usually the hash of the node's public key. | +| role | UInt8 | The node's role type. From 1 to 5 inclusive. | +| amountCommitted | UFix64 | The amount of FLOW tokens staked to register the node. This is determined by the `role`. | + +Emitted by `FlowIDTableStaking.NodeRecord.init()` when a new node is successfully created. + +After this event is emitted for your node, you can begin to perform staking transactions using it. + +### NodeRemovedAndRefunded + +```cadence +access(all) event NodeRemovedAndRefunded(nodeID: String, amount: UFix64) +``` + +| Field | Type | Description | +| ------ | ------ | --------------------------------------------------------------------------------------------------------------- | +| nodeID | String | The unique ID string for the node. 32 bytes. The same value emitted in the `NewNodeCreated` event for the node. | +| amount | UFix64 | The amount of FLOW tokens returned to the node. | + +Emitted by `FlowIDTableStaking.Admin.endStakingAuction()` if the node is being removed from the next epoch +due to a failure to meet the minimum requirements of committed tokens for the next epoch. + +After this event, the refunded FLOW tokens will be part of the node's `tokensUnstaked` balance. + +## Token Events + +These are events that concern the direct usage of FLOW tokens - staking or unstaking locked tokens, withdrawing rewards, etc. + +Events emitted when using delegation are described in the next section. + +### TokensCommitted + +```cadence +access(all) event TokensCommitted(nodeID: String, amount: UFix64) +``` + +| Field | Type | Description | +| ------ | ------ | ----------- | +| nodeID | String | The unique ID string for the node. 32 bytes. The same value emitted in the `NewNodeCreated` event for the node. | +| amount | UFix64 | The amount of additional FLOW tokens committed to the node. | + +Emitted whenever additional tokens are staked on the node for the following epoch. Specifically: + +1. By `FlowIDTableStaking.NodeStaker.stakeNewTokens()` when new tokens (tokens that have not previously been staked) are added to the system + to stake on the node during the next epoch. +2. By `FlowIDTableStaking.NodeStaker.stakeUnstakedTokens()` when unstaked tokens (tokens that were previously staked and then unstaked) + are staked again with the node for the next epoch. +3. By `FlowIDTableStaking.NodeStaker.stakeRewardedTokens()` when reward tokens (tokens paid in return for previous staking) + are staked with the node for the next epoch. + +After this event, the FLOW tokens will be part of the node's `tokensCommitted` balance. + +### TokensStaked + +```cadence +access(all) event TokensStaked(nodeID: String, amount: UFix64) +``` + +| Field | Type | Description | +| ------ | ------ | ---------- | +| nodeID | String | The unique ID string for the node. 32 bytes. The same value emitted in the `NewNodeCreated` event for the node. | +| amount | UFix64 | The amount of FLOW tokens staked to the node. | + +Emitted by `FlowIDTableStaking.Admin.moveTokens()` at the end of an epoch if committed tokens are being added to the node's tokensStaked balance. + +After this event, the tokens will be part of the node's staked balance. + +### TokensUnstaking + +```cadence +access(all) event TokensUnstaking(nodeID: String, amount: UFix64) +``` + +| Field | Type | Description | +| ------ | ------ | --------- | +| nodeID | String | The unique ID string for the node. 32 bytes. The same value emitted in the `NewNodeCreated` event for the node. | +| amount | UFix64 | The amount of FLOW tokens unstaked from the node. | + +Emitted by `FlowIDTableStaking.Admin.moveTokens()` at the end of an epoch if +a node operator's staked tokens are being unstaked in response to a request from the node operator. +After this event, the tokens will be a part of the node operator's `tokensUnstaking` balance, where they are held for a whole epoch "unstaking period" with no rewards. + +### TokensUnstaked + +```cadence +access(all) event TokensUnstaked(nodeID: String, amount: UFix64) +``` + +| Field | Type | Description | +| ------ | ------ | ---------- | +| nodeID | String | The unique ID string for the node. 32 bytes. The same value emitted in the `NewNodeCreated` event for the node. | +| amount | UFix64 | The amount of FLOW tokens unstaked from the node. | + +Emitted by `FlowIDTableStaking.NodeStaker.requestUnstaking()` and `FlowIDTableStaking.Admin.moveTokens()` +when tokens are deposited into the `tokensUnstaked` pool: + +### RewardsPaid + +```cadence +access(all) event RewardsPaid(nodeID: String, amount: UFix64) +``` + +| Field | Type | Description | +| ------ | ------ | ---------- | +| nodeID | String | The unique ID string for the node. 32 bytes. The same value emitted in the `NewNodeCreated` event for the node. | +| amount | UFix64 | The amount of FLOW tokens paid to the node this epoch as a reward. | + +Emitted by `FlowIDTableStaking.Admin.payRewards()` at the end of the epoch to pay rewards to node operators based on the tokens that they have staked. + +After this event, the reward tokens will be part of the node's tokensRewarded balance. + +The Delegator rewards are paid at the same time, see `DelegatorRewardsPaid` below. + +### UnstakedTokensWithdrawn + +```cadence +access(all) event UnstakedTokensWithdrawn(nodeID: String, amount: UFix64) +``` + +| Field | Type | Description | +| ------ | ------ | ---------- | +| nodeID | String | The unique ID string for the node. 32 bytes. The same value emitted in the `NewNodeCreated` event for the node. | +| amount | UFix64 | The amount of unstaked FLOW tokens that the node operator is withdrawing. | + +Emitted by `FlowIDTableStaking.NodeStaker.withdrawUnstakedTokens()` when the node operator calls that function to withdraw part or all of their +unstaked tokens balance. + +After this event, the FLOW tokens will be withdrawn to a newly created `FungibleToken.Vault` which the caller can deposit to the vault of their choice. + +### RewardTokensWithdrawn + +```cadence +access(all) event RewardTokensWithdrawn(nodeID: String, amount: UFix64) +``` + +| Field | Type | Description | +| ------ | ------ | ---------- | +| nodeID | String | The unique ID string for the node. 32 bytes. The same value emitted in the `NewNodeCreated` event for the node. | +| amount | UFix64 | The amount of rewarded FLOW tokens that the node operator is withdrawing. | + +Emitted by `FlowIDTableStaking.NodeStaker.withdrawRewardedTokens()` when the node operator calls that function to withdraw part or all of their +reward tokens balance. + +After this event, the FLOW tokens will be withdrawn to a newly created `FungibleToken.Vault` which the caller can deposit to the vault of their choice. + +## Delegator Events + +These are events that concern FLOW token delegation. + +### NewDelegatorCreated + +```cadence +access(all) event NewDelegatorCreated(nodeID: String, delegatorID: UInt32) +``` + +| Field | Type | Description | +| ----------- | ------ | ---------- | +| nodeID | String | The unique ID string for the node. 32 bytes. The same value emitted in the `NewNodeCreated` event for the node. | +| delegatorID | UFix64 | The ID for the new delegator. Unique within the node but not globally. | + +Emitted by `FlowIDTableStaking.Admin.registerNewDelegator()` when the node operator registers a new delegator for the node. + +Note that the delegatorID is unique within the node but is not globally unique. + +After this event, the new delegator is registered with the node. + +### DelegatorTokensCommitted + +```cadence +access(all) event DelegatorTokensCommitted(nodeID: String, delegatorID: UInt32, amount: UFix64) +``` + +| Field | Type | Description | +| ----------- | ------ | ---------- | +| nodeID | String | The unique ID string for the node. 32 bytes. The same value emitted in the `NewNodeCreated` event for the node. | +| delegatorID | UInt32 | The ID for the delegator. | +| amount | UFix64 | The amount of additional FLOW tokens committed to the node. | + +Emitted whenever additional tokens are committed for a delegator for the following epoch. Specifically: + +1. By `FlowIDTableStaking.NodeDelegator.delegateNewTokens()` when new tokens (tokens that have not previously been staked) are added to the system + to stake with the delegator during the next epoch. +2. By `FlowIDTableStaking.NodeDelegator.delegateUnstakedTokens()` when unstaked tokens (tokens that were previously staked and then unstaked) + are staked again with the delegator for the next epoch. +3. By `FlowIDTableStaking.NodeDelegator.delegateRewardedTokens()` when reward tokens (tokens paid in return for previous staking) + are staked with the delegator for the next epoch. + +After this event, the FLOW tokens will be part of the delegator's `tokensCommitted` balance. + +### DelegatorTokensStaked + +```cadence +access(all) event DelegatorTokensStaked(nodeID: String, delegatorID: UInt32, amount: UFix64) +``` + +| Field | Type | Description | +| ----------- | ------ | --------- | +| nodeID | String | The unique ID string for the node. 32 bytes. The same value emitted in the `NewNodeCreated` event for the node. | +| delegatorID | UInt32 | The ID for the delegator. | +| amount | UFix64 | The amount of FLOW tokens staked to the node. | + +Emitted by `FlowIDTableStaking.Admin.moveTokens()` at the end of an epoch if committed tokens are being added to the delegator's tokensStaked balance. + +After this event, the tokens will be part of the delegator's staked balance. + +### DelegatorTokensUnstaking + +```cadence +access(all) event DelegatorTokensUnstaking(nodeID: String, delegatorID: UInt32, amount: UFix64) +``` + +| Field | Type | Description | +| ----------- | ------ | -----------| +| nodeID | String | The unique ID string for the node. 32 bytes. The same value emitted in the `NewNodeCreated` event for the node. | +| delegatorID | UInt32 | The ID for the delegator. | +| amount | UFix64 | The amount of FLOW tokens unstaked from the node. | + +Emitted by `FlowIDTableStaking.Admin.moveTokens()` at the end of an epoch if +a delegator's staked tokens are being unstaked in response to a request from the delegator. +After this event, the tokens will be a part of the delegator's `tokensUnstaking` balance, where they are held for a whole epoch "unstaking period" with no rewards. + +### DelegatorTokensUnstaked + +```cadence +access(all) event DelegatorTokensUnstaked(nodeID: String, delegatorID: UInt32, amount: UFix64) +``` + +| Field | Type | Description | +| ----------- | ------ | ---------- | +| nodeID | String | The unique ID string for the node. 32 bytes. The same value emitted in the `NewNodeCreated` event for the node. | +| delegatorID | UInt32 | The ID for the delegator. | +| amount | UFix64 | The amount of FLOW tokens unstaked from the node. | + +Emitted by `FlowIDTableStaking.NodeDelegator.requestUnstaking()` and `FlowIDTableStaking.Admin.moveTokens()` +when tokens are deposited into the delegator's `tokensUnstaked` pool: + +### DelegatorRewardsPaid + +```cadence +access(all) event DelegatorRewardsPaid(nodeID: String, delegatorID: UInt32, amount: UFix64) +``` + +| Field | Type | Description | +| ----------- | ------ | ---------- | +| nodeID | String | The unique ID string for the node. 32 bytes. The same value emitted in the `NewNodeCreated` event for the node. | +| delegatorID | UFix64 | The ID for the delegator. Unique within the node but not globally. | +| amount | UFix64 | The amount of rewarded FLOW tokens that the delegator is paid. | + +Emitted by `FlowIDTableStaking.Admin.payRewards()` at the end of an epoch when rewards are being paid. + +After this event is emitted, the reward tokens will be part of the delegator's tokensRewarded balance. + +The Node rewards are paid at the same time, see `RewardsPaid` above. + +### DelegatorUnstakedTokensWithdrawn + +```cadence +access(all) event DelegatorUnstakedTokensWithdrawn(nodeID: String, delegatorID: UInt32, amount: UFix64) +``` + +| Field | Type | Description | +| ----------- | ------ | ---------- | +| nodeID | String | The unique ID string for the node. 32 bytes. The same value emitted in the `NewNodeCreated` event for the node. | +| delegatorID | UFix64 | The ID for the delegator. Unique within the node but not globally. | +| amount | UFix64 | The amount of unstaked FLOW tokens that the delegator is withdrawing. | + +Emitted by `FlowIDTableStaking.NodeDelegator.withdrawUnstakedTokens()` when the delegator calls that function to withdraw part or all of their +unstaked tokens balance. + +After this event, the FLOW tokens will be withdrawn to a newly created `FungibleToken.Vault` which the caller can deposit to the vault of their choice. + +### DelegatorRewardTokensWithdrawn + +```cadence +access(all) event DelegatorRewardTokensWithdrawn(nodeID: String, delegatorID: UInt32, amount: UFix64) +``` + +| Field | Type | Description | +| ----------- | ------ | ---------- | +| nodeID | String | The unique ID string for the node. 32 bytes. The same value emitted in the `NewNodeCreated` event for the node. | +| delegatorID | UFix64 | The ID for the delegator. Unique within the node but not globally. | +| amount | UFix64 | The amount of rewarded FLOW tokens that the delegator is withdrawing. | + +Emitted by `FlowIDTableStaking.NodeDelegator.withdrawRewardedTokens()` when the delegator calls that function to withdraw part or all of their +unstaked tokens balance. + +After this event, the FLOW tokens will be withdrawn to a newly created `FungibleToken.Vault` which the caller can deposit to the vault of their choice. \ No newline at end of file diff --git a/static/markdown/networks/staking/08-staking-rewards.md b/static/markdown/networks/staking/08-staking-rewards.md new file mode 100644 index 0000000000..605d6b1158 --- /dev/null +++ b/static/markdown/networks/staking/08-staking-rewards.md @@ -0,0 +1,243 @@ +--- +title: Staking and Delegation rewards +sidebar_label: How to Query Staking rewards +description: How to check the staking and delegation rewards +--- + +## Current method to check staking rewards + +Rewards payout happens automatically after the end of the epoch and without the need of an explicit transaction being submitted by the service account. +Instead of a separate reward payout transaction, the reward payout events will be recorded in the system chunk in the block that is produced at the time of the epoch transition without creating a regular transaction ID. + +The rewards payout can be queried by querying the block which contains the system chunk that contains the reward payout events. +``` +flow events get A.8624b52f9ddcd04a.FlowIDTableStaking.RewardsPaid A.8624b52f9ddcd04a.FlowIDTableStaking.DelegatorRewardsPaid --start --end -n mainnet + +where block height is the height of the block containing the rewards payout events +``` + +Example + +``` +$ flow events get A.8624b52f9ddcd04a.FlowIDTableStaking.RewardsPaid A.8624b52f9ddcd04a.FlowIDTableStaking.DelegatorRewardsPaid --start 51753836 --end 51753836 -n mainnet + +Events Block #51753836: + Index 6 + Type A.8624b52f9ddcd04a.FlowIDTableStaking.RewardsPaid + Tx ID f31815934bff124e332b3c8be5e1c7a949532707251a9f2f81def8cc9f3d1458 + Values + - nodeID (String): "a3075cf9280cab4fa0b7b1e639b675bdae3e8874557d98ee78963f0799338a5f" + - amount (UFix64): 1660.21200000 + + Index 9 + Type A.8624b52f9ddcd04a.FlowIDTableStaking.RewardsPaid + Tx ID f31815934bff124e332b3c8be5e1c7a949532707251a9f2f81def8cc9f3d1458 + Values + - nodeID (String): "cf0ff514b6aa659914b99ab1d17743edb2b69fbb338ab01945a08530a98c97d4" + - amount (UFix64): 3762.20370347 + + Index 12 + Type A.8624b52f9ddcd04a.FlowIDTableStaking.RewardsPaid + Tx ID f31815934bff124e332b3c8be5e1c7a949532707251a9f2f81def8cc9f3d1458 + Values + - nodeID (String): "de988efc8cb79d02876b7beffd404fc24b61c287ebeede567f90056f0eece90f" + - amount (UFix64): 939.85630919 + + Index 27 + Type A.8624b52f9ddcd04a.FlowIDTableStaking.RewardsPaid + Tx ID f31815934bff124e332b3c8be5e1c7a949532707251a9f2f81def8cc9f3d1458 + Values + - nodeID (String): "fa5f24a66c2f177ebc09b8b51429e9f157037880290e7858f4336479e57dc26b" + - amount (UFix64): 1660.21200000 + + Index 30 + Type A.8624b52f9ddcd04a.FlowIDTableStaking.RewardsPaid + Tx ID f31815934bff124e332b3c8be5e1c7a949532707251a9f2f81def8cc9f3d1458 + Values + - nodeID (String): "581525fa93d8fe4b334c179698c6e72baccb802593e55e40da61d24e589d85be" + - amount (UFix64): 1937.24727662 + ... + ... + + ... + ... + Index 50115 + Type A.8624b52f9ddcd04a.FlowIDTableStaking.DelegatorRewardsPaid + Tx ID f31815934bff124e332b3c8be5e1c7a949532707251a9f2f81def8cc9f3d1458 + Values + - nodeID (String): "95ffacf0c05757cff71a4ee49e025d5a6d1103a3aa7d91253079e1bfb7c22458" + - delegatorID (UInt32): 23 + - amount (UFix64): 0.10424555 + + Index 50118 + Type A.8624b52f9ddcd04a.FlowIDTableStaking.DelegatorRewardsPaid + Tx ID f31815934bff124e332b3c8be5e1c7a949532707251a9f2f81def8cc9f3d1458 + Values + - nodeID (String): "95ffacf0c05757cff71a4ee49e025d5a6d1103a3aa7d91253079e1bfb7c22458" + - delegatorID (UInt32): 18 + - amount (UFix64): 17.31047712 +``` + +Example using [Flow Go SDK](../../tools/clients/flow-go-sdk/index.md) +``` +package main + +import ( + "context" + "fmt" + client "github.com/onflow/flow-go-sdk/access/grpc" +) + +func main() { + + // the Flow testnet community Access node API endpoint + accessNodeAddress := "access.mainnet.nodes.onflow.org:9000" + + // create a gRPC client for the Access node + accessNodeClient, err := client.NewClient(accessNodeAddress) + if err != nil { + fmt.Println("err:", err.Error()) + panic(err) + } + + ctx := context.Background() + + blockEvents, err := accessNodeClient.GetEventsForHeightRange(ctx, + "A.8624b52f9ddcd04a.FlowIDTableStaking.RewardsPaid", + 51753836, + 51753836) + if err != nil { + panic(err) + } + + for _, blockEvent := range blockEvents { + fmt.Println("Block: " + blockEvent.BlockID.String()) + for _, event := range blockEvent.Events { + fmt.Println("\tEvent type: " + event.Type) + fmt.Println("\tEvent: " + event.Value.String()) + fmt.Println("\tEvent payload: " + string(event.Payload)) + } + } +} +``` + +## Check staking rewards before May 2023 + +Before May 2023, rewards payouts were done manually by the Flow governance committee. + +When the transactions executed, they generated events for the rewards paid to each node and delegator. +To check the staking and delegation rewards, those transactions should be queried directly. + +Example using [Flow cli](../../tools/flow-cli/index.md) +``` +$ flow transactions get 84eca4ff612ef70047d60510710cca872c8a17c1bd9f63686e74852b6382cc84 -n mainnet + +Status ✅ SEALED +ID 84eca4ff612ef70047d60510710cca872c8a17c1bd9f63686e74852b6382cc84 +Payer e467b9dd11fa00df +Authorizers [e467b9dd11fa00df] + +Proposal Key: + Address e467b9dd11fa00df + Index 11 + Sequence 118 + +No Payload Signatures + +Envelope Signature 0: e467b9dd11fa00df +Envelope Signature 1: e467b9dd11fa00df +Envelope Signature 2: e467b9dd11fa00df +Envelope Signature 3: e467b9dd11fa00df +Envelope Signature 4: e467b9dd11fa00df +Signatures (minimized, use --include signatures) + +Events: + Index 0 + Type A.1654653399040a61.FlowToken.TokensWithdrawn + Tx ID 84eca4ff612ef70047d60510710cca872c8a17c1bd9f63686e74852b6382cc84 + Values + - amount (UFix64): 64.59694884 + - from (Address?): 0xf919ee77447b7497 + + Index 1 + Type A.f919ee77447b7497.FlowFees.TokensWithdrawn + Tx ID 84eca4ff612ef70047d60510710cca872c8a17c1bd9f63686e74852b6382cc84 + Values + - amount (UFix64): 64.59694884 + + Index 2 + Type A.1654653399040a61.FlowToken.TokensMinted + Tx ID 84eca4ff612ef70047d60510710cca872c8a17c1bd9f63686e74852b6382cc84 + Values + - amount (UFix64): 1326397.40305116 + + Index 3 + Type A.1654653399040a61.FlowToken.TokensDeposited + Tx ID 84eca4ff612ef70047d60510710cca872c8a17c1bd9f63686e74852b6382cc84 + Values + - amount (UFix64): 1326397.40305116 + - to (Never?): nil + + Index 4 + Type A.1654653399040a61.FlowToken.TokensWithdrawn + Tx ID 84eca4ff612ef70047d60510710cca872c8a17c1bd9f63686e74852b6382cc84 + Values + - amount (UFix64): 1004.16460872 + - from (Never?): nil + + Index 5 + Type A.1654653399040a61.FlowToken.TokensDeposited + Tx ID 84eca4ff612ef70047d60510710cca872c8a17c1bd9f63686e74852b6382cc84 + Values + - amount (UFix64): 1004.16460872 + - to (Address?): 0x8624b52f9ddcd04a + ... + ... + +``` + +Example using [Flow Go SDK](../../tools/clients/flow-go-sdk/index.md) +``` +package main + +import ( + "context" + "fmt" + "github.com/onflow/flow-go-sdk" + client "github.com/onflow/flow-go-sdk/access/grpc" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" +) + +func main() { + + // the Flow mainnet community Access node API endpoint + accessNodeAddress := "access.mainnet.nodes.onflow.org:9000" + + maxGRPCMessageSize := 1024 * 1024 * 20 // to accommodate for the large transaction payload + + // create a gRPC client for the Access node + accessNodeClient, err := client.NewClient(accessNodeAddress, + grpc.WithTransportCredentials(insecure.NewCredentials()), + grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(maxGRPCMessageSize))) + if err != nil { + fmt.Println("err:", err.Error()) + panic(err) + } + + ctx := context.Background() + + txID := flow.HexToID("84eca4ff612ef70047d60510710cca872c8a17c1bd9f63686e74852b6382cc84") + + rewardsTxResult, err := accessNodeClient.GetTransactionResult(ctx, txID) + if err != nil { + panic(err) + } + + for _, event := range rewardsTxResult.Events { + fmt.Println("Event type: " + event.Type) + fmt.Println("Event: " + event.Value.String()) + fmt.Println("Event payload: " + string(event.Payload)) + } +} +``` \ No newline at end of file diff --git a/static/markdown/networks/staking/09-qc-dkg.md b/static/markdown/networks/staking/09-qc-dkg.md new file mode 100644 index 0000000000..ca89237784 --- /dev/null +++ b/static/markdown/networks/staking/09-qc-dkg.md @@ -0,0 +1,149 @@ +--- +title: Quorum Certificate and Distributed Key Generation +sidebar_label: QC and DKG +description: How the Flow protocol manages the Epoch Setup Phase +toc_max_heading_level: 4 +--- + +:::warning + + If you haven't read the Intro to Flow Staking document and the Epoch protocol document, + please read that first. Those documents provide an overview of epochs on Flow for + all users and are necessary prerequisites to this document. + +::: + +:::warning + + This document assumes you have some technical knowledge about the Flow + blockchain and programming environment. + +::: + +## Epoch Setup Phase + +**Purpose:** During the epoch setup phase, all nodes participating in the upcoming epoch +must perform setup tasks in preparation for the upcoming epoch, including +the Collector Cluster Quorum Certificate Generation and Consensus Committe Distributed Key Generation. + +**Duration:** The epoch setup phase begins right after the `EpochSetup` service event is emitted. +It ends with the block where `EpochCommit` service emitted. + +## Machine Accounts + +The processes described in this document are fully automated. + +They are expected to be performed entirely by the node software with no manual +interaction required by the node operator after the node has been set up and registered. + +To facilitate this, we recommend that node operators use a secondary "machine account" +that only stores the `FlowClusterQC.Voter` or `FlowDKG.Participant` resource objects +in addition to FLOW to pay for transaction fees. You can connect your node to this account +to participate in the Epoch Setup Phase without having to do the actions manually. + +If you are using the [Staking Collection](./14-staking-collection.md) for your node, +this functionality is built-in. When you register a node with the staking collection, +you also have to provide a public key or keys for your machine account for the node. + +If you have a node without a machine account (if you were operating a node from the time +before epochs and staking collection were enabled, for example) the staking collection +also provides a method to create a machine account for an existing node. + +See the [Staking Collection Docs](./14-staking-collection.md#machine-account-support) +for more information. + +## Collector Cluster Quorum Certificate Generation Protocol + +The collector nodes are organized into clusters and must bootstrap +the Hotstuff consensus algorithm for each cluster. To do this, +they generate the root block for their respective clusters +and submit a vote for the root block to a specialized smart contract, `FlowClusterQC`. +If 2/3 of the collectors in a cluster have voted with the same unique vote, +then the cluster is considered complete. +Once all clusters are complete, the QC is complete. + +### `FlowClusterQC` Transactions + +#### Create QC Voter Object + +A node uses the [`getClusterQCVoter()`](https://github.com/onflow/flow-core-contracts/blob/master/contracts/epochs/FlowEpoch.cdc#L905) +function in the `FlowEpoch` contract to create their Voter object and needs to provide +a reference to their `FlowIDTableStaking.NodeStaker` object to prove they are the node owner. + +When registering a node with the staking collection, this process is handled by +[the transaction to register.](./14-staking-collection.md#register-a-new-staked-node) +It also creates a machine account for the QC object. + +If a user already has a registered node with the staking collection, but hasn't created their QC Voter object yet, +they can use the [`create_machine_account.cdc` transaction.](./14-staking-collection.md#create-a-machine-account-for-an-existing-node) + +If a user is not using the staking collection, they can use the **Create QC Voter** ([QC.01](../../build/core-contracts/07-epoch-contract-reference.md#quorum-certificate-transactions-and-scripts)) +transaction. This will only store the QC Voter object in the account that stores the `NodeStaker` object. +It does not create a machine account or store it elsewhere, so it is not recommended to use. We encourage to use the staking collection instead. + +#### Submit Vote + +During the Epoch Setup Phase, the node software should submit the votes for the QC generation +automatically using the **Submit QC Vote** ([QC.02](../../build/core-contracts/07-epoch-contract-reference.md#quorum-certificate-transactions-and-scripts)) +transaction with the following arguments. + +| Argument | Type | Description | +|-------------------------|----------|-------------| +| **voteSignature** | `String` | The signed message (signed with the node's staking key) | +| **voteMessage** | `String` | The raw message itself. | + +## Consensus Committee Distributed Key Generation Protocol (DKG) + +The Random Beacon Committee for the next Epoch (currently all consensus nodes) +will run the DKG through a specialized smart contract, `FlowDKG`. +To do this, they post a series of messages to a public "whiteboard" to +collectively generate a shared key array. When each node has enough information +to generate their array of keys, they send the generated array to the smart contract +as their final submission. +If `(# of consensus nodes-1)/2` consensus nodes submit the same key array, +the DKG is considered to be complete. + +### `FlowDKG` Transactions + +#### Create DKG Participant Object + +A node uses the [`getDKGParticipant()`](https://github.com/onflow/flow-core-contracts/blob/master/contracts/epochs/FlowEpoch.cdc#L919) +function in the `FlowEpoch` contract to create their Voter object and needs to provide +a reference to their `FlowIDTableStaking.NodeStaker` object to prove they are the node owner. + +When registering a node with the staking collection, this process is handled by +[the transaction to register.](./14-staking-collection.md#register-a-new-staked-node) +It also creates a machine account for the DKG Object. + +If a user already has a registered node with the staking collection, but hasn't created their DKG Participant object yet, +they can use the [`create_machine_account.cdc` transaction.](./14-staking-collection.md#create-a-machine-account-for-an-existing-node) + +If a user is not using the staking collection, they can use the **Create DKG Participant** ([DKG.01](../../build/core-contracts/07-epoch-contract-reference.md#dkg-transactions-and-scripts)) +transaction. This will only store the DKG Participant object in the account that stores the `NodeStaker` object. +It does not create a machine account or store it elsewhere, so it is not recommended to use. +The staking collection is the recommended method. + +#### Post Whiteboard Message + +During the Epoch Setup Phase, the node software should post whiteboard messages to the DKG +automatically using the **Post Whiteboard Message** ([DKG.02](../../build/core-contracts/07-epoch-contract-reference.md#dkg-transactions-and-scripts)) +transaction with the following arguments. + +| Argument | Type | Description | +|-------------------|----------|-------------| +| **content** | `String` | The content of the whiteboard message | + +#### Send Final Submission + +During the Epoch Setup Phase, the node software should send its final submission for the DKG +automatically using the **Send Final Submission** ([DKG.03](../../build/core-contracts/07-epoch-contract-reference.md#dkg-transactions-and-scripts)) +transaction with the following arguments. + +| Argument | Type | Description | +|--------------------|-------------|-------------| +| **submission** | `[String?]` | The final key vector submission for the DKG. | + +## Monitor Events and Query State from the QC and DKG Contracts + +See the [QC and DKG events and scripts document](./10-qc-dkg-scripts-events.md) for information +about the events that can be emitted by these contracts and scripts you can use to query information. \ No newline at end of file diff --git a/static/markdown/networks/staking/10-qc-dkg-scripts-events.md b/static/markdown/networks/staking/10-qc-dkg-scripts-events.md new file mode 100644 index 0000000000..049066525d --- /dev/null +++ b/static/markdown/networks/staking/10-qc-dkg-scripts-events.md @@ -0,0 +1,97 @@ +--- +title: Query QC/DKG Info with Scripts or Events +sidebar_label: QC/DKG Scripts and Events +--- + +# Introduction + +The Cluster Quorum Certificate (QC) and Distributed Key Generation (DKG) protocol smart contracts +store a lot of different state, and the state is constantly changing. +As an external party, there are two ways to keep track of these state changes. +You can either use Cadence scripts to query the state of the contract at any given time, +or you can monitor events that are emitted by the contracts to be notified of any important occurrences. + +# Query Information with Scripts + +These events can be queried using the Go or JavaScript SDKs to extract useful notifications and information about the +state of these processes. + +## QC Scripts + +These scripts allow anyone to query information about the state of the QC contract. + +### Get Clusters + +To return a struct representing the information associated with a collector cluster, +can use the **Get Cluster** ([QC.03](../../build/core-contracts/07-epoch-contract-reference.md#quorum-certificate-transactions-and-scripts)) script with the following argument: + +| Argument | Type | Description | +|------------------|----------|-------------| +| **clusterIndex** | `UInt16` | The index of the cluster to query | + +### Get QC Enabled + +To return a boolean representing if the QC is enabled, +can use the **Get QC Enabled** ([QC.04](../../build/core-contracts/07-epoch-contract-reference.md#quorum-certificate-transactions-and-scripts)) script with no arguments. + +### Get Node Has Voted + +To return a boolean representing if a node has voted for the current QC, you +can use the **Get Node Has Voted** ([QC.05](../../build/core-contracts/07-epoch-contract-reference.md#quorum-certificate-transactions-and-scripts)) script with the following argument: + +| Argument | Type | Description | +|------------------|----------|-------------| +| **nodeID** | `String` | The node ID to check for | + +### Get Voting Complete + +To return a boolean representing if the voting for the QC phase is complete, +can use the **Get Voting Complete** ([QC.06](../../build/core-contracts/07-epoch-contract-reference.md#quorum-certificate-transactions-and-scripts)) script with no arguments. + +## QC Events + +Documentation coming soon + +## DKG Scripts + +### Get DKG Enabled + +To return a boolean representing if the DKG is enabled, you +can use the **Get DKG Enabled** ([DKG.04](../../build/core-contracts/07-epoch-contract-reference.md#dkg-transactions-and-scripts)) script with no arguments. + +### Get DKG Completed + +To return a boolean representing if the dkg is complete, you +can use the **Get DKG Complete** ([DKG.05](../../build/core-contracts/07-epoch-contract-reference.md#dkg-transactions-and-scripts)) script with no arguments. + +### Get Whiteboard Messages + +To return an array of structs representing all the whiteboard messages, you +can use the **Get DKG Whiteboard Messages** ([DKG.06](../../build/core-contracts/07-epoch-contract-reference.md#dkg-transactions-and-scripts)) script with no arguments. + +### Get Final Submissions + +To return an array of key vectors for the nodes' final submissions, you +can use the **Get Final Submissions** ([DKG.07](../../build/core-contracts/07-epoch-contract-reference.md#dkg-transactions-and-scripts)) script with no arguments. + +### Get Node Has Submitted + +To return a boolean representing if a node has sent their final submission for the DKG, you +can use the **Get Node Has Submitted** ([DKG.08](../../build/core-contracts/07-epoch-contract-reference.md#dkg-transactions-and-scripts)) script with the following argument: + +| Argument | Type | Description | +|------------------|----------|-------------| +| **nodeID** | `String` | The node ID to check for | + +## DKG Events + +```cadence +/// Emitted when the admin enables the DKG +access(all) event StartDKG() + +/// Emitted when the admin ends the DKG after enough submissions have been recorded +access(all) event EndDKG(finalSubmission: [String?]?) + +/// Emitted when a consensus node has posted a message to the DKG whiteboard +access(all) event BroadcastMessage(nodeID: String, content: String) +``` \ No newline at end of file diff --git a/static/markdown/networks/staking/11-machine-account.md b/static/markdown/networks/staking/11-machine-account.md new file mode 100644 index 0000000000..11bd0e00ff --- /dev/null +++ b/static/markdown/networks/staking/11-machine-account.md @@ -0,0 +1,47 @@ +--- +title: Machine Account +sidebar_label: Machine Account +description: Usage and Purpose of the Machine Account +--- + +### What is a Machine Account? + +A Machine Account is a Flow account which is used autonomously by a node to interact with +system smart contracts. Machine Accounts contain Cadence resources granted to network +participants which are used to participate in smart-contract-mediated protocols. Currently, +Machine Accounts are used in the [Epoch Preparation Protocol](./04-epoch-preparation.md), +which prepares the network for the next epoch. + +Your Machine Account is distinct from the account you use for staking your node (your Staking Account). +The Machine Account is intended for use by node software and does not have access to your staked tokens or staking rewards. + + + +Currently Machine Accounts are required only for `collection` and `consensus` nodes. + + + +#### Creation + +Machine Accounts are created during the [staking process](../../networks/flow-port/staking-guide.md) in Flow Port. + +#### Funding + +Machine Accounts must maintain a balance of liquid FLOW tokens to pay fees on transactions they +submit to system smart contracts. Typically very few transactions will be sent (about 1-5 per week) +however more may be required under certain circumstances and network conditions. + + + +Because some transactions sent by the Machine Account are system critical, we recommend maintaining +a balance sufficient to accommodate worst-case transaction submission numbers at all times. **See [here](./../node-ops/node-operation/monitoring-nodes.md#machine-account) for how to monitor.** + + + +When creating a new machine account, we recommend initially funding with 0.005 FLOW for collection nodes and +0.25 FLOW for consensus nodes. + +Machine account balances should be monitored and periodically refilled to ensure they have sufficient funds. +We recommend a minimum balance at all times of 0.002 FLOW for collection nodes and 0.1 FLOW for consensus nodes. + +A node operator can easily withdraw their FLOW from their machine account if they decide they don't need them there any more. \ No newline at end of file diff --git a/static/markdown/networks/staking/12-faq.md b/static/markdown/networks/staking/12-faq.md new file mode 100644 index 0000000000..71437ef9c8 --- /dev/null +++ b/static/markdown/networks/staking/12-faq.md @@ -0,0 +1,77 @@ +--- +title: Staking FAQ +sidebar_label: FAQs +description: Frequently Asked Questions +--- + +### Where will users receive their staking reward for each staking option? + +Staking rewards are not deposited directly into a user's account. +They are deposited to the user's rewards pool in their connected staking object +and can be withdrawn or restaked at any time. + +If you staked using Flow Port, then you should be able to see your staking rewards there. +You can also withdraw the rewards or manually re-stake them through Flow Port. + +If you staked using a staking provider such as Kraken, Blocto or Finoa, +please ask them how they manage staking rewards. + +### Will staking rewards be automatically re-staked? + +There will be _no_ automatic re-staking of staking rewards with Flow Port (i.e. using Ledger or Blocto). +If you want to re-stake your rewards, you must manually do so yourself. + +If you staked using a staking provider such as Kraken, Blocto or Finoa, +please ask them what their policies are. + +DeFi liquid staking strategies such as offered by [incrementFi](https://app.increment.fi/staking) +are not managed by the protocol or nodes, but are more sophisticated ways +to manage your staking. + +### Does it make a difference as to what TYPE of node we delegate to in terms of rewards? + +No, rewards are calculated the same for every node type. + +### Can a validator change its fees? + +The network enforces a delegation fee of 8% which cannot be directly changed. +Any different fees that nodes claim they have are rebates that they +offer using their own methods and are not enforced by the protocol. + +### Can a token holder stake to multiple nodes? If yes, how is the stake split between them? + +A token holder can delegate to multiple nodes from a single account if they use the +[Staking Collection](./14-staking-collection.md). + +The staking collection is enabled by default on Flow port, and many custody providers also support it. + +### Is the wallet key transferred to the staked node? + +No - The keys on the node are different from the wallet keys. The wallet keys always stay in the wallet. +A node operator generates the staking and networking keys separately which will be used on the node. + +### Can I stake through multiple accounts to meet the minimum FLOW required for staking a node? + +No, the minimum stake must come from a single account for all node types. +Temporarily, the minimum for consensus nodes can come from a combination +of staking actions from two accounts controlled by the same party. + +### How can I reach the Consensus node minimum stake of 500K FLOW + +The consensus node minimum of 500K FLOW can be met with a minimum +250,000 FLOW staking action and additional delegation +adding a minimum of 250,000 more FLOW from the same entity. + +### Is rewards payout another spork? + +No, rewards payout is not a spork but is an automatic transaction that happens +at the beginning of every new epoch. + +### Can I query an account address of a node ID or delegator ID? + +The staking smart contract does not directly associate a node or delegator with an account address. +It associates it with the assigned resource object that corresponds to that entry in the contract. +There can be any number of these objects stored in the same account, +and they can be moved to different accounts if the owner chooses. +It is possible to query the information about a node that an address runs though, by using the +`get_node_info_from_address.cdc` script. \ No newline at end of file diff --git a/static/markdown/networks/staking/13-staking-options.md b/static/markdown/networks/staking/13-staking-options.md new file mode 100644 index 0000000000..244374cc5b --- /dev/null +++ b/static/markdown/networks/staking/13-staking-options.md @@ -0,0 +1,35 @@ +--- +title: Options for Building Staking Integrations +sidebar_label: Technical Staking Options +--- + +This document describes two different methods for staking at a high level. + + + +We highly recommended you use the Staking Collection paradigm, +as this will be the most supported method for staking with any set up. + + + +# Staking Collection + +A Staking Collection is a resource that allows its owner to manage multiple staking +objects in a single account via a single storage path, and perform staking actions +using Flow. It also supports machine accounts, a necessary feature for Flow epoch node operation. + +The staking collection paradigm is the most flexible of the three choices +and will receive the most support in the future. It is the set-up that Flow Port and many other staking providers use. + +The staking collection setup and guide is detailed in the [staking collection guide.](./14-staking-collection.md) + +# Staking + +The basic method to stake is to stake directly with the `FlowIDTableStaking` smart contract. +This would involve calling the node or delegator registration functions directly in the staking +contract and storing the staking objects directly in account storage. + +This is probably the simplest way to implement this, but it is not very flexible +and not recommended. + +The basic staking guide is detailed [here](./15-staking-guide.md) \ No newline at end of file diff --git a/static/markdown/networks/staking/14-staking-collection.md b/static/markdown/networks/staking/14-staking-collection.md new file mode 100644 index 0000000000..5285829f35 --- /dev/null +++ b/static/markdown/networks/staking/14-staking-collection.md @@ -0,0 +1,555 @@ +--- +title: Manage a Staking Collection +sidebar_label: Staking Collection Guide +--- + +This document outlines the steps a token holder can take to stake +using [the `FlowIDTableStaking` contract](../../build/core-contracts/06-staking-contract-reference.md) +and [the `FlowStakingCollection` contract.](../../build/core-contracts/11-staking-collection.md) +This is the recommended and most supported way to stake FLOW. +It supports any number of nodes and delegators per account, supports locked and unlocked FLOW, +and supports easily interaction with a node's machine account for collector and consensus nodes. + +# Staking Collection Overview + +A Staking Collection is a resource that allows its owner to manage multiple staking +objects in a single account via a single storage path, and perform staking actions +using both locked and unlocked Flow. + +Before the staking collection, accounts could use the instructions in +[the unlocked staking guide](./15-staking-guide.md) +to stake with tokens. This was a bit restrictive, because that guide (and the corresponding transactions) +only supports one node and one delegator object +per account. If a user wanted to have more than one per account, +they would either have to use custom transactions with custom storage paths for each object, +or they would have had to use multiple accounts, which comes with many hassles of its own. + +The staking collection is a solution to both of these deficiencies. +When an account is set up to use a staking collection, the staking collection recognizes +the existing locked account capabilities (if they exist) and unlocked account staking objects, +and incorporates their functionality so any user can stake for a node or stake as a delegator +through a single common interface, regardless of if they have a brand new account, +or have been staking through the locked account or unlocked account before. + +The staking collection also easily allows a user to transfer their node or delegator objects +to other accounts without interrupting the staking process! + +## Staker Object Fields + +The staking collection resource has two main fields, +```cadence +access(self) var nodeStakers: @{String: FlowIDTableStaking.NodeStaker} +access(self) var nodeDelegators: @{String: FlowIDTableStaking.NodeDelegator} +``` +These dictionaries store the staking objects that are managed by the staking collection. +Access to these dictionaries are mediated by the staking methods. +When a user wants to perform a staking operation, +they specify the nodeID and/or delegatorID they want to stake for, and the function routes the function +call to the correct staking object and performs the specified operation. + +## Vault Capability Fields + +The staking collection also has a field that stores a capability for +the unlocked FLOW Vault and locked FLOW vault (if applicable) +```cadence +/// unlocked vault +access(self) var unlockedVault: Capability<&FlowToken.Vault> + +/// locked vault +/// will be nil if the account has no corresponding locked account +access(self) var lockedVault: Capability<&FlowToken.Vault>? +``` + +When a user performs staking operations like staking new tokens, +the staking collection tracks the number of unlocked tokens +and locked tokens (if applicable) that are used by the staking objects in the collection. +The collection will always try to stake any available locked tokens first. +Once all locked tokens are staked, if the user requested to stake more than the locked token balance, +the collection will then dip into the unlocked balance for the remaining tokens. +If the user has no locked tokens, the staking collection +will simply ignore the locked tokens part of the functionality and only use unlocked tokens. + +When a user withdraws tokens from a staking object, the collection +will always try to withdraw unlocked tokens first. +Any unlocked tokens are then deposited directly into the vault on the unlocked account, +and remaining locked tokens are deposited to the vault in the locked account. + +## Machine Account Support + +The staking collection also supports an important feature for epochs, machine accounts. +Machine accounts are where node operators store important resource objects +that are critical to the functionality of the epoch preparation protocol. +Every collector and consensus node should have an associated machine account that stores these objects, +and the staking collection helps the user create and manage these accounts. + +When a user registers a new collector or consensus node, +the staking collection also creates a machine account for them and registers +the required object that needs to go in the machine account. +The node operator is then responsible for adding keys to the account. +(the **Register Node** transaction includes this step). + +Once the machine account is created and set up, the node operator just has to +connect it to their node software and make sure the account has enough FLOW +to pay for transaction fees, which can be handled simply by submitting +a regular FLOW transfer to the machine account's address + +## Staking Collection Public Getter Methods + +The staking collection also defines many getter methods to query information +about an account's staking collection. You can simply call one of these methods on the contract, +providing the account address, and the contract will retrieve +the relevant info for you, like so: +```cadence +import FlowStakingCollection from 0xSTAKINGCOLLECTIONADDRESS +import FlowIDTableStaking from 0xIDENTITYTABLEADDRESS + +/// Gets an array of all the delegator metadata for delegators stored in the staking collection +access(all) fun main(address: Address): [FlowIDTableStaking.DelegatorInfo] { + return FlowStakingCollection.getAllDelegatorInfo(address: address) +} +``` + +Remember: A Staking Collection does not require an account +to have a secondary locked account or locked FLOW. +However, if an account does have an associated locked account, when the Staking Collection is initialized, +it will connect to that locked account's node and delegator objects +as well as it's locked token vault allowing it to perform staking actions with locked and unlocked FLOW. + + +Staking Collection is backwards compatible with other methods of staking on Flow. +Existing accounts with associated locked accounts +will still be able to stake in the same way as before, +but they will also be able to use the staking collection, if desired. + + +# How to use the Staking Collection + +There is a standard set of transactions provided with the staking collection. + +## Setup + +### Setup a Staking Collection + +To set up a Staking Collection, you must run the **Setup Staking Collection** ([SCO.01](../../build/core-contracts/11-staking-collection.md)) transaction. + +This transaction requires no arguments and will perform the following actions: +1. Create private capabilities for the unlocked vault and locked vault (if applicable). +2. Create a new staking collection resource object, initializing it with the unlocked and locked vault capabilities. +3. Store the staking collection at a pre-defined storage path. +4. Create a public link to the staking collection so others can query metadata about it. +5. If there are any node or delegator objects in the unlocked account, the transaction stores those in the staking collection + so they can be used through the same interface as usual. + +**No arguments** are required for the **Setup Staking Collection** transaction. + +Once this transaction is complete, your existing staking objects (if any) from your unlocked account and locked account +will be available via the staking collection and you can use all the transactions described below to access them. + +### Create a Machine Account for an existing Node + +Many nodes will have been created before the staking collection was set up and before epochs were enabled, +meaning that they don't already have an associated machine account. +These nodes need a new transaction to create the machine account for the node and save it to the staking collection. + +To create a machine account for a node that doesn't already have one, +you must submit the **Create Machine Account** ([SCO.03](../../build/core-contracts/11-staking-collection.md)) +transaction with the following arguments: + +| Argument | Type | Description | +|----------------|-------------|-------------| +| **nodeID** | `String` | The ID of the node. | +| **publicKeys** | `[String]` | The public keys to add to the machine account.| + +If the node is a collector or consensus node, this transaction creates the associated machine account, +registers the QC or DKG object, stores it in the machine account, +and adds the provided public key(s) to the machine account. +If no public keys are provided, the transaction will fail. + +## Register Stakers + +### Register a New Staked Node + +To register a new staked node, you must submit the **Register Node** ([SCO.03](../../build/core-contracts/11-staking-collection.md)) +transaction with the following arguments: + +| Argument | Type | Description | +|-----------------------|-------------|-------------| +| **id** | `String` | The ID of the new node. It must be a 32 byte `String`. The operator is free to choose this value, but it must be unique across all nodes. A recommended process to generate this is to hash the staking public key. | +| **role** | `UInt8` | The role of the new node. (1: collection, 2: consensus, 3: execution, 4: verification, 5: access) | +| **networkingAddress** | `String` | The IP address of the new node. | +| **networkingKey** | `String` | The networking public key as a hex-encoded string. | +| **stakingKey** | `String` | The staking public key as a hex-encoded string. | +| **stakingKeyPoP** | `String` | The staking key Proof-of-Possesion as a hex-encoded string. | +| **amount** | `UFix64` | The number of FLOW tokens to stake. | +| **publicKeys** | `[String]?` | The public keys to add to the machine account. `nil` if no machine account | + +This transaction registers the account as a staker with the specified node information +and attaches a `NodeStaker` resource to the `Staking Collection`. +This `NodeStaker` resourece can then later be used to perform staking actions via the staking collection staking methods. + +If the node is a collector or consensus node, it also creates the associated machine account, +registers the QC or DKG object, stores it in the machine account, +and adds the provided public key(s) to the machine account. +If the node requires a machine account and no public keys are provided, the transaction will fail. + +Once the account has registered their node using their Staking Collection, +their tokens and node information are committed to the central staking contract for the next epoch. + +At this point, the Staking Collection now has access to various staking operations that they can perform, +assuming they have the correct number of tokens to perform the action. + +### Register a New Staked Delegator + +To register a new delegator, you must submit the **Register Delegator** ([SCO.02](../../build/core-contracts/11-staking-collection.md)) +transaction with the following arguments: + +| Argument | Type | Description | +|------------|----------|-------------| +| **id** | `String` | The ID of the node to delegate to. | +| **amount** | `UFix64` | The number of FLOW tokens to delegate. | + +This transaction registers the account as a delegator to the node identified by the supplied node id. +It also attaches a `NodeDelegator` resource to the `Staking Collection`. +This `NodeDelegator` resourece can then later be used to perform delegation actions. + +Once the account has registered their new delegator using their Staking Collection, +their tokens are committed to the central staking contract for the next epoch. + +At this point, the Staking Collection now has access to various delegator operations that they can perform, +assuming they have the correct number of tokens to perform the action. + +## Staking Operations + +These transactions perform actions that directly interact with the staking contract. +Most of them will only succeed during the Staking Auction phase of the epoch. + +### Stake New Tokens + +The Staking Collection can stake additional tokens for any Node or Delegator managed by it at any time. + +The owner of a Staking Collection can use the **Stake New Tokens** ([SCO.06](../../build/core-contracts/11-staking-collection.md)) +transaction with the following arguments: + +| Argument | Type | Description | +|-------------------------|--------------------|-------------| +| **nodeID** | `String` | The nodeID of the node to stake new tokens to. | +| **delegatorID** | `Optional(UInt32)` | `nil` if staking for a node. If staking for a delegator, the delegator ID. | +| **amount** | `UFix64` | The number of FLOW tokens to stake. | + + +To stake new tokens for an active node, leave the delegatorID argument as nil. + +If staking for a delegator, delegatorID should be the delegator ID you are staking for. + + +The amount may be any number of tokens up to the sum of an accounts locked and unlocked FLOW. + +### Re-stake Unstaked Tokens + +After tokens become unstaked, the owner of a Staking Collection can choose +to re-stake the unstaked tokens to the same Node or Delegator. + +The owner of a Staking Collection can use the **Stake Unstaked Tokens** ([SCO.08](../../build/core-contracts/11-staking-collection.md)) +transaction with the following arguments: + +| Argument | Type | Description | +|-------------------------|--------------------|-------------| +| **nodeID** | `String` | The nodeID of the node to stake the unstaked tokens to. | +| **delegatorID** | `Optional(UInt32)` | `nil` if staking for a node. If staking for a delegator, the delegator ID. | +| **amount** | `UFix64` | The number of FLOW tokens to restake. | + + +To stake unstaked tokens for an active node, leave the delegatorID argument as nil. + +If staking for a delegator, delegatorID should be the delegator ID you are staking for. + + +### Re-stake Rewarded Tokens + +After earning rewards from staking, the owner of a Staking Collection +can choose to re-stake the rewarded tokens to the same node or delegator. + +The owner of a Staking Collection can use the **Stake Unstaked Tokens** ([SCO.07](../../build/core-contracts/11-staking-collection.md)) +transaction with the following arguments: + +| Argument | Type | Description | +|-------------------------|--------------------|-------------| +| **nodeID** | `String` | The nodeID of the node to stake the rewarded tokens to. | +| **delegatorID** | `Optional(UInt32)` | `nil` if staking for a node. If staking for a delegator, the delegator ID. | +| **amount** | `UFix64` | The number of FLOW tokens to restake. | + + +To stake rewarded tokens for an active node, leave the delegatorID argument as nil. + + +### Request to Unstake Tokens at the end of the Epoch + +The owner of a Staking Collection can submit a request to unstake their tokens at any time for any Node or Delegator in their collection. + +If the tokens aren't staked yet, they will be uncommitted and available to withdraw. + +_Note: unstaked tokens will be held by the central staking contract until the end of the following epoch._ +_Once the tokens are released (unstaked), they can be claimed via the [Withdraw Unstaked Tokens](#withdraw-unstaked-tokens) action below._ + +The owner of a Staking Collection can use the **Unstake Tokens** ([SCO.05](../../build/core-contracts/11-staking-collection.md)) +transaction with the following arguments: + +| Argument | Type | Description | +|-------------------------|--------------------|-------------| +| **nodeID** | `String` | The nodeID of the chosen node. | +| **delegatorID** | `Optional(UInt32)` | `nil` if staking for a node. If staking for a delegator, the delegator ID. | +| **amount** | `UFix64` | The number of FLOW tokens to restake. | + + +To unstake tokens from an active node, leave the delegatorID argument as nil. + + +### Unstake All Tokens + +The owner of a Staking Collection can use the **Unstake All** ([SCO.09](../../build/core-contracts/11-staking-collection.md)) +transaction with the following arguments: + +| Argument | Type | Description | +|-------------------------|--------------------|-------------| +| **nodeID** | `String` | The nodeID of the node to unstake all tokens from. | +| **delegatorID** | `Optional(UInt32)` | `nil` if staking for a node. If staking for a delegator, the delegator ID. | + +### Withdraw Unstaked Tokens + +After tokens for an active Node or Delegator become unstaked, +the ownder of Staking Collection can withdraw them from the central staking contract. + +The owner of a Staking Collection can use the **Withdraw Unstaked Tokens** ([SCO.11](../../build/core-contracts/11-staking-collection.md)) +transaction with the following arguments: + +| Argument | Type | Description | +|-------------------------|--------------------|-------------| +| **nodeID** | `String` | The nodeID of the node to withdraw the unstaked tokens from. | +| **delegatorID** | `Optional(UInt32)` | `nil` if staking for a node. If staking for a delegator, the delegator ID. | +| **amount** | `UFix64` | The number of FLOW tokens to withdraw. | + + +To withdraw unstaked tokens from an active node, leave the delegatorID argument as nil. + + +### Withdraw Rewarded Tokens + +After earning rewards from staking, the token holder can withdraw them from the central staking contract. + +The owner of a Staking Collection can use the **Withdraw Rewarded Tokens** ([SCO.10](../../build/core-contracts/11-staking-collection.md)) +transaction with the following arguments: + +| Argument | Type | Description | +|-------------------------|--------------------|-------------| +| **nodeID** | `String` | The nodeID of the node to withdraw the rewarded tokens from. | +| **delegatorID** | `Optional(UInt32)` | `nil` if staking for a node. If staking for a delegator, the delegator ID. | +| **amount** | `UFix64` | The number of FLOW tokens to withdraw. | + + +To withdraw rewarded tokens from an active node, leave the delegatorID argument as nil. + + +## Staking Collection Modification + +### Close a Node or Delegator + +Once a Node or Delegator has no tokens staked, comitted or in an unstaking state, it is eligible to be closed. + +Closing a Node or Delegator first returns any unstaked or rewarded tokens +to the account for which the Staking Collection is stored in. +It then destroys the NodeStaker or NodeDelegator object from within the Staking Collection. + +_Note: Once a Node or Delegator has been closed, it cannot be accessed again,_ +_and no staking or delegation actions can be further preformed on it._ + +The owner of a Staking Collection can use the **Close Stake** ([SCO.12](../../build/core-contracts/11-staking-collection.md)) +transaction with the following arguments: + +| Argument | Type | Description | +|-------------------------|--------------------|-------------| +| **nodeID** | `String` | The nodeID of the node to close. | +| **delegatorID** | `Optional(UInt32)` | `nil` if staking for a node. If staking for a delegator, the delegator ID. | + + +To close an active node, leave the delegatorID argument as nil. + + +### Transfer a Node + +A user may transfer an existing Node to another another account's Staking Collection. + +The account to transfer the Node to must have a valid Staking Collection set up. + +Transferring a Node will remove it from the authorizer's Staking Collection +and deposit it to the receiver's Staking Collection. + +_Note: Once a Node or Delegator has been transferred, it cannot be accessed again by the sender._ +_As well, all staked tokens will be considered staked by the receiver's Staking Collection._ + + +Transferring a Node will result in loss of custody of any Staked tokens for the sender. + + +The owner of a Staking Collection can use the **Transfer Node** ([SCO.13](../../build/core-contracts/11-staking-collection.md)) +transaction with the following arguments: + +| Argument | Type | Description | +|-------------------------|--------------------|-------------| +| **nodeID** | `String` | The nodeID of the node to transfer. | +| **to** | `Address` | The address of the account which contains the Staking Collection to transfer the Node to. | + +### Transfer a Delegator + +A user may transfer an existing Delegator to another another account's Staking Collection. + +The account to transfer the Delegator to must have a valid Staking Collection set up. + +Transferring a Delegator will remove it from the authorizer's Staking Collection +and deposit it to the receiver's Staking Collection. + +_Note: Once a Node or Delegator has been transferred, it cannot be accessed again by the sender._ +_As well, all staked tokens will be considered staked by the receiver's Staking Collection._ + + +Transferring a Delegator will result in loss of custody of any Staked tokens for the sender. + + +The owner of a Staking Collection can use the **Transfer Delegator** ([SCO.14](../../build/core-contracts/11-staking-collection.md)) +transaction with the following arguments: + +| Argument | Type | Description | +|-------------------------|--------------------|-------------| +| **nodeID** | `String` | The nodeID of the delegator to transfer. | +| **delegatorID** | `UInt32` | The delegatorID of the delegator to transfer. | +| **to** | `Address` | The address of the account which contains the Staking Collection to transfer the Delegator to. | + +### Update A Node's Networking Address + +A user may update their node's networking address if it has become inconsistent with the protocol state. + +This operation can only be performed in the staking auction phase of an epoch. + +_Note: Currently, if a node updates its networking address and the new address does not match_ +_what is stored in the protocol state for the node, the node will not be able to participate in the upcoming epoch_ +_Only update your networking address if you have already confirmed with the Flow team that you can._ +_This restriction will be removed once fully automated epochs are completely implemented_ + +The owner of a Staking Collection can use the **Update Networking Address** ([SCO.22](../../build/core-contracts/11-staking-collection.md)) +transaction with the following arguments: + +| Argument | Type | Description | +|-----------------|-----------|-------------| +| **nodeID** | `String` | The nodeID of the node to update. | +| **newAddress** | `String` | The new networking address | + +# Staking Collection Scripts + +These scripts allow anyone to query information about an account's staking collection + +### Get All Node Info + +To return an array of structs representing the information associated with each node managed by an account's Staking Collection, anyone +can use the **Get All Node Info** ([SCO.15](../../build/core-contracts/11-staking-collection.md)) script with the following arguments: + +| Argument | Type | Description | +|-------------|------------|-------------| +| **address** | `Addresss` | The Address of the account holding the Staking Collection to query from | + +This script returns an array of `FlowIDTableStaking.NodeInfo` [structs](https://github.com/onflow/flow-core-contracts/blob/master/contracts/FlowIDTableStaking.cdc#L264) +representing the nodes managed by an accounts Staking Collection. + +### Get All Delegator Info + +To return an array of structs representing the information associated with each delegator managed by an account's Staking Collection, anyone +can use the **Get All Delegator Info** ([SCO.16](../../build/core-contracts/11-staking-collection.md)) script with the following arguments: + +| Argument | Type | Description | +|-------------|------------|-------------| +| **address** | `Addresss` | The Address of the account holding the Staking Collection to query from | + +This script returns an array of `FlowIDTableStaking.DelegatorInfo` [structs](https://github.com/onflow/flow-core-contracts/blob/master/contracts/FlowIDTableStaking.cdc#L264) +representing the delegators managed by an accounts Staking Collection. + +### Get All Node Ids + +To return an array of Strings representing the ids associated with each node managed by an account's Staking Collection, anyone +can use the **Get All Node Ids** ([SCO.17](../../build/core-contracts/11-staking-collection.md)) script with the following arguments: + +| Argument | Type | Description | +|-------------|------------|-------------| +| **address** | `Addresss` | The Address of the account holding the Staking Collection to query from | + +This script returns an array of `String` +representing each id of each node managed by an accounts Staking Collection. + +### Get All Delegator Ids + +To return an array of structs representing the delegator ids associated with each delegation managed by an account's Staking Collection, anyone +can use the **Get All Delegator Ids** ([SCO.22](../../build/core-contracts/11-staking-collection.md)) script with the following arguments: + +| Argument | Type | Description | +|-------------|------------|-------------| +| **address** | `Addresss` | The Address of the account holding the Staking Collection to query from | + +This script returns an array of `FlowStakingCollection.DelegatorIDs` [structs](https://github.com/onflow/flow-core-contracts/blob/master/contracts/FlowStakingCollection.cdc#L40) +representing the delegator Ids of each delegator managed by an accounts Staking Collection. + +### Get Locked Tokens Used + +To query how many Locked FLOW tokens an account has staked using their Staking Collection, anyone +can use the **Get Locked Tokens Used** ([SCO.19](../../build/core-contracts/11-staking-collection.md)) script with the following arguments: + +| Argument | Type | Description | +|-------------|------------|-------------| +| **address** | `Addresss` | The Address of the account holding the Staking Collection to query from | + +This script returns a `UFix64` representing the number of Locked FLOW tokens staked using an accounts Staking Collection. + + +Note: This number does not include Locked FLOW tokens staked not through an accounts Staking Collection. + + +### Get Unlocked Tokens Used + +To query how many Unlocked FLOW tokens an account has staked using their Staking Collection, anyone +can use the **Get Unlocked Tokens Used** ([SCO.20](../../build/core-contracts/11-staking-collection.md)) script with the following arguments: + +| Argument | Type | Description | +|-------------|------------|-------------| +| **address** | `Addresss` | The Address of the account holding the Staking Collection to query from | + +This script returns a `UFix64` representing the number of Unlocked FLOW tokens staked using an accounts Staking Collection. + + +Note: This number does not include Unlocked FLOW tokens staked not through an accounts Staking Collection. + + +### Get Does Node Exist + +To query if a Node or Delegator is managed by an accounts Staking Collection, anyone +can use the **Get Does Node Exist** ([SCO.21](../../build/core-contracts/11-staking-collection.md)) script with the following arguments: + +| Argument | Type | Description | +|-------------------------|--------------------|-------------| +| **address** | `Addresss` | The Address of the account holding the Staking Collection to query from | +| **nodeID** | `String` | The nodeID of the node to check, or the nodeID of the node delegating to to check. | +| **delegatorID** | `Optional(UInt32)` | The delegatorID of the delegator to check, if checking for a delegator. | + +This script returns a `Bool`. + + +To query if a Node is managed by an accounts Staking Collection, leave the delegatorID argument as nil. +Otherwise, fill it in with the delegatorID of the Delegator. + + +### Get Machine Account Info + +To query the machine account information for an account's staking collection, anyone +can use the **Get Machine Account Info** ([SCO.21](../../build/core-contracts/11-staking-collection.md)) script with the following arguments: + +| Argument | Type | Description | +|-------------------------|--------------------|-------------| +| **address** | `Addresss` | The Address of the account holding the Staking Collection to query from | + +This script returns a `{String: FlowStakingCollection.MachineAccountInfo}`, +which is a mapping of nodeIDs to the `FlowStakingCollection.MachineAccountInfo` struct. \ No newline at end of file diff --git a/static/markdown/networks/staking/15-staking-guide.md b/static/markdown/networks/staking/15-staking-guide.md new file mode 100644 index 0000000000..d136f8cbdb --- /dev/null +++ b/static/markdown/networks/staking/15-staking-guide.md @@ -0,0 +1,260 @@ +--- +title: Basic Staking with FLOW +sidebar_label: Basic Staking Guide (Deprecated) +--- + +This document outlines the steps a token holder can take to stake and manage +a Flow node with FLOW using only the types defined in the `FlowIDTableStaking` contract. +It only supports having one node or delegator object per account and is not supported by ledger +and will likely not be supported by other wallets, so it is recommended to use the staking collection +instead. + + +This guide covers staking with **FLOW tokens**. + + +# Staking + +## Setup + +### Register a New Staked Node + +To register as a node operator with FLOW, the token holder can use the **Register Node** ([SC.11](../../build/core-contracts/06-staking-contract-reference.md#staking)) +transaction with the following arguments: + +| Argument | Type | Description | +|-----------------------|----------|-------------| +| **id** | `String` | The ID of the new node. It must be a 32 byte `String`. The operator is free to choose this value, but it must be unique across all nodes. A recommended process to generate this is to hash the staking public key. | +| **role** | `UInt8` | The role of the new node. (1: collection, 2: consensus, 3: execution, 4: verification, 5: access) | +| **networkingAddress** | `String` | The IP address of the new node. (Length must be less than 255 bytes (510 Hex characters)) | +| **networkingKey** | `String` | The networking public key as a 64 byte hex-encoded `String` (128 hex characters) | +| **stakingKey** | `String` | The staking public key as a 96 byte hex-encoded `String` (192 hex characters) | +| **amount** | `UFix64` | The number of FLOW tokens to stake. | + +This transaction registers the account as a node operator with the specified node information +and creates a public link to query the nodes ID from the account address. + +--- + +Once the token holder has registered their node, +their tokens and node information are committed to the central staking contract for the next epoch. + +At this point, the token holder now has access to various staking operations that they can perform, +assuming they have the correct number of tokens to perform the action. + +## Stake Tokens + +The token holder can stake additional tokens at any time. + +_Note: this transaction stakes additional tokens to the same node that was registered in the setup phase._ + +To stake tokens, the token holder can use the **Stake FLOW** ([SC.12](../../build/core-contracts/06-staking-contract-reference.md#staking)) +transaction with the following arguments: + +| Argument | Type | Description | +|------------|----------|-------------| +| **amount** | `UFix64` | The number of FLOW tokens to stake. | + +This transaction commits tokens to stake from the token holder's account. + +## Re-stake Unstaked Tokens + +After tokens become unstaked, the token holder can choose to re-stake the unstaked tokens to the same node. + +To staked unstaked tokens, the token holder can use the **Re-stake Unstaked FLOW** ([SC.13](../../build/core-contracts/06-staking-contract-reference.md#staking)) +transaction with the following arguments: + +| Argument | Type | Description | +|------------|----------|-------------| +| **amount** | `UFix64` | The number of unstaked FLOW tokens to stake. | + +## Re-stake Rewarded Tokens + +After earning rewards from staking, the token holder can choose to re-stake the rewarded tokens to the same node. + +To stake rewarded tokens, the token holder can use the **Re-stake Rewarded FLOW** ([SC.14](../../build/core-contracts/06-staking-contract-reference.md#staking)) +transaction with the following arguments: + +| Argument | Type | Description | +|------------|----------|-------------| +| **amount** | `UFix64` | The number of rewarded FLOW tokens to stake. | + +## Request Unstake Tokens + +The token holder can submit a request to unstake some of their tokens at any time. +If the tokens aren't staked yet, they will be uncommitted and available to withdraw. + +To request to unstake staked tokens, the token holder can use +the **Request Unstaking** ([SC.15](../../build/core-contracts/06-staking-contract-reference.md#staking)) transaction. + +| Argument | Type | Description | +|------------|----------|-------------| +| **amount** | `UFix64` | The number of rewarded FLOW tokens to request to un-stake. | + +_Note: this transaction will not succeed if the node operator has delegators and the request +would put the node operator below the minimum required tokens staked for their node type. +Use the `Unstake All` transaction instead, which will also unstake all delegators._ + +_Note: unstaked tokens will be held by the central staking contract until the end of the following epoch. +Once the tokens are released (unstaked), they can be claimed via the +[Withdraw Unstaked Tokens](#withdraw-unstaked-tokens) action below._ + +## Unstake All Tokens + +The token holder can submit a request to unstake all their tokens at any time. +If the tokens aren't staked yet, they will be uncommitted and available to withdraw. + +To unstake all staked tokens, the token holder can use +the **Unstake All FLOW** ([SC.16](../../build/core-contracts/06-staking-contract-reference.md#staking)) transaction. + +This transaction requires no arguments. + +**Warning: this will unstake all of the user's staked tokens and unstake all of the tokens +from users that are delegating FLOW to the node.** + +## Withdraw Unstaked Tokens + +After tokens become unstaked, the token holder can withdraw them from the central staking contract. + +To withdraw unstaked tokens, +the token holder can use the **Withdraw Unstaked FLOW** ([SC.17](../../build/core-contracts/06-staking-contract-reference.md#staking)) +transaction with the following arguments: + +| Argument | Type | Description | +|------------|----------|-------------| +| **amount** | `UFix64` | The number of unstaked FLOW tokens to withdraw. | + +This transaction moves the unstaked tokens back into the `FlowToken.Vault` owned by the token holder. + +## Withdraw Rewarded Tokens + +After earning rewards from staking, the token holder can withdraw them from the central staking contract. + +To withdraw rewarded tokens, +the token holder can use the **Withdraw Rewarded FLOW** ([SC.18](../../build/core-contracts/06-staking-contract-reference.md#staking)) +transaction with the following arguments: + +| Argument | Type | Description | +|------------|----------|-------------| +| **amount** | `UFix64` | The number of rewarded FLOW tokens to withdraw. | + +This transaction moves the rewarded tokens back into the `FlowToken.Vault` owned by the token holder. + +## Stake Multiple Nodes from the Same Account + +Currently, the default staking transactions can only be used as they are to stake one node per account. + +If a token holder wants to create a second staking relationship using the transactions as is, they must create a new account +and transfer their tokens to the new account. + +It is possible to have multiple nodes per account by storing the node objects at different storage paths, +but this would require small changes to these transactions to use the new storage paths. + +# Delegating + +## Setup + +## Register as a Delegator + +To register as a delegator, the token holder can use the **Register Delegator** ([SC.19](../../build/core-contracts/06-staking-contract-reference.md#delegating)) +transaction with the following arguments: + +| Argument | Type | Description | +|------------|----------|-------------| +| **id** | `String` | The ID of the node to delegate to. | +| **amount** | `UFix64` | The number of FLOW tokens to delegate. | + +This transaction registers the account as a delegator to the node ID they specified. + +--- + +## Delegate New Tokens + +The token holder can delegate additional tokens after registering as a delegator. + +_Note: this transaction delegates additional tokens to the same node that was registered in the setup phase._ + +To delegate new tokens, +the token holder can use the **Delegate New FLOW** ([SC.20](../../build/core-contracts/06-staking-contract-reference.md#delegating)) +transaction with the following arguments: + +| Argument | Type | Description | +|------------|----------|-------------| +| **amount** | `UFix64` | The number of FLOW tokens to delegate. | + +## Re-delegate Unstaked Tokens + +After delegated tokens become unstaked, the token holder can choose to re-delegate the unstaked tokens to the same node. + +To delegate unstaked tokens, +the token holder can use the **Re-delegate Unstaked FLOW** ([SC.21](../../build/core-contracts/06-staking-contract-reference.md#delegating)) +transaction with the following arguments: + +| Argument | Type | Description | +|------------|----------|-------------| +| **amount** | `UFix64` | The number of unstaked FLOW tokens to delegate. | + +## Re-delegate Rewarded Tokens + +After earning rewards from delegation, the token holder can choose to re-delegate the rewarded tokens to the same node. + +To delegate rewarded tokens, +the token holder can use the **Re-delegate Rewarded FLOW** ([SC.22](../../build/core-contracts/06-staking-contract-reference.md#delegating)) +| Argument | Type | Description | +| **amount** | `UFix64` | The number of rewarded FLOW tokens to delegate. | + +## Unstake Delegated Tokens + +The token holder can submit a request to unstake their delegated tokens at any time. +If the tokens aren't staked yet, they will be uncommitted and available to withdraw. + +To unstake delegated tokens, +the token holder can use the **Unstake Delegated FOW** ([SC.23](../../build/core-contracts/06-staking-contract-reference.md#delegating)) + +| Argument | Type | Description | +|------------|----------|-------------| +| **amount** | `UFix64` | The number of FLOW tokens to unstake. | + +_Note: unstaked delegated tokens will be held by the central staking contract for a period of time +(the rest of the current epoch plus all of the next epoch) before they are +released to the token holder. Once the tokens are released (unstaked), +they can be claimed via the [Withdraw Unstaked Tokens](#withdraw-unstaked-tokens) action below._ + +## Withdraw Unstaked Tokens + +After delegated tokens become unstaked, the token holder can withdraw them from the central staking contract. + +To withdraw unstaked tokens, +the token holder can use the **Withdraw Unstaked FLOW** ([SC.24](../../build/core-contracts/06-staking-contract-reference.md#delegating)) +transaction with the following arguments: + +| Argument | Type | Description | +|------------|----------|-------------| +| **amount** | `UFix64` | The number of unstaked FLOW tokens to withdraw. | + +This transaction moves the unstaked tokens back into the `FlowToken.Vault` owned by the token holder. + +## Withdraw Rewarded Tokens + +After earning rewards from delegation, the token holder can withdraw them from the central staking contract. + +To withdraw rewarded tokens, +the token holder can use the **Withdraw Rewarded FLOW** ([SC.25](../../build/core-contracts/06-staking-contract-reference.md#delegating)) +transaction with the following arguments: + +| Argument | Type | Description | +|------------|----------|-------------| +| **amount** | `UFix64` | The number of rewarded FLOW tokens to withdraw. | + +This transaction moves the rewarded tokens back into the `FlowToken.Vault` owned by the token holder. + +## Delegate to Multiple Nodes from the Same Account + +Currently, the default delegating transactions can only be used as they are to stake one node per account. + +If a token holder wants to create a second delegating relationship using the transactions as is, they must create a new account +and transfer their tokens to the new account. + +It is possible to have multiple delegator objects per account +by storing the node objects at different storage paths, +but this would require small changes to these transactions to use the new storage paths. \ No newline at end of file diff --git a/static/markdown/networks/staking/index.md b/static/markdown/networks/staking/index.md new file mode 100644 index 0000000000..e1faa6a3aa --- /dev/null +++ b/static/markdown/networks/staking/index.md @@ -0,0 +1,160 @@ +--- +title: Epochs, Staking & Delegating on Flow +sidebar_label: Staking and Epochs +sidebar_position: 1 +description: Introduction to how staking works on Flow +--- + +This document provides an introduction to staking FLOW tokens on the Flow network +for token holders and node operators. +Staking is an important part of the security protocol of a proof-of-stake (PoS) blockchain. +Running nodes and staking tokens contributes to the blockchain's +security and is rewarded accordingly. + +## What is Staking? + +Flow is a global network of computers working together +to maintain the security and integrity of its users' data. + +This global network is made up of many individual nodes: software applications run by people. +Every node in the network shares a small part of the responsibility +to keep the network running smoothly and to ensure that other nodes are doing the same. +This shared responsibility is a core premise of decentralization, because no single central +node is solely responsible for the security and integrity of the network and the data it contains. + +Node operators are what we call the people who run nodes. +In order to connect their software applications as nodes on the network, +a node operator must first purchase tokens. Every node operator has to temporarily give (or ‘stake’) +a large number of their tokens to the network as a promise that they will not modify their node +to do something that is against the rules of the network, like steal funds from users' accounts. +This process of temporarily giving up tokens is called staking. + +If a node ever breaks the rules defined by the network, +a number of the node operator's staked tokens will be taken from them as a punishment. +This process is automatic. Every node knows the rules defined by the network +and automatically watches other nodes and reports them if they misbehave. +Meanwhile, the network pays the node operator a reward from a mixture of +transaction fees and newly minted tokens +on a regular basis provided their node does not break the rules. + +If a node operator breaks the rules, they lose the tokens they've staked. +If they operate their node with integrity, they get rewarded with more tokens! +This is the basic incentive that enables a decentralized proof-of-stake network, like Flow. + +## How Does Staking Work on Flow? + +The Flow protocol maintains a list of node operators. +The list contains important information about each node, like their public keys, node address, +and what kind of node they are running. +(Collection, Consensus, Execution, Verification, or Access) + +A node operator registers a node by submitting a transaction containing +their node information, a cryptographic proof that they control their node info, +and the FLOW they wish to stake. +If they meet the requirements to run a node, then will be accepted to join the network! + +Once a node is staking and operating properly, it will receive periodic reward payments, +assuming it stays online and actively participates in the protocol +without committing any actions that would harm the network, which we call slashable offenses. +Once nodes have registered, they are required to operate for a protocol-specified timeframe. +This timeframe is otherwise known as an **Epoch.** + +## Epochs + +An **Epoch** is a roughly week-long period that the network uses +to manage list of nodes and pay rewards. + +- Only a pre-determined set of nodes is authorized to participate in the protocol. +The set of authorized nodes is known to all network participants. +This set is referred to as the **Identity Table**. +- An **Epoch** is defined as a period of time, where the set of authorized nodes is constant +(or can only shrink due to ejection of malicious nodes). + +Every epoch, a list of committed nodes are chosen to be the staked nodes of the network. +This list is called the **Identity Table (ID Table)**. +The node's staked tokens are locked in and cannot change for the duration of the epoch. +At the end of the epoch, rewards are paid to each staked node based on how many tokens they had staked for that epoch +and how well they performed during the epoch. Nodes can choose to join or leave, but changes to the Identity Table +can only happen at end of an epoch, which is also the beginning of a new epoch. +This process repeats itself indefinitely, as long as the network remains functioning. + +To determine the list of nodes that are included as officially staked nodes in the next epoch, +the protocol looks at the records of all the nodes that have committed tokens. +It checks to make sure each node's information is correct and that the node is running properly. +Each node also has to have committed tokens above the minimum stake required for their node role +and be authorized by the service account. +If any of these checks are insufficient, the node is not included in the next epoch. + +Every epoch, some nodes also have to perform certain processes to initialize the state and communication +with other nodes for the next epoch. These processes are called **Cluster Quorum Certificate Generation (QC)**, +and **Distributed Key Generation (DKG)**. If any node does not perform this initialization properly, +it is not included in the next epoch's Identity Table. + +If a node passes all the checks and initializations, it is approved and included as an official node for the next epoch. + +Nodes (and users who delegate to them) do not have to continue to submit +staking registration transactions every epoch in order to remain staked. +As long as they continue to run their node properly, their tokens will remain staked. +A node operator only needs to take action if they want to stake more tokens +or if they want to unstake their staked tokens. + +If a node operator or delegator decides to stake or unstake tokens, +their requests are not carried out until the end of the current epoch. +In the case of unstaking requests, they also must wait an additional +epoch before their unstaked tokens are available to withdraw. +This allows the protocol to deal with any slashable offenses that may have happened in the previous epoch. + +See the [Epochs](./04-epoch-preparation.md) section of the documentation for in-depth explanations +of the identity table, epoch schedule, QC, and DKG. + +## Rewards + +Please see the [schedule](./03-schedule.md) section of the documentation +for information about reward calculations and schedule and +what you can do with the rewards you earn by staking a node! + +## Delegation + +Any account in the network may also participate in staking by delegating their tokens to a node operator. +Every node operator in the network is eligible to receive delegations, there is no opting out. + +To delegate to a node, a user simply specifies the ID of the node they want to delegate to +and the amount of tokens they want to delegate. +The tokens are committed and managed in the exact same way that normal staked tokens are managed. + +Rewards for delegators are also calculated in the exact same way that rewards for node operators are calculated, +with one difference in that 8% of the calculated amount is given to the delegatee (the node being delegated to). +The remaining 92% is awarded to the delegator. + +## How Do I Stake? + +So you have decided you want to be a part of the Flow network? Welcome! +You are joining a group of people from all around the world that are a part of a movement that is bringing decentralization and transparency into the world. + +### Staking using Flow Port + +[Flow Port](https://port.onflow.org/) is a simple browser-based app for the Flow blockchain +that provides functionality for sending, receiving, and staking tokens. +Any wallet that uses the [Flow Client Library](../../tools/clients/fcl-js/index.md) +is compatible with Flow Port. + +If you created your account using [Flow Port](https://port.onflow.org/), +you can also stake and earn rewards using the Flow Port. +Follow this [step-by-step guide](../../networks/flow-port/staking-guide.md) to stake using Flow Port. +Flow Port currently supports staking as a node, delegating, +and reward withdrawal using **Flow Reference Wallet**, **Ledger**, **Shadow**, **NuFi**, and any other FCL compatible accounts / wallets. + +### Staking via a Custody Provider + +If you are using a custody provider who controls your account and private keys for you, +such as Kraken, Finoa, or Coinlist, they all have different policies and processes +for what you need to do to stake your tokens, the rewards you receive, +and the fees that they take from your staking rewards. + +### Manual Staking or Building your own Staking Integration + +If you are self-custodying your Flow account and keys, or you want to build a staking service for customers, +you will need to learn more about how staking works, +the various methods for staking, and how you can participate safely and reliably. +See the [staking technical overview](./06-technical-overview.md) first +for information about technical integration. \ No newline at end of file diff --git a/static/markdown/templates/tutorial.md b/static/markdown/templates/tutorial.md new file mode 100644 index 0000000000..14e27baaeb --- /dev/null +++ b/static/markdown/templates/tutorial.md @@ -0,0 +1,58 @@ +--- +title: Title, shorten if necessary, will be on sidebar +description: A one sentence description. +sidebar_position: 5 +keywords: + - keywords + - describing + - the main topics + - cursor is great at this +--- + +# Title + +1-2 Paragraphs describing what the tutorial will teach, why someone might learn it, and if possible, a link to a live version of the app demoing the techniques and content taught. + +## Objectives + +After completing this guide, you'll be able to: + +- 3-5 appropriate level Bloom's taxonomy verb objectives +- Don't wordsmith these +- It's ok of they're repetitive + +## Prerequisites + +### Next.js and Modern Frontend Development + +This tutorial uses [Next.js]. You don't need to be an expert, but it's helpful to be comfortable with development using a current React framework. You'll be on your own to select and use a package manager, manage Node versions, and other frontend environment tasks. If you don't have your own preference, you can just follow along with us and use [Yarn]. + +## Part 1 + +Text can go here. Usually it will be either an introduction to a long section with subsections, or a short section with no subsections that doesn't fit under a higher level. + +### Subsection 1 + +Divide each part into appropriate categories. + +**Avoid h4 and above** + +## Part 2 + +More text goes here + +## Conclusion + +In this tutorial, you ... + +Now that you have completed the tutorial, you should be able to: + +- Copy/paste the Objectives from above here + +(OPTIONAL) Now that you've completed this tutorial, you're ready to... + + + +[Cadence]: https://cadence-lang.org/docs +[Next.js]: https://nextjs.org/docs/app/getting-started/installation +[Yarn]: https://yarnpkg.com \ No newline at end of file diff --git a/static/markdown/tools/clients/fcl-js/api.md b/static/markdown/tools/clients/fcl-js/api.md new file mode 100644 index 0000000000..285e4cb694 --- /dev/null +++ b/static/markdown/tools/clients/fcl-js/api.md @@ -0,0 +1,2128 @@ +--- +sidebar_label: FCL Reference +sidebar_position: 2 +--- + +# Flow Client Library (FCL) API Reference + +> For release updates, [see the repo](https://github.com/onflow/fcl-js/releases) + +## Configuration + +FCL has a mechanism that lets you configure various aspects of FCL. When you move from one instance of the Flow Blockchain to another (Local Emulator to Testnet to Mainnet) the only thing you should need to change for your FCL implementation is your configuration. + +--- + +### Setting Configuration Values + +Values only need to be set once. We recommend doing this once and as early in the life cycle as possible. To set a configuration value, the `put` method on the `config` instance needs to be called, the `put` method returns the `config` instance so they can be chained. + +Alternatively, you can set the config by passing a JSON object directly. + +```javascript + + +fcl + .config() // returns the config instance + .put('foo', 'bar') // configures "foo" to be "bar" + .put('baz', 'buz'); // configures "baz" to be "buz" + +// OR + +fcl.config({ + foo: 'bar', + baz: 'buz', +}); +``` + +### Getting Configuration Values + +The `config` instance has an **asynchronous** `get` method. You can also pass it a fallback value. + +```javascript + + +fcl.config().put('foo', 'bar').put('woot', 5).put('rawr', 7); + +const FALLBACK = 1; + +async function addStuff() { + var woot = await fcl.config().get('woot', FALLBACK); // will be 5 -- set in the config before + var rawr = await fcl.config().get('rawr', FALLBACK); // will be 7 -- set in the config before + var hmmm = await fcl.config().get('hmmm', FALLBACK); // will be 1 -- uses fallback because this isnt in the config + + return woot + rawr + hmmm; +} + +addStuff().then((d) => console.log(d)); // 13 (5 + 7 + 1) +``` + +### Common Configuration Keys + +| Name | Example | Description | +| ------------------------------------ | ------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `accessNode.api` **(required)** | `https://rest-testnet.onflow.org` | API URL for the Flow Blockchain Access Node you want to be communicating with. See all available access node endpoints [here](https://developers.onflow.org/http-api/). | +| `app.detail.title` | `Cryptokitties` | Your applications title, can be requested by wallets and other services. Used by WalletConnect plugin & Wallet Discovery service. | +| `app.detail.icon` | `https://fcl-discovery.onflow.org/images/blocto.png` | Url for your applications icon, can be requested by wallets and other services. Used by WalletConnect plugin & Wallet Discovery service. | +| `app.detail.description` | `Cryptokitties is a blockchain game` | Your applications description, can be requested by wallets and other services. Used by WalletConnect plugin & Wallet Discovery service. | +| `app.detail.url` | `https://cryptokitties.co` | Your applications url, can be requested by wallets and other services. Used by WalletConnect plugin & Wallet Discovery service. | +| `challenge.handshake` | **DEPRECATED** | Use `discovery.wallet` instead. | +| `discovery.authn.endpoint` | `https://fcl-discovery.onflow.org/api/testnet/authn` | Endpoint for alternative configurable Wallet Discovery mechanism. Read more on [discovery](#discovery) | +| `discovery.wallet` **(required)** | `https://fcl-discovery.onflow.org/testnet/authn` | Points FCL at the Wallet or Wallet Discovery mechanism. | +| `discovery.wallet.method` | `IFRAME/RPC`, `POP/RPC`, `TAB/RPC`, `HTTP/POST`, or `EXT/RPC` | Describes which service strategy a wallet should use. | +| `fcl.limit` | `100` | Specifies fallback compute limit if not provided in transaction. Provided as integer. | +| `flow.network` **(recommended)** | `testnet` | Used in conjunction with stored interactions and provides FCLCryptoContract address for `testnet` and `mainnet`. Possible values: `local`, `testnet`, `mainnet`. | +| `walletconnect.projectId` | `YOUR_PROJECT_ID` | Your app's WalletConnect project ID. See [WalletConnect Cloud](https://cloud.walletconnect.com/sign-in) to obtain a project ID for your application. | +| `walletconnect.disableNotifications` | `false` | Optional flag to disable pending WalletConnect request notifications within the application's UI. | + +## Using Contracts in Scripts and Transactions + +### Address Replacement + +Configuration keys that start with `0x` will be replaced in FCL scripts and transactions, this allows you to write your script or transaction Cadence code once and not have to change it when you point your application at a difference instance of the Flow Blockchain. + +```javascript + + +fcl.config().put('0xFungibleToken', '0xf233dcee88fe0abe'); + +async function myScript() { + return fcl + .send([ + fcl.script` + import FungibleToken from 0xFungibleToken // will be replaced with 0xf233dcee88fe0abe because of the configuration + + access(all) fun main() { /* Rest of the script goes here */ } + `, + ]) + .then(fcl.decode); +} + +async function myTransaction() { + return fcl + .send([ + fcl.transaction` + import FungibleToken from 0xFungibleToken // will be replaced with 0xf233dcee88fe0abe because of the configuration + + transaction { /* Rest of the transaction goes here */ } + `, + ]) + .then(fcl.decode); +} +``` + +#### Example + +```javascript + + +fcl + .config() + .put('flow.network', 'testnet') + .put('walletconnect.projectId', 'YOUR_PROJECT_ID') + .put('accessNode.api', 'https://rest-testnet.onflow.org') + .put('discovery.wallet', 'https://fcl-discovery.onflow.org/testnet/authn') + .put('app.detail.title', 'Test Harness') + .put('app.detail.icon', 'https://i.imgur.com/r23Zhvu.png') + .put('app.detail.description', 'A test harness for FCL') + .put('app.detail.url', 'https://myapp.com') + .put('service.OpenID.scopes', 'email email_verified name zoneinfo') + .put('0xFlowToken', '0x7e60df042a9c0868'); +``` + +### Using `flow.json` for Contract Imports + +A simpler and more flexible way to manage contract imports in scripts and transactions is by using the `config.load` method in FCL. This lets you load contract configurations from a `flow.json` file, keeping your import syntax clean and allowing FCL to pick the correct contract addresses based on the network you're using. + +### Setting Up + +#### 1. Define Your Contracts in `flow.json` + +Here’s an example of a `flow.json` file with aliases for multiple networks: + +```json +{ + "contracts": { + "HelloWorld": { + "source": "./cadence/contracts/HelloWorld.cdc", + "aliases": { + "testnet": "0x1cf0e2f2f715450", + "mainnet": "0xf8d6e0586b0a20c7" + } + } + } +} +``` + +- **`source`**: Points to the contract file in your project. +- **`aliases`**: Maps each network to the correct contract address. + +#### 2. Configure FCL + +Load the `flow.json` file and set up FCL to use it: + +```javascript + + + +config({ + 'flow.network': 'testnet', // Choose your network, e.g., testnet or mainnet + 'accessNode.api': 'https://rest-testnet.onflow.org', // Access node for the network + 'discovery.wallet': `https://fcl-discovery.onflow.org/testnet/authn`, // Wallet discovery +}).load({ flowJSON }); +``` + +With this setup, FCL will automatically use the correct contract address based on the selected network (e.g., `testnet` or `mainnet`). + +#### 3. Use Contract Names in Scripts and Transactions + +After setting up `flow.json`, you can import contracts by name in your Cadence scripts or transactions: + +```cadence +import "HelloWorld" + +access(all) fun main(): String { + return HelloWorld.sayHello() +} +``` + +FCL replaces `"HelloWorld"` with the correct address from the `flow.json` configuration. + +> **Note**: Don’t store private keys in your `flow.json`. Instead, use the [key/location syntax](../../../tools/flow-cli/flow.json/security.md) to keep sensitive keys in a separate, `.gitignore`-protected file. + +## Wallet Interactions + +These methods allows dapps to interact with FCL compatible wallets in order to authenticate the user and authorize transactions on their behalf. + +> ⚠️These methods are **async**. + +--- + +### `authenticate` + +> ⚠️**This method can only be used in web browsers.** + +Calling this method will authenticate the current user via any wallet that supports FCL. Once called, FCL will initiate communication with the configured `discovery.wallet` endpoint which lets the user select a wallet to authenticate with. Once the wallet provider has authenticated the user, FCL will set the values on the [current user](#currentuserobject) object for future use and authorization. + +#### Note + +⚠️`discovery.wallet` value **must** be set in the configuration before calling this method. See [FCL Configuration](#configuration). + +📣 The default discovery endpoint will open an iframe overlay to let the user choose a supported wallet. + +#### Usage + +```javascript + +fcl + .config() + .put('accessNode.api', 'https://rest-testnet.onflow.org') + .put('discovery.wallet', 'https://fcl-discovery.onflow.org/testnet/authn'); +// anywhere on the page +fcl.authenticate(); +``` + +#### Note + +⚠️ `authenticate` can also take a service returned from [discovery](#discovery) with `fcl.authenticate({ service })`. + +--- + +### `unauthenticate` + +> ⚠️**This method can only be used in web browsers.** + +Logs out the current user and sets the values on the [current user](#currentuserobject) object to null. + +#### Note + +⚠️The current user must be authenticated first. + +#### Usage + +```javascript + +fcl.config().put('accessNode.api', 'https://rest-testnet.onflow.org'); +// first authenticate to set current user +fcl.authenticate(); +// ... somewhere else & sometime later +fcl.unauthenticate(); +// fcl.currentUser.loggedIn === null +``` + +--- + +### `reauthenticate` + +> ⚠️**This method can only be used in web browsers.** + +A **convenience method** that calls [`fcl.unauthenticate()`](#unauthenticate) and then [`fcl.authenticate()`](#authenticate) for the current user. + +#### Note + +⚠️The current user must be authenticated first. + +#### Usage + +```javascript + +// first authenticate to set current user +fcl.authenticate(); +// ... somewhere else & sometime later +fcl.reauthenticate(); +// logs out user and opens up login/sign-up flow +``` + +--- + +### `signUp` + +> ⚠️**This method can only be used in web browsers.** + +A **convenience method** that calls and is equivalent to [`fcl.authenticate()`](#authenticate). + +--- + +### `logIn` + +> ⚠️**This method can only be used in web browsers.** + +A **convenience method** that calls and is equivalent to [`fcl.authenticate()`](#authenticate). + +--- + +### `authz` + +A **convenience method** that produces the needed authorization details for the current user to submit transactions to Flow. It defines a signing function that connects to a user's wallet provider to produce signatures to submit transactions. + +> 📣 You can replace this function with your own [authorization function](#authorization-function) if needed. + +#### Returns + +| Type | Description | +| ------------------------------------------- | -------------------------------------------------------------------------------------------------------- | +| [AuthorizationObject](#authorizationobject) | An object containing the necessary details from the current user to authorize a transaction in any role. | + +#### Usage + +**Note:** The default values for `proposer`, `payer`, and `authorizations` are already `fcl.authz` so there is no need to include these parameters, it is shown only for example purposes. See more on [signing roles](../../../build/basics/transactions.md). + +```javascript + +// login somewhere before +fcl.authenticate(); +// once logged in authz will produce values +console.log(fcl.authz); +// prints {addr, signingFunction, keyId, sequenceNum} from the current authenticated user. + +const txId = await fcl.mutate({ + cadence: ` + import Profile from 0xba1132bc08f82fe2 + + transaction(name: String) { + prepare(account: auth(BorrowValue) &Account) { + account.storage.borrow<&{Profile.Owner}>(from: Profile.privatePath)!.setName(name) + } + } + `, + args: (arg, t) => [arg('myName', t.String)], + proposer: fcl.authz, // optional - default is fcl.authz + payer: fcl.authz, // optional - default is fcl.authz + authorizations: [fcl.authz], // optional - default is [fcl.authz] +}); +``` + +--- + +## Current User + +Holds the [current user](#currentuserobject), if set, and offers a set of functions to manage the authentication and authorization of the user. + +> ⚠️**The following methods can only be used in web browsers.** + +--- + +### `currentUser.subscribe` + +The callback passed to subscribe will be called when the user authenticates and un-authenticates, making it easy to update the UI accordingly. + +#### Arguments + +| Name | Type | | +| ---------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------- | +| `callback` | function | The callback will be called with the [current user](#currentuserobject) as the first argument when the current user is set or removed. | + +#### Usage + +```javascript + + + +export function AuthCluster() { + const [user, setUser] = useState({ loggedIn: null }); + useEffect(() => fcl.currentUser.subscribe(setUser), []); // sets the callback for FCL to use + + if (user.loggedIn) { + return ( +
    + {user?.addr ?? 'No Address'} + {/* once logged out in setUser(user) will be called */} +
    + ); + } else { + return ( +
    + {' '} + {/* once logged in setUser(user) will be called */} + {/* once signed up, setUser(user) will be called */} +
    + ); + } +} +``` + +--- + +### `currentUser.snapshot` + +Returns the [current user](#currentuserobject) object. This is the same object that is set and available on [`fcl.currentUser.subscribe(callback)`](#currentusersubscribe). + +#### Usage + +```javascript +// returns the current user object +const user = fcl.currentUser.snapshot(); + +// subscribes to the current user object and logs to console on changes +fcl.currentUser.subscribe(console.log); +``` + +--- + +### `currentUser.authenticate` + +Equivalent to `fcl.authenticate`. + +--- + +### `currentUser.unauthenticate` + +Equivalent to `fcl.unauthenticate`. + +--- + +### `currentUser.authorization` + +Equivalent to `fcl.authz` + +--- + +### `currentUser.signUserMessage` + +A method to use allowing the user to personally sign data via FCL Compatible Wallets/Services. + +> ⚠️ This method requires the current user's wallet to support a signing service endpoint. Currently, only Blocto is compatible with this feature by default. + +#### Arguments + +| Name | Type | Description | +| --------- | --------------------- | --------------------------------- | +| `message` | string **(required)** | A hexadecimal string to be signed | + +#### Returns + +| Type | Description | +| ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `Array` | An Array of [CompositeSignatures](https://github.com/onflow/fcl-js/blob/master/packages/fcl-core/src/wallet-provider-spec/draft-v2.md#compositesignature): {`addr`, `keyId`, `signature`} | + +#### Usage + +```javascript + + +export const signMessage = async () => { + const MSG = Buffer.from('FOO').toString('hex'); + try { + return await currentUser.signUserMessage(MSG); + } catch (error) { + console.log(error); + } +}; +``` + +--- + +## Discovery + +### `discovery` + +Discovery abstracts away code so that developers don't have to deal with the discovery of Flow compatible wallets, integration, or authentication. Using `discovery` from FCL allows dapps to list and authenticate with wallets while having full control over the UI. Common use cases for this are login or registration pages. + +(Alternatively, if you don't need control over your UI you can continue to use the `discovery.wallet` config value documented in the [Quickstart](../../../build/getting-started/fcl-quickstart.md) for the simplest configuration.) + +> ⚠️**The following methods can only be used in web browsers.** + +#### Note + +⚠️`discovery.authn.endpoint` value **must** be set in the configuration before calling this method. See [FCL Configuration](#configuration). + +### Suggested Configuration + +| Environment | Example | +| ----------- | ---------------------------------------------------- | +| Mainnet | `https://fcl-discovery.onflow.org/api/authn` | +| Testnet | `https://fcl-discovery.onflow.org/api/testnet/authn` | + +If the Discovery endpoint is set in config, then you can iterate through authn services and pass the chosen service to [authenticate](#authenticate) to authenticate a user. + +#### Usage + +```javascript +import './config'; + + + +function Component() { + const [wallets, setWallets] = useState([]); + useEffect( + () => fcl.discovery.authn.subscribe((res) => setWallets(res.results)), + [], + ); + + return ( +
    + {wallets.map((wallet) => ( + + ))} +
    + ); +} +``` + +### authn + +#### More Configuration + +By default, limited functionality services or services that require developer registration, like Ledger or Dapper Wallet, require apps to opt-in in order to display to users. To enable opt-in services in an application, use the `discovery.authn.include` property in your configuration with a value of an array of services you'd like your app to opt-in to displaying for users. + +Additionally, you can use the `discovery.authn.exclude` property to exclude any services from being displayed to users. + +```javascript + + +config({ + 'discovery.authn.endpoint': + 'https://fcl-discovery.onflow.org/api/testnet/authn', // Endpoint set to Testnet + 'discovery.authn.include': ['0x9d2e44203cb13051'], // Ledger wallet address on Testnet set to be included + 'discovery.authn.exclude': ['0x123456789abcdef01'], // Example of excluding a wallet by address +}); +``` + +**Opt-In Wallet Addresses on Testnet and Mainnet** + +| Service | Testnet | Mainnet | +| --------------- | ------------------ | ------------------ | +| `Dapper Wallet` | 0x82ec283f88a62e65 | 0xead892083b3e2c6c | +| `Ledger` | 0x9d2e44203cb13051 | 0xe5cd26afebe62781 | + +For more details on wallets, view the [service list here](https://github.com/onflow/fcl-discovery/blob/87e172db85d185882d9fde007c95f08bc2a1cccb/data/services.json). + +--- + +### `discovery.authn.snapshot()` + +Return a list of `authn` services. + +### `discovery.authn.subscribe(callback)` + +The callback sent to `subscribe` will be called with a list of `authn` services. + +--- + +## On-chain Interactions + +> 📣 **These methods can be used in browsers and NodeJS.** + +These methods allows dapps to interact directly with the Flow blockchain via a set of functions that currently use the [Access Node API](../../../networks/access-onchain-data/index.md). + +--- + +### Query and Mutate Flow with Cadence + +If you want to run arbitrary Cadence scripts on the blockchain, these methods offer a convenient way to do so **without having to build, send, and decode interactions**. + +### `query` + +Allows you to submit scripts to query the blockchain. + +#### Options + +_Pass in the following as a single object with the following keys.All keys are optional unless otherwise stated._ + +| Key | Type | Description | +| --------- | ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `cadence` | string **(required)** | A valid cadence script. | +| `args` | [ArgumentFunction](#argumentfunction) | Any arguments to the script if needed should be supplied via a function that returns an array of arguments. | +| `limit` | number | Compute (Gas) limit for query. Read the [documentation about computation cost](../../../build/basics/fees.md) for information about how computation cost is calculated on Flow. | + +#### Returns + +| Type | Description | +| ---- | -------------------------------------- | +| any | A JSON representation of the response. | + +#### Usage + +```javascript + + +const result = await fcl.query({ + cadence: ` + access(all) fun main(a: Int, b: Int, addr: Address): Int { + log(addr) + return a + b + } + `, + args: (arg, t) => [ + arg(7, t.Int), // a: Int + arg(6, t.Int), // b: Int + arg('0xba1132bc08f82fe2', t.Address), // addr: Address + ], +}); +console.log(result); // 13 +``` + +#### Examples + +- [Additional Explanation](https://gist.github.com/orodio/3bf977a0bd45b990d16fdc1459b129a2) + +--- + +### `mutate` + +Allows you to submit transactions to the blockchain to potentially mutate the state. + +⚠️When being used in the browser, `fcl.mutate` uses the built-in `fcl.authz` function to produce the authorization (signatures) for the current user. When calling this method from Node.js, you will need to supply your own custom authorization function. + +#### Options + +_Pass in the following as a single object with the following keys. All keys are optional unless otherwise stated._ + +| Key | Type | Description | +| ---------- | ------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `cadence` | string **(required)** | A valid cadence transaction. | +| `args` | [ArgumentFunction](#argumentfunction) | Any arguments to the script if needed should be supplied via a function that returns an array of arguments. | +| `limit` | number | Compute (Gas) limit for query. Read the [documentation about computation cost](../flow-go-sdk/index.md#gas-limit) for information about how computation cost is calculated on Flow. | +| `proposer` | [AuthorizationFunction](#authorization-function) | The authorization function that returns a valid [AuthorizationObject](#authorizationobject) for the [proposer role](#transactionrolesobject). | + +#### Returns + +| Type | Description | +| ------ | ------------------- | +| string | The transaction ID. | + +#### Usage + +```javascript + +// login somewhere before +fcl.authenticate(); + +const txId = await fcl.mutate({ + cadence: ` + import Profile from 0xba1132bc08f82fe2 + + transaction(name: String) { + prepare(account: auth(BorrowValue) &Account) { + account.storage.borrow<&{Profile.Owner}>(from: Profile.privatePath)!.setName(name) + } + } + `, + args: (arg, t) => [arg('myName', t.String)], +}); +``` + +#### Examples + +- [Additional explanation](https://gist.github.com/orodio/3bf977a0bd45b990d16fdc1459b129a2) +- [Custom authorization function](#authorization-function) + +--- + +### `verifyUserSignatures` (Deprecated) + +Use `fcl.AppUtils.verifyUserSignatures` + +## AppUtils + +### `AppUtils.verifyUserSignatures` + +A method allowing applications to cryptographically verify a message was signed by a user's private key/s. This is typically used with the response from `currentUser.signUserMessage`. + +#### Note + +⚠️ `fcl.config.flow.network` or options override is required to use this api. See [FCL Configuration](#configuration). + +#### Arguments + +| Name | Type | Description | +| --------------------- | --------------------- | ---------------------------------------------------------------------------------------------------- | +| `message` | string **(required)** | A hexadecimal string | +| `compositeSignatures` | Array **(required)** | An Array of `CompositeSignatures` | +| `opts` | Object **(optional)** | `opts.fclCryptoContract` can be provided to override FCLCryptoContract address for local development | + +#### Returns + +| Type | Description | +| ------- | ----------------------------- | +| Boolean | `true` if verified or `false` | + +#### Usage + +```javascript + + +const isValid = await fcl.AppUtils.verifyUserSignatures( + Buffer.from('FOO').toString('hex'), + [ + { + f_type: 'CompositeSignature', + f_vsn: '1.0.0', + addr: '0x123', + keyId: 0, + signature: 'abc123', + }, + ], + { fclCryptoContract }, +); +``` + +#### Examples + +- [fcl-next-harness](https://github.com/onflow/fcl-next-harness) + +--- + +### `AppUtils.verifyAccountProof` + +A method allowing applications to cryptographically prove that a user controls an on-chain account. During user authentication, some FCL compatible wallets will choose to support the FCL `account-proof` service. If a wallet chooses to support this service, and the user approves the signing of message data, they will return `account-proof` data and a signature(s) that can be used to prove a user controls an on-chain account. +See [proving-authentication](https://github.com/onflow/fcl-js/blob/master/docs/reference/proving-authentication.mdx) documentaion for more details. + +⚠️ `fcl.config.flow.network` or options override is required to use this api. See [FCL Configuration](#configuration). + +#### Arguments + +| Name | Type | Description | +| ------------------ | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `appIdentifier` | string **(required)** | A hexadecimal string | +| `accountProofData` | Object **(required)** | Object with properties:
    `address`: `string` - A Flow account address.
    `nonce`: `string` - A random string in hexadecimal format (minimum 32 bytes in total, i.e 64 hex characters)
    `signatures`: `Object[]` - An array of composite signatures to verify | +| `opts` | Object **(optional)** | `opts.fclCryptoContract` can be provided to overide FCLCryptoContract address for local development | + +#### Returns + +| Type | Description | +| ------- | ----------------------------- | +| Boolean | `true` if verified or `false` | + +#### Usage + +```javascript + + +const accountProofData = { + address: "0x123", + nonce: "F0123" + signatures: [{f_type: "CompositeSignature", f_vsn: "1.0.0", addr: "0x123", keyId: 0, signature: "abc123"}], +} + +const isValid = await fcl.AppUtils.verifyAccountProof( + "AwesomeAppId", + accountProofData, + {fclCryptoContract} +) + +``` + +#### Examples + +- [fcl-next-harness](https://github.com/onflow/fcl-next-harness) + +--- + +### Query and mutate the blockchain with Builders + +In some cases, you may want to utilize pre-built interactions or build more complex interactions than what the `fcl.query` and `fcl.mutate` interface offer. To do this, FCL uses a pattern of building up an interaction with a combination of builders, resolving them, and sending them to the chain. + +> ⚠️**Recommendation:** Unless you have a specific use case that require usage of these builders, you should be able to achieve most cases with `fcl.query({...options}` or `fcl.mutate({...options})` + +### `send` + +Sends arbitrary scripts, transactions, and requests to Flow. + +This method consumes an array of [builders](#builders) that are to be resolved and sent. The builders required to be included in the array depend on the [interaction](#interaction) that is being built. + +#### Note + +⚠️Must be used in conjuction with [`fcl.decode(response)`](#decode) to get back correct keys and all values in JSON. + +#### Arguments + +| Name | Type | Description | +| ---------- | ----------------------- | ---------------------- | +| `builders` | [[Builders](#builders)] | See builder functions. | + +#### Returns + +| Type | Description | +| --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | +| [ResponseObject](#responseobject) | An object containing the data returned from the chain. Should always be decoded with `fcl.decode()` to get back appropriate JSON keys and values. | + +#### Usage + +```javascript + + +// a script only needs to resolve the arguments to the script +const response = await fcl.send([fcl.script`${script}`, fcl.args(args)]); +// note: response values are encoded, call await fcl.decode(response) to get JSON + +// a transaction requires multiple 'builders' that need to be resolved prior to being sent to the chain - such as setting the authorizations. +const response = await fcl.send([ + fcl.transaction` + ${transaction} + `, + fcl.args(args), + fcl.proposer(proposer), + fcl.authorizations(authorizations), + fcl.payer(payer), + fcl.limit(9999), +]); +// note: response contains several values (Cad) +``` + +--- + +### `decode` + +Decodes the response from `fcl.send()` into the appropriate JSON representation of any values returned from Cadence code. + +#### Note + +📣 To define your own decoder, see [`tutorial`](https://github.com/onflow/fcl-js/tree/master/packages/sdk/src/decode). + +#### Arguments + +| Name | Type | Description | +| ---------- | --------------------------------- | ------------------------------------------------------ | +| `response` | [ResponseObject](#responseobject) | Should be the response returned from `fcl.send([...])` | + +#### Returns + +| Type | Description | +| ---- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| any | A JSON representation of the raw string response depending on the cadence code executed.
    The return value can be a single value and type or an object with multiple types. | + +#### Usage + +```javascript + + +// simple script to add 2 numbers +const response = await fcl.send([ + fcl.script` + access(all) fun main(int1: Int, int2: Int): Int { + return int1 + int2 + } + `, + fcl.args([fcl.arg(1, fcl.t.Int), fcl.arg(2, fcl.t.Int)]), +]); + +const decoded = await fcl.decode(response); + +assert(3 === decoded); +assert(typeof decoded === 'number'); +``` + +--- + +## Builders + +These methods fill out various portions of a transaction or script template in order to +build, resolve, and send it to the blockchain. A valid populated template is referred to as an [Interaction](#interaction). + +⚠️**These methods must be used with `fcl.send([...builders]).then(fcl.decode)`** + +### Query Builders + +### `getAccount` + +A builder function that returns the interaction to get an account by address. + +⚠️Consider using the pre-built interaction [`fcl.account(address)`](#account) if you do not need to pair with any other builders. + +#### Arguments + +| Name | Type | Description | +| --------- | ------------------- | ---------------------------------------------------------------------------------- | +| `address` | [Address](#address) | Address of the user account with or without a prefix (both formats are supported). | + +#### Returns after decoding + +| Type | Description | +| ------------------------- | ---------------------------------------- | +| [AccountObject](#account) | A JSON representation of a user account. | + +#### Usage + +```javascript + + +// somewhere in an async function +// fcl.account is the same as this function +const getAccount = async (address) => { + const account = await fcl.send([fcl.getAccount(address)]).then(fcl.decode); + return account; +}; +``` + +--- + +### `getBlock` + +A builder function that returns the interaction to get the latest block. + +📣 Use with `fcl.atBlockId()` and `fcl.atBlockHeight()` when building the interaction to get information for older blocks. + +⚠️Consider using the pre-built interaction [`fcl.getblock(isSealed)`](#getblock) if you do not need to pair with any other builders. + +#### Arguments + +| Name | Type | Default | Description | +| ---------- | ------- | ------- | ------------------------------------------------------------------------------ | +| `isSealed` | boolean | false | If the latest block should be sealed or not. See [block states](#interaction). | + +#### Returns after decoding + +| Type | Description | +| --------------------------- | ----------------------------------------------------- | +| [BlockObject](#blockobject) | The latest block if not used with any other builders. | + +#### Usage + +```javascript + + +const latestSealedBlock = await fcl + .send([ + fcl.getBlock(true), // isSealed = true + ]) + .then(fcl.decode); +``` + +--- + +### `atBlockHeight` + +A builder function that returns a partial interaction to a block at a specific height. + +⚠️Use with other interactions like [`fcl.getBlock()`](#getblock) to get a full interaction at the specified block height. + +#### Arguments + +| Name | Type | Description | +| ------------- | ------ | ------------------------------------------------------ | +| `blockHeight` | number | The height of the block to execute the interaction at. | + +#### Returns + +| Type | Description | +| ----------------------------------- | ----------------------------------------------------------------------------------------------------------- | +| [Partial Interaction](#interaction) | A partial interaction to be paired with another interaction such as `fcl.getBlock()` or `fcl.getAccount()`. | + +#### Usage + +```javascript + + +await fcl.send([fcl.getBlock(), fcl.atBlockHeight(123)]).then(fcl.decode); +``` + +--- + +### `atBlockId` + +A builder function that returns a partial interaction to a block at a specific block ID. + +⚠️Use with other interactions like [`fcl.getBlock()`](#getblock) to get a full interaction at the specified block ID. + +#### Arguments + +| Name | Type | Description | +| --------- | ------ | -------------------------------------------------- | +| `blockId` | string | The ID of the block to execute the interaction at. | + +#### Returns + +| Type | Description | +| ----------------------------------- | ----------------------------------------------------------------------------------------------------------- | +| [Partial Interaction](#interaction) | A partial interaction to be paired with another interaction such as `fcl.getBlock()` or `fcl.getAccount()`. | + +#### Usage + +```javascript + + +await fcl.send([fcl.getBlock(), fcl.atBlockId('23232323232')]).then(fcl.decode); +``` + +--- + +### `getBlockHeader` + +A builder function that returns the interaction to get a block header. + +📣 Use with `fcl.atBlockId()` and `fcl.atBlockHeight()` when building the interaction to get information for older blocks. + +#### Returns after decoding + +| Type | Description | +| --------------------------------------- | ------------------------------------------------------------ | +| [BlockHeaderObject](#blockheaderobject) | The latest block header if not used with any other builders. | + +#### Usage + +```javascript + + +const latestBlockHeader = await fcl + .send([fcl.getBlockHeader()]) + .then(fcl.decode); +``` + +### `getEventsAtBlockHeightRange` + +A builder function that returns all instances of a particular event (by name) within a height range. + +⚠️The block range provided must be from the current spork. + +⚠️The block range provided must be 250 blocks or lower per request. + +#### Arguments + +| Name | Type | Description | +| ----------------- | ----------------------- | ---------------------------------------------------------------- | +| `eventName` | [EventName](#eventname) | The name of the event. | +| `fromBlockHeight` | number | The height of the block to start looking for events (inclusive). | +| `toBlockHeight` | number | The height of the block to stop looking for events (inclusive). | + +#### Returns after decoding + +| Type | Description | +| ------------------------------ | ---------------------------------------------- | +| [[EventObject]](#event-object) | An array of events that matched the eventName. | + +#### Usage + +```javascript + + +const events = await fcl + .send([ + fcl.getEventsAtBlockHeightRange( + 'A.7e60df042a9c0868.FlowToken.TokensWithdrawn', + 35580624, + 35580624, + ), + ]) + .then(fcl.decode); +``` + +--- + +### `getEventsAtBlockIds` + +A builder function that returns all instances of a particular event (by name) within a set of blocks, specified by block ids. + +⚠️The block range provided must be from the current spork. + +#### Arguments + +| Name | Type | Description | +| ----------- | ----------------------- | ----------------------------------------- | +| `eventName` | [EventName](#eventname) | The name of the event. | +| `blockIds` | number | The ids of the blocks to scan for events. | + +#### Returns after decoding + +| Type | Description | +| ------------------------------ | ---------------------------------------------- | +| [[EventObject]](#event-object) | An array of events that matched the eventName. | + +#### Usage + +```javascript + + +const events = await fcl + .send([ + fcl.getEventsAtBlockIds('A.7e60df042a9c0868.FlowToken.TokensWithdrawn', [ + 'c4f239d49e96d1e5fbcf1f31027a6e582e8c03fcd9954177b7723fdb03d938c7', + '5dbaa85922eb194a3dc463c946cc01c866f2ff2b88f3e59e21c0d8d00113273f', + ]), + ]) + .then(fcl.decode); +``` + +--- + +### `getCollection` + +A builder function that returns all a collection containing a list of transaction ids by its collection id. + +⚠️The block range provided must be from the current spork. All events emitted during past sporks is current unavailable. + +#### Arguments + +| Name | Type | Description | +| -------------- | ------ | ------------------------- | +| `collectionID` | string | The id of the collection. | + +#### Returns after decoding + +| Type | Description | +| ------------------------------------- | --------------------------------------------------------------------------------- | +| [CollectionObject](#collectionobject) | An object with the id and a list of transactions within the requested collection. | + +#### Usage + +```javascript + + +const collection = await fcl + .send([ + fcl.getCollection( + 'cccdb0c67d015dc7f6444e8f62a3244ed650215ed66b90603006c70c5ef1f6e5', + ), + ]) + .then(fcl.decode); +``` + +--- + +### `getTransactionStatus` + +A builder function that returns the status of transaction in the form of a [TransactionStatusObject](#transactionstatusobject). + +⚠️The transactionID provided must be from the current spork. + +📣 Considering [subscribing to the transaction from `fcl.tx(id)`](#tx) instead of calling this method directly. + +#### Arguments + +| Name | Type | Description | +| --------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------- | +| `transactionId` | string | The transactionID returned when submitting a transaction. Example: `9dda5f281897389b99f103a1c6b180eec9dac870de846449a302103ce38453f3` | + +#### Returns after decoding + +#### Returns + +| Type | Description | +| --------------------------------------------------- | ------------------------------------------------------ | +| [TransactionStatusObject](#transactionstatusobject) | Object representing the result/status of a transaction | + +#### Usage + +```javascript + + +const status = await fcl + .send([ + fcl.getTransactionStatus( + '9dda5f281897389b99f103a1c6b180eec9dac870de846449a302103ce38453f3', + ), + ]) + .then(fcl.decode); +``` + +--- + +### `getTransaction` + +A builder function that returns a [transaction object](#transactionobject) once decoded. + +⚠️The transactionID provided must be from the current spork. + +📣 Considering using [`fcl.tx(id).onceExecuted()`](#tx) instead of calling this method directly. + +#### Arguments + +| Name | Type | Description | +| --------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------- | +| `transactionId` | string | The transactionID returned when submitting a transaction. Example: `9dda5f281897389b99f103a1c6b180eec9dac870de846449a302103ce38453f3` | + +#### Returns after decoding + +#### Returns + +| Type | Description | +| --------------------------------------- | -------------------------------------------------------------- | +| [TransactionObject](#transactionobject) | An full transaction object containing a payload and signatures | + +#### Usage + +```javascript + + +const tx = await fcl + .send([ + fcl.getTransaction( + '9dda5f281897389b99f103a1c6b180eec9dac870de846449a302103ce38453f3', + ), + ]) + .then(fcl.decode); +``` + +--- + +### `subscribeEvents` + + +The subscribeEvents SDK builder is for more advanced use cases where you wish to directly specify a starting block to listen for events. For most use cases, consider using the pre-built interaction [`fcl.events(eventTypes)`](#events). + + +A build that returns a [event stream connection](#eventstream) once decoded. It will establish a WebSocket connection to the Access Node and subscribe to events with the given parameters. + +#### Arguments + +| Name | Type | Description | +| ------------- | --------------------------- | --------------------------------- | +| `eventFilter` | [EventFilter](#eventfilter) | The event filter to subscribe to. | + +#### Returns after decoding + +#### Returns + +| Type | Description | +| ------------------------------------- | -------------------------------- | +| [EventStreamConnection](#eventstream) | A connection to the event stream | + +#### Usage + +```javascript + + +const eventStream = await fcl + .send([ + fcl.subscribeEvents({ + eventTypes: 'A.7e60df042a9c0868.FlowToken.TokensWithdrawn', + }), + ]) + .then(fcl.decode); + +eventStream.on('heartbeat', (heartbeat) => { + console.log(heartbeat); +}); + +eventStream.on('events', (event) => { + console.log(event); +}); + +eventStream.on('error', (error) => { + console.log(error); +}); + +eventStream.on('end', () => { + console.log('Connection closed'); +}); + +eventStream.close(); +``` + +--- + +### `getEvents` (Deprecated) + +Use [`fcl.getEventsAtBlockHeightRange`](#geteventsatblockheightrange) or [`fcl.getEventsAtBlockIds`](#geteventsatblockids). + +--- + +### `getLatestBlock` (Deprecated) + +Use [`fcl.getBlock`](#getblock). + +--- + +### `getBlockById` (Deprecated) + +Use [`fcl.getBlock`](#getblock) and [`fcl.atBlockId`](#atblockid). + +--- + +### `getBlockByHeight` (Deprecated) + +Use [`fcl.getBlock`](#getblock) and [`fcl.atBlockHeight`](#atblockheight). + +--- + +### Utility Builders + +These builders are used to compose interactions with other builders such as scripts and transactions. + +> ⚠️**Recommendation:** Unless you have a specific use case that require usage of these builders, you should be able to achieve most cases with `fcl.query({...options}` or `fcl.mutate({...options})` + +### `arg` + +A utility builder to be used with `fcl.args[...]` to create FCL supported arguments for interactions. + +#### Arguments + +| Name | Type | Description | +| ------- | --------------- | --------------------------------------------------------- | +| `value` | any | Any value that you are looking to pass to other builders. | +| `type` | [FType](#ftype) | A type supported by Flow. | + +#### Returns + +| Type | Description | +| --------------------------------- | ----------------------------------- | +| [ArgumentObject](#argumentobject) | Holds the value and type passed in. | + +#### Usage + +```javascript + + +await fcl + .send([ + fcl.script` + access(all) fun main(a: Int, b: Int): Int { + return a + b + } + `, + fcl.args([ + fcl.arg(5, fcl.t.Int), // a + fcl.arg(4, fcl.t.Int), // b + ]), + ]) + .then(fcl.decode); +``` + +--- + +### `args` + +A utility builder to be used with other builders to pass in arguments with a value and supported type. + +#### Arguments + +| Name | Type | Description | +| ------ | ------------------------------------- | --------------------------------------------------------------------- | +| `args` | [[Argument Objects]](#argumentobject) | An array of arguments that you are looking to pass to other builders. | + +#### Returns + +| Type | Description | +| ----------------------------------- | ------------------------------------------------------------------------------------------------------------------- | +| [Partial Interaction](#interaction) | An interaction that contains the arguments and types passed in. This alone is a partial and incomplete interaction. | + +#### Usage + +```javascript + + +await fcl + .send([ + fcl.script` + access(all) fun main(a: Int, b: Int): Int { + return a + b + } + `, + fcl.args([ + fcl.arg(5, fcl.t.Int), // a + fcl.arg(4, fcl.t.Int), // b + ]), + ]) + .then(fcl.decode); // 9 +``` + +--- + +### Template Builders + +> ⚠️**_Recommended:_** The following functionality is simplified by [`fcl.query({...options}`](#query) or [`fcl.mutate({...options})`](#mutate) and is reccomended to use over the functions below. + +### `script` + +A template builder to use a Cadence script for an interaction. + +📣 Use with `fcl.args(...)` to pass in arguments dynamically. + +#### Arguments + +| Name | Type | Description | +| ------ | ------ | ------------------------------- | +| `CODE` | string | Should be valid Cadence script. | + +#### Returns + +| Type | Description | +| --------------------------- | --------------------------------------------- | +| [Interaction](#interaction) | An interaction containing the code passed in. | + +#### Usage + +```javascript + + +const code = ` + access(all) fun main(): Int { + return 5 + 4 + } +`; +const answer = await fcl.send([fcl.script(code)]).then(fcl.decode); +console.log(answer); // 9 +``` + +--- + +### `transaction` + +A template builder to use a Cadence transaction for an interaction. + +⚠️Must be used with `fcl.payer`, `fcl.proposer`, `fcl.authorizations` to produce a valid interaction before sending to the chain. + +📣 Use with `fcl.args[...]` to pass in arguments dynamically. + +#### Arguments + +| Name | Type | Description | +| ------ | ------ | -------------------------------------- | +| `CODE` | string | Should be valid a Cadence transaction. | + +#### Returns + +| Type | Description | +| ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | +| [Partial Interaction](#interaction) | An partial interaction containing the code passed in. Further builders are required to complete the interaction - see warning. | + +#### Usage + +```javascript + + +const code = ` + access(all) fun main(): Int { + return 5 + 4 + } +`; +const answer = await fcl.send([fcl.script(code)]).then(fcl.decode); +console.log(answer); // 9 +``` + +--- + +## Pre-built Interactions + +These functions are abstracted short hand ways to skip the send and decode steps of sending an interaction to the chain. More pre-built interactions are coming soon. + +### `account` + +A pre-built interaction that returns the details of an account from their public address. + +#### Arguments + +| Name | Type | Description | +| --------- | ------------------- | ---------------------------------------------------------------------------------- | +| `address` | [Address](#address) | Address of the user account with or without a prefix (both formats are supported). | + +#### Returns + +| Type | Description | +| ------------------------------- | ---------------------------------------- | +| [AccountObject](#accountobject) | A JSON representation of a user account. | + +#### Usage + +```javascript + +const account = await fcl.account('0x1d007d755706c469'); +``` + +--- + +### `block` + +A pre-built interaction that returns the latest block (optionally sealed or not), by id, or by height. + +#### Arguments + +| Name | Type | Default | Description | +| -------- | ------- | ------- | ------------------------------------------------------------------------------ | +| `sealed` | boolean | false | If the latest block should be sealed or not. See [block states](#interaction). | +| `id` | string | | ID of block to get. | +| `height` | int | | Height of block to get. | + +#### Returns + +| Type | Description | +| --------------------------- | --------------------------------- | +| [BlockObject](#blockobject) | A JSON representation of a block. | + +#### Usage + +```javascript + +await fcl.block(); // get latest finalized block +await fcl.block({ sealed: true }); // get latest sealed block +await fcl.block({ + id: '0b1bdfa9ddaaf31d53c584f208313557d622d1fedee1586ffc38fb5400979faa', +}); // get block by id +await fcl.block({ height: 56481953 }); // get block by height +``` + +--- + +### `latestBlock` (Deprecated) + +A pre-built interaction that returns the latest block (optionally sealed or not). + +#### Arguments + +| Name | Type | Default | Description | +| ---------- | ------- | ------- | ------------------------------------------------------------------------------ | +| `isSealed` | boolean | false | If the latest block should be sealed or not. See [block states](#interaction). | + +#### Returns + +| Type | Description | +| --------------------------- | --------------------------------- | +| [BlockObject](#blockobject) | A JSON representation of a block. | + +#### Usage + +```javascript + +const latestBlock = await fcl.latestBlock(); +``` + +--- + +## Transaction Status Utility + +### `tx` + +A utility function that lets you set the transaction to get subsequent status updates (via polling) and the finalized result once available. +⚠️The poll rate is set at `2500ms` and will update at that interval until transaction is sealed. + +#### Arguments + +| Name | Type | Description | +| --------------- | ------ | ----------------------- | +| `transactionId` | string | A valid transaction id. | + +#### Returns + +| Name | Type | Description | +| ----------------- | -------- | --------------------------------------------------------------------------------------------------------- | +| `snapshot()` | function | Returns the current state of the transaction. | +| `subscribe(cb)` | function | Calls the `cb` passed in with the new transaction on a status change. | +| `onceFinalized()` | function | Provides the transaction once status `2` is returned. See [Tranasaction Statuses](#transaction-statuses). | +| `onceExecuted()` | function | Provides the transaction once status `3` is returned. See [Tranasaction Statuses](#transaction-statuses). | +| `onceSealed()` | function | Provides the transaction once status `4` is returned. See [Tranasaction Statuses](#transaction-statuses). | + +#### Usage + +```javascript + + +const [txStatus, setTxStatus] = useState(null); +useEffect(() => fcl.tx(txId).subscribe(setTxStatus)); +``` + +--- + +## Event Polling Utility + +### `events` + +A utility function that lets you set the transaction to get subsequent status updates (via polling) and the finalized result once available. +⚠️The poll rate is set at `10000ms` and will update at that interval for getting new events. + +Note: +⚠️`fcl.eventPollRate` value **could** be set to change the polling rate of all events subcribers, check [FCL Configuration](#configuration) for guide. + +#### Arguments + +| Name | Type | Description | +| ------------------- | ----------------------------------------- | ------------------------------------------------ | +| `eventNameOrFilter` | string | [EventFilter](#eventfilter) | The name of the event or an event filter object. | + +#### Returns + +| Name | Type | Description | +| --------------- | -------- | -------------------------------------------- | +| `subscribe(cb)` | function | Calls the `cb` passed in with the new event. | + +#### Usage + +```javascript + +// in some react component +fcl.events(eventName).subscribe((event) => { + console.log(event); +}); +``` + +#### Examples + +- [Flow-view-source example](https://github.com/orodio/flow-view-source/blob/master/src/pages/event.comp.js) + +--- + +## Types, Interfaces, and Definitions + +--- + +### `Builders` + +Builders are modular functions that can be coupled together with `fcl.send([...builders])` to create an [Interaction](#interaction). The builders needed to create an interaction depend on the script or transaction that is being sent. + +--- + +### `Interaction` + +An interaction is an object containing the information to perform an action on chain.This object is populated through builders and converted into the approriate access node API call. See the interaction object [here](https://github.com/onflow/fcl-js/blob/master/packages/sdk/src/interaction/interaction.ts). A 'partial' interaction is an interaction object that does not have sufficient information to the intended on-chain action. Multiple partial interactions (through builders) can be coupled to create a complete interaction. + +--- + +### `CurrentUserObject` + +| Key | Value Type | Default | Description | +| ----------- | ------------------- | --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `addr` | [Address](#address) | `null` | The public address of the current user | +| `cid` | string | `null` | Allows wallets to specify a [content identifier](https://docs.ipfs.io/concepts/content-addressing/) for user metadata. | +| `expiresAt` | number | `null` | Allows wallets to specify a time-frame for a valid session. | +| `f_type` | string | `'USER'` | A type identifier used internally by FCL. | +| `f_vsn` | string | `'1.0.0'` | FCL protocol version. | +| `loggedIn` | boolean | `null` | If the user is logged in. | +| `services` | `[ServiceObject]` | `[]` | A list of trusted services that express ways of interacting with the current user's identity, including means to further discovery, [authentication, authorization](https://gist.github.com/orodio/a74293f65e83145ec8b968294808cf35#you-know-who-the-user-is), or other kinds of interactions. | + +--- + +### `AuthorizationObject` + +This type conforms to the interface required for FCL to authorize transaction on behalf o the current user. + +| Key | Value Type | Description | +| ----------------- | ------------------- | ------------------------------------------------------------------------------------------------- | +| `addr` | [Address](#address) | The address of the authorizer | +| `signingFunction` | function | A function that allows FCL to sign using the authorization details and produce a valid signature. | +| `keyId` | number | The index of the key to use during authorization. (Multiple keys on an account is possible). | +| `sequenceNum` | number | A number that is incremented per transaction using they keyId. | + +--- + +### `SignableObject` + +An object that contains all the information needed for FCL to sign a message with the user's signature. + +| Key | Value Type | Description | +| ----------- | ------------------- | ---------------------------------------------------------------------------------------------------- | +| `addr` | [Address](#address) | The address of the authorizer | +| `keyId` | number | The index of the key to use during authorization. (Multiple keys on an account is possible). | +| `signature` | function | A [SigningFunction](#signing-function) that can produce a valid signature for a user from a message. | + +--- + +### `AccountObject` + +The JSON representation of an account on the Flow blockchain. + +| Key | Value Type | Description | +| ----------- | ----------------------------- | ------------------------------------------------------------------------------------------ | +| `address` | [Address](#address) | The address of the account | +| `balance` | number | The FLOW balance of the account in 10^8. | +| `code` | [Code](#code) | The code of any Cadence contracts stored in the account. | +| `contracts` | Object: [Contract](#contract) | An object with keys as the contract name deployed and the value as the the cadence string. | +| `keys` | [[KeyObject]](#keyobject) | Any contracts deployed to this account. | + +--- + +### `Address` + +| Value Type | Description | +| ----------------- | --------------------------------------------------------------------------------------------------------------------------------- | +| string(formatted) | A valid Flow address should be 16 characters in length.
    A `0x` prefix is optional during inputs.
    eg. `f8d6e0586b0a20c1` | + +--- + +### `ArgumentObject` + +An argument object created by `fcl.arg(value,type)` + +| Key | Value Type | Description | +| ------- | --------------- | ------------------------------------------------- | +| `value` | any | Any value to be used as an argument to a builder. | +| `xform` | [FType](#ftype) | Any of the supported types on Flow. | + +--- + +### `ArgumentFunction` + +An function that takes the `fcl.arg` function and fcl types `t` and returns an array of `fcl.arg(value,type)`. + +`(arg, t) => Array` + +| Parameter Name | Value Type | Description | +| -------------- | ---------------- | ------------------------------------------------------------------------- | +| `arg` | function | A function that returns an [ArgumentObject](#argumentobject) - `fcl.arg`. | +| `t` | [FTypes](#ftype) | An object with acccess to all of the supported types on Flow. | + +**Returns** + +| Value Type | Description | +| ------------ | -------------------- | +| `[fcl.args]` | Array of `fcl.args`. | + +--- + +### `Authorization Function` + +An authorization function must produce the information of the user that is going to sign and a signing function to use the information to produce a signature. + +⚠️This function is always async. + +📣 By default FCL exposes `fcl.authz` that produces the authorization object for the current user (given they are signed in and only on the browser). Replace this with your own function that conforms to this interface to use it wherever an authorization object is needed. + +| Parameter Name | Value Type | Description | +| -------------- | ------------------------------- | ---------------------------------------------- | +| `account` | [AccountObject](#accountobject) | The account of the user that is going to sign. | + +**Returns** + +| Value Type | Description | +| ------------------------------------------------------ | --------------------------------------------------------------------------------------------- | +| `Promise<[AuthorizationObject](#authorizationobject)>` | The object that contains all the information needed by FCL to authorize a user's transaction. | + +#### Usage + +--- + +```javascript +const authorizationFunction = async (account) => { + // authorization function need to return an account + const { address, keys } = account + const tempId = `${address}-${keys[process.env.minterAccountIndex]}`; + const keyId = Number(KEY_ID); + let signingFunction = async signable => { + return { + keyId, + addr: fcl.withPrefix(address), + signature: sign(process.env.FLOW_MINTER_PRIVATE_KEY, signable.message), // signing function, read below + } + } + return { + ...account, + address, + keyId, + tempId, + signingFunction, + } +``` + +- [Detailed explanation](https://github.com/onflow/fcl-js/blob/master/packages/fcl-core/src/wallet-provider-spec/authorization-function.md) + +--- + +### `Signing Function` + +Consumes a payload and produces a signature for a transaction. + +⚠️This function is always async. + +📣 Only write your own signing function if you are writing your own custom authorization function. + +#### Payload + +Note: These values are destructed from the payload object in the first argument. + +| Parameter Name | Value Type | Description | +| -------------- | ---------- | ------------------------------------------------------------------------------------------------------------------------------------ | +| `message` | string | The encoded string which needs to be used to produce the signature. | +| `addr` | string | The encoded string which needs to be used to produce the signature. | +| `keyId` | string | The encoded string which needs to be used to produce the signature. | +| `roles` | string | The encoded string which needs to be used to produce the signature. | +| `voucher` | object | The raw transactions information, can be used to create the message for additional safety and lack of trust in the supplied message. | + +**Returns** + +| Value Type | Description | +| -------------------------------------------- | --------------------------------------------------------------------------------------------- | +| `Promise<[SignableObject](#signableobject)>` | The object that contains all the information needed by FCL to authorize a user's transaction. | + +#### Usage + +```javascript + + + +const ec: EC = new EC('p256'); + +const produceSignature = (privateKey, msg) => { + const key = ec.keyFromPrivate(Buffer.from(privateKey, 'hex')); + const sig = key.sign(this.hashMsg(msg)); + const n = 32; + const r = sig.r.toArrayLike(Buffer, 'be', n); + const s = sig.s.toArrayLike(Buffer, 'be', n); + return Buffer.concat([r, s]).toString('hex'); +}; + +const signingFunction = ({ + message, // The encoded string which needs to be used to produce the signature. + addr, // The address of the Flow Account this signature is to be produced for. + keyId, // The keyId of the key which is to be used to produce the signature. + roles: { + proposer, // A Boolean representing if this signature to be produced for a proposer. + authorizer, // A Boolean representing if this signature to be produced for a authorizer. + payer, // A Boolean representing if this signature to be produced for a payer. + }, + voucher, // The raw transactions information, can be used to create the message for additional safety and lack of trust in the supplied message. +}) => { + return { + addr, // The address of the Flow Account this signature was produced for. + keyId, // The keyId for which key was used to produce the signature. + signature: produceSignature(message), // The hex encoded string representing the signature of the message. + }; +}; +``` + +#### Examples: + +- [Detailed explanation](https://github.com/onflow/fcl-js/blob/master/packages/fcl-core/src/wallet-provider-spec/authorization-function.md) + +--- + +### `TransactionObject` + +| Key | Value Type | Description | +| -------------------- | ------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `args` | object | A list of encoded Cadence values passed into this transaction. These have not been decoded by the JS-SDK. | +| `authorizers` | [\[Address\]](#address) | A list of the accounts that are authorizing this transaction to mutate to their on-chain account state. [See more here](../../../build/basics/transactions.md#signer-roles). | +| `envelopeSignatures` | [\[SignableObject\]](#signableobject) | A list of signatures generated by the payer role. [See more here](../../../build/basics/transactions.md#signing-a-transaction). | +| `gasLimit` | number | The maximum number of computational units that can be used to execute this transaction. [See more here](../../../build/basics/fees.md). | +| `payer` | [Address](#address) | The account that pays the fee for this transaction. [See more here](../../../build/basics/transactions.md#signer-roles). | +| `payloadSignatures` | [\[SignableObject\]](#signableobject) | A list of signatures generated by the proposer and authorizer roles. [See more here](../../../build/basics/transactions.md#signing-a-transaction). | +| `proposalKey` | [\[ProposalKey\]](#proposalkeyobject) | The account key used to propose this transaction | +| `referenceBlockId` | string | A reference to the block used to calculate the expiry of this transaction. | +| `script` | string | The UTF-8 encoded Cadence source code that defines the execution logic for this transaction | + +### `TransactionRolesObject` + +| Key Name | Value Type | Description | +| ---------- | ---------- | -------------------------------------------------------------------------- | +| proposer | boolean | A Boolean representing if this signature to be produced for a proposer. | +| authorizer | boolean | A Boolean representing if this signature to be produced for an authorizer. | +| payer | boolean | A Boolean representing if this signature to be produced for a payer. | + +For more on what each transaction role means, see [singing roles](../../../build/basics/transactions.md#signer-roles). + +### `TransactionStatusObject` + +| Key | Value Type | Description | +| -------------- | ------------------------------------------ | ----------------------------------------------------------------------------------- | +| `blockId` | string | ID of the block that contains the transaction. | +| `events` | [[EventObject]](#event-object) | An array of events that were emitted during the transaction. | +| `status` | [TransactionStatus](#transaction-statuses) | The status of the transaction on the blockchain. | +| `statusString` | [TransactionStatus](#transaction-statuses) | The `status` as as descriptive text (e.g. "FINALIZED"). | +| `errorMessage` | string | An error message if it exists. Default is an empty string `''`. | +| `statusCode` | number | The pass/fail status. 0 indicates the transaction succeeded, 1 indicates it failed. | + +### `EventName` + +| Value Type | Description | +| ----------------- | ----------------------------------------------------------------------------------------------------------------------------------- | +| string(formatted) | A event name in Flow must follow the format `A.{AccountAddress}.{ContractName}.{EventName}`
    eg. `A.ba1132bc08f82fe2.Debug.Log` | + +### `Contract` + +| Value Type | Description | +| ----------------- | ---------------------------------------------------- | +| string(formatted) | A formatted string that is a valid cadence contract. | + +### `KeyObject` + +This is the JSON representation of a key on the Flow blockchain. + +| Key | Value Type | Description | +| ---------------- | ---------- | ---------------------------------------------------------------------------------------- | +| `index` | number | The address of the account | +| `publicKey` | string | The public portion of a public/private key pair | +| `signAlgo` | number | An index referring to one of `ECDSA_P256` or `ECDSA_secp256k1` | +| `hashAlgo` | number | An index referring to one of `SHA2_256` or `SHA3_256` | +| `weight` | number | A number between 1 and 1000 indicating the relative weight to other keys on the account. | +| `sequenceNumber` | number | This number is incremented for every transaction signed using this key. | +| `revoked` | boolean | If this key has been disabled for use. | + +### `ProposalKeyObject` + +ProposalKey is the account key used to propose this transaction. + +A proposal key references a specific key on an account, along with an up-to-date sequence number for that key. This sequence number is used to prevent replay attacks. + +You can find more information about sequence numbers [here](../../../build/basics/transactions.md#sequence-numbers) + +| Key | Value Type | Description | +| ---------------- | ------------------- | ------------------------------------------------------------------------- | +| `address` | [Address](#address) | The address of the account | +| `keyIndex` | number | The index of the account key being referenced | +| `sequenceNumber` | number | The sequence number associated with this account key for this transaction | + +### `BlockObject` + +The JSON representation of a key on the Flow blockchain. + +| Key | Value Type | Description | +| ---------------------- | --------------------------------------------------------- | ---------------------------------------------------------- | +| `id` | string | The id of the block. | +| `parentId` | string | The id of the parent block. | +| `height` | number | The height of the block. | +| `timestamp` | object | Contains time related fields. | +| `collectionGuarantees` | [[CollectionGuaranteeObject](#collectionguaranteeobject)] | Contains the ids of collections included in the block. | +| `blockSeals` | [SealedBlockObject] | The details of which nodes executed and sealed the blocks. | +| `signatures` | Uint8Array([numbers]) | All signatures. | + +### `BlockHeaderObject` + +The subset of the [BlockObject](#blockobject) containing only the header values of a block. + +| Key | Value Type | Description | +| ----------- | ---------- | ----------------------------- | +| `id` | string | The id of the block. | +| `parentId` | string | The id of the parent block. | +| `height` | number | The height of the block. | +| `timestamp` | object | Contains time related fields. | + +### `CollectionGuaranteeObject` + +A collection that has been included in a block. + +| Key | Value Type | Description | +| -------------- | ----------------------------------- | -------------------- | +| `collectionId` | string | The id of the block. | +| `signatures` | [SignatureObject](#SignatureObject) | All signatures. | + +### `CollectionObject` + +A collection is a list of transactions that are contained in the same block. + +| Key | Value Type | Description | +| ---------------- | ---------- | ------------------------------------------------------- | +| `id` | string | The id of the collection. | +| `transactionIds` | [string] | The ids of the transactions included in the collection. | + +### `ResponseObject` + +The format of all responses in FCL returned from `fcl.send(...)`. For full details on the values and descriptions of the keys, view [here](https://github.com/onflow/fcl-js/tree/master/packages/sdk/src/response). + +| Key | +| ------------------- | +| `tag` | +| `transaction` | +| `transactionStatus` | +| `transactionId` | +| `encodedData` | +| `events` | +| `account` | +| `block` | +| `blockHeader` | +| `latestBlock` | +| `collection` | + +### `Event Object` + +| Key | Value Type | Description | +| ------------------ | ----------------------- | ----------------------------------------------------------------------------------------------------- | +| `blockId` | string | ID of the block that contains the event. | +| `blockHeight` | number | Height of the block that contains the event. | +| `blockTimestamp` | string | The timestamp of when the block was sealed in a `DateString` format. eg. `'2021-06-25T13:42:04.227Z'` | +| `type` | [EventName](#eventname) | A string containing the event name. | +| `transactionId` | string | Can be used to query transaction information, eg. via a Flow block explorer. | +| `transactionIndex` | number | Used to prevent replay attacks. | +| `eventIndex` | number | Used to prevent replay attacks. | +| `data` | any | The data emitted from the event. | + +### `Transaction Statuses` + +The status of a transaction will depend on the Flow blockchain network and which phase it is in as it completes and is finalized. + +| Status Code | Description | +| ----------- | --------------------------------------------------------------------------------------------------------------------- | +| `0` | Unknown | +| `1` | Transaction Pending - Awaiting Finalization | +| `2` | Transaction Finalized - Awaiting Execution | +| `3` | Transaction Executed - Awaiting Sealing | +| `4` | Transaction Sealed - Transaction Complete. At this point the transaction result has been committed to the blockchain. | +| `5` | Transaction Expired | + +### `GRPC Statuses` + +The access node GRPC implementation follows the standard GRPC Core status code spec. View [here](https://grpc.github.io/grpc/core/md_doc_statuscodes.html). + +### `FType` + +FCL arguments must specify one of the following support types for each value passed in. + +| Type | Example | +| ------------ | -------------------------------------------------------------------------------------------------------------------- | +| `UInt` | `fcl.arg(1, t.UInt)` | +| `UInt8` | `fcl.arg(8, t.UInt8)` | +| `UInt16` | `fcl.arg(16, t.UInt16)` | +| `UInt32` | `fcl.arg(32, t.UInt32)` | +| `UInt64` | `fcl.arg(64, t.UInt64)` | +| `UInt128` | `fcl.arg(128, t.UInt128)` | +| `UInt256` | `fcl.arg(256, t.UInt256)` | +| `Int` | `fcl.arg(1, t.Int)` | +| `Int8` | `fcl.arg(8, t.Int8)` | +| `Int16` | `fcl.arg(16, t.Int16)` | +| `Int32` | `fcl.arg(32, t.Int32)` | +| `Int64` | `fcl.arg(64, t.Int64)` | +| `Int128` | `fcl.arg(128, t.Int128)` | +| `Int256` | `fcl.arg(256, t.Int256)` | +| `Word8` | `fcl.arg(8, t.Word8)` | +| `Word16` | `fcl.arg(16, t.Word16)` | +| `Word32` | `fcl.arg(32, t.Word32)` | +| `Word64` | `fcl.arg(64, t.Word64)` | +| `UFix64` | `fcl.arg("64.123", t.UFix64)` | +| `Fix64` | `fcl.arg("64.123", t.Fix64)` | +| `String` | `fcl.arg("Flow", t.String)` | +| `Character` | `fcl.arg("c", t.String)` | +| `Bool` | `fcl.arg(true, t.String)` | +| `Address` | `fcl.arg("0xABC123DEF456", t.Address)` | +| `Optional` | `fcl.arg("Flow", t.Optional(t.String))` | +| `Array` | `fcl.args([ fcl.arg(["First", "Second"], t.Array(t.String)) ])` | +| `Dictionary` | `fcl.args([fcl.arg([{key: 1, value: "one"}, {key: 2, value: "two"}], t.Dictionary({key: t.Int, value: t.String}))])` | +| `Path` | `fcl.arg({ domain: "public", identifier: "flowTokenVault" }, t.Path)` | + +--- + +### `EventFilter` + +An object that contains the parameters to filter events, used for event streaming in the [`fcl.events`](#events) function. + +| Name | Value Type | Description | +| ------------------------ | ------------------------- | ----------------------------------------------------------------------------------------------------------------------- | +| `startBlockId` | string | undefined | The block ID to start listening for events. Example: `9dda5f281897389b99f103a1c6b180eec9dac870de846449a302103ce38453f3` | +| `startHeight` | number | undefined | The block height to start listening for events. Example: `123` | +| `eventTypes` | string[] | undefined | The event types to listen for. Example: `A.7e60df042a9c0868.FlowToken.TokensWithdrawn` | +| `addresses` | string[] | undefined | The addresses to listen for. Example: `0x7e60df042a9c0868` | +| `contracts` | string[] | undefined | The contracts to listen for. Example: `0x7e60df042a9c0868` | +| `opts.heartbeatInterval` | number | undefined | The interval in milliseconds to send a heartbeat to the Access Node. Example: `10000` | + +### `StreamConnection` + +A stream connection is an object for subscribing to generic data from any WebSocket data stream. This is the base type for all stream connections. Two channels, `close` and `error`, are always available, as they are used to signal the end of the stream and any errors that occur. + +```ts +interface StreamConnection { + // Subscribe to a channel + on( + channel: C, + listener: (data: ChannelMap[C]) => void, + ): this; + on(event: 'close', listener: () => void): this; + on(event: 'error', listener: (err: any) => void): this; + + // Unsubscribe from a channel + off( + event: C, + listener: (data: ChannelMap[C]) => void, + ): this; + off(event: 'close', listener: () => void): this; + off(event: 'error', listener: (err: any) => void): this; + + // Close the connection + close(): void; +} +``` + +#### Usage + +```ts + + +const stream: StreamConnection = ... + +stream.on("close", () => { + // Handle close +}) + +stream.on("error", (err) => { + // Handle error +}) + +stream.close() +``` + +### `EventStream` + +An event stream is a stream connection that emits events and block heartbeats. Based on the connection parameters, heartbeats will be emitted at least as often as some fixed block height interval. It is a specific variant of a [StreamConnection](#streamconnection). + +```ts +type EventStream = StreamConnection<{ + events: Event[]; + heartbeat: BlockHeartbeat; +}>; +``` + +#### Usage + +```ts + + +const stream: EventStream = ... + +stream.on("events", (events) => { + // Handle events +}) + +stream.on("heartbeat", (heartbeat) => { + // Handle heartbeat +}) + +// Close the stream +stream.close() +``` + +### `BlockHeartbeat` + +```ts +export interface BlockHeartbeat { + blockId: string; + blockHeight: number; + timestamp: string; +} +``` + +#### Usage + +```ts + + +const heartbeat: BlockHeartbeat = ... +``` + +### SignatureObject + +Signature objects are used to represent a signature for a particular message as well as the account and keyId which signed for this message. + +| Key | Value Type | Description | +| ----------- | ------------------- | -------------------------------------------------------------------------------------------- | +| `addr` | [Address](#address) | the address of the account which this signature has been generated for | +| `keyId` | number | The index of the key to use during authorization. (Multiple keys on an account is possible). | +| `signature` | string | a hexidecimal-encoded string representation of the generated signature | \ No newline at end of file diff --git a/static/markdown/tools/clients/fcl-js/authentication.md b/static/markdown/tools/clients/fcl-js/authentication.md new file mode 100644 index 0000000000..2525b1b141 --- /dev/null +++ b/static/markdown/tools/clients/fcl-js/authentication.md @@ -0,0 +1,50 @@ +# Authentication + +Authentication in FCL is closely tied to the concept of `currentUser`. In fact, `fcl.authenticate` and `fcl.unauthenticate` are simply aliases for `fcl.currentUser.authenticate()` and `fcl.currentUser.unauthenticate()`, respectively. So, let’s take a closer look at `currentUser`. + +As an onchain app developer using FCL, the primary authentication functionalities revolve around: + +- Determining the `currentUser` and whether they are logged in. +- Logging a user in. +- Logging a user out. + +Due to the way FCL works, logging in and signing up are essentially the same process. + +# Retrieving Information About the Current User + +FCL provides two ways to get information about the current user: + +1. **A promise-based method** that returns a snapshot of the user’s data. +2. **A subscription-based method** that triggers a callback function with the latest user information whenever it changes. + +### Snapshot of the Current User + +```javascript + + +const currentUser = await fcl.currentUser.snapshot() +console.log("The Current User:", currentUser) +``` + +### Subscribe to the Current User + +```javascript + + +// Returns an unsubscribe function +const unsubscribe = fcl.currentUser.subscribe(currentUser => { + console.log("The Current User:", currentUser) +}) +``` + +# Authenticating and Unauthenticating + +The TL;DR: Call `fcl.authenticate()` to log in and `fcl.unauthenticate()` to log out. + +On Flow mainnet, no additional configuration is needed—your app’s users will go through the authentication process and be able to use any FCL-compatible wallet provider. + +During development, you’ll likely want to configure your app to use [`@onflow/dev-wallet`](https://github.com/onflow/fcl-dev-wallet). The [Quick Start](../../../build/getting-started/fcl-quickstart.md) guide will walk you through setting it up. + +We also recommend using the [FCL Discovery Service](discovery.md) to help users discover and connect to FCL-compatible wallets. + +Whether you're new to building onchain, or an established veteran, we’re here to help. If you run into any issues, reach out to us on [Discord](https://discord.gg/flow) — we’re happy to assist! \ No newline at end of file diff --git a/static/markdown/tools/clients/fcl-js/configure-fcl.md b/static/markdown/tools/clients/fcl-js/configure-fcl.md new file mode 100644 index 0000000000..558c5a5e2f --- /dev/null +++ b/static/markdown/tools/clients/fcl-js/configure-fcl.md @@ -0,0 +1,149 @@ +--- +title: How to Configure FCL +--- + +## Configuration + +FCL provides a mechanism to configure various aspects of its behavior. The key principle is that when switching between different Flow Blockchain environments (e.g., Local Emulator → Testnet → Mainnet), the only required change should be your FCL configuration. + +## Setting Configuration Values + +Values only need to be set once. We recommend doing this once and as early in the life cycle as possible. +To set a configuration value, the `put` method on the `config` instance needs to be called, the `put` method returns the `config` instance so they can be chained. + +```javascript + + +fcl + .config() // returns the config instance + .put('foo', 'bar') // configures "foo" to be "bar" + .put('baz', 'buz'); // configures "baz" to be "buz" +``` + +## Getting Configuration Values + +The `config` instance has an asynchronous `get` method. You can also pass it a fallback value incase the configuration state does not include what you are wanting. + +```javascript + + +fcl.config().put('foo', 'bar').put('woot', 5).put('rawr', 7); + +const FALLBACK = 1; + +async function addStuff() { + var woot = await fcl.config().get('woot', FALLBACK); // will be 5 -- set in the config before + var rawr = await fcl.config().get('rawr', FALLBACK); // will be 7 -- set in the config before + var hmmm = await fcl.config().get('hmmm', FALLBACK); // will be 1 -- uses fallback because this isnt in the config + + return woot + rawr + hmmm; +} + +addStuff().then((d) => console.log(d)); // 13 (5 + 7 + 1) +``` + +## Common Configuration Keys + +- `accessNode.api` -- Api URL for the Flow Blockchain Access Node you want to be communicating with. +- `app.detail.title` - **(INTRODUCED `@onflow/fcl@0.0.68`)** Your applications title, can be requested by wallets and other services. Used by WalletConnect plugin & Wallet Discovery service. +- `app.detail.icon` - **(INTRODUCED `@onflow/fcl@0.0.68`)** Url for your applications icon, can be requested by wallets and other services. Used by WalletConnect plugin & Wallet Discovery service. +- `app.detail.description` - **(INTRODUCED `@onflow/fcl@1.11.0`)** Your applications description, can be requested by wallets and other services. Used by WalletConnect plugin & Wallet Discovery service. +- `app.detail.url` - **(INTRODUCED `@onflow/fcl@1.11.0`)** Your applications url, can be requested by wallets and other services. Used by WalletConnect plugin & Wallet Discovery service. +- `challenge.handshake` -- **(DEPRECATED `@onflow/fcl@0.0.68`)** Points FCL at the Wallet or Wallet Discovery mechanism. +- `discovery.wallet` -- **(INTRODUCED `@onflow/fcl@0.0.68`)** Points FCL at the Wallet or Wallet Discovery mechanism. +- `discovery.wallet.method` -- Describes which service strategy a wallet should use: `IFRAME/RPC`, `POP/RPC`, `TAB/RPC`, `HTTP/POST`, `EXT/RPC` +- `env` -- **(DEPRECATED `@onflow/fcl@1.0.0`)** Used in conjunction with stored interactions. Possible values: `local`, `testnet`, `mainnet` +- `fcl.limit` -- Specifies fallback compute limit if not provided in transaction. Provided as integer. +- `flow.network` (recommended) -- **(INTRODUCED `@onflow/fcl@1.0.0`)** Used in conjunction with stored interactions and provides FCLCryptoContract address for `testnet` and `mainnet`. Possible values: `local`, `testnet`, `mainnet`. +- `service.OpenID.scopes` - **(INTRODUCED `@onflow/fcl@0.0.68`)** Open ID Connect claims for Wallets and OpenID services. +- `walletconnect.projectId` -- **(INTRODUCED `@onflow/fcl@1.11.0`)** Your app's WalletConnect project ID. See [WalletConnect Cloud](https://cloud.walletconnect.com/sign-in) to obtain a project ID for your application. +- `walletconnect.disableNotifications` -- **(INTRODUCED `@onflow/fcl@1.13.0`)** Flag to disable pending WalletConnect request notifications within the application's UI. Default is `false`. + +## Using Contracts in Scripts and Transactions + +### Address Replacement + +Configuration keys that start with `0x` will be replaced in FCL scripts and transactions, this allows you to write your script or transaction Cadence code once and not have to change it when you point your application at a difference instance of the Flow Blockchain. + +```javascript + + +fcl.config().put('0xFungibleToken', '0xf233dcee88fe0abe'); + +async function myScript() { + return fcl + .send([ + fcl.script` + import FungibleToken from 0xFungibleToken // will be replaced with 0xf233dcee88fe0abe because of the configuration + + access(all) fun main() { /* Rest of the script goes here */ } + `, + ]) + .then(fcl.decode); +} + +async function myTransaction() { + return fcl + .send([ + fcl.transaction` + import FungibleToken from 0xFungibleToken // will be replaced with 0xf233dcee88fe0abe because of the configuration + + transaction { /* Rest of the transaction goes here */ } + `, + ]) + .then(fcl.decode); +} +``` + +#### Example + +```javascript + + +fcl + .config() + .put('flow.network', 'testnet') + .put('accessNode.api', 'https://rest-testnet.onflow.org') + .put('discovery.wallet', 'https://fcl-discovery.onflow.org/testnet/authn') + .put('walletconnect.projectId', 'YOUR_PROJECT_ID') + .put('app.detail.title', 'Test Harness') + .put('app.detail.icon', 'https://i.imgur.com/r23Zhvu.png') + .put('app.detail.description', 'A test harness for FCL') + .put('app.detail.url', 'https://myapp.com') + .put('0xFlowToken', '0x7e60df042a9c0868'); +``` + +### Using `flow.json` + +A simpler way to import contracts in scripts and transactions is to use the `config.load` method to ingest your contracts from your `flow.json` file. This keeps the import syntax unified across tools and lets FCL figure out which address to use for what network based on the network provided in config. To use `config.load` you must first import your `flow.json` file and then pass it to `config.load` as a parameter. + +```javascript + + + +config({ + 'flow.network': 'testnet', + 'accessNode.api': 'https://rest-testnet.onflow.org', + 'discovery.wallet': `https://fcl-discovery.onflow.org/testnet/authn`, +}).load({ flowJSON }); +``` + +Let's say your `flow.json` file looks like this: + +``` +{ + "contracts": { + "HelloWorld": "cadence/contracts/HelloWorld.cdc" + } +} +``` + +Then in your scripts and transactions, all you have to do is: + +``` +import "HelloWorld" +``` + +FCL will automatically replace the contract name with the address for the network you are using. + +> Note: never put private keys in your `flow.json`. You should use the [key/location syntax](../../flow-cli/flow.json/security.md) to separate your keys into a separate git ignored file. \ No newline at end of file diff --git a/static/markdown/tools/clients/fcl-js/cross-vm/ethereum-provider.md b/static/markdown/tools/clients/fcl-js/cross-vm/ethereum-provider.md new file mode 100644 index 0000000000..ec0a2763a6 --- /dev/null +++ b/static/markdown/tools/clients/fcl-js/cross-vm/ethereum-provider.md @@ -0,0 +1,132 @@ +--- +sidebar_position: 1 +title: FCL Ethereum Provider +description: An EIP-1193 provider that uses an FCL-authenticated Cadence Owned Account (COA) under the hood. +--- + +:::info + +This package is currently in alpha and is subject to change. + +::: + +# FCL Ethereum Provider + +Exposes a client-side [EIP-1193](https://eips.ethereum.org/EIPS/eip-1193) compatible Ethereum provider that uses an FCL-authenticated Cadence Owned Account (COA) under the hood. +If a wallet does not natively provide EVM capabilities, this provider emulates Ethereum JSON-RPC by delegating to FCL for signing and COA interactions. + +## Installation + +```bash +npm install @onflow/fcl-ethereum-provider +``` + +## Usage + +```ts + + + +// Configure FCL (pointing to whichever Flow network you require) +fcl.config({ + "accessNode.api": "https://rest-testnet.onflow.org", + "discovery.wallet": "https://fcl-discovery.onflow.org/testnet/authn", +}) + +// Create the EIP-1193 provider +const provider = createEthereumProvider({ + // Optional configuration: + // service?: Service // Custom FCL service config + // gateway?: Eip1193Provider | string // EVM Gateway provider or URL +}) + +// Example: request EVM-style accounts (COA addresses) +const accounts = await provider.request({ method: "eth_requestAccounts" }) +console.log("EVM Accounts:", accounts) + +// Use the same session to sign a message +const signature = await provider.request({ + method: "personal_sign", + params: ["0x68656c6c6f20776f726c64", accounts[0]], // hex-encoded "hello world" +}) +console.log("Signature:", signature) + +// Or send transactions +const txHash = await provider.request({ + method: "eth_sendTransaction", + params: [ + { + from: accounts[0], + to: "0x1234...", + data: "0xabcd1234...", + value: "0x0", + }, + ], +}) +console.log("Transaction Hash:", txHash) +``` + +## API + +### `createEthereumProvider(config?: CreateEthereumProviderConfig): Eip1193Provider` + +- **Parameters** + - `config.service?: Service` + An [FCL “Service” object][fcl-service-docs] for custom FCL authentication flows. If omitted, the default FCL discovery service is used. + - `config.gateway?: Eip1193Provider | string` + An EIP-1193 provider (or a string URL) pointing to a Flow EVM gateway. Defaults to the public Flow EVM gateway if omitted. + +- **Returns**: An [EIP-1193](https://eips.ethereum.org/EIPS/eip-1193) provider instance you can pass into EVM tooling or interact with directly in your app. + +## Supported JSON-RPC Methods + +Below are the main request methods handled within the FCL Ethereum provider: + +1. **`eth_requestAccounts` / `eth_accounts`** + - **Behavior**: + - Invokes the FCL authentication flow (if not already authenticated) + - Returns the Cadence-Owned Account (COA) address + - Stores the COA at `/storage/evm` (creates if missing) + +2. **`eth_sendTransaction`** + - **Behavior**: + - Wraps the transaction in a Cadence transaction that invokes `coa.call(...)` in the Flow EVM + - Uses the user’s authenticated COA for signing + - Returns the resulting EVM transaction hash + +3. **`personal_sign`** + - **Behavior**: + - Requests a user signature via FCL’s `signUserMessage` or equivalent mechanism + - Returns an RLP-encoded [COA ownership proof](https://github.com/onflow/flow-go/blob/master/fvm/evm/types/proof.go#L139) in place of a raw secp256k1 signature + +4. **`eth_signTypedData_v4`** + - **Behavior**: + - Requests user signature for typed data (hash) via FCL + - Returns an RLP-encoded [COA ownership proof](https://github.com/onflow/flow-go/blob/master/fvm/evm/types/proof.go#L139) + +5. **`eth_chainId`** + - **Behavior**: + - Returns the numeric Flow EVM chain ID (e.g., `0x747` for Flow EVM Mainnet) + +6. **`wallet_switchEthereumChain`** + - **Behavior**: + - Allows dApps to request switching to a different Flow EVM chain (e.g. testnet to mainnet). + - Under the hood, this can trigger reconfiguration of FCL for a different Flow access node and Flow EVM gateway if recognized. + - If the requested chain ID is not recognized, the call will throw an error (matching EIP-1193 standard error codes). + +7. **`wallet_addEthereumChain`** + - **Behavior**: + - Allows a dApp to request adding a Flow EVM chain config. + - If the chain is recognized by the provider or is one the provider can handle, it will register it. Otherwise, it may reject with an EIP-1193 error. + - Since Flow EVM is typically a single chain per environment, usage is limited. However, in principle, custom EVM networks or local dev can be added if your provider/gateway supports them. + +### Fallback Behavior + +Any unknown or unsupported request methods will be proxied to the `gateway` (if you provided a standard JSON-RPC URL or EIP-1193 provider). If the gateway does not handle them, an error will be returned. + +## Provider Events + +- **`connect`**: Emitted once the user successfully authenticates via FCL, indicating that the provider is ready. +- **`disconnect`**: Emitted if the FCL session ends or user explicitly logs out, severing the session. +- **`accountsChanged`**: Emitted when the current user changes (e.g. re-authentication, or switching user in the wallet). +- **`chainChanged`**: Emitted when the user switches to a different Flow EVM chain (e.g. testnet to mainnet). \ No newline at end of file diff --git a/static/markdown/tools/clients/fcl-js/cross-vm/index.md b/static/markdown/tools/clients/fcl-js/cross-vm/index.md new file mode 100644 index 0000000000..810ab83a49 --- /dev/null +++ b/static/markdown/tools/clients/fcl-js/cross-vm/index.md @@ -0,0 +1,38 @@ +--- +title: Cross VM Packages +description: FCL packages for cross-VM (Flow + EVM) applications. +--- + +# FCL Cross-VM Packages + +These packages enable you to leverage Flow’s Cadence-Owned Account (COA) within Ethereum tooling (e.g., Wagmi, RainbowKit). They provide a unified approach for cross-VM apps on Flow and EVM, letting you perform EVM-like operations using Cadence accounts. + +For background and motivation, see the [FCL Ethereum Provider for Cross-VM Apps FLIP #316](https://github.com/onflow/flips/blob/c0fe9b71a9afb85fe70a69cf7c0870b5d327e679/application/20241223-fcl-ethereum-provider.md). + +| Package | Purpose | +|-----------------------------------------------|-------------------------------------------------------------------------------------------------| +| [@onflow/fcl-ethereum-provider](#onflowfcl-ethereum-provider) | Provides an EIP-1193-compliant Ethereum provider backed by an FCL-authenticated COA. | +| [@onflow/fcl-wagmi-adapter](#onflowfcl-wagmi-adapter) | Integrates Flow-based COAs with Wagmi, exposing them as Ethereum accounts in your dApp. | +| [@onflow/fcl-rainbowkit-adapter](#onflowfcl-rainbowkit-adapter)| Enables a Flow-based wallet option in your RainbowKit wallet selection modal. | + +## `@onflow/fcl-ethereum-provider` + +- **Description**: A drop-in EIP-1193 provider that authenticates users via [FCL](https://developers.flow.com/) and lets them sign transactions/messages with their COA. +- **Use Cases**: + - Integrate Flow EVM with any generic EVM library or framework. + - Direct control over JSON-RPC calls (e.g., `provider.request({ method: 'eth_sendTransaction' })`). +- **Link to Docs**: [Read the @onflow/fcl-ethereum-provider Reference »](ethereum-provider.mdx) + +## `@onflow/fcl-wagmi-adapter` + +- **Description**: A Wagmi connector that uses `@onflow/fcl-ethereum-provider` under the hood so you can sign in with your COA through standard Wagmi flows. +- **Use Cases**: + - Add Flow-based COAs to an existing Wagmi-powered dApp as if they were Ethereum wallets. +- **Link to Docs**: [Read the @onflow/fcl-wagmi-adapter Reference »](wagmi-adapter.mdx) + +## `@onflow/fcl-rainbowkit-adapter` + +- **Description**: A RainbowKit adapter that surfaces a Flow-based wallet in the wallet selection modal, making it easy to sign transactions via COAs in a RainbowKit environment. +- **Use Cases**: + - Offer Flow-based wallets (e.g., Flow Wallet) alongside popular Ethereum wallets in RainbowKit. +- **Link to Docs**: [Read the @onflow/fcl-rainbowkit-adapter Reference »](rainbowkit-adapter.mdx) \ No newline at end of file diff --git a/static/markdown/tools/clients/fcl-js/cross-vm/rainbowkit-adapter.md b/static/markdown/tools/clients/fcl-js/cross-vm/rainbowkit-adapter.md new file mode 100644 index 0000000000..b563055670 --- /dev/null +++ b/static/markdown/tools/clients/fcl-js/cross-vm/rainbowkit-adapter.md @@ -0,0 +1,79 @@ +--- +sidebar_position: 1 +title: FCL Rainbowkit Adapter +description: FCL adapter for using Flow wallets in RainbowKit applications. +--- + +:::info + +This package is currently in alpha and is subject to change. + +::: + +# FCL RainbowKit Adapter + +Offers a **RainbowKit**-compatible wallet definition that uses Flow’s COA via FCL. Once installed, RainbowKit can display a “Flow Wallet” (or other FCL-enabled wallets) in its wallet selection modal. + +## Installation + +```bash +npm install @onflow/fcl-rainbowkit-adapter +``` + +## Usage + +Below is a typical usage example that shows how to set up a **RainbowKit** config for the Flow testnet, using this adapter. (From your provided sample.) + +```ts + + + + + + +// Configure FCL (Flow testnet in this example) +fcl.config({ + "accessNode.api": "https://rest-testnet.onflow.org", + "discovery.wallet": "https://fcl-discovery.onflow.org/testnet/authn", + "walletconnect.projectId": "9b70cfa398b2355a5eb9b1cf99f4a981", // example WC projectId +}) + +// Create a list of connectors from your wallets +const connectors = connectorsForWallets([ + { + groupName: "Recommended", + wallets: [ + flowWallet(), + ], + }, +], { + appName: 'RainbowKit demo', + projectId: '9b70cfa398b2355a5eb9b1cf99f4a981', +}) + +// Wagmi config +export const config = createConfig({ + chains: [flowTestnet], + connectors, + ssr: true, + transports: { + [flowTestnet.id]: http(), + } +}); +``` + +## API + +### `flowWallet(options?: FlowWalletOptions): RainbowKitWallet` + +- Returns a RainbowKit-compatible wallet definition that integrates **@onflow/fcl-ethereum-provider**. +- **Parameters** + - `options?: FlowWalletOptions` – optional configuration, such as names/icons or custom gateway endpoints. +- **Returns**: A `RainbowKitWallet` object to be included in `connectorsForWallets`. + +### `createFclConnector(config?: CreateFclConnectorOptions): Connector` + +- A lower-level helper to build your own FCL-based EIP-1193 connectors for RainbowKit if you don’t want the preconfigured `flowWallet`. +- **Parameters** + - `config?: CreateFclConnectorOptions` – typical Wagmi + FCL config object (i.e., chain ID, network URL, FCL services, etc.). +- **Returns**: A valid Wagmi `Connector` for EVM interactions via FCL. \ No newline at end of file diff --git a/static/markdown/tools/clients/fcl-js/cross-vm/wagmi-adapter.md b/static/markdown/tools/clients/fcl-js/cross-vm/wagmi-adapter.md new file mode 100644 index 0000000000..3b2d86af7d --- /dev/null +++ b/static/markdown/tools/clients/fcl-js/cross-vm/wagmi-adapter.md @@ -0,0 +1,71 @@ +--- +sidebar_position: 1 +title: FCL Wagmi Adapter +description: FCL adapter for using Cadence-Owned Accounts (COAs) in Wagmi applications. +--- + +:::info + +This package is currently in alpha and is subject to change. + +::: + +# FCL Wagmi Adapter + +Provides a **Wagmi** connector that uses **@onflow/fcl-ethereum-provider** under the hood, allowing you to integrate Flow-based Cadence-Owned Accounts (COAs) seamlessly into Wagmi applications. + +## Installation + +```bash +npm install @onflow/fcl-wagmi-adapter +``` + +## Usage + +**Basic Example**: + +```ts + + + + + + +// Configure FCL for Flow +fcl.config({ + "accessNode.api": "https://rest-testnet.onflow.org", + "discovery.wallet": "https://fcl-discovery.onflow.org/testnet/authn", +}) + +// Set up Wagmi for Flow Testnet +const { chains, provider } = configureChains( + [flowTestnet], + [publicProvider()] +) + +// Create a connector that uses FCL under the hood +const fclConnector = fclWagmiConnector({ + // optional: you can pass any config your provider or FCL needs +}) + +// Create the Wagmi client +const wagmiClient = createClient({ + autoConnect: true, + connectors: [fclConnector], + provider, +}) + +// The rest of your dApp logic... +``` + +## API + +### `fclWagmiConnector(options?: FclWagmiConnectorOptions): Connector` + +- **Parameters** + - `options?: object` – any additional configuration for the underlying FCL provider (gateway URL, custom FCL service, etc.) +- **Returns**: A Wagmi `Connector` object that can be used in `createClient` or `getDefaultConfig`. + +**Notes**: +- This connector essentially wraps `@onflow/fcl-ethereum-provider` as an EIP-1193 provider to talk to Flow EVM via Wagmi. +- The user’s authenticated COA is exposed as the “account” in Wagmi context. \ No newline at end of file diff --git a/static/markdown/tools/clients/fcl-js/discovery.md b/static/markdown/tools/clients/fcl-js/discovery.md new file mode 100644 index 0000000000..1a8951df29 --- /dev/null +++ b/static/markdown/tools/clients/fcl-js/discovery.md @@ -0,0 +1,203 @@ +--- +title: Wallet Discovery +--- + +## Wallet Discovery + +Knowing all the wallets available to users on a blockchain can be challenging. FCL's Discovery mechanism relieves much of the burden of integrating with Flow compatible wallets and let's developers focus on building their dapp and providing as many options as possible to their users. + +There are two ways an app can use Discovery: + +1. The **UI version** which can be configured for display via iFrame, Popup, or Tab. +2. The **API version** which allows you to access authentication services directly in your code via `fcl.discovery.authn` method which we'll describe below. + +## UI Version + +When authenticating via FCL using Discovery UI, a user is shown a list of services they can use to login. + +![FCL Default Discovery UI](./images/discovery.png) + +This method is the simplest way to integrate Discovery and its wallets and services into your app. All you have to do is configure `discovery.wallet` with the host endpoint for testnet or mainnet. + +> **Note**: Opt-in wallets, like Ledger and Dapper Wallet, require you to explicitly state you'd like to use them. For more information on including opt-in wallets, [see these docs](./api.md#more-configuration). +> +> A [Dapper Wallet](https://meetdapper.com/developers) developer account is required. To enable Dapper Wallet inside FCL, you need to [follow this guide](https://docs.meetdapper.com/quickstart). + +```javascript + + +config({ + 'accessNode.api': 'https://rest-testnet.onflow.org', + 'discovery.wallet': 'https://fcl-discovery.onflow.org/testnet/authn', +}); +``` + +Any time you call `fcl.authenticate` the user will be presented with that screen. + +To change the default view from iFrame to popup or tab set `discovery.wallet.method` to `POP/RPC` (opens as a popup) or `TAB/RPC` (opens in a new tab). More info about service methods can be [found here](https://github.com/onflow/fcl-js/blob/9bce741d3b32fde18b07084b62ea15f9bbdb85bc/packages/fcl/src/wallet-provider-spec/draft-v3.md). + +### Branding Discovery UI + +Starting in version 0.0.79-alpha.4, dapps now have the ability to display app a title and app icon in the Discovery UI by setting a few values in their FCL app config. This branding provides users with messaging that has clear intent before authenticating to add a layer of trust. + +All you have to do is set `app.detail.icon` and `app.detail.title` like this: + +```javascript + + +config({ + 'app.detail.icon': 'https://placekitten.com/g/200/200', + 'app.detail.title': 'Kitten Dapp', +}); +``` + +**Note:** If these configuration options aren't set, Dapps using the Discovery API will still display a default icon and "Unknown App" as the title when attempting to authorize a user who is not logged in. It is highly recommended to set these values accurately before going live. + +## API Version + +If you want more control over your authentication UI, the Discovery API is also simple to use as it exposes Discovery directly in your code via `fcl`. + +Setup still requires configuration of the Discovery endpoint, but when using the API it is set via `discovery.authn.endpoint` as shown below. + +```javascript + + +config({ + 'accessNode.api': 'https://rest-testnet.onflow.org', + 'discovery.authn.endpoint': + 'https://fcl-discovery.onflow.org/api/testnet/authn', +}); +``` + +You can access services in your Dapp from `fcl.discovery`: + +```javascript + + +fcl.discovery.authn.subscribe(callback); + +// OR + +fcl.discovery.authn.snapshot(); +``` + +In order to authenticate with a service (for example, when a user click's "login"), pass the selected service to the `fcl.authenticate` method described here [in the API reference](./api.md#authenticate): + +```jsx +fcl.authenticate({ service }); +``` + +A simple React component may end up looking like this: + +```jsx +import './config'; + + + +function Component() { + const [services, setServices] = useState([]); + useEffect( + () => fcl.discovery.authn.subscribe((res) => setServices(res.results)), + [], + ); + + return ( +
    + {services.map((service) => ( + + ))} +
    + ); +} +``` + +Helpful fields for your UI can be found in the `provider` object inside of the service. Fields include the following: + +```json +{ + ..., + "provider": { + "address": "0xf086a545ce3c552d", + "name": "Blocto", + "icon": "/images/blocto.png", + "description": "Your entrance to the blockchain world.", + "color": "#afd8f7", + "supportEmail": "support@blocto.app", + "authn_endpoint": "https://flow-wallet-testnet.blocto.app/authn", + "website": "https://blocto.portto.io" + } +} +``` + +## Network Configuration + +### Discovery UI URLs + +| Environment | Example | +| ----------- | ------------------------------------------------ | +| Mainnet | `https://fcl-discovery.onflow.org/authn` | +| Testnet | `https://fcl-discovery.onflow.org/testnet/authn` | +| Local | `https://fcl-discovery.onflow.org/local/authn` | + +### Discovery API Endpoints + +| Environment | Example | +| ----------- | ---------------------------------------------------- | +| Mainnet | `https://fcl-discovery.onflow.org/api/authn` | +| Testnet | `https://fcl-discovery.onflow.org/api/testnet/authn` | +| Local | `https://fcl-discovery.onflow.org/api/local/authn` | + +> Note: Local will return [Dev Wallet](https://github.com/onflow/fcl-dev-wallet) on emulator for developing locally with the default port of 8701. If you'd like to override the default port add ?port=0000 with the port being whatever you'd like to override it to. + +## Other Configuration + +> Note: Configuration works across both UI and API versions of Discovery. + +### Include Opt-In Wallets + +**Starting in FCL v0.0.78-alpha.10** + +Opt-in wallets are those that don't have support for authentication, authorization, and user signature services. Or, support only a limited set of transactions. + +To include opt-in wallets from FCL: + +``` + + +fcl.config({ + "discovery.wallet": "https://fcl-discovery.onflow.org/testnet/authn", + "discovery.authn.endpoint": "https://fcl-discovery.onflow.org/api/testnet/authn", + "discovery.authn.include": ["0x123"] // Service account address +}) +``` + +**Opt-In Wallet Addresses on Testnet and Mainnet** + +| Service | Testnet | Mainnet | +| --------------- | ------------------ | ------------------ | +| `Dapper Wallet` | 0x82ec283f88a62e65 | 0xead892083b3e2c6c | +| `Ledger` | 0x9d2e44203cb13051 | 0xe5cd26afebe62781 | + +To learn more about other possible configurations, check out the following links: + +- [Discovery API Docs](./api.md#discovery-1) +- [Discovery Github Repo](https://github.com/onflow/fcl-discovery) + +### Exclude Wallets + +To exclude wallets from FCL Discovery, you can use the `discovery.authn.exclude` configuration option. This allows you to specify a list of service account addresses that you want to hide from the Discovery UI or API. + +```javascript + +fcl.config({ + 'discovery.wallet': 'https://fcl-discovery.onflow.org/testnet/authn', + 'discovery.authn.endpoint': + 'https://fcl-discovery.onflow.org/api/testnet/authn', + 'discovery.authn.exclude': ['0x123', '0x456'], // Service account addresses to exclude +}); +``` \ No newline at end of file diff --git a/static/markdown/tools/clients/fcl-js/index.md b/static/markdown/tools/clients/fcl-js/index.md new file mode 100644 index 0000000000..f291bc4485 --- /dev/null +++ b/static/markdown/tools/clients/fcl-js/index.md @@ -0,0 +1,194 @@ +--- +sidebar_position: 3 +--- + +# Flow Client Library (FCL) + +## 🌟 What is FCL? + +The **Flow Client Library (FCL) JS** is a package designed to facilitate interactions between dapps, wallets, and the Flow blockchain. It provides a standardized way for applications to connect with users and their wallets, **eliminating the need for custom integrations**. + +### 🔑 Key Features: +- 🔌 **Universal Wallet Support** – Works seamlessly with all FCL-compatible wallets, making authentication simple. +- 🔐 **Secure Authentication** – Standardized authentication flow ensures a smooth user experience. +- ⚡ **Blockchain Interactions** – Enables querying, mutating, and interacting with smart contracts on Flow. +- 🛠️ **Full-Featured Utilities** – Offers built-in functions to streamline blockchain development. +- 🌍 **Flexible Environment** – Can run in both browser and server environments, though wallet interactions are browser-only. + +FCL was created to make building Flow-connected applications **easy, secure, and scalable** by defining **standardized communication patterns** between wallets, applications, and users. + +For iOS, we also offer [FCL Swift](https://github.com/Outblock/fcl-swift). + +--- +## Getting Started + +### Requirements +- Node version `v12.0.0 or higher`. + +### Installation + +To use the FCL JS in your application, install using **yarn** or **npm** + +```shell +npm i -S @onflow/fcl +``` + +```shell +yarn add @onflow/fcl +``` +#### Importing + +**ES6** +```js + +``` +**Node.js** +```js +const fcl = require("@onflow/fcl"); +``` +--- +## FCL for Dapps +#### Wallet Interactions + +- *Wallet Discovery* and *Sign-up/Login*: Onboard users with ease. Never worry about supporting multiple wallets. + Authenticate users with any [FCL compatible wallet](#current-wallet-providers). +```js +// in the browser + + +fcl.config({ + "discovery.wallet": "https://fcl-discovery.onflow.org/testnet/authn", // Endpoint set to Testnet +}) + +fcl.authenticate() +``` +![FCL Default Discovery UI](images/discovery.png) + +> **Note**: A [Dapper Wallet](https://meetdapper.com/developers) developer account is required. To enable Dapper Wallet inside FCL, you need to [follow this guide](https://docs.meetdapper.com/get-started). + +- *Interact with smart contracts*: Authorize transactions via the user's chosen wallet +- *Prove ownership of a wallet address*: Signing and verifying user signed data + +[Learn more about wallet interactions >](api.md#wallet-interactions) + +#### Blockchain Interactions +- *Query the chain*: Send arbitrary Cadence scripts to the chain and receive back decoded values +```js + + +const result = await fcl.query({ + cadence: ` + pub fun main(a: Int, b: Int, addr: Address): Int { + log(addr) + return a + b + } + `, + args: (arg, t) => [ + arg(7, t.Int), // a: Int + arg(6, t.Int), // b: Int + arg("0xba1132bc08f82fe2", t.Address), // addr: Address + ], +}); +console.log(result); // 13 +``` +- *Mutate the chain*: Send arbitrary transactions with your own signatures or via a user's wallet to perform state changes on chain. +```js + +// in the browser, FCL will automatically connect to the user's wallet to request signatures to run the transaction +const txId = await fcl.mutate({ + cadence: ` + import Profile from 0xba1132bc08f82fe2 + + transaction(name: String) { + prepare(account: AuthAccount) { + account.borrow<&{Profile.Owner}>(from: Profile.privatePath)!.setName(name) + } + } + `, + args: (arg, t) => [arg("myName", t.String)], +}); +``` + +[Learn more about on-chain interactions >](api.md#on-chain-interactions) + +#### Utilities +- Get account details from any Flow address +- Get the latest block +- Transaction status polling +- Event polling +- Custom authorization functions + +[Learn more about utilities >](api.md#pre-built-interactions) + +## Typescript Support + +FCL JS supports TypeScript. If you need to import specific types, you can do so via the [@onflow/typedefs](https://github.com/onflow/fcl-js/tree/master/packages/typedefs) package. + +```typescript + + +const newUser: CurrentUser = { + addr: null, + cid: null, + expiresAt: null, + f_type: 'User', + f_vsn: '1.0.0', + loggedIn: null, + services: [] +} +``` + +For all type definitions available, see [this file](https://github.com/onflow/fcl-js/blob/master/packages/typedefs/src/index.ts) + +## Next Steps + +- See the [Flow App Quick Start](../../../build/getting-started/fcl-quickstart.md). +- See the full [API Reference](api.md) for all FCL functionality. +- Learn Flow's smart contract language to build any script or transactions: [Cadence](https://cadence-lang.org). +- Explore all of Flow [docs and tools](https://developers.flow.com). + +--- +## FCL for Wallet Providers +Wallet providers on Flow have the flexibility to build their user interactions and UI through a variety of ways: +- Front channel communication via Iframe, pop-up, tab, or extension +- Back channel communication via HTTP + +FCL is agnostic to the communication channel and be configured to create both custodial and non-custodial wallets. This enables users to interact with wallet providers without needing to download an app or extension. + +The communication channels involve responding to a set of pre-defined FCL messages to deliver the requested information to the dapp. Implementing a FCL compatible wallet on Flow is as simple as filling in the responses with the appropriate data when FCL requests them. If using any of the front-channel communication methods, FCL also provides a set of [wallet utilities](https://github.com/onflow/fcl-js/blob/master/packages/fcl-core/src/wallet-utils/index.js) to simplify this process. + +### Current Wallet Providers +- [Flow Wallet](https://wallet.flow.com/) +- [NuFi Wallet](https://nu.fi/) +- [Blocto](https://blocto.portto.io/en/) +- [Ledger](https://ledger.com) (limited transaction support) +- [Dapper Wallet](https://www.meetdapper.com/) (beta access - general availability coming soon) + +### Wallet Discovery +It can be difficult to get users to discover new wallets on a chain. To solve this, we created a [wallet discovery service](https://github.com/onflow/fcl-discovery) that can be configured and accessed through FCL to display all available Flow wallet providers to the user. This means: +- Dapps can display and support all FCL compatible wallets that launch on Flow without needing to change any code +- Users don't need to sign up for new wallets - they can carry over their existing one to any dapp that uses FCL for authentication and authorization. + +The discovery feature can be used via API allowing you to customize your own UI or you can use the default UI without any additional configuration. + +> Note: To get your wallet added to the discovery service, make a PR in [fcl-discovery](https://github.com/onflow/fcl-discovery). + +### Building a FCL compatible wallet + +- Read the [wallet guide](https://github.com/onflow/fcl-js/blob/master/packages/fcl-core/src/wallet-provider-spec/draft-v4.md) to understand the implementation details. +- Review the architecture of the [FCL dev wallet](https://github.com/onflow/fcl-dev-wallet) for an overview. +- If building a non-custodial wallet, see the [Account API](https://github.com/onflow/flow-account-api) and the [FLIP](https://github.com/onflow/flow/pull/727) on derivation paths and key generation. + +--- + +## 🛠 Want to Use the Flow SDK Directly? + +If you prefer to interact with Flow at a **lower level** without using FCL, you can use the [Flow JavaScript SDK](sdk-guidelines.md) directly. The SDK provides raw access to Flow's API for sending transactions, executing scripts, and managing accounts. + +FCL is built **on top of the Flow SDK**, making it easier to handle authentication, wallet interactions, and dapp connectivity. Choose the approach that best fits your use case. + +## Support + +- Notice a problem or want to request a feature? [Add an issue](https://github.com/onflow/fcl-js/issues). +- Join the Flow community on [Discord](https://discord.gg/flow) to keep up to date and to talk to the team. +- Read the [Contributing Guide](https://github.com/onflow/fcl-js/blob/master/CONTRIBUTING.md) to learn how to contribute to the project. \ No newline at end of file diff --git a/static/markdown/tools/clients/fcl-js/installation.md b/static/markdown/tools/clients/fcl-js/installation.md new file mode 100644 index 0000000000..ac2840298b --- /dev/null +++ b/static/markdown/tools/clients/fcl-js/installation.md @@ -0,0 +1,34 @@ +# Installation + +This chapter explains the installation of the FCL JS library in your system. However, before moving to the installation, let us verify the prerequisite first. + +## Prerequisite +- Node.js version v12.0.0 or higher. + +FCL JS depends on Node.js version v12.0.0 or higher. You can check your currently installed version using the below command: + +```javascript +node --version +``` + +If Node.js is not installed on your system, you can download and install it by visiting [Node.js Download](https://nodejs.org/en/download/). + +Install FCL JS using **npm** or **yarn** + +```shell +npm i -S @onflow/fcl +``` + +```shell +yarn add @onflow/fcl +``` +#### Importing + +**ES6** +```js + +``` +**Node.js** +```js +const fcl = require("@onflow/fcl"); +``` \ No newline at end of file diff --git a/static/markdown/tools/clients/fcl-js/interaction-templates.md b/static/markdown/tools/clients/fcl-js/interaction-templates.md new file mode 100644 index 0000000000..fd90066dfb --- /dev/null +++ b/static/markdown/tools/clients/fcl-js/interaction-templates.md @@ -0,0 +1,266 @@ +--- +title: Interaction Templates +--- + +# Interaction Templates + +> Interaction Templates are a concept established in FLIP-934. Read the FLIP [here](https://github.com/onflow/flips/blob/main/application/20220503-interaction-templates.md) + +> "Interaction" in this context refers to the higher order term establised in FLIP-934 that encompases a transaction and script, things that _interact_ with the blockchain. + +## Overview + +Interaction Templates establish a format for metadata that exists about an interaction. Interaction Templates can include: + +- Human readable, internationalized messages about the interaction +- The Cadence code to carry out the interaction +- Information about arguments such as internationalized human readable messages and what the arguments act upon +- Contract dependencies the Interaction engages with, pinned to a version of them and their dependency tree + +Applications and Wallets can use Interaction Templates and it's interaction metadata. + +For example Applications and Wallets can extract the internationalized human readable messaging from an Interaction Template to display to their users prior to execution of the interaction. + +## For Applications + +FCL `mutate` and `query` can accept an Interaction Template. FCL `mutate` and `query` will use the Interaction Template to: + +- Extract the Cadence code to carry out the interaction +- Extract dependency configuration for the interaction (eg: Information about contract import addresses) + +Here is an example of using `mutate` with an Interaction Template: +```javascript + + + +const txId = await fcl.mutate({ + template: myTransactionTemplate +}) +``` + +An Interaction Template can also be used with `query`: +```javascript + + + +const info = await fcl.query({ + template: myScriptTemplate +}) +``` + +Interaction Templates can be resolved from remote locations: + +```javascript + + +const txId = await fcl.mutate({ + template: "http://interactions.awesome-crypto-project.com/buy-nft" +}) + +const nftInfo = await fcl.query({ + template: "http://interactions.awesome-crypto-project.com/read-nft", + args: (arg, t) => [arg("nft-id", t.String)] +}) +``` + +FCL will resolve the template from the remote location before using it to execute its underlying transaction or script. + +> 💡 By requesting an Interaction Template from an external location, applications have a mechanism to always retrieve the most up to date way of accomplishing an interaction. + +By default FCL supports resolving Interaction Templates over http/https, but FCL can also be configured with various other ways to resolve Interaction Templates: + +```javascript + + +await fcl.config().put("document.resolver.ipfs", async ({ url }) => { + const jsonTemplate = getDocumentFromIPFS(url) // resolve interaction template from ipfs + return jsonTemplate +}) + +const txId = await fcl.mutate({ + template: "ipfs://IPFSHASHGOESHERE" +}) +``` + +## For Wallets + +Wallets can use Interaction Templates to: +- Display internationalized human readable information about a transaction to their users during signing +- Verify the dependencies of an Interaction Template have not changed since when the Interaction Template was created +- Using Interaction Template Audits, gain confidence in the correctness and safety of an Interaction Template and it's underlying transaction + +When recieving a transaction to sign, wallets can query for an Interaction Template that corresponds to it. + +Flow operates an "Interaction Template Discovery Service" which wallets can use to query for Interaction Templates. Anyone can run an "Interaction Template Discovery Service" and wallets can choose to query from any of them. + +```javascript +const cadence = cadenceFromTransactionToSign +const network = "mainnet" // "mainnet" | "testnet" + +const cadence_base64 = btoa(cadence) + +const interactionTemplate = await fetch( + "https://flix.flow.com/v1/templates/search", + { + method: "POST", + headers: { + "Content-Type": "application/json" + } + body: JSON.stringify({ + cadence_base64, + network + }) + } +) +``` + +> 📖 For more on the "Interaction Template Discovery Service" that Flow operates, see [here](https://github.com/onflow/flow-interaction-template-service) + +> ❗️ Not all transactions will have a corresponding Interaction Template. Wallets are encouraged to always support signing transactions that do not have a corresponding Interaction Template, or if they fail to discover one. + +Once a wallet has a corresponding Interaction Template for a given transaction, they may also may wish to verify that the transaction it represents is safe to sign, and that the Interaction Template is accurate for that transaction. + +To do so, wallets can rely on themselves, along with external Interaction Template Auditors to gain confidence in the Interaction Template and it's underlying transaction. Interaction Template Auditors are entities that audit Interaction Templates for correctness and safety. + +> 💡 Anyone can be an Interaction Template Auditor. Wallets can choose auditors they trust, if any. + +Wallets can specify auditors it trusts to FCL by configuring FCL with the address of each auditor: + +```javascript + + +await fcl.config().put("flow.network", "mainnet") + +const auditorA_FlowAddress = "0xABC123DEF456" +const auditorB_FlowAddress = "0xFFAA1212DEFF" + +await fcl.config().put("flow.auditors", [ + auditorA_FlowAddress, + auditorB_FlowAddress +]) +``` + +Wallets can check if the auditors they configured FCL with have audited a given Interaction Template: + +```javascript + + + +const audits = await fcl.InteractionTemplateUtils + .getInteractionTemplateAudits({ + template: myTransactionTemplate + }) + +/** + * audits = { + * "0xABC123DEF456": true, + * "0xFFAA1212DEFF": false + * } + ** / +``` + +The Flow team operates these auditor accounts: + +| Flow Team Auditor Accounts | Address | +|----------------------------|:-------------------| +| TestNet | 0xf78bfc12d0a786dc | +| MainNet | 0xfd100e39d50a13e6 | + +Since not all auditors that a wallet trusts may have audited a given Interaction Template, trusting multiple auditors can increase the chance that at least one of the trusted auditors has audited the Interaction Template. + +> ❗️ Auditors can revoke audits at any time, so be sure to always check an Interaction Template's audit status. + +Since contracts on Flow are mutable, wallets may additionally wish to verify that none of the dependency tree for the transaction an Interaction Template represents has changed since when it was created and of what it was audited against. + +```javascript + + + +const hasDependencyTreeChanged = await fcl.InteractionTemplateUtils + .verifyDependencyPinsSameAtLatestSealedBlock({ + template: myTransactionTemplate + }) +``` + +If the dependency tree has changed, wallets may choose to disregard the Interaction Template (and it's audits). + +Once the Interaction Template has been sufficiently audited by auditors the wallet trusts, and it's dependency tree determined unchanged since the interaction was created and audited against, then the wallet can use the Interaction Template with greater confidence in it's correctness and safety. + +The wallet may then decide to render human readable information about the transaction such as: +- Internationalized 'title' and 'description' of the transaction +- Internationalized 'title' for each of the transactions arguments alongside the arguments value + +The wallet may then also make the status of it's audits known to the user in their UI. This allows the user to have greater confidence in the safety of the transaction. + +## Data Structure + +The following is an example Interaction Template that corresponds to a "Transfer FLOW" transaction: + +```json +{ + "f_type": "InteractionTemplate", + "f_version": "1.0.0", + "id": "290b6b6222b2a77b16db896a80ddf29ebd1fa3038c9e6625a933fa213fce51fa", + "data": { + "type": "transaction", + "interface": "", + "messages": { + "title": { + "i18n": { + "en-US": "Transfer Tokens" + } + }, + "description": { + "i18n": { + "en-US": "Transfer tokens from one account to another" + } + } + }, + "cadence": "import FungibleToken from 0xFUNGIBLETOKENADDRESS\ntransaction(amount: UFix64, to: Address) {\nlet vault: @FungibleToken.Vault\nprepare(signer: &Account) {\nself.vault <- signer\n.borrow<&{FungibleToken.Provider}>(from: /storage/flowTokenVault)!\n.withdraw(amount: amount)\n}\nexecute {\ngetAccount(to)\n.capabilities.get(/public/flowTokenReceiver)!\n.borrow<&{FungibleToken.Receiver}>()!\n.deposit(from: <-self.vault)\n}\n}", + "dependencies": { + "0xFUNGIBLETOKENADDRESS": { + "FungibleToken": { + "mainnet": { + "address": "0xf233dcee88fe0abe", + "fq_address": "A.0xf233dcee88fe0abe.FungibleToken", + "contract": "FungibleToken", + "pin": "83c9e3d61d3b5ebf24356a9f17b5b57b12d6d56547abc73e05f820a0ae7d9cf5", + "pin_block_height": 34166296 + }, + "testnet": { + "address": "0x9a0766d93b6608b7", + "fq_address": "A.0x9a0766d93b6608b7.FungibleToken", + "contract": "FungibleToken", + "pin": "83c9e3d61d3b5ebf24356a9f17b5b57b12d6d56547abc73e05f820a0ae7d9cf5", + "pin_block_height": 74776482 + } + } + } + }, + "arguments": { + "amount": { + "index": 0, + "type": "UFix64", + "messages": { + "title": { + "i18n": { + "en-US": "The amount of FLOW tokens to send" + } + } + } + }, + "to": { + "index": 1, + "type": "Address", + "messages": { + "title": { + "i18n": { + "en-US": "The Flow account the tokens will go to" + } + } + } + } + } + } +} +``` \ No newline at end of file diff --git a/static/markdown/tools/clients/fcl-js/proving-authentication.md b/static/markdown/tools/clients/fcl-js/proving-authentication.md new file mode 100644 index 0000000000..20781bfb0a --- /dev/null +++ b/static/markdown/tools/clients/fcl-js/proving-authentication.md @@ -0,0 +1,178 @@ +--- +title: Proving Ownership of a Flow Account +--- + +## Proving Ownership of a Flow Account + +A common desire that application developers have is to be able to prove that a +user controls an on-chain account. Proving ownership of an on-chain account is a +way to authenticate a user with an application backend. Fortunately, +FCL provides a way to achieve this. + +During user authentication, some FCL compatible wallets will choose to support +the FCL `account-proof` service. If a wallet chooses to support this service, and +the user approves the signing of message data, they will return `account-proof` data +and a signature(s) that can be used to prove a user controls an on-chain account. + +We'll walk through how you, an application developer, can use the `account-proof` service to +authenticate a user. + +> Are you an FCL Wallet Developer? Check out the wallet provider specific docs +> [here](https://github.com/onflow/fcl-js/tree/master/packages/fcl/src/wallet-provider-spec/provable-authn.md) + +### Authenticating a user using `account-proof` + +In order to authenticate your users via a wallet provider's account-proof service, your application needs to +configure FCL by setting `fcl.accountProof.resolver` and providing two pieces of information. + +The `fcl.accountProof.resolver` is an async resolver function used by FCL to retrieve account proof data +from your application server. It can be set in your application configuration under the `fcl.accountProof.resolver` +key. The resolved data should include a specific application identifier (`appIdentifier`) and a random `nonce`. +This data will be sent to the wallet for signing by the user. If the user approves and authentication is successfull, +a signature is returned to the client in the data field of an `account-proof` service. + +**Application Identifier** + +An application identifier is a human-readable string that uniquely identifies your application name. +The identifier is displayed by wallets when users are asked to approve a signing request. +It helps users compare against the request origin and detect some malicious phishing attempts, +improving trust of the application and signing process. + +**Random Nonce** + +In addition to the `appIdentifier` your application must provide a **minimum 32-byte random nonce** as a hex string. + +If for any reason your application backend does not want to request an `account-proof` during authentication, +it should send a response of `null`. If FCL receives a `null` response from the `accountProof.resolver` it will +continue the authentication process with the wallet but will not request an account-proof and no signature will be returned. + +> In the case of a network or server error FCL will cancel the authentication process and return a rejected promise. + +```js + + +type AccountProofData { + // e.g. "Awesome App (v0.0)" - A human readable string to identify your application during signing + appIdentifier: string; + + // e.g. "75f8587e5bd5f9dcc9909d0dae1f0ac5814458b2ae129620502cb936fde7120a" - minimum 32-byte random nonce as hex string + nonce: string; +} + +type AccountProofDataResolver = () => Promise; + +config({ + "fcl.accountProof.resolver": accountProofDataResolver +}) +``` + +Here is the suggested order of operations of how your application might use the +`account-proof` service: + +- A user would like to authenticate via your application client using FCL. The process is triggered + by a call to `fcl.authenticate()`. If `fcl.accountProof.resolver` is configured, FCL will attempt + to retrieve the account proof data (`appIdentifier` and `nonce`) and trigger your server to start a new + account proof authentication process. +- Your application server generates a **minimum 32-byte random nonce** using a local source of entropy and + sends it to the client. The server saves the challenge for future look-ups. +- If FCL successfully retrieves the `account-proof` data, it continues the authentication process over a secure channel with the wallet. + FCL includes the `appIdentifier` and `nonce` as part of the `FCL:VIEW:READY:RESPONSE` or HTTP POST request body. + If the resolver function call fails to retrieve the nonce, FCL will cancel the authentication process. +- If the wallet supports account proofs and the user approves authentication with the wallet, the wallet will return the `account-proof` + service with its response. + +The data within the `account-proof` service will look like this: + +```js +{ + f_type: "Service", // Its a service! + f_vsn: "1.0.0", // Follows the v1.0.0 spec for the service + type: "account-proof", // The type of service it is + method: "DATA", // Its data! + uid: "awesome-wallet#account-proof", // A unique identifier for the service + data: { + f_type: "account-proof", + f_vsn: "2.0.0" + + // The user's address (8 bytes, i.e 16 hex characters) + address: "0xf8d6e0586b0a20c7", + + // Nonce signed by the current account-proof (minimum 32 bytes in total, i.e 64 hex characters) + nonce: "75f8587e5bd5f9dcc9909d0dae1f0ac5814458b2ae129620502cb936fde7120a", + + signatures: [CompositeSignature], + } +} +``` + +- Your application client initiates a secure channel with your application server + to relay the `account-proof` data and authenticate the user with your server. + Subsequent exchanges between the client and server will happen over this channel. + +- Your application server receives the `account-proof` data structure, and can then + begin the verification process. + + - The server checks if the Flow address corresponds to an existing application + account and determines whether it needs to sign in a returning user or create + a new account. It is up to your application to decide how to manage + the two cases. + - The server looks the challenge up. If the nonce is not found or the nonce + has expired, reject the authentication request, otherwise continue. + - The server determines whether the `CompositeSignature` in the + `account-proof` data structure contains valid signatures for the nonce + and on-chain accounts (more details in the section below on how this is done). + - If the verification is successful, delete the `nonce` or mark it as expired, + the application account defined by the on-chain address is successfully + logged in. Otherwise the authentication fails and the `nonce` is not deleted. + +**Verification** + +Your application can verify the signature against the data from `account-proof` +data using FCL's provided utility: + +```js + + + + const accountProofData = { + accountProof.address, // address of the user authenticating + accountProof.nonce, // nonce + accountProof.signatures // signatures + } + + const isValid = await AppUtils.verifyAccountProof( + appIdentifier, + accountProofData + ) +``` + +## Implementation considerations: + +- The authentication assumes the Flow address is the identifier of the user's application account. + If an existing user doesn't have a Flow address in their profile, or if they decide to authenticate using + a Flow address different than the one saved in their profile, the user's account won't be found and the + process would consider a new user creating an account. It is useful for your application to consider + other authentication methods that allow an existing user to update the Flow address in their profile so + they are able to use FCL authentication. +- In the `account-proof` flow as described in this document, + the backend doesn't know the user's account address at the moment of generating a nonce. + This results in the nonces not being tied to particular Flow addresses. The backend should + enforce an expiry window for each nonce to avoid the pool of valid nonces from growing indefinitely. + Your application is encouraged to implement further mitigations against malicious attempts and + maintain a scalable authentication process. +- FCL `account-proof` provides functionality to prove a user is in control of + a Flow address. All other aspects of authentication, authorization and session management + are up to the application. There are many resources available for setting up secure user + authentication systems. Application developers should carefully consider what's best for their use + case and follow industry best practices. +- It is important to use a secure source of entropy to generate the random nonces. The source should insure + nonces are not predictable by looking at previously generated nonces. Moreover, backend should use its own + local source and not rely on a publicly available source. Using a nonce of at least 32-bytes insures + it is extremely unlikely to have a nonce collision. +- Your application identifier `appIdentifier` is a constant defined by your backend. It is + important that the backend uses the `appIdentifier` it expects when verifying the signatures, + and not rely on an identifier passed along with the `account-proof`. For this reason, + `appIdentifier` is not included in the `account-proof` data. +- A successful FCL authentication proves the user fully controls a Flow account. This means the user + controls one or many account keys with weights that add up to the full account weight. The authentication + would fail if the user doesn't control keys that add up to a full weight. \ No newline at end of file diff --git a/static/markdown/tools/clients/fcl-js/scripts.md b/static/markdown/tools/clients/fcl-js/scripts.md new file mode 100644 index 0000000000..ff6c9092ce --- /dev/null +++ b/static/markdown/tools/clients/fcl-js/scripts.md @@ -0,0 +1,106 @@ +# Scripts + +Scripts let you run non-permanent Cadence scripts on the Flow blockchain. They can return data. + +They always need to contain a `access(all) fun main()` function as an entry point to the script. + +`fcl.query` is a function that sends Cadence scripts to the chain and receives back decoded responses. + +The `cadence` key inside the object sent to the `query` function is a [JavaScript Tagged Template Literal](https://styled-components.com/docs/advanced#tagged-template-literals) that we can pass Cadence code into. + +### Sending Your First Script + +The following example demonstrates how to send a script to the Flow blockchain. This script adds two numbers and returns the result. + +```javascript + + +const response = await fcl.query({ + cadence: ` + access(all) fun main(): Int { + return 1 + 2 + } + ` +}) + +console.log(response) // 3 +``` + +### A More Complex Script + +[Resources](https://cadence-lang.org/docs/language/resources) and [Structs](https://cadence-lang.org/docs/language/composite-types#structures) are complex data types that are fairly common place in Cadence. + +In the following code snippet, our script defines a struct called `Point`, it then returns a list of them. + +The closest thing to a Structure in JavaScript is an object. In this case when we decode this response, we would be expecting to get back an array of objects, where the objects have an `x` and `y` value. + +```javascript + + +const response = await fcl.query({ + cadence: ` + access(all) struct Point { + access(all) var x: Int + access(all) var y: Int + + init(x: Int, y: Int) { + self.x = x + self.y = y + } + } + + access(all) fun main(): [Point] { + return [Point(x: 1, y: 1), Point(x: 2, y: 2)] + } + ` +}) + +console.log(response) // [{x:1, y:1}, {x:2, y:2}] +``` + +### Transforming Data with Custom Decoders + +In our app, we probably have a way of representing these Cadence values internally. In the above example it might be a `Point` class. + +FCL enables us to provide custom decoders that we can use to transform the data we receive from the Flow blockchain at the edge, before anything else in our dapp gets a chance to look at it. + +We add these custom decoders by [Configuring FCL](./configure-fcl.md). +This lets us set it once when our dapp starts up and use our normalized data through out the rest of our dapp. + +In the below example we will use the concept of a `Point` again, but this time, we will add a custom decoder, that enables `fcl.decode` to transform it into a custom JavaScript `Point` class. + +```javascript + + +class Point { + constructor({ x, y }) { + this.x = x + this.y = y + } +} + +fcl.config() + .put("decoder.Point", point => new Point(point)) + +const response = await fcl.query({ + cadence: ` + access(all) struct Point { + access(all) var x: Int + access(all) var y: Int + + init(x: Int, y: Int) { + self.x = x + self.y = y + } + } + + access(all) fun main(): [Point] { + return [Point(x: 1, y: 1), Point(x: 2, y: 2)] + } + ` +}) + +console.log(response) // [Point{x:1, y:1}, Point{x:2, y:2}] +``` + +To learn more about `query`, check out the [API documentation](./api.md#query). \ No newline at end of file diff --git a/static/markdown/tools/clients/fcl-js/sdk-guidelines.md b/static/markdown/tools/clients/fcl-js/sdk-guidelines.md new file mode 100644 index 0000000000..f9a956f2e5 --- /dev/null +++ b/static/markdown/tools/clients/fcl-js/sdk-guidelines.md @@ -0,0 +1,667 @@ +--- +title: SDK Reference +sidebar_label: SDK Reference +sidebar_position: 2 +--- + +## Overview + +This reference documents methods available in the SDK that can be accessed via FCL, and explains in detail how these methods work. +FCL/SDKs are open source, and you can use them according to the licence. + +The library client specifications can be found here: + +[](./api.md) + +## Getting Started + +### Installing +NPM: +``` +npm install --save @onflow/fcl @onflow/types +``` + +Yarn: +``` +yarn add @onflow/fcl @onflow/types +``` + +### Importing the Library +```javascript + + +``` + +## Connect +[](./configure-fcl.md) + +By default, the library uses HTTP to communicate with the access nodes and it must be configured with the correct access node API URL. An error will be returned if the host is unreachable. + +📖**The HTTP/REST API information** can be found [here](/http-api/). The public Flow HTTP/REST access nodes are accessible at: +- Testnet `https://rest-testnet.onflow.org` +- Mainnet `https://rest-mainnet.onflow.org` +- Local Emulator `127.0.0.1:8888` + +Example: +```javascript + + +config({ + "accessNode.api": "https://rest-testnet.onflow.org" +}) +``` + +## Querying the Flow Network +After you have established a connection with an access node, you can query the Flow network to retrieve data about blocks, accounts, events and transactions. We will explore how to retrieve each of these entities in the sections below. + +### Get Blocks +[](./api.md#getblock) + +Query the network for block by id, height or get the latest block. + +📖 **Block ID** is SHA3-256 hash of the entire block payload. This hash is stored as an ID field on any block response object (ie. response from `GetLatestBlock`). + +📖 **Block height** expresses the height of the block on the chain. The latest block height increases by one for every valid block produced. + +#### Examples + +This example depicts ways to get the latest block as well as any other block by height or ID: + +``` + + +// Get latest block +const latestBlock = await fcl.latestBlock(true); // If true, get the latest sealed block + +// Get block by ID (uses builder function) +await fcl.send([fcl.getBlock(), fcl.atBlockId("23232323232")]).then(fcl.decode); + +// Get block at height (uses builder function) +await fcl.send([fcl.getBlock(), fcl.atBlockHeight(123)]).then(fcl.decode) +``` +Result output: [BlockObject](./api.md#blockobject) + +### Get Account +[](./api.md#account) + +Retrieve any account from Flow network's latest block or from a specified block height. + +📖 **Account address** is a unique account identifier. Be mindful about the `0x` prefix, you should use the prefix as a default representation but be careful and safely handle user inputs without the prefix. + +An account includes the following data: +- Address: the account address. +- Balance: balance of the account. +- Contracts: list of contracts deployed to the account. +- Keys: list of keys associated with the account. + +#### Examples +Example depicts ways to get an account at the latest block and at a specific block height: + +```javascript + + +// Get account from latest block height +const account = await fcl.account("0x1d007d755706c469"); + +// Get account at a specific block height +fcl.send([ + fcl.getAccount("0x1d007d755706c469"), + fcl.atBlockHeight(123) +]); +``` +Result output: [AccountObject](./api.md#accountobject) + +### Get Transactions +[](./api.md#gettransaction) + +Retrieve transactions from the network by providing a transaction ID. After a transaction has been submitted, you can also get the transaction result to check the status. + +📖 **Transaction ID** is a hash of the encoded transaction payload and can be calculated before submitting the transaction to the network. + +⚠️ The transaction ID provided must be from the current spork. + +📖 **Transaction status** represents the state of a transaction in the blockchain. Status can change until it is finalized. + +| Status | Final | Description | +| ------------ | ------- | ----------- | +| UNKNOWN | ❌ | The transaction has not yet been seen by the network | +| PENDING | ❌ | The transaction has not yet been included in a block | +| FINALIZED | ❌ | The transaction has been included in a block | +| EXECUTED | ❌ | The transaction has been executed but the result has not yet been sealed | +| SEALED | ✅ | The transaction has been executed and the result is sealed in a block | +| EXPIRED | ✅ | The transaction reference block is outdated before being executed | + +```javascript + + +// Snapshot the transaction at a point in time +fcl.tx(transactionId).snapshot(); + +// Subscribe to a transaction's updates +fcl.tx(transactionId).subscribe(callback); + +// Provides the transaction once the status is finalized +fcl.tx(transactionId).onceFinalized(); + +// Provides the transaction once the status is executed +fcl.tx(transactionId).onceExecuted(); + +// Provides the transaction once the status is sealed +fcl.tx(transactionId).onceSealed(); +``` +Result output: [TransactionStatusObject](./api.md#gettransactionstatus) + +### Get Events +[](./api.md#geteventsatblockheightrange) + +Retrieve events by a given type in a specified block height range or through a list of block IDs. + +📖 **Event type** is a string that follow a standard format: +``` +A.{contract address}.{contract name}.{event name} +``` + +Please read more about [events in the documentation](https://cadence-lang.org/docs/language/core-events). The exception to this standard are +core events, and you should read more about them in [this document](https://cadence-lang.org/docs/language/core-events). + +📖 **Block height range** expresses the height of the start and end block in the chain. + +#### Examples +Example depicts ways to get events within block range or by block IDs: + +```javascript + + +// Get events at block height range +await fcl + .send([ + fcl.getEventsAtBlockHeightRange( + "A.7e60df042a9c0868.FlowToken.TokensWithdrawn", // event name + 35580624, // block to start looking for events at + 35580624 // block to stop looking for events at + ), + ]) + .then(fcl.decode); + +// Get events from list of block ids +await fcl + .send([ + fcl.getEventsAtBlockIds("A.7e60df042a9c0868.FlowToken.TokensWithdrawn", [ + "c4f239d49e96d1e5fbcf1f31027a6e582e8c03fcd9954177b7723fdb03d938c7", + "5dbaa85922eb194a3dc463c946cc01c866f2ff2b88f3e59e21c0d8d00113273f", + ]), + ]) + .then(fcl.decode); +``` +Result output: [EventObject](./api.md#event-object) + +### Get Collections +[](./api.md#getcollection) + +Retrieve a batch of transactions that have been included in the same block, known as ***collections***. +Collections are used to improve consensus throughput by increasing the number of transactions per block and they act as a link between a block and a transaction. + +📖 **Collection ID** is SHA3-256 hash of the collection payload. + +Example retrieving a collection: +```javascript + + +const collection = await fcl + .send([ + fcl.getCollection( + "cccdb0c67d015dc7f6444e8f62a3244ed650215ed66b90603006c70c5ef1f6e5" + ), + ]) + .then(fcl.decode); +``` +Result output: [CollectionObject](./api.md#collectionobject) + +### Execute Scripts +[](./api.md#query) + +Scripts allow you to write arbitrary non-mutating Cadence code on the Flow blockchain and return data. You can learn more about [Cadence here](https://cadence-lang.org/docs/language) and [scripts here](./scripts.md), but we are now only interested in executing the script code and getting back the data. + +We can execute a script using the latest state of the Flow blockchain or we can choose to execute the script at a specific time in history defined by a block height or block ID. + +📖 **Block ID** is SHA3-256 hash of the entire block payload, but you can get that value from the block response properties. + +📖 **Block height** expresses the height of the block in the chain. + +```javascript + + +const result = await fcl.query({ + cadence: ` + access(all) fun main(a: Int, b: Int, addr: Address): Int { + log(addr) + return a + b + } + `, + args: (arg, t) => [ + arg(7, t.Int), // a: Int + arg(6, t.Int), // b: Int + arg("0xba1132bc08f82fe2", t.Address), // addr: Address + ], +}); +``` +Example output: +```bash +console.log(result); // 13 +``` + +## Mutate Flow Network +Flow, like most blockchains, allows anybody to submit a transaction that mutates the shared global chain state. A transaction is an object that holds a payload, which describes the state mutation, and one or more authorizations that permit the transaction to mutate the state owned by specific accounts. + +Transaction data is composed and signed with help of the SDK. The signed payload of transaction then gets submitted to the access node API. If a transaction is invalid or the correct number of authorizing signatures are not provided, it gets rejected. + +## Transactions +A transaction is nothing more than a signed set of data that includes script code which are instructions on how to mutate the network state and properties that define and limit it's execution. All these properties are explained bellow. + +📖 **Script** field is the portion of the transaction that describes the state mutation logic. On Flow, transaction logic is written in [Cadence](https://cadence-lang.org/docs). Here is an example transaction script: +``` +transaction(greeting: String) { + execute { + log(greeting.concat(", World!")) + } +} +``` + +📖 **Arguments**. A transaction can accept zero or more arguments that are passed into the Cadence script. The arguments on the transaction must match the number and order declared in the Cadence script. Sample script from above accepts a single `String` argument. + +📖 **[Proposal key](../../../build/basics/transactions.md#proposal-key)** must be provided to act as a sequence number and prevent replay and other potential attacks. + +Each account key maintains a separate transaction sequence counter; the key that lends its sequence number to a transaction is called the proposal key. + +A proposal key contains three fields: +- Account address +- Key index +- Sequence number + +A transaction is only valid if its declared sequence number matches the current on-chain sequence number for that key. The sequence number increments by one after the transaction is executed. + +📖 **[Payer](../../../build/basics/transactions.md#signer-roles)** is the account that pays the fees for the transaction. A transaction must specify exactly one payer. The payer is only responsible for paying the network and gas fees; the transaction is not authorized to access resources or code stored in the payer account. + +📖 **[Authorizers](../../../build/basics/transactions.md#signer-roles)** are accounts that authorize a transaction to read and mutate their resources. A transaction can specify zero or more authorizers, depending on how many accounts the transaction needs to access. + +The number of authorizers on the transaction must match the number of `&Account` parameters declared in the prepare statement of the Cadence script. + +Example transaction with multiple authorizers: +``` +transaction { + prepare(authorizer1: &Account, authorizer2: &Account) { } +} +``` + +📖 **Gas limit** is the limit on the amount of computation a transaction requires, and it will abort if it exceeds its gas limit. +Cadence uses metering to measure the number of operations per transaction. You can read more about it in the [Cadence documentation](https://cadence-lang.org/docs). + +The gas limit depends on the complexity of the transaction script. Until dedicated gas estimation tooling exists, it's best to use the emulator to test complex transactions and determine a safe limit. + +📖 **Reference block** specifies an expiration window (measured in blocks) during which a transaction is considered valid by the network. +A transaction will be rejected if it is submitted past its expiry block. Flow calculates transaction expiry using the _reference block_ field on a transaction. +A transaction expires after `600` blocks are committed on top of the reference block, which takes about 10 minutes at average Mainnet block rates. + +### Mutate +[](./api.md#mutate) + +FCL "mutate" does the work of building, signing, and sending a transaction behind the scenes. In order to mutate the blockchain state using FCL, you need to do the following: + +```javascript + + +await fcl.mutate({ + cadence: ` + transaction(a: Int) { + prepare(acct: &Account) { + log(acct) + log(a) + } + } + `, + args: (arg, t) => [ + arg(6, t.Int) + ], + limit: 50 +}) +``` + +Flow supports great flexibility when it comes to transaction signing, we can define multiple authorizers (multi-sig transactions) and have different payer account than proposer. We will explore advanced signing scenarios bellow. + +### [Single party, single signature](../../../build/basics/transactions.md#single-party-single-signature) + +- Proposer, payer and authorizer are the same account (`0x01`). +- Only the envelope must be signed. +- Proposal key must have full signing weight. + +| Account | Key ID | Weight | +| ------- | ------ | ------ | +| `0x01` | 1 | 1000 | + +```javascript +// There are multiple ways to acheive this + + +// FCL provides currentUser as an authorization function +await fcl.mutate({ + cadence: ` + transaction { + prepare(acct: &Account) {} + } + `, + proposer: currentUser, + payer: currentUser, + authorizations: [currentUser], + limit: 50, +}) + +// Or, simplified + +mutate({ + cadence: ` + transaction { + prepare(acct: &Account) {} + } + `, + authz: currentUser, // Optional. Will default to currentUser if not provided. + limit: 50, +}) + +// Or, create a custom authorization function +const authzFn = async (txAccount) => { + return { + ...txAccount, + addr: "0x01", + keyId: 0, + signingFunction: async(signable) => { + return { + addr: "0x01", + keyId: 0, + signature + } + } + } +} + +mutate({ + cadence: ` + transaction { + prepare(acct: &Account) {} + } + `, + proposer: authzFn, + payer: authzFn, + authorizations: [authzFn], + limit: 50, +}) +``` + +### [Single party, multiple signatures](../../../build/basics/transactions.md#single-party-multiple-signatures) + +- Proposer, payer and authorizer are the same account (`0x01`). +- Only the envelope must be signed. +- Each key has weight 500, so two signatures are required. + +| Account | Key ID | Weight | +| ------- | ------ | ------ | +| `0x01` | 1 | 500 | +| `0x01` | 2 | 500 | + +**[](https://github.com/onflow/flow-go-sdk/tree/master/examples#single-party-multiple-signatures)** +```javascript + + +const authzFn = async (txAccount) => { + return [ + { + ...txAccount, + addr: "0x01", + keyId: 0, + signingFunction: async(signable) => { + return { + addr: "0x01", + keyId: 0, + signature + } + } + }, + { + ...txAccount, + addr: "0x01", + keyId: 1, + signingFunction: async(signable) => { + return { + addr: "0x01", + keyId: 1, + signature + } + } + } + ] +} + +mutate({ + cadence: ` + transaction { + prepare(acct: &Account) {} + } + `, + proposer: authzFn, + payer: authzFn, + authorizations: [authzFn], + limit: 50, +}) +``` + +### [Multiple parties](../../../build/basics/transactions.md#multiple-parties) + +- Proposer and authorizer are the same account (`0x01`). +- Payer is a separate account (`0x02`). +- Account `0x01` signs the payload. +- Account `0x02` signs the envelope. + - Account `0x02` must sign last since it is the payer. + +| Account | Key ID | Weight | +| ------- | ------ | ------ | +| `0x01` | 1 | 1000 | +| `0x02` | 3 | 1000 | + +**[](https://github.com/onflow/flow-go-sdk/tree/master/examples#multiple-parties)** +```javascript + + +const authzFn = async (txAccount) => { + return { + ...txAccount, + addr: "0x01", + keyId: 0, + signingFunction: async(signable) => { + return { + addr: "0x01", + keyId: 0, + signature + } + } + } +} + +const authzTwoFn = async (txAccount) => { + return { + ...txAccount, + addr: "0x02", + keyId: 0, + signingFunction: async(signable) => { + return { + addr: "0x02", + keyId: 0, + signature + } + } + } +} + +mutate({ + cadence: ` + transaction { + prepare(acct: &Account) {} + } + `, + proposer: authzFn, + payer: authzTwoFn, + authorizations: [authzFn], + limit: 50, +}) +``` + +### [Multiple parties, two authorizers](../../../build/basics/transactions.md#multiple-parties) + +- Proposer and authorizer are the same account (`0x01`). +- Payer is a separate account (`0x02`). +- Account `0x01` signs the payload. +- Account `0x02` signs the envelope. + - Account `0x02` must sign last since it is the payer. +- Account `0x02` is also an authorizer to show how to include two `&Account` objects into an transaction + +| Account | Key ID | Weight | +| ------- | ------ | ------ | +| `0x01` | 1 | 1000 | +| `0x02` | 3 | 1000 | + +**[](https://github.com/onflow/flow-go-sdk/tree/master/examples#multiple-parties-two-authorizers)** +```javascript + + +const authzFn = async (txAccount) => { + return { + ...txAccount, + addr: "0x01", + keyId: 0, + signingFunction: async(signable) => { + return { + addr: "0x01", + keyId: 0, + signature + } + } + } +} + +const authzTwoFn = async (txAccount) => { + return { + ...txAccount, + addr: "0x02", + keyId: 0, + signingFunction: async(signable) => { + return { + addr: "0x02", + keyId: 0, + signature + } + } + } +} + +mutate({ + cadence: ` + transaction { + prepare(acct: &Account, acct2: &Account) {} + } + `, + proposer: authzFn, + payer: authzTwoFn, + authorizations: [authzFn, authzTwoFn], + limit: 50, +}) +``` + +### [Multiple parties, multiple signatures](../../../build/basics/transactions.md#multiple-parties) + +- Proposer and authorizer are the same account (`0x01`). +- Payer is a separate account (`0x02`). +- Account `0x01` signs the payload. +- Account `0x02` signs the envelope. + - Account `0x02` must sign last since it is the payer. +- Both accounts must sign twice (once with each of their keys). + +| Account | Key ID | Weight | +| ------- | ------ | ------ | +| `0x01` | 1 | 500 | +| `0x01` | 2 | 500 | +| `0x02` | 3 | 500 | +| `0x02` | 4 | 500 | + +```javascript + + +const authzFn = async (txAccount) => { + return [ + { + ...txAccount, + addr: "0x01", + keyId: 0, + signingFunction: async(signable) => { + return { + addr: "0x01", + keyId: 0, + signature + } + } + }, + { + ...txAccount, + addr: "0x01", + keyId: 1, + signingFunction: async(signable) => { + return { + addr: "0x01", + keyId: 1, + signature + } + } + } + ] +} + +const authzTwoFn = async (txAccount) => { + return [ + { + ...txAccount, + addr: "0x02", + keyId: 0, + signingFunction: async(signable) => { + return { + addr: "0x02", + keyId: 0, + signature + } + } + }, + { + ...txAccount, + addr: "0x02", + keyId: 1, + signingFunction: async(signable) => { + return { + addr: "0x02", + keyId: 1, + signature + } + } + } + ] +} + +mutate({ + cadence: ` + transaction { + prepare(acct: &Account) {} + } + `, + proposer: authzFn, + payer: authzTwoFn, + authorizations: [authzFn], + limit: 50, +}) +``` + +After a transaction has been **built** and **signed**, it can be sent to the Flow blockchain where it will be executed. If sending was successful you can then [retrieve the transaction result](#get-transactions). \ No newline at end of file diff --git a/static/markdown/tools/clients/fcl-js/transactions.md b/static/markdown/tools/clients/fcl-js/transactions.md new file mode 100644 index 0000000000..71b2061254 --- /dev/null +++ b/static/markdown/tools/clients/fcl-js/transactions.md @@ -0,0 +1,136 @@ +# Transactions + +Transactions let you send Cadence code to the Flow blockchain that permanently alters its state. + +We are assuming you have read the [Scripts Documentation](./scripts.md) before this, as transactions are sort of scripts with more required things. + +While `query` is used for sending scripts to the chain, `mutate` is used for building and sending transactions. Just like [scripts](./scripts.md), `fcl.mutate` is a [JavaScript Tagged Template Literal](https://styled-components.com/docs/advanced#tagged-template-literals) that we can pass Cadence code into. + +Unlike scripts, they require a little more information, things like a proposer, authorizations and a payer, which may be a little confusing and overwhelming. + +## Sending Your First Transaction + +There is a lot to unpack in the following code snippet. +It sends a transaction to the Flow blockchain. For the transaction, the current user is authorizing it as both the `proposer` and the `payer`. +Something that is unique to Flow is the one paying for the transaction doesn't always need to be the one performing the transaction. +Proposers and Payers are special kinds of authorizations that are always required for a transaction. +The `proposer` acts similar to the `nonce` in Ethereum transactions, and helps prevent repeat attacks. +The `payer` is who will be paying for the transaction. +If these are not set, FCL defaults to using the current user for all roles. + +`fcl.mutate` will return a `transactionId`. We can pass the response directly to `fcl.tx` and then use the `onceExecuted` method which resolves a promise when a transaction result is available. + +```javascript + + +const transactionId = await fcl.mutate({ + cadence: ` + transaction { + execute { + log("Hello from execute") + } + } + `, + proposer: fcl.currentUser, + payer: fcl.currentUser, + limit: 50 +}) + +const transaction = await fcl.tx(transactionId).onceExecuted() +console.log(transaction) // The transactions status and events after being executed +``` + +## Authorizing a Transaction + +The below code snippet is the same as the above one, except for one extremely important difference. +Our Cadence code this time has a prepare statement, and we are using the `fcl.currentUser` when constructing our transaction. + +The `prepare` statement's arguments directly map to the order of the authorizations in the `authorizations` array. +Four authorizations means four `&Account`s as arguments passed to `prepare`. In this case though there is only one, and it is the `currentUser`. + +These authorizations are important as you can only access/modify an accounts storage if you have the said accounts authorization. + +```javascript + + +const transactionId = await fcl.mutate({ + cadence: ` + transaction { + prepare(acct: &Account) { + log("Hello from prepare") + } + execute { + log("Hello from execute") + } + } + `, + proposer: fcl.currentUser, + payer: fcl.currentUser, + authorizations: [fcl.currentUser], + limit: 50 +}) + +const transaction = await fcl.tx(transactionId).onceExecuted() +console.log(transaction) // The transactions status and events after being executed +``` + +To learn more about `mutate`, check out the [API documentation](./api.md#mutate). + +## Transaction Finality + +As of **FCL v1.15.0**, it is now recommended to use use `onceExecuted` in most cases, leading to a 2.5x reduction in latency when waiting for a transaction result. For example, the following code snippet should be updated from: + +```ts + +const result = await fcl.tx(txId).onceSealed() +``` + +to: + +```ts + +const result = await fcl.tx(txId).onceExecuted() +``` + +Developers manually subscribing to transaction statuses should update their listeners to treat "executed" as the final status (see the release notes [here](https://github.com/onflow/fcl-js/releases/tag/%40onflow%2Ffcl%401.15.0)). For example, the following code snippet should be updated from: + +```ts + + + +fcl.tx(txId).subscribe((txStatus) => { + if ( + txStatus.status === TransactionExecutionStatus.SEALED + ) { + console.log("Transaction executed!") + } +}) +``` + +```ts + + + +fcl.tx(txId).subscribe((txStatus) => { + if ( + // SEALED status is no longer necessary + txStatus.status === TransactionExecutionStatus.EXECUTED + ) { + console.log("Transaction executed!") + } +}) +``` + +The "executed" status corresponds to soft finality, indicating that the transaction has been included in a block and a transaction status is available, backed by a cryptographic proof. Only in rare cases should a developer need to wait for "sealed" status in their applications and you can learn more about the different transaction statuses on Flow [here](../../../build/basics/transactions.md#transaction-status). + +See the following video for demonstration of how to update your code to wait for "executed" status: + + \ No newline at end of file diff --git a/static/markdown/tools/clients/fcl-js/user-signatures.md b/static/markdown/tools/clients/fcl-js/user-signatures.md new file mode 100644 index 0000000000..790fb7eaa0 --- /dev/null +++ b/static/markdown/tools/clients/fcl-js/user-signatures.md @@ -0,0 +1,109 @@ +--- +title: Signing and Verifying Arbitrary Data +--- + +## Signing Arbitrary Data + +Cryptographic signatures are a key part of the blockchain. They are used to prove ownership of an address without exposing its private key. While primarily used for signing transactions, cryptographic signatures can also be used to sign arbitrary messages. + +FCL has a feature that lets you send arbitrary data to a configured wallet/service where the user may approve signing it with their private key/s. + +## Verifying User Signatures + +What makes message signatures more interesting is that we can use Flow blockchain to verify the signatures. Cadence has a built-in function `publicKey.verify` that will verify a signature against a Flow account given the account address. + +FCL includes a utility function, `AppUtils.verifyUserSignatures`, for verifying one or more signatures against an account's public key on the Flow blockchain. + +You can use both in tandem to prove a user is in control of a private key or keys. + +This enables cryptographically-secure login flow using a message-signing-based authentication mechanism with a user’s public address as their identifier. + +--- + +## `currentUser.signUserMessage()` + +A method to use allowing the user to personally sign data via FCL Compatible Wallets/Services. + +> :Note: **Requires authentication/configuration with an authorized signing service.** + +### Arguments + +| Name | Type | Description | +| --------- | ------ | --------------------------------- | +| `message` | string | A hexadecimal string to be signed | + +#### Returns + +| Type | Description | +| ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `Array` | An Array of [CompositeSignatures](https://github.com/onflow/fcl-js/blob/master/packages/fcl-core/src/wallet-provider-spec/draft-v2.md#compositesignature): {`addr`, `keyId`, `signature`} | + +#### Usage + +```javascript + + +const signMessage = async () => { + const MSG = Buffer.from("FOO").toString("hex") + try { + return await fcl.currentUser.signUserMessage(MSG) + } catch (error) { + console.log(error) + } +} +``` + +--- + +## `AppUtils.verifyUserSignatures` + +#### Note + +⚠️ `fcl.config.flow.network` or options override is required to use this API. See [FCL Configuration](./configure-fcl.md). + +A method allowing applications to cryptographically verify the ownership of a Flow account by verifying a message was signed by a user's private key/s. This is typically used with the response from `currentUser.signUserMessage`. + +### Arguments + +| Name | Type | Description | +| --------------------- | --------------------- | --------------------------------- | +| `message` | string **(required)** | A hexadecimal string | +| `compositeSignatures` | Array **(required)** | An Array of `CompositeSignatures` | +| `opts` | Object **(optional)** | `opts.fclCryptoContract` can be provided to override FCLCryptoContract address for local development | + +#### Returns + +| Type | Description | +| ------- | ---------------------------- | +| Boolean | `true` if verified or `false` | + +#### Usage + +```javascript +/** + * Verify a valid signature/s for an account on Flow. + * + * @param {string} msg - A message string in hexadecimal format + * @param {Array} compSigs - An array of Composite Signatures + * @param {string} compSigs[].addr - The account address + * @param {number} compSigs[].keyId - The account keyId + * @param {string} compSigs[].signature - The signature to verify + * @param {Object} [opts={}] - Options object + * @param {string} opts.fclCryptoContract - An optional override of Flow account address where the FCLCrypto contract is deployed + * @return {bool} + * + * @example + * + * const isValid = await fcl.AppUtils.verifyUserSignatures( + * Buffer.from('FOO').toString("hex"), + * [{f_type: "CompositeSignature", f_vsn: "1.0.0", addr: "0x123", keyId: 0, signature: "abc123"}], + * {fclCryptoContract} + * ) + */ +``` + +#### Examples + +Use cases include cryptographic login, message validation, verifiable credentials, and others. + +--- \ No newline at end of file diff --git a/static/markdown/tools/clients/fcl-js/wallet-connect.md b/static/markdown/tools/clients/fcl-js/wallet-connect.md new file mode 100644 index 0000000000..3e0419cc9d --- /dev/null +++ b/static/markdown/tools/clients/fcl-js/wallet-connect.md @@ -0,0 +1,209 @@ +--- +title: WalletConnect 2.0 Manual Configuration +--- + +:::warning +This guide is for advanced users who want to manually configure WalletConnect 2.0 with FCL-JS. Since `@onflow/fcl@1.11.0`, FCL-JS has supported WalletConnect 2.0 out of the box. For most users, we recommend using this built-in WalletConnect 2.0 support ([see how to configure FCL-JS here](./configure-fcl.md)). +::: + +To improve developer experience and streamline **Flow** dApp integration with **WalletConnect 2.0** wallets, **FCL `^1.3.0`** introduces support for **`discovery-service`** plugins. These **`ServicePlugins`** allow for injection of client configured **services**, service **methods**, and the execution **strategies** required to interact with them. +FCL dApps can opt-in through use of the [**fcl-wc**](https://www.npmjs.com/package/@onflow/fcl-wc) package and **FCL Plugin Registry**. + +When using FCL Discovery for authentication, dApps are able to support most FCL-compatible wallets and their users on Flow without any custom integrations or changes needed to the dApp code. + +These instructions explain how dApps can also add support for FCL compatible wallets that use the WalletConnect 2.0 protocol. + +## How does it work? + +- The **`fcl-wc`** package is used to initialize a **WalletConnect 2.0** [**`SignClient`**](https://docs.walletconnect.com/2.0/introduction/sign) instance, and build a **`discovery-service`** **`ServicePlugin`** based on dApp specified options. +- **`discovery-service`** plugins are used to add opt-in wallets and other services to **FCL Wallet Discovery** (UI/API). +- The **FCL Plugin Registry** offers dApps the ability to add new services, methods, and the execution strategies needed to interact with them. + +### Requirements + +- `fcl` version >= `1.3.0` +- `fcl-wc` version >= `1.0.0` + +### Implementation path + +| | | | +| :--------------------------------------------------------------------: | :------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------ | +| [**1**](#1-add-required-packages) | Add required packages | Install and import minimum `fcl` and `fcl-wc` [versions](#requirements) | +| [**2**](#2-obtain-a-walletconnect-projectid) | Obtain a WalletConnect `projectID` | Visit [WalletConnect Cloud Registry](https://cloud.walletconnect.com/) and register for public relay server access and an application `projectId` | +| [**3**](#3-initialize-walletconnect-signclient-and-fclwcserviceplugin) | Initialize WalletConnect `SignClient` and `FclWcServicePlugin` | Initialize WalletConnect `SignClient` and `FclWcServicePlugin` with [configuration options](#configuration-options) | +| [**4**](#4-add-fclwcserviceplugin-to-fcl-plugin-registry) | Add `FclWcServicePlugin` to FCL Plugin Registry | Inject `FclWcServicePlugin` via `fcl.pluginRegistry.add(FclWcServicePlugin)` | + +### 1. Add required packages + +Install the `fcl` and `fcl-wc` packages: + +```bash +npm install @onflow/fcl @onflow/fcl-wc +``` + +### 2. Obtain a WalletConnect projectID + +Visit [WalletConnect Cloud Registry](https://cloud.walletconnect.com/) and register for public relay server access and an application **`projectId`**. + +### 3. Initialize WalletConnect `SignClient` and `FclWcServicePlugin` + +In addition to the WalletConnect `SignClient`, the `init` method of `fcl-wc` returns a [`ServicePlugin`](#serviceplugin-spec) object. This object can be injected using the [FCL Plugin Registry](#pluginregistry) to add support for new service methods and their corresponding execution strategies (like `WC/RPC` for WalletConnect ). +A `discovery-service` `ServicePlugin` may also include additional opt-in wallets to offer your users through FCL Wallet Discovery. + +#### Configuration options + +Initialize WalletConnect `SignClient` and `FclWcServicePlugin` with the following configuration options: + +| Name | Type | Default | Description | +| ---------------------- | ---------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `projectId` | boolean **(required)** | null | A WalletConnect projectId for public relay server access. Your Project ID can be obtained from [WalletConnect Cloud Dashboard](https://cloud.walletconnect.com/app) | +| `metadata` | object | `{ }` | Optional dApp metadata to describe your application and define its appearance in a web browser. More details can be found [here](https://docs.walletconnect.com/2.0/swift/sign/dapp-usage) | +| `includeBaseWC` | boolean | false | Optional configuration to include a generic WalletConnect service in FCL Discovery (UI/API).
    :exclamation: BaseWC Service offers no deeplink support for mobile. | +| `wcRequestHook` | function | null | Optional function is called on all desktop WalletConnect client session proposals and signing requests. Use this to handle alerting user to check wallet for approval. | +| `pairingModalOverride` | function | null | Optional function called to allow override of included QRCodeModal. Function receives two arguments:
    1. Connection `uri` to display QR code or send to wallet to create pairing.
    2. Callback function to manually cancel the request. | +| `wallets` | array | `[ ]` | Optional list of WalletConnect `authn` services to include in FCL Wallet Discovery (UI/API).
    :exclamation: Only available for use on **`testnet`**. These services will be combined with wallets returned from [WalletConnect cloud registry API](https://cloud.walletconnect.com/) and sent to Discovery for display in UI and inclusion in API response. | +| `disableNotifications` | boolean | false | Optional flag to disable pending WalletConnect request notifications within the application's UI. | + +#### Returns + +| Name | Type | Description | +| ----------------------------------------- | --------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | +| [FclWcServicePlugin](#fclwcserviceplugin) | `ServicePlugin` | A `ServicePlugin` of type `discovery-service`. May also include optional `authn` services to offer through FCL Wallet Discovery (UI/API). | +| [client](#) | `SignClient` | An initialized WalletConnect [`SignClient`](https://docs.walletconnect.com/2.0/introduction/sign). | + +```js +const FclWcServicePlugin = { + name: "fcl-plugin-service-walletconnect", + f_type: "ServicePlugin", // the type of FCL plugin + type: "discovery-service", // the is a service sent to Discovery + services: [Service], // (optional) Generic, Cloud Registry and client injected WalletConnect services + serviceStrategy: {method: "WC/RPC", exec: execStrategy, // the method name and execution strategy for WalletConnect services +} +``` + +:exclamation: Setting FCL config `flow.network` to **`testnet`** or **`mainnet`** is required to use `fcl-wc` as it enables `"WC/RPC"` service strategy to request correct chain permissions. + +``` + + +config({ + "flow.network": "mainnet" +}) +``` + +See [FCL Configuration](./configure-fcl.md) for more information. + +### 4. Add FclWcServicePlugin to FCL Plugin Registry + +In addition to the WalletConnect `SignClient`, the `init` method of `fcl-wc` returns a [`ServicePlugin`](#serviceplugin-spec) object. This object can be injected into the FCL Plugin Registry to add FCL support for new service methods, (like WC/RPC for WalletConnect) and their corresponding execution strategies. + +#### Usage + +```js + + + +const { FclWcServicePlugin, client } = await init({ + projectId: WC_PROJECT_ID, // required + metadata: WC_APP_METADATA, // optional + includeBaseWC: false, // optional, default: false + wallets: [], // optional, default: [] + wcRequestHook: (wcRequestData) => { + // optional,default: null + handlePendingRequest(data); + }, + pairingModalOverride: (uri, rejectPairingRequest) => { + // optional,default: null + handlePendingPairingRequest(data); + }, +}); + +fcl.pluginRegistry.add(FclWcServicePlugin); +``` + +--- + +### ServicePlugin Spec + +| Key | Value Type | Description | +| ----------------- | ------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `name` | string | The name of the plugin. | +| `f_type` | string | The type of plugin (currently only supports `ServicePlugin` type). | +| `type` | string | The plugin subtype (currently only supports `discovery-service` type). | +| `services` | array | A list of services to add to FCL. | +| `serviceStrategy` | `{ method: string, exec: function }` | The method and corresponding strategy FCL uses to interact with the service. A service with the `service.method` property set to `"WC/RPC"` tells FCL to use the corresponding service strategy if it is supported by the dApp. | + +--- + +## Integrating With Wallet Discovery + +Knowing all the wallets available to users on a blockchain can be challenging. FCL's Discovery mechanism relieves much of the burden of integrating with Flow compatible wallets and let's developers focus on building their dApp and providing as many options as possible to their users. + +There are two ways an app can use [Wallet Discovery](./discovery.md): + +1. The UI version which can be configured for display via iFrame, Popup, or Tab. + +2. The API version which allows you to access authentication services directly in your code via `fcl.discovery.authn` method which we'll describe below. + +When using FCL Wallet Discovery for authentication, dApps are able to support FCL-compatible wallets on Flow without any custom integrations or changes needed to the dApp code. + +#### `discovery-service` ServicePlugin + +`FclWcServicePlugin` is a `ServicePlugin` of type `discovery-service`. `discovery-service` plugins may include additional authentication services to offer through FCL Wallet Discovery. + +Once a valid `discovery-service` plugin is registered, FCL shares client supported services with Discovery to add registered and injected wallets to the UI and API. + +To connect a Flow supported wallet using WalletConnect 2.0, users of your dApp will go through the authentication process and have the option to select their preferred wallet. + +:exclamation: Once a WalletConnect session is established and a `currentUser` is authenticated, FCL will handle client pairings and sessions during FCL `authn`, and initiate signing requests as part of `authz` using `fcl.mutate` and [`user-sign`](https://github.com/onflow/fcl-js/blob/master/docs/networks/user-signatures.mdx) using `fcl.signUserMessage`. + +### How to add your FCL compatible WalletConnect wallet to Discovery (UI/API) + +1. [Submit a PR](https://github.com/onflow/fcl-discovery/blob/master/data/services.json) to add your wallet to FCL Wallet Discovery `services.json` +2. Submit your FCL compatible wallet to [WalletConnect Cloud Registry](https://cloud.walletconnect.com/) +3. Add Wallet Service to `fcl-wc` init options. :exclamation: testnet only. + +FCL tells Wallet Discovery which services are supported by the client (installed extensions and `discovery-service` `ServicePlugins`) so only those supported will be shown in Discovery UI or returned via Discovery API. + +![Wallet Discovery UI](./images/wc-discovery.png) + +## Wallet Provider Spec + +### Implementation path + +| | | | +| :---: | :------------------------------------------------------------------------------------------------------------------------------------ | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **1** | Obtain a WalletConnect `projectId` | Register to receive a `projectId` from the [WalletConnect Cloud Registry](https://cloud.walletconnect.com/). | +| **2** | Conform to [FCL Wallet Provider Spec](https://github.com/onflow/fcl-js/blob/master/packages/fcl/src/wallet-provider-spec/draft-v4.md) | Compatible wallets must support `flow_authn`, `flow_authz`, and `flow_user_sign` methods and wrap data in the appropriate FCL Response type. Services returned with the `AuthnResponse` of `flow_authn` should set `service.endpoint` to corresponding methods.
    **ServiceType** `authz` : `flow_authz`
    **ServiceType** `user-signature` : `flow_user_sign` | +| **3** | Add wallet to WalletConnect Cloud Registry API **(optional)** | Submit your wallet to be included in the [WalletConnect Cloud Registry API and Explorer](https://explorer.walletconnect.com/) | +| **4** | Responses | All responses need to be wrapped in a [`PollingResponse`](https://github.com/onflow/fcl-js/blob/master/packages/fcl/src/wallet-provider-spec/draft-v4.md#pollingresponse) | + +#### Metadata requirements + +:exclamation: In order to correctly identify, improve pairing, and include deep link support for mobile, services using the `WC/RPC` method need to use the same universal link as their `uid` and `url` in Wallet metadata. +Wallets sourced from WalletConnect Cloud Registry automatically build the service from data and will set the `service.uid` to the universal link. + +```javascript + + +export let signClient: SignClient; + +export async function createSignClient() { + signClient = await SignClient.init({ + projectId: PROJECT_ID, + relayUrl: 'wss://relay.walletconnect.com', + metadata: { + name: 'Awesome Wallet', + description: 'Awesome Wallet with FCL Support for WalletConnect', + url: 'https://deeplink.awesome-wallet.com/', + icons: ['https://avatars.githubusercontent.com/u/37784886'], + }, + }); +} +``` + +## Next steps + +1. Read the [FCL Wallet Provider Spec](https://github.com/onflow/fcl-js/blob/master/packages/fcl/src/wallet-provider-spec/draft-v4.md). +2. Check out the a WalletConnect 2.0 [React POC Wallet](https://github.com/gregsantos/flow-walletconnect-v2-react-wallet) and [FCL Flow dApp](https://github.com/gregsantos/flow-walletconnect-v2-react-dapp) with support for WalletConnect v2.0. +3. Read and review the [WalletConnect 2.0 Docs](https://docs.walletconnect.com/2.0/), [examples and resources](https://docs.walletconnect.com/2.0/introduction/examples-and-resources). \ No newline at end of file diff --git a/static/markdown/tools/clients/flow-go-sdk/index.md b/static/markdown/tools/clients/flow-go-sdk/index.md new file mode 100644 index 0000000000..6945b77fd6 --- /dev/null +++ b/static/markdown/tools/clients/flow-go-sdk/index.md @@ -0,0 +1,1172 @@ +--- +title: Flow Go SDK +--- + + +
    + +## Overview + +This reference documents all the methods available in the SDK, and explains in detail how these methods work. +SDKs are open source, and you can use them according to the licence. + +The library client specifications can be found here: + +[](https://pkg.go.dev/github.com/onflow/flow-go-sdk/client) + +## Getting Started + +### Installing + +The recommended way to install Go Flow SDK is by using Go modules. + +If you already initialized your Go project, you can run the following command in your terminal: + +```sh +go get github.com/onflow/flow-go-sdk +``` + +It's usually good practice to pin your dependencies to a specific version. +Refer to the [SDK releases](https://github.com/onflow/flow-go-sdk/tags) page to identify the latest version. + +### Importing the Library + +After the library has been installed you can import it. + +```go +import "github.com/onflow/flow-go-sdk" +``` + +## Connect + +[](https://pkg.go.dev/github.com/onflow/flow-go-sdk/client#New) + +The Go SDK library uses HTTP or gRPC APIs to communicate with the access nodes and it must be configured with correct access node API URL. +The library provides default factories for connecting to Flow AN APIs and you can easily switch between HTTP or gRPC if you use the provided client interface. + +You can check more examples for creating clients in the examples: +**[](https://github.com/onflow/flow-go-sdk/blob/master/examples/http_grpc_clients/main.go)** + +Basic Example: + +```go +// common client interface +var flowClient client.Client + +// initialize an http emulator client +flowClient, err := http.NewClient(http.EmulatorHost) + +// initialize a gPRC emulator client +flowClient, err = grpc.NewClient(grpc.EmulatorHost) +``` + +You can also initialize an HTTP client or gRPC client directly which will offer you access to network specific options, +but be aware you won't be able to easily switch between those since they don't implement a common interface. This is only +advisable if the implementation needs the access to those advanced options. +Advanced Example: + +```go +// initialize http specific client +httpClient, err := http.NewHTTPClient(http.EMULATOR_URL) + +// initialize grpc specific client +grpcClient, err := grpc.NewGRPCClient( + grpc.EMULATOR_URL, + grpcOpts.WithTransportCredentials(insecure.NewCredentials()), +) +``` + +## Querying the Flow Network + +After you have established a connection with an access node, you can query the +Flow network to retrieve data about blocks, accounts, events and transactions. We will explore +how to retrieve each of these entities in the sections below. + +### Get Blocks + +[](https://pkg.go.dev/github.com/onflow/flow-go-sdk/client#Client.GetBlockByHeight) + +Query the network for block by id, height or get the latest block. + +📖 **Block ID** is SHA3-256 hash of the entire block payload. This hash is stored as an ID field on any block response object (ie. response from `GetLatestBlock`). + +📖 **Block height** expresses the height of the block on the chain. The latest block height increases by one for every valid block produced. + +#### Examples + +This example depicts ways to get the latest block as well as any other block by height or ID: + +**[](https://github.com/onflow/flow-go-sdk/blob/master/examples/get_blocks/main.go)** + +```go +func demo() { + ctx := context.Background() + flowClient := examples.NewFlowClient() + + // get the latest sealed block + isSealed := true + latestBlock, err := flowClient.GetLatestBlock(ctx, isSealed) + printBlock(latestBlock, err) + + // get the block by ID + blockID := latestBlock.ID.String() + blockByID, err := flowClient.GetBlockByID(ctx, flow.HexToID(blockID)) + printBlock(blockByID, err) + + // get block by height + blockByHeight, err := flowClient.GetBlockByHeight(ctx, 0) + printBlock(blockByHeight, err) +} + +func printBlock(block *flow.Block, err error) { + examples.Handle(err) + + fmt.Printf("\nID: %s\n", block.ID) + fmt.Printf("height: %d\n", block.Height) + fmt.Printf("timestamp: %s\n\n", block.Timestamp) +} +``` + +Result output: + +```bash +ID: 835dc83939141097aa4297aa6cf69fc600863e3b5f9241a0d7feac1868adfa4f +height: 10 +timestamp: 2021-10-06 15:06:07.105382 +0000 UTC + +ID: 835dc83939141097aa4297aa6cf69fc600863e3b5f9241a0d7feac1868adfa4f +height: 10 +timestamp: 2021-10-06 15:06:07.105382 +0000 UTC + +ID: 7bc42fe85d32ca513769a74f97f7e1a7bad6c9407f0d934c2aa645ef9cf613c7 +height: 0 +timestamp: 2018-12-19 22:32:30.000000042 +0000 UTC +``` + +### Get Account + +[](https://pkg.go.dev/github.com/onflow/flow-go-sdk/client#Client.GetAccount) + +Retrieve any account from Flow network's latest block or from a specified block height. +The `GetAccount` method is actually an alias for the get account at latest block method. + +📖 **Account address** is a unique account identifier. Be mindful about the `0x` prefix, you should use the prefix as a default representation but be careful and safely handle user inputs without the prefix. + +An account includes the following data: + +- Address: the account address. +- Balance: balance of the account. +- Contracts: list of contracts deployed to the account. +- Keys: list of keys associated with the account. + +#### Examples + +Example depicts ways to get an account at the latest block and at a specific block height: + +**[](https://github.com/onflow/flow-go-sdk/blob/master/examples/get_accounts/main.go)** + +```go +func demo() { + ctx := context.Background() + flowClient := examples.NewFlowClient() + + // get account from the latest block + address := flow.HexToAddress("f8d6e0586b0a20c7") + account, err := flowClient.GetAccount(ctx, address) + printAccount(account, err) + + // get account from the block by height 0 + account, err = flowClient.GetAccountAtBlockHeight(ctx, address, 0) + printAccount(account, err) +} + +func printAccount(account *flow.Account, err error) { + examples.Handle(err) + + fmt.Printf("\nAddress: %s", account.Address.String()) + fmt.Printf("\nBalance: %d", account.Balance) + fmt.Printf("\nContracts: %d", len(account.Contracts)) + fmt.Printf("\nKeys: %d\n", len(account.Keys)) +} +``` + +Result output: + +```bash +Address: f8d6e0586b0a20c7 +Balance: 999999999999600000 +Contracts: 2 +Keys: 1 + +Address: f8d6e0586b0a20c7 +Balance: 999999999999600000 +Contracts: 2 +Keys: 1 +``` + +### Get Transactions + +[](https://pkg.go.dev/github.com/onflow/flow-go-sdk/client#Client.GetTransaction) + +Retrieve transactions from the network by providing a transaction ID. After a transaction has been submitted, you can also get the transaction result to check the status. + +📖 **Transaction ID** is a hash of the encoded transaction payload and can be calculated before submitting the transaction to the network. + +⚠️ The transaction ID provided must be from the current spork. + +📖 **Transaction status** represents the state of transaction in the blockchain. Status can change until it is sealed. + +| Status | Final | Description | +| --------- | ----- | ------------------------------------------------------------------------ | +| UNKNOWN | ❌ | The transaction has not yet been seen by the network | +| PENDING | ❌ | The transaction has not yet been included in a block | +| FINALIZED | ❌ | The transaction has been included in a block | +| EXECUTED | ❌ | The transaction has been executed but the result has not yet been sealed | +| SEALED | ✅ | The transaction has been executed and the result is sealed in a block | +| EXPIRED | ✅ | The transaction reference block is outdated before being executed | + +**[](https://github.com/onflow/flow-go-sdk/blob/master/examples/get_transactions/main.go)** + +```go +func demo(txID flow.Identifier) { + ctx := context.Background() + flowClient := examples.NewFlowClient() + + tx, err := flowClient.GetTransaction(ctx, txID) + printTransaction(tx, err) + + txr, err := flowClient.GetTransactionResult(ctx, txID) + printTransactionResult(txr, err) +} + +func printTransaction(tx *flow.Transaction, err error) { + examples.Handle(err) + + fmt.Printf("\nID: %s", tx.ID().String()) + fmt.Printf("\nPayer: %s", tx.Payer.String()) + fmt.Printf("\nProposer: %s", tx.ProposalKey.Address.String()) + fmt.Printf("\nAuthorizers: %s", tx.Authorizers) +} + +func printTransactionResult(txr *flow.TransactionResult, err error) { + examples.Handle(err) + + fmt.Printf("\nStatus: %s", txr.Status.String()) + fmt.Printf("\nError: %v", txr.Error) +} +``` + +Example output: + +```bash +ID: fb1272c57cdad79acf2fcf37576d82bf760e3008de66aa32a900c8cd16174e1c +Payer: f8d6e0586b0a20c7 +Proposer: f8d6e0586b0a20c7 +Authorizers: [] +Status: SEALED +Error: +``` + +### Get Events + +[](https://pkg.go.dev/github.com/onflow/flow-go-sdk/client#Client.GetEventsForBlockIDs) + +Retrieve events by a given type in a specified block height range or through a list of block IDs. + +📖 **Event type** is a string that follow a standard format: + +``` +A.{contract address}.{contract name}.{event name} +``` + +Please read more about [events in the documentation](../../../build/core-contracts/03-flow-token.md). The exception to this standard are +core events, and you should read more about them in [this document](https://cadence-lang.org/docs/language/core-events). + +📖 **Block height range** expresses the height of the start and end block in the chain. + +#### Examples + +Example depicts ways to get events within block range or by block IDs: + +**[](https://github.com/onflow/flow-go-sdk/blob/master/examples/get_events/main.go)** + +```go +func demo(deployedContract *flow.Account, runScriptTx *flow.Transaction) { + ctx := context.Background() + flowClient := examples.NewFlowClient() + + // Query for account creation events by type + result, err := flowClient.GetEventsForHeightRange(ctx, "flow.AccountCreated", 0, 30) + printEvents(result, err) + + // Query for our custom event by type + customType := fmt.Sprintf("AC.%s.EventDemo.EventDemo.Add", deployedContract.Address.Hex()) + result, err = flowClient.GetEventsForHeightRange(ctx, customType, 0, 10) + printEvents(result, err) + + // Get events directly from transaction result + txResult, err := flowClient.GetTransactionResult(ctx, runScriptTx.ID()) + examples.Handle(err) + printEvent(txResult.Events) +} + +func printEvents(result []client.BlockEvents, err error) { + examples.Handle(err) + + for _, block := range result { + printEvent(block.Events) + } +} + +func printEvent(events []flow.Event) { + for _, event := range events { + fmt.Printf("\n\nType: %s", event.Type) + fmt.Printf("\nValues: %v", event.Value) + fmt.Printf("\nTransaction ID: %s", event.TransactionID) + } +} +``` + +Example output: + +```bash +Type: flow.AccountCreated +Values: flow.AccountCreated(address: 0xfd43f9148d4b725d) +Transaction ID: ba9d53c8dcb0f9c2f854f93da8467a22d053eab0c540bde0b9ca2f7ad95eb78e + +Type: flow.AccountCreated +Values: flow.AccountCreated(address: 0xeb179c27144f783c) +Transaction ID: 8ab7bfef3de1cf8b2ffb36559446100bf4129a9aa88d6bc59f72a467acf0c801 + +... + +Type: A.eb179c27144f783c.EventDemo.Add +Values: A.eb179c27144f783c.EventDemo.Add(x: 2, y: 3, sum: 5) +Transaction ID: f3a2e33687ad23b0e02644ebbdcd74a7cd8ea7214065410a8007811d0bcbd353 +``` + +### Get Collections + +[](https://pkg.go.dev/github.com/onflow/flow-go-sdk/client#Client.GetCollection) + +Retrieve a batch of transactions that have been included in the same block, known as **_collections_**. +Collections are used to improve consensus throughput by increasing the number of transactions per block and they act as a link between a block and a transaction. + +📖 **Collection ID** is SHA3-256 hash of the collection payload. + +Example retrieving a collection: + +```go +func demo(exampleCollectionID flow.Identifier) { + ctx := context.Background() + flowClient := examples.NewFlowClient() + + // get collection by ID + collection, err := flowClient.GetCollection(ctx, exampleCollectionID) + printCollection(collection, err) +} + +func printCollection(collection *flow.Collection, err error) { + examples.Handle(err) + + fmt.Printf("\nID: %s", collection.ID().String()) + fmt.Printf("\nTransactions: %s", collection.TransactionIDs) +} +``` + +Example output: + +```bash +ID: 3d7b8037381f2497d83f2f9e09422c036aae2a59d01a7693fb6003b4d0bc3595 +Transactions: [cf1184e3de4bd9a7232ca3d0b9dd2cfbf96c97888298b81a05c086451fa52ec1] +``` + +### Execute Scripts + +[](https://pkg.go.dev/github.com/onflow/flow-go-sdk/client#Client.ExecuteScriptAtLatestBlock) + +Scripts allow you to write arbitrary non-mutating Cadence code on the Flow blockchain and return data. You can learn more about [Cadence and scripts here](https://cadence-lang.org/docs/language), but we are now only interested in executing the script code and getting back the data. + +We can execute a script using the latest state of the Flow blockchain or we can choose to execute the script at a specific time in history defined by a block height or block ID. + +📖 **Block ID** is SHA3-256 hash of the entire block payload, but you can get that value from the block response properties. + +📖 **Block height** expresses the height of the block in the chain. + +**[](https://github.com/onflow/flow-go-sdk/blob/master/examples/execute_script/main.go)** + +```go +func demo() { + ctx := context.Background() + flowClient := examples.NewFlowClient() + + script := []byte(` + access(all) fun main(a: Int): Int { + return a + 10 + } + `) + args := []cadence.Value{ cadence.NewInt(5) } + value, err := flowClient.ExecuteScriptAtLatestBlock(ctx, script, args) + + examples.Handle(err) + fmt.Printf("\nValue: %s", value.String()) + + complexScript := []byte(` + access(all) struct User { + access(all) var balance: UFix64 + access(all) var address: Address + access(all) var name: String + + init(name: String, address: Address, balance: UFix64) { + self.name = name + self.address = address + self.balance = balance + } + } + + access(all) fun main(name: String): User { + return User( + name: name, + address: 0x1, + balance: 10.0 + ) + } + `) + args = []cadence.Value{ cadence.NewString("Dete") } + value, err = flowClient.ExecuteScriptAtLatestBlock(ctx, complexScript, args) + printComplexScript(value, err) +} + +type User struct { + balance uint64 + address flow.Address + name string +} + +func printComplexScript(value cadence.Value, err error) { + examples.Handle(err) + fmt.Printf("\nString value: %s", value.String()) + + s := value.(cadence.Struct) + u := User{ + balance: s.Fields[0].ToGoValue().(uint64), + address: s.Fields[1].ToGoValue().([flow.AddressLength]byte), + name: s.Fields[2].ToGoValue().(string), + } + + fmt.Printf("\nName: %s", u.name) + fmt.Printf("\nAddress: %s", u.address.String()) + fmt.Printf("\nBalance: %d", u.balance) +} +``` + +Example output: + +```bash +Value: 15 +String value: s.34a17571e1505cf6770e6ef16ca387e345e9d54d71909f23a7ec0d671cd2faf5.User(balance: 10.00000000, address: 0x1, name: "Dete") +Name: Dete +Address: 0000000000000001 +Balance: 1000000000 +``` + +## Mutate Flow Network + +Flow, like most blockchains, allows anybody to submit a transaction that mutates the shared global chain state. A transaction is an object that holds a payload, which describes the state mutation, and one or more authorizations that permit the transaction to mutate the state owned by specific accounts. + +Transaction data is composed and signed with help of the SDK. The signed payload of transaction then gets submitted to the access node API. If a transaction is invalid or the correct number of authorizing signatures are not provided, it gets rejected. + +Executing a transaction requires couple of steps: + +- [Building transaction](#build-the-transaction). +- [Signing transaction](#sign-transactions). +- [Sending transaction](#send-transactions). + +## Transactions + +A transaction is nothing more than a signed set of data that includes script code which are instructions on how to mutate the network state and properties that define and limit it's execution. All these properties are explained bellow. + +📖 **Script** field is the portion of the transaction that describes the state mutation logic. On Flow, transaction logic is written in [Cadence](https://cadence-lang.org/docs). Here is an example transaction script: + +``` +transaction(greeting: String) { + execute { + log(greeting.concat(", World!")) + } +} +``` + +📖 **Arguments**. A transaction can accept zero or more arguments that are passed into the Cadence script. The arguments on the transaction must match the number and order declared in the Cadence script. Sample script from above accepts a single `String` argument. + +📖 **[Proposal key](../../../build/basics/transactions.md#proposal-key)** must be provided to act as a sequence number and prevent reply and other potential attacks. + +Each account key maintains a separate transaction sequence counter; the key that lends its sequence number to a transaction is called the proposal key. + +A proposal key contains three fields: + +- Account address +- Key index +- Sequence number + +A transaction is only valid if its declared sequence number matches the current on-chain sequence number for that key. The sequence number increments by one after the transaction is executed. + +📖 **[Payer](../../../build/basics/transactions.md#signer-roles)** is the account that pays the fees for the transaction. A transaction must specify exactly one payer. The payer is only responsible for paying the network and gas fees; the transaction is not authorized to access resources or code stored in the payer account. + +📖 **[Authorizers](../../../build/basics/transactions.md#signer-roles)** are accounts that authorize a transaction to read and mutate their resources. A transaction can specify zero or more authorizers, depending on how many accounts the transaction needs to access. + +The number of authorizers on the transaction must match the number of &Account parameters declared in the prepare statement of the Cadence script. + +Example transaction with multiple authorizers: + +``` +transaction { + prepare(authorizer1: &Account, authorizer2: &Account) { } +} +``` + +#### Gas Limit + +📖 **Gas limit** is the limit on the amount of computation a transaction requires, and it will abort if it exceeds its gas limit. +Cadence uses metering to measure the number of operations per transaction. You can read more about it in the [Cadence documentation](https://cadence-lang.org/docs). + +The gas limit depends on the complexity of the transaction script. Until dedicated gas estimation tooling exists, it's best to use the emulator to test complex transactions and determine a safe limit. + +#### Reference Block + +📖 **Reference block** specifies an expiration window (measured in blocks) during which a transaction is considered valid by the network. +A transaction will be rejected if it is submitted past its expiry block. Flow calculates transaction expiry using the _reference block_ field on a transaction. +A transaction expires after `600` blocks are committed on top of the reference block, which takes about 10 minutes at average Mainnet block rates. + +### Build Transactions + +[](https://pkg.go.dev/github.com/onflow/flow-go-sdk#Transaction) + +Building a transaction involves setting the required properties explained above and producing a transaction object. + +Here we define a simple transaction script that will be used to execute on the network and serve as a good learning example. + +``` +transaction(greeting: String) { + + let guest: Address + + prepare(authorizer: &Account) { + self.guest = authorizer.address + } + + execute { + log(greeting.concat(",").concat(self.guest.toString())) + } +} +``` + +**[](https://github.com/onflow/flow-go-sdk/blob/master/examples/transaction_signing/single_party/main.go)** + +```go +import ( + "context" + "os" + "github.com/onflow/flow-go-sdk" + "github.com/onflow/flow-go-sdk/client" +) + +func main() { + + greeting, err := os.ReadFile("Greeting2.cdc") + if err != nil { + panic("failed to load Cadence script") + } + + proposerAddress := flow.HexToAddress("9a0766d93b6608b7") + proposerKeyIndex := 3 + + payerAddress := flow.HexToAddress("631e88ae7f1d7c20") + authorizerAddress := flow.HexToAddress("7aad92e5a0715d21") + + var accessAPIHost string + + // Establish a connection with an access node + flowClient := examples.NewFlowClient() + + // Get the latest sealed block to use as a reference block + latestBlock, err := flowClient.GetLatestBlockHeader(context.Background(), true) + if err != nil { + panic("failed to fetch latest block") + } + + // Get the latest account info for this address + proposerAccount, err := flowClient.GetAccountAtLatestBlock(context.Background(), proposerAddress) + if err != nil { + panic("failed to fetch proposer account") + } + + // Get the latest sequence number for this key + sequenceNumber := proposerAccount.Keys[proposerKeyIndex].SequenceNumber + + tx := flow.NewTransaction(). + SetScript(greeting). + SetComputeLimit(100). + SetReferenceBlockID(latestBlock.ID). + SetProposalKey(proposerAddress, proposerKeyIndex, sequenceNumber). + SetPayer(payerAddress). + AddAuthorizer(authorizerAddress) + + // Add arguments last + + hello := cadence.NewString("Hello") + + err = tx.AddArgument(hello) + if err != nil { + panic("invalid argument") + } +} +``` + +After you have successfully [built a transaction](#build-the-transaction) the next step in the process is to sign it. + +### Sign Transactions + +[](https://pkg.go.dev/github.com/onflow/flow-go-sdk#Transaction.SignEnvelope) + +Flow introduces new concepts that allow for more flexibility when creating and signing transactions. +Before trying the examples below, we recommend that you read through the [transaction signature documentation](../../../build/basics/transactions.md. + +After you have successfully [built a transaction](#build-the-transaction) the next step in the process is to sign it. Flow transactions have envelope and payload signatures, and you should learn about each in the [signature documentation](../../../build/basics/transactions.md). + +Quick example of building a transaction: + +```go +import ( + "github.com/onflow/flow-go-sdk" + "github.com/onflow/flow-go-sdk/crypto" +) + +var ( + myAddress flow.Address + myAccountKey flow.AccountKey + myPrivateKey crypto.PrivateKey +) + +tx := flow.NewTransaction(). + SetScript([]byte("transaction { execute { log(\"Hello, World!\") } }")). + SetComputeLimit(100). + SetProposalKey(myAddress, myAccountKey.Index, myAccountKey.SequenceNumber). + SetPayer(myAddress) +``` + +Transaction signing is done through the `crypto.Signer` interface. The simplest (and least secure) implementation of `crypto.Signer` is `crypto.InMemorySigner`. + +Signatures can be generated more securely using keys stored in a hardware device such as an [HSM](https://en.wikipedia.org/wiki/Hardware_security_module). The `crypto.Signer` interface is intended to be flexible enough to support a variety of signer implementations and is not limited to in-memory implementations. + +Simple signature example: + +```go +// construct a signer from your private key and configured hash algorithm +mySigner, err := crypto.NewInMemorySigner(myPrivateKey, myAccountKey.HashAlgo) +if err != nil { + panic("failed to create a signer") +} + +err = tx.SignEnvelope(myAddress, myAccountKey.Index, mySigner) +if err != nil { + panic("failed to sign transaction") +} +``` + +Flow supports great flexibility when it comes to transaction signing, we can define multiple authorizers (multi-sig transactions) and have different payer account than proposer. We will explore advanced signing scenarios bellow. + +### [Single party, single signature](../../../build/basics/transactions.md#single-party-single-signature) + +- Proposer, payer and authorizer are the same account (`0x01`). +- Only the envelope must be signed. +- Proposal key must have full signing weight. + +| Account | Key ID | Weight | +| ------- | ------ | ------ | +| `0x01` | 1 | 1000 | + +**[](https://github.com/onflow/flow-go-sdk/tree/master/examples#single-party-single-signature)** + +```go +account1, _ := c.GetAccount(ctx, flow.HexToAddress("01")) + +key1 := account1.Keys[0] + +// create signer from securely-stored private key +key1Signer := getSignerForKey1() + +referenceBlock, _ := flow.GetLatestBlock(ctx, true) +tx := flow.NewTransaction(). + SetScript([]byte(` + transaction { + prepare(signer: &Account) { log(signer.address) } + } + `)). + SetComputeLimit(100). + SetProposalKey(account1.Address, key1.Index, key1.SequenceNumber). + SetReferenceBlockID(referenceBlock.ID). + SetPayer(account1.Address). + AddAuthorizer(account1.Address) + +// account 1 signs the envelope with key 1 +err := tx.SignEnvelope(account1.Address, key1.Index, key1Signer) +``` + +### [Single party, multiple signatures](../../../build/basics/transactions.md#single-party-multiple-signatures) + +- Proposer, payer and authorizer are the same account (`0x01`). +- Only the envelope must be signed. +- Each key has weight 500, so two signatures are required. + +| Account | Key ID | Weight | +| ------- | ------ | ------ | +| `0x01` | 1 | 500 | +| `0x01` | 2 | 500 | + +**[](https://github.com/onflow/flow-go-sdk/tree/master/examples#single-party-multiple-signatures)** + +```go +account1, _ := c.GetAccount(ctx, flow.HexToAddress("01")) + +key1 := account1.Keys[0] +key2 := account1.Keys[1] + +// create signers from securely-stored private keys +key1Signer := getSignerForKey1() +key2Signer := getSignerForKey2() + +referenceBlock, _ := flow.GetLatestBlock(ctx, true) +tx := flow.NewTransaction(). + SetScript([]byte(` + transaction { + prepare(signer: &Account) { log(signer.address) } + } + `)). + SetComputeLimit(100). + SetProposalKey(account1.Address, key1.Index, key1.SequenceNumber). + SetReferenceBlockID(referenceBlock.ID). + SetPayer(account1.Address). + AddAuthorizer(account1.Address) + +// account 1 signs the envelope with key 1 +err := tx.SignEnvelope(account1.Address, key1.Index, key1Signer) + +// account 1 signs the envelope with key 2 +err = tx.SignEnvelope(account1.Address, key2.Index, key2Signer) +``` + +### [Multiple parties](../../../build/basics/transactions.md#multiple-parties) + +- Proposer and authorizer are the same account (`0x01`). +- Payer is a separate account (`0x02`). +- Account `0x01` signs the payload. +- Account `0x02` signs the envelope. + - Account `0x02` must sign last since it is the payer. + +| Account | Key ID | Weight | +| ------- | ------ | ------ | +| `0x01` | 1 | 1000 | +| `0x02` | 3 | 1000 | + +**[](https://github.com/onflow/flow-go-sdk/tree/master/examples#multiple-parties)** + +```go +account1, _ := c.GetAccount(ctx, flow.HexToAddress("01")) +account2, _ := c.GetAccount(ctx, flow.HexToAddress("02")) + +key1 := account1.Keys[0] +key3 := account2.Keys[0] + +// create signers from securely-stored private keys +key1Signer := getSignerForKey1() +key3Signer := getSignerForKey3() + +referenceBlock, _ := flow.GetLatestBlock(ctx, true) +tx := flow.NewTransaction(). + SetScript([]byte(` + transaction { + prepare(signer: &Account) { log(signer.address) } + } + `)). + SetComputeLimit(100). + SetProposalKey(account1.Address, key1.Index, key1.SequenceNumber). + SetReferenceBlockID(referenceBlock.ID). + SetPayer(account2.Address). + AddAuthorizer(account1.Address) + +// account 1 signs the payload with key 1 +err := tx.SignPayload(account1.Address, key1.Index, key1Signer) + +// account 2 signs the envelope with key 3 +// note: payer always signs last +err = tx.SignEnvelope(account2.Address, key3.Index, key3Signer) +``` + +### [Multiple parties, two authorizers](../../../build/basics/transactions.md#multiple-parties) + +- Proposer and authorizer are the same account (`0x01`). +- Payer is a separate account (`0x02`). +- Account `0x01` signs the payload. +- Account `0x02` signs the envelope. + - Account `0x02` must sign last since it is the payer. +- Account `0x02` is also an authorizer to show how to include two `&Account` objects into an transaction + +| Account | Key ID | Weight | +| ------- | ------ | ------ | +| `0x01` | 1 | 1000 | +| `0x02` | 3 | 1000 | + +**[](https://github.com/onflow/flow-go-sdk/tree/master/examples#multiple-parties-two-authorizers)** + +```go +account1, _ := c.GetAccount(ctx, flow.HexToAddress("01")) +account2, _ := c.GetAccount(ctx, flow.HexToAddress("02")) + +key1 := account1.Keys[0] +key3 := account2.Keys[0] + +// create signers from securely-stored private keys +key1Signer := getSignerForKey1() +key3Signer := getSignerForKey3() + +referenceBlock, _ := flow.GetLatestBlock(ctx, true) +tx := flow.NewTransaction(). + SetScript([]byte(` + transaction { + prepare(signer1: &Account, signer2: &Account) { + log(signer.address) + log(signer2.address) + } + } + `)). + SetComputeLimit(100). + SetProposalKey(account1.Address, key1.Index, key1.SequenceNumber). + SetReferenceBlockID(referenceBlock.ID). + SetPayer(account2.Address). + AddAuthorizer(account1.Address). + AddAuthorizer(account2.Address) + +// account 1 signs the payload with key 1 +err := tx.SignPayload(account1.Address, key1.Index, key1Signer) + +// account 2 signs the envelope with key 3 +// note: payer always signs last +err = tx.SignEnvelope(account2.Address, key3.Index, key3Signer) +``` + +### [Multiple parties, multiple signatures](../../../build/basics/transactions.md#multiple-parties) + +- Proposer and authorizer are the same account (`0x01`). +- Payer is a separate account (`0x02`). +- Account `0x01` signs the payload. +- Account `0x02` signs the envelope. + - Account `0x02` must sign last since it is the payer. +- Both accounts must sign twice (once with each of their keys). + +| Account | Key ID | Weight | +| ------- | ------ | ------ | +| `0x01` | 1 | 500 | +| `0x01` | 2 | 500 | +| `0x02` | 3 | 500 | +| `0x02` | 4 | 500 | + +**[](https://github.com/onflow/flow-go-sdk/tree/master/examples#multiple-parties-multiple-signatures)** + +```go +account1, _ := c.GetAccount(ctx, flow.HexToAddress("01")) +account2, _ := c.GetAccount(ctx, flow.HexToAddress("02")) + +key1 := account1.Keys[0] +key2 := account1.Keys[1] +key3 := account2.Keys[0] +key4 := account2.Keys[1] + +// create signers from securely-stored private keys +key1Signer := getSignerForKey1() +key2Signer := getSignerForKey1() +key3Signer := getSignerForKey3() +key4Signer := getSignerForKey4() + +referenceBlock, _ := flow.GetLatestBlock(ctx, true) +tx := flow.NewTransaction(). + SetScript([]byte(` + transaction { + prepare(signer: &Account) { log(signer.address) } + } + `)). + SetComputeLimit(100). + SetProposalKey(account1.Address, key1.Index, key1.SequenceNumber). + SetReferenceBlockID(referenceBlock.ID). + SetPayer(account2.Address). + AddAuthorizer(account1.Address) + +// account 1 signs the payload with key 1 +err := tx.SignPayload(account1.Address, key1.Index, key1Signer) + +// account 1 signs the payload with key 2 +err = tx.SignPayload(account1.Address, key2.Index, key2Signer) + +// account 2 signs the envelope with key 3 +// note: payer always signs last +err = tx.SignEnvelope(account2.Address, key3.Index, key3Signer) + +// account 2 signs the envelope with key 4 +// note: payer always signs last +err = tx.SignEnvelope(account2.Address, key4.Index, key4Signer) +``` + +### Send Transactions + +[](https://pkg.go.dev/github.com/onflow/flow-go-sdk/client#Client.SendTransaction) + +After a transaction has been [built](#build-the-transaction) and [signed](#sign-transactions), it can be sent to the Flow blockchain where it will be executed. If sending was successful you can then [retrieve the transaction result](#get-transactions). + +**[](https://github.com/onflow/flow-go-sdk/blob/master/examples/send_transactions/main.go)** + +```go +func demo(tx *flow.Transaction) { + ctx := context.Background() + flowClient := examples.NewFlowClient() + + err := flowClient.SendTransaction(ctx, *tx) + if err != nil { + fmt.Println("error sending transaction", err) + } +} +``` + +### Create Accounts + +[](https://pkg.go.dev/github.com/onflow/flow-go-sdk/templates#CreateAccount) + +On Flow, account creation happens inside a transaction. Because the network allows for a many-to-many relationship between public keys and accounts, it's not possible to derive a new account address from a public key offline. + +The Flow VM uses a deterministic address generation algorithm to assign account addresses on chain. You can find more details about address generation in the [accounts & keys documentation](../../../build/basics/accounts.md). + +#### Public Key + +Flow uses ECDSA key pairs to control access to user accounts. Each key pair can be used in combination with the SHA2-256 or SHA3-256 hashing algorithms. + +⚠️ You'll need to authorize at least one public key to control your new account. + +Flow represents ECDSA public keys in raw form without additional metadata. Each key is a single byte slice containing a concatenation of its X and Y components in big-endian byte form. + +A Flow account can contain zero (not possible to control) or more public keys, referred to as account keys. Read more about [accounts in the documentation](../../../build/basics/accounts.md). + +An account key contains the following data: + +- Raw public key (described above) +- Signature algorithm +- Hash algorithm +- Weight (integer between 0-1000) + +Account creation happens inside a transaction, which means that somebody must pay to submit that transaction to the network. We'll call this person the account creator. Make sure you have read [sending a transaction section](#send-transactions) first. + +```go +var ( + creatorAddress flow.Address + creatorAccountKey *flow.AccountKey + creatorSigner crypto.Signer +) + +var accessAPIHost string + +// Establish a connection with an access node +flowClient := examples.NewFlowClient() + +// Use the templates package to create a new account creation transaction +tx := templates.CreateAccount([]*flow.AccountKey{accountKey}, nil, creatorAddress) + +// Set the transaction payer and proposal key +tx.SetPayer(creatorAddress) +tx.SetProposalKey( + creatorAddress, + creatorAccountKey.Index, + creatorAccountKey.SequenceNumber, +) + +// Get the latest sealed block to use as a reference block +latestBlock, err := flowClient.GetLatestBlockHeader(context.Background(), true) +if err != nil { + panic("failed to fetch latest block") +} + +tx.SetReferenceBlockID(latestBlock.ID) + +// Sign and submit the transaction +err = tx.SignEnvelope(creatorAddress, creatorAccountKey.Index, creatorSigner) +if err != nil { + panic("failed to sign transaction envelope") +} + +err = flowClient.SendTransaction(context.Background(), *tx) +if err != nil { + panic("failed to send transaction to network") +} +``` + +After the account creation transaction has been submitted you can retrieve the new account address by [getting the transaction result](#get-transactions). + +The new account address will be emitted in a system-level `flow.AccountCreated` event. + +```go +result, err := flowClient.GetTransactionResult(ctx, tx.ID()) +if err != nil { + panic("failed to get transaction result") +} + +var newAddress flow.Address + +if result.Status != flow.TransactionStatusSealed { + panic("address not known until transaction is sealed") +} + +for _, event := range result.Events { + if event.Type == flow.EventAccountCreated { + newAddress = flow.AccountCreatedEvent(event).Address() + break + } +} +``` + +### Generate Keys + +[](../../../build/basics/accounts.md#signature-and-hash-algorithms) + +Flow uses [ECDSA](https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm) signatures to control access to user accounts. Each key pair can be used in combination with the `SHA2-256` or `SHA3-256` hashing algorithms. + +Here's how to generate an ECDSA private key for the P-256 (secp256r1) curve. + +```go +import "github.com/onflow/flow-go-sdk/crypto" + +// deterministic seed phrase +// note: this is only an example, please use a secure random generator for the key seed +seed := []byte("elephant ears space cowboy octopus rodeo potato cannon pineapple") + +privateKey, err := crypto.GeneratePrivateKey(crypto.ECDSA_P256, seed) + +// the private key can then be encoded as bytes (i.e. for storage) +encPrivateKey := privateKey.Encode() +// the private key has an accompanying public key +publicKey := privateKey.PublicKey() +``` + +The example above uses an ECDSA key pair on the P-256 (secp256r1) elliptic curve. Flow also supports the secp256k1 curve used by Bitcoin and Ethereum. Read more about [supported algorithms here](../../../build/basics/accounts.md#signature-and-hash-algorithms). + +### Transfering Flow + +This is an example of how to construct a FLOW token transfer transaction +with the Flow Go SDK. + +## Cadence Script + +The following Cadence script will transfer FLOW tokens from a sender +to a recipient. + +_Note: this transaction is only compatible with Flow Mainnet._ + +```cadence +// This transaction is a template for a transaction that +// could be used by anyone to send tokens to another account +// that has been set up to receive tokens. +// +// The withdraw amount and the account from getAccount +// would be the parameters to the transaction + +import "FungibleToken" +import "FlowToken" + +transaction(amount: UFix64, to: Address) { + + // The Vault resource that holds the tokens that are being transferred + let sentVault: @{FungibleToken.Vault} + + prepare(signer: auth(BorrowValue) &Account) { + + // Get a reference to the signer's stored vault + let vaultRef = signer.storage.borrow(from: /storage/flowTokenVault) + ?? panic("Could not borrow reference to the owner's Vault!") + + // Withdraw tokens from the signer's stored vault + self.sentVault <- vaultRef.withdraw(amount: amount) + } + + execute { + + // Get a reference to the recipient's Receiver + let receiverRef = getAccount(to) + .capabilities.borrow<&{FungibleToken.Receiver}>(/public/flowTokenReceiver) + ?? panic("Could not borrow receiver reference to the recipient's Vault") + + // Deposit the withdrawn tokens in the recipient's receiver + receiverRef.deposit(from: <-self.sentVault) + } +} +``` + +## Build the Transaction + +```go +import ( + "github.com/onflow/cadence" + "github.com/onflow/flow-go-sdk" +) + +// Replace with script above +const transferScript string = TOKEN_TRANSFER_CADENCE_SCRIPT + +var ( + senderAddress flow.Address + senderAccountKey flow.AccountKey + senderPrivateKey crypto.PrivateKey +) + +func main() { + tx := flow.NewTransaction(). + SetScript([]byte(transferScript)). + SetComputeLimit(100). + SetPayer(senderAddress). + SetAuthorizer(senderAddress). + SetProposalKey(senderAddress, senderAccountKey.Index, senderAccountKey.SequenceNumber) + + amount, err := cadence.NewUFix64("123.4") + if err != nil { + panic(err) + } + + recipient := cadence.NewAddress(flow.HexToAddress("0xabc...")) + + err = tx.AddArgument(amount) + if err != nil { + panic(err) + } + + err = tx.AddArgument(recipient) + if err != nil { + panic(err) + } +} +``` \ No newline at end of file diff --git a/static/markdown/tools/clients/flow-go-sdk/migration-v0.25.0.md b/static/markdown/tools/clients/flow-go-sdk/migration-v0.25.0.md new file mode 100644 index 0000000000..25445c489c --- /dev/null +++ b/static/markdown/tools/clients/flow-go-sdk/migration-v0.25.0.md @@ -0,0 +1,67 @@ +# Migration Guide v0.25.0 + +The Go SDK version 0.25.0 introduced breaking changes in the API and package naming. +Changes were required to make the implementation of the new HTTP access node API available. + +We will list all the changes and provide examples on how to migrate. + +- **Renamed package: client -> access:** the `client` package was renamed to `access` +which now includes both `grpc` package containing previously only gRPC implementation and +also `http` package containing the new HTTP API implementation. +- **Removed package: convert:** the `convert` package was removed and all its functions were moved +to each of the corresponding `grpc` or `http` packages. The methods were also changed to not be exported, +so you can no longer use them outside the `convert` package. +- **New clients:** new clients were added each implementing the functions from the client interface +and exposing a factory for creating them. +- **New Client Interface**: new client interface was created which is now network agnostic, meaning it +doesn't any more expose additional options in the API that were used to pass gRPC specific options. You can +still pass those options but you must use the network specific client as shown in the example bellow. +The interface also changed some functions: + - `GetCollectionByID` renamed to `GetCollection` + - `Close() error` was added + +### Migration + +#### Creating a Client +Creating a client for communicating with the access node has changed since it's now possible +to pick and choose between HTTP and gRPC communication protocols. + +*Previous versions:* +```go +// initialize a gRPC emulator client +flowClient, err := client.New("127.0.0.1:3569", grpc.WithInsecure()) +``` + +*Version 0.25.0*: +```go +// common client interface +var flowClient access.Client + +// initialize an http emulator client +flowClient, err := http.NewClient(http.EmulatorHost) + +// initialize a gPRC emulator client +flowClient, err = grpc.NewClient(grpc.EmulatorHost) +``` + +#### Using the gRPC Client with Options +Using the client is in most cases the same except for the advance case of passing additional +options to the gRPC client which is no longer possible in the base client, you must use a +network specific client as shown in the advanced example: + +*Previous versions:* +```go +// initialize a gRPC emulator client +flowClient, err := client.New("127.0.0.1:3569", grpc.WithInsecure()) +latestBlock, err := flowClient.GetLatestBlock(ctx, true, MaxCallSendMsgSize(100)) +``` + +*Version 0.25.0:* +```go +// initialize a grpc network specific client +flowClient, err := NewBaseClient( + grpc.EmulatorHost, + grpc.WithTransportCredentials(insecure.NewCredentials()), +) +latestBlock, err := flowClient.GetLatestBlock(ctx, true, MaxCallSendMsgSize(100)) +``` \ No newline at end of file diff --git a/static/markdown/tools/clients/index.md b/static/markdown/tools/clients/index.md new file mode 100644 index 0000000000..cdc7a902e8 --- /dev/null +++ b/static/markdown/tools/clients/index.md @@ -0,0 +1,158 @@ +--- +title: Client Tools +description: Comprehensive guide to Flow's client tools and SDKs, including FCL-JS, Go SDK, and various language-specific implementations for interacting with the Flow blockchain. +sidebar_position: 6 +keywords: + - FCL + - Flow Client Library + - SDKs + - client tools + - JavaScript + - Go + - Python + - Ruby + - JVM + - Swift + - .NET + - Rust + - PHP + - Elixir + - HTTP API + - blockchain + - development + - integration + - wallets + - authentication + - transactions + - cross-vm + - EVM + - Cadence +--- + +# Client Tools + +Flow provides a comprehensive suite of client tools and SDKs designed to help developers build applications that interact with the Flow blockchain. These tools support various programming languages and platforms, offering different levels of abstraction and functionality. + +## JavaScript (FCL) + +[Flow Client Library (FCL)] is the primary JavaScript/TypeScript client for Flow. It provides: + +- Wallet integration and authentication +- Transaction and script execution +- Cross-VM functionality for EVM integration +- TypeScript support +- Built-in security features + +## Go SDK + +[Flow Go SDK] offers a robust set of packages for Go developers, including: + +- High-performance blockchain interaction +- Transaction building and signing +- Account management +- Event subscription +- Comprehensive testing utilities + +## Python SDK + +[Flow Python SDK] provides Python developers with: + +- Simple blockchain interaction +- Transaction management +- Account handling +- Event monitoring +- Easy integration with Python applications + +## Ruby + +[FlowClient] is a Ruby gRPC client that enables: + +- Direct blockchain communication +- Transaction processing +- Account management +- Event handling +- Ruby-native blockchain integration + +## JVM + +[Flow JVM SDK] supports JVM-compatible languages (Java, Kotlin, Scala) with: + +- Kotlin-first implementation +- Transaction management +- Account handling +- Event subscription +- Cross-platform compatibility + +## Swift + +[flow-swift] is designed for iOS development, offering: + +- Native iOS integration +- Wallet connectivity +- Transaction management +- Account handling +- SwiftUI support + +## .NET + +[flow.net] provides .NET developers with: + +- C# and .NET Core support +- Transaction management +- Account handling +- Event monitoring +- Cross-platform compatibility + +## Rust + +[Rust SDK] offers Rust developers: + +- High-performance blockchain interaction +- Type-safe transaction handling +- Account management +- Event subscription +- Memory safety guarantees + +## PHP + +[PHP SDK] enables PHP developers to: + +- Integrate blockchain functionality +- Handle transactions +- Manage accounts +- Monitor events +- Build web applications + +## Elixir + +[OnFlow] provides Elixir developers with: + +- Functional blockchain interaction +- Transaction management +- Account handling +- Event subscription +- Comprehensive documentation + +## HTTP API + +[Flow OpenAPI] specification provides: + +- RESTful API endpoints +- Standardized API documentation +- Language-agnostic integration +- Easy API testing +- Swagger/OpenAPI support + +Each client tool is designed with specific use cases and developer needs in mind. Choose the one that best fits your development environment and requirements. + +[Flow Client Library (FCL)]: ./fcl-js/index.md +[Flow Go SDK]: ./flow-go-sdk/index.md +[Flow Python SDK]: https://github.com/janezpodhostnik/flow-py-sdk +[FlowClient]: https://github.com/glucode/flow_client +[Flow JVM SDK]: https://github.com/onflow/flow-jvm-sdk +[flow-swift]: https://github.com/Outblock/flow-swift +[flow.net]: https://github.com/tyronbrand/flow.net +[Rust SDK]: https://github.com/fee1-dead/flow.rs +[PHP SDK]: https://github.com/mayvenstudios/flow-php-sdk +[OnFlow]: https://github.com/nkezhaya/on_flow +[Flow OpenAPI]: /http-api \ No newline at end of file diff --git a/static/markdown/tools/emulator/index.md b/static/markdown/tools/emulator/index.md new file mode 100644 index 0000000000..e8a2a991be --- /dev/null +++ b/static/markdown/tools/emulator/index.md @@ -0,0 +1,23 @@ +--- +title: Flow Emulator +description: A development tool that looks, acts and talks like Flow +sidebar_position: 3 +--- + +The Flow Emulator is a lightweight tool that emulates the behaviour of the real Flow network. + +The emulator exposes a gRPC server that implements the Flow Access API, +which is designed to have near feature parity with the real network API. + +## Running the emulator with the Flow CLI + +The emulator is bundled with the [Flow CLI](../../tools/flow-cli/index.md), a command-line interface for working with Flow. + +### Installation + +Follow [these steps](../../tools/flow-cli/install.md) to install the Flow CLI on macOS, Linux, and Windows. + +## Usage + +To learn more about using the Emulator, +have a look at [the README of the repository](https://github.com/onflow/flow-emulator/#starting-the-server). \ No newline at end of file diff --git a/static/markdown/tools/error-codes.md b/static/markdown/tools/error-codes.md new file mode 100644 index 0000000000..0731ac736e --- /dev/null +++ b/static/markdown/tools/error-codes.md @@ -0,0 +1,284 @@ +--- +title: Error Codes +sidebar_position: 7 +--- + +# Error Codes + +List of error codes returned from failing transactions and scripts. The error code has an accompanied error message that usually gives more clarification. This list is meant to give more information and helpful hints. +[Code file](https://github.com/onflow/flow-go/blob/master/fvm/errors/codes.go) + +### 1006 + +**ErrCodeInvalidProposalSignatureError** + +Example: +`...` + +### 1007 + +**ErrCodeInvalidProposalSeqNumberError** + +Example: +`[Error Code: 1007] invalid proposal key: public key 0 on account xxx has sequence number xxx, but given xxx` + +### 1008 + +**ErrCodeInvalidPayloadSignatureError** + +Example: +`[Error Code: 1008] invalid payload signature: public key 0 on account xxx does not have a valid signature: signature is not valid` + +### 1009 + +**ErrCodeInvalidEnvelopeSignatureError** + +Example: +`[Error Code: 1009] invalid envelope key: public key 1 on account xxx does not have a valid signature: signature is not valid` + +### 1051 + +**ErrCodeValueError** + +Example: +`[Error Code: 1051] invalid value (xxx): invalid encoded public key value: rlp: expected input list for flow.runtimeAccountPublicKeyWrapper...` + +### 1052 + +**ErrCodeInvalidArgumentError** + +Example: +`[Error Code: 1052] transaction arguments are invalid: (argument is not json decodable: failed to decode value: runtime error: slice bounds out of range [:2] with length 0)` + +### 1053 + +**ErrCodeInvalidAddressError** + +Example: +`...` + +### 1054 + +**ErrCodeInvalidLocationError** + +Example: +`[Error Code: 1054] location (../contracts/FungibleToken.cdc) is not a valid location: expecting an AddressLocation, but other location types are passed ../contracts/FungibleToken.cdc` + +### 1055 + +**ErrCodeAccountAuthorizationError** + +Example: +`[Error Code: 1055] authorization failed for account e85d442d61a611d8: payer account does not have sufficient signatures (1 < 1000)` + +### 1056 + +**ErrCodeOperationAuthorizationError** + +Example: +`[Error Code: 1056] (RemoveContract) is not authorized: removing contracts requires authorization from specific accounts goroutine 5688834491 [running]:` + +### 1057 + +**ErrCodeOperationNotSupportedError** + +Example: +`...` + +### 1101 + +**ErrCodeCadenceRunTimeError** + +Example: +`[Error Code: 1101] cadence runtime error Execution failed: error: pre-condition failed: Amount withdrawn must be less than or equal than the balance of the Vault` + +### 1103 + +**ErrCodeStorageCapacityExceeded** + +Example: +`[Error Code: 1103] The account with address (xxx) uses 96559611 bytes of storage which is over its capacity (96554500 bytes). Capacity can be increased by adding FLOW tokens to the account.` + +For more information refer to [Fees](../build/basics/fees.md#maximum-available-balance) + +### 1105 + +**ErrCodeEventLimitExceededError** + +Example: +`[Error Code: 1105] total event byte size (256200) exceeds limit (256000)` + +### 1106 + +**ErrCodeLedgerInteractionLimitExceededError** + +Example: +`[Error Code: 1106] max interaction with storage has exceeded the limit (used: 20276498 bytes, limit 20000000 bytes)` + +### 1107 + +**ErrCodeStateKeySizeLimitError** + +Example: +`...` + +### 1108 + +**ErrCodeStateValueSizeLimitError** + +Example: +`...` + +### 1109 + +**ErrCodeTransactionFeeDeductionFailedError** + +Example: +`[Error Code: 1109] failed to deduct 0 transaction fees from 14af75b8c487333c: Execution failed: f919ee77447b7497.FlowFees:97:24` + +### 1110 + +**ErrCodeComputationLimitExceededError** + +Example: +`[Error Code: 1110] computation exceeds limit (100)` + +### 1111 + +**ErrCodeMemoryLimitExceededError** + +Example: +`...` + +### 1112 + +**ErrCodeCouldNotDecodeExecutionParameterFromState** + +Example: +`...` + +### 1113 + +**ErrCodeScriptExecutionTimedOutError** + +Example: +`...` + +### 1114 + +**ErrCodeScriptExecutionCancelledError** + +Example: +`...` + +### 1115 + +**ErrCodeEventEncodingError** + +Example: +`...` + +### 1116 + +**ErrCodeInvalidInternalStateAccessError** + +Example: +`...` + +### 1118 + +**ErrCodeInsufficientPayerBalance** + +Example: +` [Error Code: 1118] payer ... has insufficient balance to attempt transaction execution (required balance: 0.00100000)` + +### 1201 + +**ErrCodeAccountNotFoundError** + +Example: +`[Error Code: 1201] account not found for address xxx` + +### 1202 + +**ErrCodeAccountPublicKeyNotFoundError** + +Example: +`[Error Code: 1202] account public key not found for address xxx and key index 3` + +### 1203 + +**ErrCodeAccountAlreadyExistsError** + +Example: +`...` + +### 1204 + +**ErrCodeFrozenAccountError** + +Example: +`...` + +### 1206 + +**ErrCodeAccountPublicKeyLimitError** + +Example: +`...` + +### 1251 + +**ErrCodeContractNotFoundError** + +Example: +`...` + +### 2000 + +**FailureCodeUnknownFailure** + +Example: +`...` + +### 2001 + +**FailureCodeEncodingFailure** + +Example: +`...` + +### 2002 + +**FailureCodeLedgerFailure** + +Example: +`...` + +### 2003 + +**FailureCodeStateMergeFailure** + +Example: +`...` + +### 2004 + +**FailureCodeBlockFinderFailure** + +Example: +`...` + +### 2006 + +**FailureCodeParseRestrictedModeInvalidAccessFailure** + +Example: +`...` + +### 2007 + +**FailureCodePayerBalanceCheckFailure** + +Example: +`...` \ No newline at end of file diff --git a/static/markdown/tools/flow-cli/_template.md b/static/markdown/tools/flow-cli/_template.md new file mode 100644 index 0000000000..f910511fed --- /dev/null +++ b/static/markdown/tools/flow-cli/_template.md @@ -0,0 +1,128 @@ +--- +title: -title- +sidebar_label: +description: -description- +--- + +\{short description\} + +```shell +{command} +``` + +\{optional warning\} + +## Example Usage + +```shell +{usage example with response} +``` + +## Arguments + +### \{Argument 1\} + +- Name: `\{argument\}` +- Valid Input: `\{input\}` + +\{argument general description\} + +## Arguments + +### Address + +- Name: `address` +- Valid Input: Flow account address + +Flow [account address](../../../build/basics/accounts.md) (prefixed with `0x` or not). + +## Flags + +### \{Option 1\} + +- Flag: `\{flag value\}` +- Valid inputs: \{input description\} + +\{flag general description\} + +### Signer + +- Flag: `--signer` +- Valid inputs: the name of an account defined in the configuration (`flow.json`) + +Specify the name of the account that will be used to sign the transaction. + +### Host + +- Flag: `--host` +- Valid inputs: an IP address or hostname. +- Default: `127.0.0.1:3569` (Flow Emulator) + +Specify the hostname of the Access API that will be +used to execute the commands. + +### Network Key + +- Flag: `--network-key` +- Valid inputs: A valid network public key of the host in hex string format + +Specify the network public key of the Access API that will be +used to create a secure GRPC client when executing the command. + +### Network + +- Flag: `--network` +- Short Flag: `-n` +- Valid inputs: the name of a network defined in the configuration (`flow.json`) +- Default: `emulator` + +Specify which network you want the command to use for execution. + +### Filter + +- Flag: `--filter` +- Short Flag: `-x` +- Valid inputs: case-sensitive name of the result property. + +Specify any property name from the result you want to return as the only value. + +### Output + +- Flag: `--output` +- Short Flag: `-o` +- Valid inputs: `json`, `inline` + +Specify in which format you want to display the result. + +### Save + +- Flag: `--save` +- Short Flag: `-s` +- Valid inputs: valid filename + +Specify the filename where you want the result to be saved. + +### Log + +- Flag: `--log` +- Short Flag: `-l` +- Valid inputs: `none`, `error`, `debug` +- Default: `info` + +Specify the log level. Control how much output you want to see while command execution. + +### Configuration + +- Flag: `--config-path` +- Short Flag: `-f` +- Valid inputs: valid filename + +Specify a filename for the configuration files, you can provide multiple configuration +files by using `-f` flag multiple times. + +### Version Check + +- Flag: `--skip-version-check` +- Default: `false` + +Skip version check during start up to speed up process for slow connections. \ No newline at end of file diff --git a/static/markdown/tools/flow-cli/accounts/account-add-contract.md b/static/markdown/tools/flow-cli/accounts/account-add-contract.md new file mode 100644 index 0000000000..2670eb4d58 --- /dev/null +++ b/static/markdown/tools/flow-cli/accounts/account-add-contract.md @@ -0,0 +1,201 @@ +--- +title: Deploy a Contract +sidebar_position: 3 +--- + +Deploy a new contract to a Flow account using the Flow CLI. + +```shell +flow accounts add-contract [ ...] [flags] +``` + +⚠️ Deprecation notice: using name argument in adding contract command will be deprecated soon. +```shell +flow accounts add-contract [ ...] [flags] +``` + +## Example Usage + +```shell +> flow accounts add-contract ./FungibleToken.cdc + +Contract 'FungibleToken' deployed to the account 0xf8d6e0586b0a20c7 + +Address 0xf8d6e0586b0a20c7 +Balance 99999999999.70000000 +Keys 1 + +Key 0 Public Key 640a5a359bf3536d15192f18d872d57c98a96cb871b92b70cecb0739c2d5c37b4be12548d3526933c2cda9b0b9c69412f45ffb6b85b6840d8569d969fe84e5b7 + Weight 1000 + Signature Algorithm ECDSA_P256 + Hash Algorithm SHA3_256 + Revoked false + Sequence Number 6 + Index 0 + +Contracts Deployed: 1 +Contract: 'FungibleToken' +``` +**Testnet Example** +``` +> flow accounts add-contract ./FungibleToken.cdc --signer alice --network testnet + +Contract 'FungibleToken' deployed to the account 0xf8d6e0586b0a20c7 + +Address 0xf8d6e0586b0a20c7 +Balance 99999999999.70000000 +Keys 1 + +Key 0 Public Key 640a5a359bf3536d15192f18d872d57c98a96cb871b92b70cecb0739c2d5c37b4be12548d3526933c2cda9b0b9c69412f45ffb6b85b6840d8569d969fe84e5b7 + Weight 1000 + Signature Algorithm ECDSA_P256 + Hash Algorithm SHA3_256 + Revoked false + Sequence Number 6 + Index 0 + +Contracts Deployed: 1 +Contract: 'FungibleToken' +``` +*Make sure alice account is defined in flow.json* + +## Arguments + +### Name + +- Name: `name` +- Valid inputs: any string value. + +Name of the contract as it is defined in the contract source code. + +⚠️ Deprecation notice: use filename argument only, no need to use name argument. + +### Filename + +- Name: `filename` +- Valid inputs: a path in the current filesystem. + +Path to the file containing the contract source code. + +### Arguments +- Name: `argument` +- Valid inputs: valid [cadence values](https://cadencelang.dev/docs/1.0/json-cadence-spec) + matching argument type in transaction code. + +Input arguments values matching corresponding types in the source code and passed in the same order. + +Example: +```shell +> flow accounts add-contract ./contract.cdc Hello 2 +``` +Transaction code: +``` +access(all) contract HelloWorld { + init(a:String, b:Int) { + } +} +``` + +## Flags + +### Signer + +- Flag: `--signer` +- Valid inputs: the name of an account defined in the configuration (`flow.json`) + +Specify the name of the account that will be used to sign the transaction. + +### Arguments JSON + +- Flag: `--args-json` +- Valid inputs: arguments in JSON-Cadence form. +- Example: `flow accounts add-contract ./tx.cdc '[{"type": "String", "value": "Hello"}]'` + +Arguments passed to the Cadence transaction in Cadence JSON format. +Cadence JSON format contains `type` and `value` keys and is +[documented here](https://cadencelang.dev/docs/1.0/json-cadence-spec). + +### Include Fields + +- Flag: `--include` +- Valid inputs: `contracts` + +Specify fields to include in the result output. Applies only to the text output. + +### Host + +- Flag: `--host` +- Valid inputs: an IP address or hostname. +- Default: `127.0.0.1:3569` (Flow Emulator) + +Specify the hostname of the Access API that will be +used to execute the command. This flag overrides +any host defined by the `--network` flag. + +### Network Key + +- Flag: `--network-key` +- Valid inputs: A valid network public key of the host in hex string format + +Specify the network public key of the Access API that will be +used to create a secure GRPC client when executing the command. + +### Network + +- Flag: `--network` +- Short Flag: `-n` +- Valid inputs: the name of a network defined in the configuration (`flow.json`). +- Default: `emulator` + +Specify which network you want the command to use for execution. + +### Filter + +- Flag: `--filter` +- Short Flag: `-x` +- Valid inputs: a case-sensitive name of the result property. + +Specify any property name from the result you want to return as the only value. + +### Output + +- Flag: `--output` +- Short Flag: `-o` +- Valid inputs: `json`, `inline` + +Specify the format of the command results. + +### Save + +- Flag: `--save` +- Short Flag: `-s` +- Valid inputs: a path in the current filesystem. + +Specify the filename where you want the result to be saved + +### Log + +- Flag: `--log` +- Short Flag: `-l` +- Valid inputs: `none`, `error`, `debug` +- Default: `info` + +Specify the log level. Control how much output you want to see during command execution. + +### Configuration + +- Flag: `--config-path` +- Short Flag: `-f` +- Valid inputs: a path in the current filesystem. +- Default: `flow.json` + +Specify the path to the `flow.json` configuration file. +You can use the `-f` flag multiple times to merge +several configuration files. + +### Version Check + +- Flag: `--skip-version-check` +- Default: `false` + +Skip version check during start up to speed up process for slow connections. \ No newline at end of file diff --git a/static/markdown/tools/flow-cli/accounts/account-fund.md b/static/markdown/tools/flow-cli/accounts/account-fund.md new file mode 100644 index 0000000000..b8d33a57de --- /dev/null +++ b/static/markdown/tools/flow-cli/accounts/account-fund.md @@ -0,0 +1,37 @@ +--- +title: Funding a Testnet Account +description: How to fund a Testnet Flow account from the command line +sidebar_position: 7 +--- + +:::info + +The [Flow Testnet Faucet](https://testnet-faucet.onflow.org/) allows users to create accounts and receive 1,000 Testnet FLOW tokens for testing and development purposes. You can also fund an existing Testnet accounts without needing to create one through the site, or through the CLI. + +::: + +Fund a valid Testnet Flow Account using the Flow CLI. + +```shell +flow accounts fund
    +``` + +## Example Usage + +``` +> flow accounts fund 8e94eaa81771313a + +Opening the faucet to fund 0x8e94eaa81771313a on your native browser. + +If there is an issue, please use this link instead: https://testnet-faucet.onflow.org/fund-account?address=8e94eaa81771313a + +``` + +## Arguments + +### Address + +- Name: `address` +- Valid Input: Flow Testnet account address. + +Flow [account address](../../../build/basics/accounts.md) (prefixed with `0x` or not). \ No newline at end of file diff --git a/static/markdown/tools/flow-cli/accounts/account-remove-contract.md b/static/markdown/tools/flow-cli/accounts/account-remove-contract.md new file mode 100644 index 0000000000..e034e9191c --- /dev/null +++ b/static/markdown/tools/flow-cli/accounts/account-remove-contract.md @@ -0,0 +1,158 @@ +--- +title: Remove a Contract +sidebar_position: 5 +--- +_This feature is only found in the Emulator. You **cannot** remove a contract on Testnet or Mainnet._ + +Remove an existing contract deployed to a Flow account using the Flow CLI. + +```shell +flow accounts remove-contract +``` + +## Example Usage + +```shell +> flow accounts remove-contract FungibleToken + +Contract 'FungibleToken' removed from account '0xf8d6e0586b0a20c7' + +Address 0xf8d6e0586b0a20c7 +Balance 99999999999.70000000 +Keys 1 + +Key 0 Public Key 640a5a359bf3536d15192f18d872d57c98a96cb871b92b70cecb0739c2d5c37b4be12548d3526933c2cda9b0b9c69412f45ffb6b85b6840d8569d969fe84e5b7 + Weight 1000 + Signature Algorithm ECDSA_P256 + Hash Algorithm SHA3_256 + Revoked false + Sequence Number 6 + Index 0 + +Contracts Deployed: 0 +``` +**Testnet Example** +``` +> flow accounts remove-contract FungibleToken --signer alice --network testnet + +Contract 'FungibleToken' removed from account '0xf8d6e0586b0a20c7' + +Address 0xf8d6e0586b0a20c7 +Balance 99999999999.70000000 +Keys 1 + +Key 0 Public Key 640a5a359bf3536d15192f18d872d57c98a96cb871b92b70cecb0739c2d5c37b4be12548d3526933c2cda9b0b9c69412f45ffb6b85b6840d8569d969fe84e5b7 + Weight 1000 + Signature Algorithm ECDSA_P256 + Hash Algorithm SHA3_256 + Revoked false + Sequence Number 6 + Index 0 + +Contracts Deployed: 0 + +``` +*Make sure alice account is defined in flow.json* + +## Arguments + +### Name + +- Name: `name` +- Valid inputs: any string value. + +Name of the contract as it is defined in the contract source code. + +## Flags + +### Signer + +- Flag: `--signer` +- Valid inputs: the name of an account defined in the configuration (`flow.json`). + +Specify the name of the account that will be used to sign the transaction. + +### Include Fields + +- Flag: `--include` +- Valid inputs: `contracts` + +Specify fields to include in the result output. Applies only to the text output. + +### Host + +- Flag: `--host` +- Valid inputs: an IP address or hostname. +- Default: `127.0.0.1:3569` (Flow Emulator) + +Specify the hostname of the Access API that will be +used to execute the command. This flag overrides +any host defined by the `--network` flag. + +### Network Key + +- Flag: `--network-key` +- Valid inputs: A valid network public key of the host in hex string format + +Specify the network public key of the Access API that will be +used to create a secure GRPC client when executing the command. + +### Network + +- Flag: `--network` +- Short Flag: `-n` +- Valid inputs: the name of a network defined in the configuration (`flow.json`) +- Default: `emulator` + +Specify which network you want the command to use for execution. + +### Filter + +- Flag: `--filter` +- Short Flag: `-x` +- Valid inputs: a case-sensitive name of the result property + +Specify any property name from the result you want to return as the only value. + +### Output + +- Flag: `--output` +- Short Flag: `-o` +- Valid inputs: `json`, `inline` + +Specify the format of the command results. + +### Save + +- Flag: `--save` +- Short Flag: `-s` +- Valid inputs: a path in the current filesystem + +Specify the filename where you want the result to be saved + +### Log + +- Flag: `--log` +- Short Flag: `-l` +- Valid inputs: `none`, `error`, `debug` +- Default: `info` + +Specify the log level. Control how much output you want to see during command execution. + +### Configuration + +- Flag: `--config-path` +- Short Flag: `-f` +- Valid inputs: a path in the current filesystem +- Default: `flow.json` + +Specify the path to the `flow.json` configuration file. +You can use the `-f` flag multiple times to merge +several configuration files. + +### Version Check + +- Flag: `--skip-version-check` +- Default: `false` + +Skip version check during start up to speed up process for slow connections. \ No newline at end of file diff --git a/static/markdown/tools/flow-cli/accounts/account-staking-info.md b/static/markdown/tools/flow-cli/accounts/account-staking-info.md new file mode 100644 index 0000000000..c94a166120 --- /dev/null +++ b/static/markdown/tools/flow-cli/accounts/account-staking-info.md @@ -0,0 +1,138 @@ +--- +title: Account Staking Info +description: How to get staking info +sidebar_position: 6 +--- + +Retrieve staking information for the account on the Flow network using Flow CLI. + +```shell +flow accounts staking-info
    +``` + +## Example Usage + +```shell +> accounts staking-info 535b975637fb6bee --host access.testnet.nodes.onflow.org:9000 + +Account Staking Info: + ID: "ca00101101010100001011010101010101010101010101011010101010101010" + Initial Weight: 100 + Networking Address: "ca00101101010100001011010101010101010101010101011010101010101010" + Networking Key: "ca00101101010100001011010101010101010101010101011010101010101010ca00101101010100001011010101010101010101010101011010101010101010" + Role: 1 + Staking Key: "ca00101101010100001011010101010101010101010101011010101010101010ca00101101010100001011010101010101010101010101011010101010101010ca00101101010100001011010101010101010101010101011010101010101010" + Tokens Committed: 0.00000000 + Tokens To Unstake: 0.00000000 + Tokens Rewarded: 82627.77000000 + Tokens Staked: 250000.00000000 + Tokens Unstaked: 0.00000000 + Tokens Unstaking: 0.00000000 + Node Total Stake (including delegators): 250000.00000000 + +Account Delegation Info: + ID: 7 + Tokens Committed: 0.00000000 + Tokens To Unstake: 0.00000000 + Tokens Rewarded: 30397.81936000 + Tokens Staked: 100000.00000000 + Tokens Unstaked: 0.00000000 + Tokens Unstaking: 0.00000000 + +``` + +## Arguments + +### Address + +- Name: `address` +- Valid Input: Flow account address. + +Flow [account address](../../../build/basics/accounts.md) (prefixed with `0x` or not). + +## Flags + +### Include Fields + +- Flag: `--include` +- Valid inputs: `contracts` + +Specify fields to include in the result output. Applies only to the text output. + +### Host + +- Flag: `--host` +- Valid inputs: an IP address or hostname. +- Default: `127.0.0.1:3569` (Flow Emulator) + +Specify the hostname of the Access API that will be +used to execute the command. This flag overrides +any host defined by the `--network` flag. + +### Network Key + +- Flag: `--network-key` +- Valid inputs: A valid network public key of the host in hex string format + +Specify the network public key of the Access API that will be +used to create a secure GRPC client when executing the command. + +### Network + +- Flag: `--network` +- Short Flag: `-n` +- Valid inputs: the name of a network defined in the configuration (`flow.json`) +- Default: `emulator` + +Specify which network you want the command to use for execution. + +### Filter + +- Flag: `--filter` +- Short Flag: `-x` +- Valid inputs: a case-sensitive name of the result property + +Specify any property name from the result you want to return as the only value. + +### Output + +- Flag: `--output` +- Short Flag: `-o` +- Valid inputs: `json`, `inline` + +Specify the format of the command results. + +### Save + +- Flag: `--save` +- Short Flag: `-s` +- Valid inputs: a path in the current filesystem + +Specify the filename where you want the result to be saved + +### Log + +- Flag: `--log` +- Short Flag: `-l` +- Valid inputs: `none`, `error`, `debug` +- Default: `info` + +Specify the log level. Control how much output you want to see during command execution. + +### Configuration + +- Flag: `--config-path` +- Short Flag: `-f` +- Valid inputs: a path in the current filesystem +- Default: `flow.json` + +Specify the path to the `flow.json` configuration file. +You can use the `-f` flag multiple times to merge +several configuration files. + +### Version Check + +- Flag: `--skip-version-check` +- Default: `false` + +Skip version check during start up to speed up process for slow connections. \ No newline at end of file diff --git a/static/markdown/tools/flow-cli/accounts/account-update-contract.md b/static/markdown/tools/flow-cli/accounts/account-update-contract.md new file mode 100644 index 0000000000..52276a24b7 --- /dev/null +++ b/static/markdown/tools/flow-cli/accounts/account-update-contract.md @@ -0,0 +1,206 @@ +--- +title: Update a Contract +sidebar_position: 4 +--- + +Update an existing contract deployed to a Flow account using the Flow CLI. + +```shell +flow accounts update-contract [ ...] [flags] +``` + +⚠️ Deprecation notice: using name argument in update contract command will be deprecated soon. +```shell +flow accounts update-contract [ ...] [flags] +``` + +## Example Usage + +```shell +> flow accounts update-contract ./FungibleToken.cdc + +Contract 'FungibleToken' updated on account '0xf8d6e0586b0a20c7' + +Address 0xf8d6e0586b0a20c7 +Balance 99999999999.70000000 +Keys 1 + +Key 0 Public Key 640a5a359bf3536d15192f18d872d57c98a96cb871b92b70cecb0739c2d5c37b4be12548d3526933c2cda9b0b9c69412f45ffb6b85b6840d8569d969fe84e5b7 + Weight 1000 + Signature Algorithm ECDSA_P256 + Hash Algorithm SHA3_256 + Revoked false + Sequence Number 6 + Index 0 + +Contracts Deployed: 1 +Contract: 'FungibleToken' +``` +**Testnet Example** +``` +> flow accounts update-contract ./FungibleToken.cdc --signer alice --network testnet + +Contract 'FungibleToken' updated on account '0xf8d6e0586b0a20c7' + +Address 0xf8d6e0586b0a20c7 +Balance 99999999999.70000000 +Keys 1 + +Key 0 Public Key 640a5a359bf3536d15192f18d872d57c98a96cb871b92b70cecb0739c2d5c37b4be12548d3526933c2cda9b0b9c69412f45ffb6b85b6840d8569d969fe84e5b7 + Weight 1000 + Signature Algorithm ECDSA_P256 + Hash Algorithm SHA3_256 + Revoked false + Sequence Number 6 + Index 0 + +Contracts Deployed: 1 +Contract: 'FungibleToken' +``` +*Make sure alice account is defined in flow.json* + +## Arguments + +### Name +- Name: `name` +- Valid inputs: Any string value + +Name of the contract as it is defined in the contract source code. + +⚠️ Deprecation notice: use filename argument only, no need to use name argument. + +### Filename +- Name: `filename` +- Valid inputs: Any filename and path valid on the system. + +Filename of the file containing contract source code. + +### Arguments +- Name: `argument` +- Valid inputs: valid [cadence values](https://cadencelang.dev/docs/1.0/json-cadence-spec) + matching argument type in transaction code. + +Input arguments values matching corresponding types in the source code and passed in the same order. + +Example: +```shell +> flow accounts update-contract ./contract.cdc Hello 2 +``` +Transaction code: +``` +access(all) contract HelloWorld { + init(a:String, b:Int) { + } +} +``` + +## Flags + +### Signer + +- Flag: `--signer` +- Valid inputs: the name of an account defined in the configuration (`flow.json`) + +Specify the name of the account that will be used to sign the transaction. + +### Show Diff + +- Flag: `--show-diff` +- Valid inputs: `true`, `false` + +Shows a diff to approve before updating between deployed contract and new contract updates. + +### Arguments JSON + +- Flag: `--args-json` +- Valid inputs: arguments in JSON-Cadence form. +- Example: `flow accounts update-contract ./tx.cdc '[{"type": "String", "value": "Hello"}]'` + +Arguments passed to the Cadence transaction in Cadence JSON format. +Cadence JSON format contains `type` and `value` keys and is +[documented here](https://cadencelang.dev/docs/1.0/json-cadence-spec). + +### Include Fields + +- Flag: `--include` +- Valid inputs: `contracts` + +Specify fields to include in the result output. Applies only to the text output. + +### Host + +- Flag: `--host` +- Valid inputs: an IP address or hostname. +- Default: `127.0.0.1:3569` (Flow Emulator) + +Specify the hostname of the Access API that will be +used to execute the command. This flag overrides +any host defined by the `--network` flag. + +### Network Key + +- Flag: `--network-key` +- Valid inputs: A valid network public key of the host in hex string format + +Specify the network public key of the Access API that will be +used to create a secure GRPC client when executing the command. + +### Network + +- Flag: `--network` +- Short Flag: `-n` +- Valid inputs: the name of a network defined in the configuration (`flow.json`) +- Default: `emulator` + +Specify which network you want the command to use for execution. + +### Filter + +- Flag: `--filter` +- Short Flag: `-x` +- Valid inputs: a case-sensitive name of the result property + +Specify any property name from the result you want to return as the only value. + +### Output + +- Flag: `--output` +- Short Flag: `-o` +- Valid inputs: `json`, `inline` + +Specify the format of the command results. + +### Save + +- Flag: `--save` +- Short Flag: `-s` +- Valid inputs: a path in the current filesystem + +Specify the filename where you want the result to be saved + +### Log + +- Flag: `--log` +- Short Flag: `-l` +- Valid inputs: `none`, `error`, `debug` +- Default: `info` + +Specify the log level. Control how much output you want to see during command execution. + +### Configuration + +- Flag: `--config-path` +- Short Flag: `-f` +- Valid inputs: a path in the current filesystem +- Default: `flow.json` + +Specify the path to the `flow.json` configuration file. +You can use the `-f` flag multiple times to merge +several configuration files. + +### Version Check + +- Flag: `--skip-version-check` +- Default: `false` + +Skip version check during start up to speed up process for slow connections. \ No newline at end of file diff --git a/static/markdown/tools/flow-cli/accounts/create-accounts.md b/static/markdown/tools/flow-cli/accounts/create-accounts.md new file mode 100644 index 0000000000..2a40a737c0 --- /dev/null +++ b/static/markdown/tools/flow-cli/accounts/create-accounts.md @@ -0,0 +1,210 @@ +--- +title: Create an Account +description: How to create a Flow account from the command line +sidebar_position: 2 +--- + +The Flow CLI provides a command to submit an account creation +transaction to any Flow Access API. There are two options how to create an account, you can use the +interactive mode which guides you through the process and creates the account for you or by using +the manual process which requires a pre-existing account on the network you chose. + +## Interactive Mode +Creating the account in interactive mode prompts you for an account name and network selection. +After you enter the required information the account will be created for you and saved to `flow.json`. +If account creation is done on testnet or mainnet the account key will be saved to a separate key file, +which will also be put in `.gitignore`. You can [read more about key security here](../flow.json/security.md). + +💡 _Please note that the account creation process can take up to a minute so please be patient._ + +```shell +flow accounts create + +Enter an account name: mike +✔ Testnet + +🎉 New account created with address 0x77e6ae4c8c2f1dd6 and name mike on Testnet network. + +Here’s a summary of all the actions that were taken: + - Added the new account to flow.json. + - Saved the private key to mike.pkey. + - Added mike.pkey to .gitignore. +``` + +## Manual Mode +Manual mode requires you to have a pre-existing account on the network which you will have to provide as a signer. +That account must be added to `flow.json` for the command to work. You also have to generate a key pair, we +suggest using the `flow keys generate` command, [which you can read more about here](../keys/generate-keys.md). + +```shell +# Create an account on Flow Testnet +> flow accounts create \ + --key a69c6986e846ba6d0....1397f5904cd319c3e01e96375d5777f1a47010 \ + --signer my-testnet-account + +Address 0x01cf0e2f2f715450 +Balance 10000000 +Keys 1 + +Key 0 Public Key a69c6986e846ba6d0....1397f5904cd319c3e01e96375d5777f1a47010 + Weight 1000 + Signature Algorithm ECDSA_P256 + Hash Algorithm SHA3_256 + +Contracts Deployed: 0 +``` + +In the above example, the `flow.json` file would look something like this: + +```json +{ + "accounts": { + "my-testnet-account": { + "address": "a2c4941b5f3c7151", + "key": "12c5dfde...bb2e542f1af710bd1d40b2" + } + } +} +``` + +## Flags + +### Public Key + +- Flag: `--key` +- Valid inputs: a hex-encoded public key in raw form. + +Specify the public key that will be added to the new account +upon creation. + +### Key Weight + +- Flag: `--key-weight` +- Valid inputs: number between 0 and 1000 +- Default: 1000 + +Specify the weight of the public key being added to the new account. + +When opting to use this flag, you must specify a `--key-weight` flag for each public `--key` flag provided. + +### Public Key Signature Algorithm + +- Flag: `--sig-algo` +- Valid inputs: `"ECDSA_P256", "ECDSA_secp256k1"` +- Default: `"ECDSA_P256"` + +Specify the ECDSA signature algorithm for the provided public key. +This option can only be used together with the `--key` flag. + +Flow supports the secp256k1 and P-256 curves. + +### Public Key Hash Algorithm + +- Flag: `--hash-algo` +- Valid inputs: `"SHA2_256", "SHA3_256"` +- Default: `"SHA3_256"` + +Specify the hash algorithm that will be paired with the public key +upon account creation. + +### Signer + +- Flag: `--signer` +- Valid inputs: the name of an account defined in `flow.json`. + +Specify the name of the account that will be used to sign the transaction +and pay the account creation fee. + +### Contract + +- Flag: `--contract` +- Valid inputs: String with format `name:filename`, where `name` is + name of the contract as it is defined in the contract source code + and `filename` is the filename of the contract source code. + +Specify one or more contracts to be deployed during account creation. + +### Include Fields + +- Flag: `--include` +- Valid inputs: `contracts` + +Specify fields to include in the result output. Applies only to the text output. + +### Host + +- Flag: `--host` +- Valid inputs: an IP address or hostname. +- Default: `127.0.0.1:3569` (Flow Emulator) + +Specify the hostname of the Access API that will be +used to execute the command. This flag overrides +any host defined by the `--network` flag. + +### Network Key + +- Flag: `--network-key` +- Valid inputs: A valid network public key of the host in hex string format + +Specify the network public key of the Access API that will be +used to create a secure GRPC client when executing the command. + +### Network + +- Flag: `--network` +- Short Flag: `-n` +- Valid inputs: the name of a network defined in the configuration (`flow.json`) +- Default: `emulator` + +Specify which network you want the command to use for execution. + +### Filter + +- Flag: `--filter` +- Short Flag: `-x` +- Valid inputs: a case-sensitive name of the result property. + +Specify any property name from the result you want to return as the only value. + +### Output + +- Flag: `--output` +- Short Flag: `-o` +- Valid inputs: `json`, `inline` + +Specify the format of the command results. + +### Save + +- Flag: `--save` +- Short Flag: `-s` +- Valid inputs: a path in the current filesystem. + +Specify the filename where you want the result to be saved + +### Log + +- Flag: `--log` +- Short Flag: `-l` +- Valid inputs: `none`, `error`, `debug` +- Default: `info` + +Specify the log level. Control how much output you want to see during command execution. + +### Configuration + +- Flag: `--config-path` +- Short Flag: `-f` +- Valid inputs: a path in the current filesystem. +- Default: `flow.json` + +Specify the path to the `flow.json` configuration file. +You can use the `-f` flag multiple times to merge +several configuration files. + +### Version Check + +- Flag: `--skip-version-check` +- Default: `false` + +Skip version check during start up to speed up process for slow connections. \ No newline at end of file diff --git a/static/markdown/tools/flow-cli/accounts/get-accounts.md b/static/markdown/tools/flow-cli/accounts/get-accounts.md new file mode 100644 index 0000000000..5d49a3e6fa --- /dev/null +++ b/static/markdown/tools/flow-cli/accounts/get-accounts.md @@ -0,0 +1,133 @@ +--- +title: Get an Account +description: How to get a Flow account from the command line +sidebar_position: 1 +--- + +The Flow CLI provides a command to fetch any account by its address from the Flow network. + +```shell +flow accounts get
    +``` + +## Example Usage + +```shell +flow accounts get 0xf8d6e0586b0a20c7 +``` + +### Example response +```shell +Address 0xf8d6e0586b0a20c7 +Balance 99999999999.70000000 +Keys 1 + +Key 0 Public Key 640a5a359bf3536d15192f18d872d57c98a96cb871b92b70cecb0739c2d5c37b4be12548d3526933c2cda9b0b9c69412f45ffb6b85b6840d8569d969fe84e5b7 + Weight 1000 + Signature Algorithm ECDSA_P256 + Hash Algorithm SHA3_256 + Revoked false + Sequence Number 6 + Index 0 + +Contracts Deployed: 2 +Contract: 'FlowServiceAccount' +Contract: 'FlowStorageFees' + +``` + +## Arguments + +### Address + +- Name: `address` +- Valid Input: Flow account address + +Flow [account address](../../../build/basics/accounts.md) (prefixed with `0x` or not). + +## Flags + +### Include Fields + +- Flag: `--include` +- Valid inputs: `contracts` + +Specify fields to include in the result output. Applies only to the text output. + +### Host + +- Flag: `--host` +- Valid inputs: an IP address or hostname. +- Default: `127.0.0.1:3569` (Flow Emulator) + +Specify the hostname of the Access API that will be +used to execute the command. This flag overrides +any host defined by the `--network` flag. + +### Network Key + +- Flag: `--network-key` +- Valid inputs: A valid network public key of the host in hex string format + +Specify the network public key of the Access API that will be +used to create a secure GRPC client when executing the command. + +### Network + +- Flag: `--network` +- Short Flag: `-n` +- Valid inputs: the name of a network defined in the configuration (`flow.json`) +- Default: `emulator` + +Specify which network you want the command to use for execution. + +### Filter + +- Flag: `--filter` +- Short Flag: `-x` +- Valid inputs: a case-sensitive name of the result property. + +Specify any property name from the result you want to return as the only value. + +### Output + +- Flag: `--output` +- Short Flag: `-o` +- Valid inputs: `json`, `inline` + +Specify the format of the command results. + +### Save + +- Flag: `--save` +- Short Flag: `-s` +- Valid inputs: a path in the current filesystem. + +Specify the filename where you want the result to be saved + +### Log + +- Flag: `--log` +- Short Flag: `-l` +- Valid inputs: `none`, `error`, `debug` +- Default: `info` + +Specify the log level. Control how much output you want to see during command execution. + +### Configuration + +- Flag: `--config-path` +- Short Flag: `-f` +- Valid inputs: a path in the current filesystem. +- Default: `flow.json` + +Specify the path to the `flow.json` configuration file. +You can use the `-f` flag multiple times to merge +several configuration files. + +### Version Check + +- Flag: `--skip-version-check` +- Default: `false` + +Skip version check during start up to speed up process for slow connections. \ No newline at end of file diff --git a/static/markdown/tools/flow-cli/boilerplate.md b/static/markdown/tools/flow-cli/boilerplate.md new file mode 100644 index 0000000000..081c98f469 --- /dev/null +++ b/static/markdown/tools/flow-cli/boilerplate.md @@ -0,0 +1,103 @@ +--- +title: Cadence Boilerplate Generation +sidebar_label: Cadence Boilerplate +description: Cadence Boilerplate Generation via the CLI +sidebar_position: 16 +--- + +## Introduction + +Flow CLI now includes a feature to automatically generate boilerplate code for contracts, transactions, and scripts. This feature enhances the development experience by simplifying the initial setup of various components in Flow. + +```shell +> flow generate +Usage: + flow generate [command] + +Aliases: + generate, g + +Available Commands: + contract Generate a new contract + script Generate a new script + transaction Generate a new transaction +``` + +## Generate Contract + +To create a new contract with basic structure, use the `contract` command. It creates a new Cadence file with a template contract definition. + +```shell +flow generate contract [ContractName] +``` + +### Usage Example + +```shell +> flow generate contract HelloWorld +``` + +This command creates a file `cadence/contracts/HelloWorld.cdc` with the following content: + +```cadence +access(all) contract HelloWorld { + init() {} +} +``` + +## Generate Transaction + +For initializing a transaction, use the `transaction` command. It sets up a new Cadence file with a template transaction structure. + +```shell +flow generate transaction [TransactionName] +``` + +### Usage Example + +```shell +> flow generate transaction SayHello +``` + +This command creates a file `cadence/transactions/SayHello.cdc` with the following content: + +```cadence +transaction() { + prepare() {} + + execute {} +} +``` + +## Generate Script + +Similarly, to start a new script, the `script` command generates a Cadence file with a basic script structure. + +```shell +flow generate script [ScriptName] +``` + +### Usage Example + +```shell +> flow generate script ReadHello +``` + +This command creates a file `cadence/scripts/ReadHello.cdc` with the following content: + +```cadence +access(all) fun main() {} +``` + +## Optional `--dir` Flag + +The `--dir` flag is an optional feature in the Flow CLI `generate` commands, allowing you to specify a custom directory for the generated contract, transaction, or script files. If this flag is not provided, the CLI adheres to the recommended project setup: + +- Contracts are generated in the `cadence/contracts` directory. +- Transactions are generated in the `cadence/transactions` directory. +- Scripts are generated in the `cadence/scripts` directory. + +- **Usage**: `--dir=` +- **Example**: `flow generate contract HelloWorld --dir=custom_contracts` + +Use the `--dir` flag only if your project requires a different organizational structure than the default. \ No newline at end of file diff --git a/static/markdown/tools/flow-cli/data-collection.md b/static/markdown/tools/flow-cli/data-collection.md new file mode 100644 index 0000000000..48ac58fc93 --- /dev/null +++ b/static/markdown/tools/flow-cli/data-collection.md @@ -0,0 +1,30 @@ +--- +title: Data Collection +description: Data collected from Flow CLI usage +sidebar_position: 17 +--- + +Flow CLI tracks flow command usage count using Mixpanel. + +Data collection is enabled by default. Users can opt out of our data collection through running `flow settings metrics disable`. +To opt back in, users can run `flow settings metrics enable`. + +## Why do we collect data about flow cli usage? + +Collecting aggregate command count allow us to prioritise features and fixes based on how users use flow cli. + +## What data do we collect? + +We only collect the number of times a command is executed. + +We don't keep track of the values of arguments, flags used +and the values of the flags used. We also don't associate any commands to any particular user. + +The only property that we collect from our users are their preferences for opting in / out of data collection. +The analytics user ID is specific to Mixpanel and does not permit Flow CLI maintainers to e.g. track you across websites you visit. + +Further details regarding the data collected can be found under Mixpanel's data collection page in `Ingestion API` +section of https://help.mixpanel.com/hc/en-us/articles/115004613766-Default-Properties-Collected-by-Mixpanel. + +Please note that although Mixpanel's page above mentions that geolocation properties are recorded by default, +we have turned off geolocation data reporting to Mixpanel. \ No newline at end of file diff --git a/static/markdown/tools/flow-cli/dependency-manager.md b/static/markdown/tools/flow-cli/dependency-manager.md new file mode 100644 index 0000000000..d1d4389eda --- /dev/null +++ b/static/markdown/tools/flow-cli/dependency-manager.md @@ -0,0 +1,130 @@ +--- +title: Dependency Manager +sidebar_label: Dependency Manager +description: Dependency Manager for the Flow Blockchain. +sidebar_position: 11 +--- + +The Dependency Manager in the Flow CLI streamlines the development process when you use contracts from outside your project. It eliminates the manual tasks of copying, pasting, and updating contracts that you use or build upon, such as core contracts or any other ecosystem contracts. + +For example, if you wanted to build a new application using the `FlowToken` contract, you would traditionally need to locate the contract on the network, copy it into your local project, and add it to your `flow.json`. You would repeat this process for each import (dependency) it relies on, like the `NonFungibleToken` contract. The Dependency Manager simplifies this process with a few straightforward commands. + +## `install` + +The `install` command allows you to install dependencies and all their sub-dependencies with ease. You can use it to install specific dependencies or to install all dependencies listed in your `flow.json`. + +### Installing Specific Dependencies + +If you know the address and name of the contract you want to install (which can often be found via the [Contract Browser](https://contractbrowser.com/)), you can use the following syntax: + +```bash +flow dependencies install testnet://7e60df042a9c0868.FlowToken +``` + +In this command, the string `testnet://7e60df042a9c0868.FlowToken` used as the `source` in the `flow.json` is broken down as: + +- **Network:** `testnet` +- **Address:** `7e60df042a9c0868` +- **Contract Name:** `FlowToken` + +This specifies the remote source of the contract on the network that will be used as the source of truth. + +### Installing Core Contracts Using Simplified Syntax + +For core contracts, you can use a simplified syntax that defaults to the Flow Mainnet: + +```bash +flow dependencies install FlowToken +``` + +This command is functionally equivalent to: + +```bash +flow dependencies install mainnet://1654653399040a61.FlowToken +``` + +### Installing Multiple Dependencies + +You can also install multiple dependencies at once. For example: + +```bash +flow dependencies install testnet://7e60df042a9c0868.FlowToken NonFungibleToken +``` + +This command installs both the `FlowToken` contract from Testnet and the `NonFungibleToken` contract from Mainnet. + +### Installing All Dependencies From an Address + +Sometimes you may want to install all the contracts that exist at a particular address, rather than specifying each contract name individually. You can do this by omitting the contract name in the dependency source. For example: + +```bash +flow dependencies install testnet://7e60df042a9c0868 +``` + +This tells the Dependency Manager to fetch every contract deployed at the `7e60df042a9c0868` address on `testnet` and store them in your `imports` folder. You can later import these contracts in your code or use them in your deployments as needed. + +### Installing Dependencies from `flow.json` + +If you run the `install` command without specifying any dependencies, it will install all the dependencies listed in your `flow.json` file and ensure they are up to date: + +```bash +flow dependencies install +``` + +This command checks all the dependencies specified in your `flow.json`, installs them, and updates them if there have been changes on the network. + +### Example `flow.json` Entry + +After installing, your `flow.json` might include an entry like: + +```json +{ + "dependencies": { + "FlowToken": { + "source": "testnet://7e60df042a9c0868.FlowToken", + "aliases": { + "emulator": "0ae53cb6e3f42a79" + } + } + } +} +``` + +### Other Things to Note + +- After installation, a local folder named `imports` will be created. It's recommended to add this folder to your `.gitignore`, as it stores your dependencies locally. +- If the contracts change on the network, the Dependency Manager will prompt you to update the local dependencies in your `imports` folder. The hash saved in the dependency object is used for this check, so avoid removing it. +- Dependencies function just like local contracts. You can add them to [`deployments` in your `flow.json`](./deployment/deploy-project-contracts.md) and run `flow project deploy`. You can also import them in your scripts, transactions, and contracts (e.g., `import "FlowToken"`). +- Core contract aliases are automatically added for you across all networks. + +## `discover` + +The `discover` command helps you interactively find and install core contracts for your project. Core contracts are standard smart contracts maintained by the Flow Foundation and are commonly used across the Flow ecosystem (learn more about core contracts [here](../../build/core-contracts/index.md)). + +To use the `discover` command, run: + +```bash +flow dependencies discover +``` + +You'll be presented with a list of available core contracts to install: + +```shell +Select any core contracts you would like to install or skip to continue. +Use arrow keys to navigate, space to select, enter to confirm or skip, q to quit: + +> [ ] FlowEpoch + [ ] FlowIDTableStaking + [ ] FlowClusterQC + [ ] FlowDKG + [ ] FlowServiceAccount + [ ] NodeVersionBeacon + [ ] RandomBeaconHistory + [ ] FlowStorageFees + [ ] FlowFees + [ ] FungibleTokenSwitchboard + [ ] EVM + [ ] Crypto +``` + +After selecting the contracts, press `enter` to confirm. The selected contracts will be added to your `flow.json` file and will be accessible in your project. \ No newline at end of file diff --git a/static/markdown/tools/flow-cli/deployment/deploy-project-contracts.md b/static/markdown/tools/flow-cli/deployment/deploy-project-contracts.md new file mode 100644 index 0000000000..c9f8e03be5 --- /dev/null +++ b/static/markdown/tools/flow-cli/deployment/deploy-project-contracts.md @@ -0,0 +1,269 @@ +--- +title: Deploy a Project +description: How to deploy Flow project contracts with the CLI +sidebar_position: 3 +--- + +```shell +flow project deploy +``` + +This command automatically deploys your project's contracts based on the +configuration defined in your `flow.json` file. + +Before using this command, read about how to +[configure project contracts and deployment targets](./project-contracts.md). + +## Example Usage + +```shell +> flow project deploy --network=testnet + +Deploying 2 contracts for accounts: my-testnet-account + +NonFungibleToken -> 0x8910590293346ec4 +KittyItems -> 0x8910590293346ec4 + +✨ All contracts deployed successfully +``` + +In the example above, your `flow.json` file might look something like this: + +```json +{ + ... + "contracts": { + "NonFungibleToken": "./cadence/contracts/NonFungibleToken.cdc", + "KittyItems": "./cadence/contracts/KittyItems.cdc" + }, + "deployments": { + "testnet": { + "my-testnet-account": ["KittyItems", "NonFungibleToken"] + } + }, + ... +} +``` + +Here's a sketch of the contract source files: + +```cadence NonFungibleToken.cdc +access(all) contract NonFungibleToken { + // ... +} +``` + +```cadence KittyItems.cdc + + +access(all) contract KittyItems { + // ... +} +``` + +## Initialization Arguments +Deploying contracts that take initialization arguments +can be achieved with adding those arguments to the configuration. + +Each deployment can be specified as an object containing +`name` and `args` key specifying arguments to be +used during the deployment. Example: + +``` +... + "deployments": { + "testnet": { + "my-testnet-account": [ + "NonFungibleToken", { + "name": "Foo", + "args": [ + { "type": "String", "value": "Hello World" }, + { "type": "UInt32", "value": "10" } + ] + }] + } + } +... +``` + +⚠️ Warning: before proceeding, +we recommend reading the [Flow CLI security guidelines](../flow.json/security.md) +to learn about the best practices for private key storage. + +## Dependency Resolution + +The `deploy` command attempts to resolve the import statements in all contracts being deployed. + +After the dependencies are found, the CLI will deploy the contracts in a deterministic order +such that no contract is deployed until all of its dependencies are deployed. +The command will return an error if no such ordering exists due to one or more cyclic dependencies. + +In the example above, `Foo` will always be deployed before `Bar`. + +## Address Replacement + +After resolving all dependencies, the `deploy` command rewrites each contract so +that its dependencies are imported from their _target addresses_ rather than their +source file location. + +The rewritten versions are then deployed to their respective targets, +leaving the original contract files unchanged. + +In the example above, the `KittyItems` contract would be rewritten like this: + +```cadence KittyItems.cdc +import NonFungibleToken from 0xf8d6e0586b0a20c7 + +access(all) contract KittyItems { + // ... +} +``` +## Merging Multiple Configuration Files + +You can use the `-f` flag multiple times to merge several configuration files. + +If there is an overlap in any of the fields in the configuration between two or more configuration files, the value of +the overlapped field in the resulting configuration will come from the configuration file that is on the further right +order in the list of configuration files specified in the -f flag + +Let's look at an example of `deploy` commands with multiple configuration files below + +```cadence flow.json +{ + "accounts": { + "admin-account": { + "address": "f8d6e0586b0a20c7", + "key": "21c5dfdeb0ff03a7a73ef39788563b62c89adea67bbb21ab95e5f710bd1d40b7" + }, + "test-account": { + "address": "f8d6e0586b0a20c8", + "key": "52d5dfdeb0ff03a7a73ef39788563b62c89adea67bbb21ab95e5f710bd1d51c9" + } + } +} +``` +```cadence private.json +{ + "accounts":{ + "admin-account":{ + "address":"f1d6e0586b0a20c7", + "key":"3335dfdeb0ff03a7a73ef39788563b62c89adea67bbb21ab95e5f710bd1d40b7" + } + } +} +``` +In the example above, when we try to use the `deploy` command with multiple configuration files and there is an overlap +in the `admin-account` account in `accounts` field of the configuration, the resulting configuration will be like this + +> flow project deploy -f flow.json -f private.json +``` +{ + "accounts":{ + "admin-account":{ + "address":"f1d6e0586b0a20c7", + "key":"3335dfdeb0ff03a7a73ef39788563b62c89adea67bbb21ab95e5f710bd1d40b7" + }, + "test-account":{ + "address":"f8d6e0586b0a20c8", + "key":"52d5dfdeb0ff03a7a73ef39788563b62c89adea67bbb21ab95e5f710bd1d51c9" + } + } +} +``` + +## Flags + +### Allow Updates + +- Flag: `--update` +- Valid inputs: `true`, `false` +- Default: `false` + +Indicate whether to overwrite and upgrade existing contracts. Only contracts with difference with existing contracts +will be overwritten. + +### Show Update Diff + +- Flag: `--show-diff` +- Valid inputs: `true`, `false` +- Default: `false` + +Shows a diff to approve before updating between deployed contract and new contract updates. + +### Host + +- Flag: `--host` +- Valid inputs: an IP address or hostname. +- Default: `127.0.0.1:3569` (Flow Emulator) + +Specify the hostname of the Access API that will be +used to execute the command. This flag overrides +any host defined by the `--network` flag. + +### Network Key + +- Flag: `--network-key` +- Valid inputs: A valid network public key of the host in hex string format + +Specify the network public key of the Access API that will be +used to create a secure GRPC client when executing the command. + +### Network + +- Flag: `--network` +- Short Flag: `-n` +- Valid inputs: the name of a network defined in the configuration (`flow.json`) +- Default: `emulator` + +Specify which network you want the command to use for execution. + +### Filter + +- Flag: `--filter` +- Short Flag: `-x` +- Valid inputs: a case-sensitive name of the result property. + +Specify any property name from the result you want to return as the only value. + +### Output + +- Flag: `--output` +- Short Flag: `-o` +- Valid inputs: `json`, `inline` + +Specify the format of the command results. + +### Save + +- Flag: `--save` +- Short Flag: `-s` +- Valid inputs: a path in the current filesystem. + +Specify the filename where you want the result to be saved + +### Log + +- Flag: `--log` +- Short Flag: `-l` +- Valid inputs: `none`, `error`, `debug` +- Default: `info` + +Specify the log level. Control how much output you want to see during command execution. + +### Configuration + +- Flag: `--config-path` +- Short Flag: `-f` +- Valid inputs: a path in the current filesystem. +- Default: `flow.json` + +Specify the path to the `flow.json` configuration file. +You can use the `-f` flag multiple times to merge +several configuration files. + +### Version Check + +- Flag: `--skip-version-check` +- Default: `false` + +Skip version check during start up to speed up process for slow connections. \ No newline at end of file diff --git a/static/markdown/tools/flow-cli/deployment/emulator-snapshot.md b/static/markdown/tools/flow-cli/deployment/emulator-snapshot.md new file mode 100644 index 0000000000..f9bd6f964e --- /dev/null +++ b/static/markdown/tools/flow-cli/deployment/emulator-snapshot.md @@ -0,0 +1,57 @@ +--- +title: Create Emulator Snapshot +description: How to start create emulator snapshot from the command line +sidebar_position: 4 +--- + +The Flow CLI provides a command to create emulator snapshots, which are points in blockchain +history you can later jump to and reset the state to that moment. This can be useful for testing where you +establish a begining state, run tests and after revert back to the initial state. + +The command syntax is: +```shell +flow emulator snapshot create|load|list {name} +``` + +## Example Usage + +### Create a new snapshot +Create a new emulator snapshot at the current block with a name of `myInitialState`. +```shell +> flow emulator snapshot create myInitialState +``` + +### Load an existing snapshot +To jump to a previously created snapshot we use the load command in combination with the name. +```shell +> flow emulator snapshot load myInitialState +``` + +### List all existing snapshots +To list all the existing snapshots we previously created and can load to we run the following command: +```shell +> flow emulator list +``` + +To learn more about using the Emulator, have a look at the [README of the repository](https://github.com/onflow/flow-emulator). + +## Flags + +### Emulator Flags +You can specify any [emulator flags found here](https://github.com/onflow/flow-emulator#configuration) and they will be applied to the emulator service. + +### Configuration + +- Flag: `--config-path` +- Short Flag: `-f` +- Valid inputs: valid filename + +Specify a filename for the configuration files, you can provide multiple configuration +files by using `-f` flag multiple times. + +### Version Check + +- Flag: `--skip-version-check` +- Default: `false` + +Skip version check during start up to speed up process for slow connections. \ No newline at end of file diff --git a/static/markdown/tools/flow-cli/deployment/project-contracts.md b/static/markdown/tools/flow-cli/deployment/project-contracts.md new file mode 100644 index 0000000000..7e7da8942a --- /dev/null +++ b/static/markdown/tools/flow-cli/deployment/project-contracts.md @@ -0,0 +1,51 @@ +--- +title: Add Project Contracts +description: How to define the Cadence contracts for Flow project +sidebar_position: 2 +--- + +## Add a Contract + +To add a contract to your project, update the `"contracts"` section of your `flow.json` file. + +Contracts are specified as key-value pairs, where the key is the contract name, +and the value is the location of the Cadence source code. + +For example, the configuration below will register the +contract `Foo` from the `FooContract.cdc` file. + +```json +{ + "contracts": { + "Foo": "./cadence/contracts/FooContract.cdc" + } +} +``` + +## Define Contract Deployment Targets + +Once a contract is added, it can then be assigned to one or more deployment targets. + +A deployment target is an account to which the contract will be deployed. +In a typical project, a contract has one deployment target per network (e.g. Emulator, Testnet, Mainnet). + +Deployment targets are defined in the `"deployments"` section of your `flow.json` file. + +Targets are grouped by their network, where each network is a mapping from target account to contract list. +Multiple contracts can be deployed to the same target account. + +For example, here's how we'd deploy contracts `Foo` and `Bar` to the account `my-testnet-account`: + +```json +{ + "contracts": { + "Foo": "./cadence/contracts/FooContract.cdc", + "Bar": "./cadence/contracts/BarContract.cdc" + }, + "deployments": { + "testnet": { + "my-testnet-account": ["Foo", "Bar"] + } + } +} +``` \ No newline at end of file diff --git a/static/markdown/tools/flow-cli/deployment/start-emulator.md b/static/markdown/tools/flow-cli/deployment/start-emulator.md new file mode 100644 index 0000000000..e5e55ff15b --- /dev/null +++ b/static/markdown/tools/flow-cli/deployment/start-emulator.md @@ -0,0 +1,70 @@ +--- +title: Start Emulator +description: How to start the Flow Emulator from the command line +sidebar_position: 1 +--- + +The Flow Emulator is a lightweight development tool that mimics the behavior of the real Flow network. It is bundled with the [Flow CLI](https://docs.onflow.org/flow-cli/), which makes starting and configuring the emulator straightforward. + +## Initial Configuration + +The emulator requires a configuration file (`flow.json`). If you don’t already have one, create it using the `flow init` command: + +```bash +flow init +``` + +This initializes a default configuration file that the emulator will use. + +## Starting the Emulator + +To start the emulator with default settings, use the following command: + +```bash +flow emulator +``` + +This will start the emulator with the configuration defined in `flow.json`. + +### Example Output + +When you run the `flow emulator` command, you will see output similar to the following: + +```bash +INFO[0000] ⚙️ Using service account 0xf8d6e0586b0a20c7 serviceAddress=f8d6e0586b0a20c7 ... +INFO[0000] 🌱 Starting Flow Emulator +INFO[0000] 🛠 GRPC server started on 127.0.0.1:3569 +INFO[0000] 📡 HTTP server started on 127.0.0.1:8080 +``` + +## Customizing the Emulator + +You can customize the emulator behavior by using flags. Here are some examples: + +Change the gRPC and REST API ports: + +```bash +flow emulator --port 9000 --rest-port 9001 +``` + +Enable persistence of state across restarts: + +```bash +flow emulator --persist +``` + +Enable detailed logs for debugging: + +```bash +flow emulator --verbose +``` + +For a complete list of available flags, run: + +```bash +flow emulator --help +``` + +## Learn More + +To explore advanced features like snapshots, rollbacks, and debugging, visit the [Flow Emulator README](https://github.com/onflow/flow-emulator). \ No newline at end of file diff --git a/static/markdown/tools/flow-cli/flix.md b/static/markdown/tools/flow-cli/flix.md new file mode 100644 index 0000000000..94d7a2f16b --- /dev/null +++ b/static/markdown/tools/flow-cli/flix.md @@ -0,0 +1,555 @@ +--- +title: Flow Interaction Templates (FLIX) +sidebar_label: Flow Interaction Templates (FLIX) +description: Flow Interaction Templates (FLIX) via the CLI +sidebar_position: 15 +--- + +FLIX helps developers reuse existing Cadence transactions and scripts to easily integrate with existing Cadence smart contracts. Get more information about [Flow Interaction Templates](../../build/advanced-concepts/flix.md) + +## Introduction + +The Flow CLI provides a `flix` command with a few sub commands `execute` and `package`. Get familiar with Flow Interaction Templates [(FLIX)](https://github.com/onflow/flips/blob/main/application/20220503-interaction-templates.md). FLIX are a standard for distributing Cadence scripts and transactions, and metadata in a way that is consumable by tooling and wallets. FLIX can be audited for correctness and safety by auditors in the ecosystem. + +```shell +>flow flix +execute, generate, package + +Usage: + flow flix [command] + +Available Commands: + execute execute FLIX template with a given id, name, local filename, or url + generate generate FLIX json template given local Cadence filename + package package file for FLIX template fcl-js is default + +``` + +### Execute + +The Flow CLI provides a `flix` command to `execute` FLIX. The Cadence being execute in the FLIX can be a transaction or script. + +```shell +flow flix execute [ ...] [flags] +``` + +:::warning + +A FLIX template might only support testnet and/or mainnet. Generally, emulator is not supported. This can be the case if the FLIX template relies on contract dependencies. + +::: + +Queries can be a FLIX `id`, `name`, `url` or `path` to a local FLIX file. + +### Execute Usage + +```shell +# Execute a FLIX transaction by name on Testnet +flow flix execute transfer-flow 5.0 "0x123" --network testnet --signer "testnet-account" +``` + +```shell +# Execute a FLIX script by id on Testnet +flow flix execute bd10ab0bf472e6b58ecc0398e9b3d1bd58a4205f14a7099c52c0640d9589295f --network testnet +``` + +```shell +# Execute a local FLIX script by path on Testnet +flow flix execute ./multiply.template.json 2 3 --network testnet +``` + +The Flow CLI provides a `flix` command to `package` up generated plain and simple JavaScript. This JavaScript uses FCL (Flow Client Library) to call the cadence the Flow Interaction Templates (FLIX) is based on. + +:::info + +Currently, `flix package` command only supports generating FCL (Flow Client Library) specific JavaScript and TypeScirpt, there are plans to support other languages like golang. + +::: + +```shell +flow flix package [flags] +``` + +### Generate + +Generate FLIX json file. This command will take in a Cadence file and produce a FLIX json file. There are two ways to provide metadata to populate the FLIX json structure. + - Use `--pre-fill` flag to pass in a pre populated FLIX json structure + - Use `--exclude-networks` flag to specify excluded networks when generating a FLIX templates. Example, `--exclude-networks testnet,mainnet` + +:::warning + +When generating a FLIX template, make sure all contract dependencies have been deployed to the supported networks. Add any aliases to your flow.json that will be needed to populate dependencies. Verify all dependencies have been populated after generating. + +::: + +### Generate Usage + +```shell +# Generate FLIX json file using cadence transaction or script, this example is not using a prefilled json file so will not have associated message metadata +flow flix generate cadence/transactions/update-helloworld.cdc --save cadence/templates/update-helloworld.template.json +``` + +Example of Cadence simple, no metadata associated +```cadence + +import "HelloWorld" +access(all) fun main(): String { + return HelloWorld.greeting +} +``` + +### Cadence Doc Pragma: +It's recommended to use pragma to set the metadata for the script or transaction. More information on [Cadence Doc Pragma FLIP](https://github.com/onflow/flips/blob/main/application/20230406-interaction-template-cadence-doc.md) + +A pragma is short for "pragmatic information", it's special instructions to convey information to a processor in this case the utility that generates FLIX. +```cadence +import "HelloWorld" + +#interaction ( + version: "1.1.0", + title: "Update Greeting", + description: "Update the greeting on the HelloWorld contract", + language: "en-US", +) + +transaction(greeting: String) { + + prepare(acct: &Account) { + log(acct.address) + } + + execute { + HelloWorld.updateGreeting(newGreeting: greeting) + } +} + +``` + +:::info +Cadence v0.42.7 supports additional Cadence pragma functionality that FlIX utility can use to generate FLIX. It will support parameters "title" and "description". +::: + +The resulting json metadata is extracted from Cadence Doc Pragma +```json +{ + "f_type": "InteractionTemplate", + "f_version": "1.1.0", + "id": "", + "data": { + "type": "transaction", + "interface": "", + "messages": [ + { + "key": "title", + "i18n": [ + { + "tag": "en-US", + "translation": "Update Greeting" + } + ] + }, + { + "key": "description", + "i18n": [ + { + "tag": "en-US", + "translation": "Update the greeting on the HelloWorld contract" + } + ] + } + ], + "cadence": {}, + "dependencies": [], + "parameters": [ + { + "label": "greeting", + "index": 0, + "type": "String", + "messages": [] + } + ] + } +} +``` + +Example of using a prefilled FLIX json file. No need to use Cadence pragma when using a prefilled FLIX json file. This method separates FLIX specific information from the transaction or script Cadence. Use the `flow flix generate` command: + +```shell +flow flix generate cadence/scripts/read-helloworld.cdc --pre-fill cadence/templates/read-helloworld.prefill.json --save cadence/templates/read-helloworld.template.json +``` + +Using a pre-filled FLIX template, the cadence can be simple but no metadata accompanies it. + +```cadence +import "HelloWorld" +access(all) fun main(): String { + return HelloWorld.greeting +} +``` + +Example of json prefill file with message metadata: +```json +{ + "f_type": "InteractionTemplate", + "f_version": "1.1.0", + "id": "", + "data": { + "type": "script", + "interface": "", + "messages": [ + { + "key": "title", + "i18n": [ + { + "tag": "en-US", + "translation": "Get Greeting" + } + ] + }, + { + "key": "description", + "i18n": [ + { + "tag": "en-US", + "translation": "Call HelloWorld contract to get greeting" + } + ] + } + ] + } +} + +``` + +The resulting FLIX json file after generation: + +```json +{ + "f_type": "InteractionTemplate", + "f_version": "1.1.0", + "id": "fd9abd34f51741401473eb1cf676b105fed28b50b86220a1619e50d4f80b0be1", + "data": { + "type": "script", + "interface": "", + "messages": [ + { + "key": "title", + "i18n": [ + { + "tag": "en-US", + "translation": "Get Greeting" + } + ] + }, + { + "key": "description", + "i18n": [ + { + "tag": "en-US", + "translation": "Call HelloWorld contract to get greeting" + } + ] + } + ], + "cadence": { + "body": "import \"HelloWorld\"\naccess(all) fun main(): String {\n return HelloWorld.greeting\n}\n", + "network_pins": [ + { + "network": "testnet", + "pin_self": "41c4c25562d467c534dc92baba92e0c9ab207628731ee4eb4e883425abda692c" + } + ] + }, + "dependencies": [ + { + "contracts": [ + { + "contract": "HelloWorld", + "networks": [ + { + "network": "testnet", + "address": "0xe15193734357cf5c", + "dependency_pin_block_height": 137864533, + "dependency_pin": { + "pin": "aad46badcab3caaeb4f0435625f43e15bb4c15b1d55c74a89e6f04850c745858", + "pin_self": "a06b3cd29330a3c22df3ac2383653e89c249c5e773fd4bbee73c45ea10294b97", + "pin_contract_name": "HelloWorld", + "pin_contract_address": "0xe15193734357cf5c", + "imports": [] + } + } + ] + } + ] + } + ], + "parameters": null + } +} + +``` + +### Package + +Queries can be a FLIX `url` or `path` to a local FLIX file. This command leverages [FCL](../clients/fcl-js/) which will execute FLIX cadence code. Package files can be generated in JavaScript or TypeScript. + +:::warning + +Currently package doesn't support `id`, `name` flix query. + +::: + +### Package Usage + +```shell +# Generate packaged code that leverages FCL to call the Cadence transaction code, `--save` flag will save the output to a specific file +flow flix package transfer-flow --save ./package/transfer-flow.js +``` + +```shell +# Generate package code for a FLIX script using id, since there is no saving file, the result will display in terminal +flow flix package bd10ab0bf472e6b58ecc0398e9b3d1bd58a4205f14a7099c52c0640d9589295f +``` + +```shell +# Generate package code using local template file to save in a local file +flow flix package ./multiply.template.json --save ./multiply.js +``` + +```shell +# Generate package code using local template file to save in a local typescript file +flow flix package ./multiply.template.json --lang ts --save ./multiply.ts +``` + +### Example Package Output +```shell +flow flix package https://flix.flow.com/v1/templates\?name\=transfer-flow +``` + +```javascript + +/** + This binding file was auto generated based on FLIX template v1.0.0. + Changes to this file might get overwritten. + Note fcl version 1.3.0 or higher is required to use templates. +**/ + + +const flixTemplate = "https://flix.flow.com/v1/templates?name=transfer-flow" + +/** +* Transfer tokens from one account to another +* @param {Object} Parameters - parameters for the cadence +* @param {string} Parameters.amount - The amount of FLOW tokens to send: UFix64 +* @param {string} Parameters.to - The Flow account the tokens will go to: Address +* @returns {Promise} - returns a promise which resolves to the transaction id +*/ +export async function transferTokens({amount, to}) { + const transactionId = await fcl.mutate({ + template: flixTemplate, + args: (arg, t) => [arg(amount, t.UFix64), arg(to, t.Address)] + }); + + return transactionId +} + +``` + +```shell +# Generate TypeScript version of package file +flow flix package https://flix.flow.com/v1/templates?name=transfer-flow --lang ts +``` + +```typescript + +/** + This binding file was auto generated based on FLIX template v1.1.0. + Changes to this file might get overwritten. + Note fcl version 1.9.0 or higher is required to use templates. +**/ + + +const flixTemplate = "https://flix.flow.com/v1/templates?name=transfer-flow" + +interface TransferTokensParams { + amount: string; // The amount of FLOW tokens to send + to: string; // The Flow account the tokens will go to +} + +/** +* transferTokens: Transfer tokens from one account to another +* @param string amount - The amount of FLOW tokens to send +* @param string to - The Flow account the tokens will go to +* @returns {Promise} - Returns a promise that resolves to the transaction ID +*/ +export async function transferTokens({amount, to}: TransferTokensParams): Promise { + const transactionId = await fcl.mutate({ + template: flixTemplate, + args: (arg, t) => [arg(amount, t.UFix64), arg(to, t.Address)] + }); + + return transactionId +} + +``` +:::warning + +Notice that fcl v1.9.0 is needed to use FLIX v1.1 templates + +::: + +## Resources + +To find out more about FLIX, see the [read the FLIP](https://github.com/onflow/flips/blob/main/application/20220503-interaction-templates.md). + +For a list of all templates, check out the [FLIX template repository](https://github.com/onflow/flow-interaction-template-service/tree/master/templates). + +To generate a FLIX, see the [FLIX CLI readme](https://github.com/onflow/flow-interaction-template-tools/tree/master/cli). + +## Arguments +- Name: `argument` +- Valid input: valid [FLIX](https://github.com/onflow/flips/blob/main/application/20220503-interaction-templates.md) + +Input argument value matching corresponding types in the source code and passed in the same order. +You can pass a `nil` value to optional arguments by executing the flow FLIX execute script like this: `flow flix execute template.json nil`. + +## Flags + +### Arguments JSON + +- Flag: `--args-json` +- Valid inputs: arguments in JSON-Cadence form. +- Example: `flow flix execute template.script.json '[{"type": "String", "value": "Hello World"}]'` + +Arguments passed to the Cadence script in the Cadence JSON format. +Cadence JSON format contains `type` and `value` keys and is +[documented here](https://cadencelang.dev/docs/1.0/json-cadence-spec). + +## Pre Fill + +- Flag: `--pre-fill` +- Valid inputs: a json file in the FLIX json structure [FLIX json format](https://github.com/onflow/flips/blob/main/application/20220503-interaction-templates.md) + +## Block Height + +- Flag: `--block-height` +- Valid inputs: a block height number + +## Block ID + +- Flag: `--block-id` +- Valid inputs: a block ID + +### Signer + +- Flag: `--signer` +- Valid inputs: the name of an account defined in the configuration (`flow.json`) + +Specify the name of the account that will be used to sign the transaction. + +### Proposer + +- Flag: `--proposer` +- Valid inputs: the name of an account defined in the configuration (`flow.json`) + +Specify the name of the account that will be used as proposer in the transaction. + +### Payer + +- Flag: `--payer` +- Valid inputs: the name of an account defined in the configuration (`flow.json`) + +Specify the name of the account that will be used as payer in the transaction. + +### Authorizer + +- Flag: `--authorizer` +- Valid inputs: the name of a single or multiple comma-separated accounts defined in the configuration (`flow.json`) + +Specify the name of the account(s) that will be used as authorizer(s) in the transaction. If you want to provide multiple authorizers separate them using commas (e.g. `alice,bob`) + +### Gas Limit + +- Flag: `--gas-limit` +- Valid inputs: an integer greater than zero. +- Default: `1000` + +Specify the gas limit for this transaction. + +### Host + +- Flag: `--host` +- Valid inputs: an IP address or hostname. +- Default: `127.0.0.1:3569` (Flow Emulator) + +Specify the hostname of the Access API that will be +used to execute the command. This flag overrides +any host defined by the `--network` flag. + +### Network Key + +- Flag: `--network-key` +- Valid inputs: A valid network public key of the host in hex string format + +Specify the network public key of the Access API that will be +used to create a secure GRPC client when executing the command. + +### Network + +- Flag: `--network` +- Short Flag: `-n` +- Valid inputs: the name of a network defined in the configuration (`flow.json`) +- Default: `emulator` + +Specify which network you want the command to use for execution. + +### Filter + +- Flag: `--filter` +- Short Flag: `-x` +- Valid inputs: a case-sensitive name of the result property. + +Specify any property name from the result you want to return as the only value. + +### Output + +- Flag: `--output` +- Short Flag: `-o` +- Valid inputs: `json`, `inline` + +Specify the format of the command results. + +### Save + +- Flag: `--save` +- Short Flag: `-s` +- Valid inputs: a path in the current filesystem. + +Specify the filename where you want the result to be saved + +### Log + +- Flag: `--log` +- Short Flag: `-l` +- Valid inputs: `none`, `error`, `debug` +- Default: `info` + +Specify the log level. Control how much output you want to see during command execution. + +### Configuration + +- Flag: `--config-path` +- Short Flag: `-f` +- Valid inputs: a path in the current filesystem. +- Default: `flow.json` + +Specify the path to the `flow.json` configuration file. +You can use the `-f` flag multiple times to merge +several configuration files. + +### Version Check + +- Flag: `--skip-version-check` +- Default: `false` + +Skip version check during start up to speed up process for slow connections. \ No newline at end of file diff --git a/static/markdown/tools/flow-cli/flow.json/configuration.md b/static/markdown/tools/flow-cli/flow.json/configuration.md new file mode 100644 index 0000000000..01ba73e5ed --- /dev/null +++ b/static/markdown/tools/flow-cli/flow.json/configuration.md @@ -0,0 +1,368 @@ +--- +title: Configuration +description: What is Flow CLI Configuration +sidebar_position: 2 +--- + +Flow CLI uses a state called configuration which is stored in a file (usually `flow.json`). + +Flow configuration (`flow.json`) file will contain the following properties: + +- A `networks` list pre-populated with the Flow emulator, testnet and mainnet connection configuration. +- An `accounts` list pre-populated with the Flow Emulator service account. +- A `deployments` empty object where all [deployment targets](../deployment/project-contracts.md#define-contract-deployment-targets) can be defined. +- A `contracts` empty object where you [define contracts](../deployment/project-contracts.md#add-a-contract) you wish to deploy. + +## Example Project Configuration + +```json +{ + "networks": { + "emulator": "127.0.0.1:3569", + "mainnet": "access.mainnet.nodes.onflow.org:9000", + "testnet": "access.devnet.nodes.onflow.org:9000" + }, + "accounts": { + "emulator-account": { + "address": "f8d6e0586b0a20c7", + "key": "ae1b44c0f5e8f6992ef2348898a35e50a8b0b9684000da8b1dade1b3bcd6ebee", + } + }, + "deployments": {}, + "contracts": {} +} +``` + +## Configuration + +Below is an example of a configuration file for a complete Flow project. +We'll walk through each property one by one. + +```json +{ + "contracts": { + "NonFungibleToken": "./cadence/contracts/NonFungibleToken.cdc", + "Kibble": "./cadence/contracts/Kibble.cdc", + "KittyItems": "./cadence/contracts/KittyItems.cdc", + "KittyItemsMarket": "./cadence/contracts/KittyItemsMarket.cdc", + "FungibleToken": { + "source": "./cadence/contracts/FungibleToken.cdc", + "aliases": { + "testnet": "9a0766d93b6608b7", + "emulator": "ee82856bf20e2aa6" + } + } + }, + + "deployments": { + "testnet": { + "admin-account": ["NonFungibleToken"], + "user-account": ["Kibble", "KittyItems", "KittyItemsMarket"] + }, + "emulator": { + "emulator-account": [ + "NonFungibleToken", + "Kibble", + "KittyItems", + "KittyItemsMarket" + ] + } + }, + + "accounts": { + "admin-account": { + "address": "3ae53cb6e3f42a79", + "key": "12332967fd2bd75234ae9037dd4694c1f00baad63a10c35172bf65fbb8ad1111" + }, + "user-account": { + "address": "e2a8b7f23e8b548f", + "key": "22232967fd2bd75234ae9037dd4694c1f00baad63a10c35172bf65fbb8ad1111" + }, + "emulator-account": { + "address": "f8d6e0586b0a20c7", + "key": "2eae2f31cb5b756151fa11d82949c634b8f28796a711d7eb1e52cc301ed11111", + } + }, + + "networks": { + "emulator": "127.0.0.1:3569", + "mainnet": "access.mainnet.nodes.onflow.org:9000", + "testnet": "access.devnet.nodes.onflow.org:9000", + "testnetSecure": { + "Host": "access-001.devnet30.nodes.onflow.org:9001", + "NetworkKey": "ba69f7d2e82b9edf25b103c195cd371cf0cc047ef8884a9bbe331e62982d46daeebf836f7445a2ac16741013b192959d8ad26998aff12f2adc67a99e1eb2988d" + } + } +} +``` + +### Contracts + +Contracts are specified as key-value pairs, where the key is the contract name, +and the value is the location of the Cadence source code. + +The advanced format allows us to specify aliases for each network. + +#### Simple Format + +```json +... + +"contracts": { + "NonFungibleToken": "./cadence/contracts/NonFungibleToken.cdc" +} + +... +``` + +#### Advanced Format + +Using advanced format we can define `aliases`. Aliases define an address where the contract is already deployed for that specific network. +In the example scenario below the contract `FungibleToken` would be imported from the address `9a0766d93b6608b7` when deploying to testnet network +and address `ee82856bf20e2aa6` when deploying to the Flow emulator. +We can specify aliases for each network we have defined. When deploying to testnet it is always a good idea to specify aliases for all the [common contracts](../../../build//core-contracts/index.md) that have already been deployed to the testnet. + +⚠️ If we use an alias for the contract we should not specify it in the `deployment` section for that network. + +```json +... +"FungibleToken": { + "source": "./cadence/contracts/FungibleToken.cdc", + "aliases": { + "testnet": "9a0766d93b6608b7", + "emulator": "ee82856bf20e2aa6" + } +} +... +``` + +Format used to specify advanced contracts is: +```json +"CONTRACT NAME": { + "source": "CONTRACT SOURCE FILE LOCATION", + "aliases": { + "NETWORK NAME": "ADDRESS ON SPECIFIED NETWORK WITH DEPLOYED CONTRACT" + ... + } +} +``` + +### Accounts + +The accounts section is used to define account properties such as keys and addresses. +Each account must include a name, which is then referenced throughout the configuration file. + +#### Simple Format + +When using the simple format, simply specify the address for the account, and a single hex-encoded +private key. + +```json +... + +"accounts": { + "admin-account": { + "address": "3ae53cb6e3f42a79", + "key": "12332967fd2bd75234ae9037dd4694c1f00baad63a10c35172bf65fbb8ad1111" + } +} + +... +``` + +#### Advanced format + +The advanced format allows us to define more properties for the account. +We can define the signature algorithm and hashing algorithm, as well as custom key formats. + +Please note that we can use `service` for address in case the account is used on `emulator` network as this is a special +value that is defined on the run time to the default service address on the emulator network. + +**Example for advanced hex format:** +```json +... + +"accounts": { + "admin-account": { + "address": "service", + "key":{ + "type": "hex", + "index": 0, + "signatureAlgorithm": "ECDSA_P256", + "hashAlgorithm": "SHA3_256", + "privateKey": "12332967fd2bd75234ae9037dd4694c1f00baad63a10c35172bf65fbb8ad1111" + } + } +} + +... +``` + +You can also use BIP44 to derive keys from a mnemonic. For more details please see the [FLIP](https://github.com/onflow/flips/blob/main/application/20201125-bip-44-multi-account.md) + +**Example for BIP44 format:** +```json +... + +"accounts": { + "admin-account": { + "address": "service", + "key":{ + "type": "bip44", + "index": 0, + "signatureAlgorithm": "ECDSA_P256", + "hashAlgorithm": "SHA3_256", + "mnemonic": "skull design wagon top faith actor valley crystal subject volcano access join", + "derivationPath": "m/44'/539'/0'/0/0" + } + } +} + +... +``` + +Note: Default value for `derivationPath` is `m/44'/539'/0'/0/0` if omitted. + +You can also use a key management system (KMS) to sign the transactions. Currently, we only support Google KMS. + +**Example for Google KMS format:** +```json +... +"accounts": { + "admin-account": { + "address": "service", + "key": { + "type": "google-kms", + "index": 0, + "signatureAlgorithm": "ECDSA_P256", + "hashAlgorithm": "SHA3_256", + "resourceID": "projects/flow/locations/us/keyRings/foo/bar/cryptoKeyVersions/1" + } + } +} +... +``` + +You can store the account key to a separate file and provide the file location as part of the key configuration. + +**Example for separate key file:** +```json +... +"accounts": { + "admin-account": { + "address": "service", + "key": { + "type": "file", + "location": "./test.key" + } + } +} +... +``` +Inside the `test.key` file you should only put the hex key content (e.g. `12332967fd2bd75234ae9037dd4694c1f00baad63a10c35172bf65fbb8ad1111`) + +### Deployments + +The deployments section defines where the `project deploy` command will deploy specified contracts. +This configuration property acts as the glue that ties together accounts, +contracts and networks, all of which are referenced by name. + +In the deployments section we specify the network, account name and list of contracts to be deployed to that account. + +Format specifying the deployment is: +```json +... +"deployments": { + "NETWORK": { + "ACCOUNT NAME": ["CONTRACT NAME"] + } +} + +... +``` + +```json +... + +"deployments": { + "emulator": { + "emulator-account": [ + "NonFungibleToken", + "Kibble", + "KittyItems", + "KittyItemsMarket" + ] + }, + "testnet": { + "admin-account": ["NonFungibleToken"], + "user-account": [ + "Kibble", + "KittyItems", + "KittyItemsMarket" + ] + } +} + +... +``` + +### Networks + +Use this section to define networks and connection parameters for that specific network. + +Format for networks is: + +```json +... +"networks": { + "NETWORK NAME": "ADDRESS" +} +... +``` + +```json +... +"networks": { + "NETWORK NAME": { + "host": "ADDRESS", + "key": "ACCESS NODE NETWORK KEY" + } +} +... +``` + +```json +... + +"networks": { + "emulator": "127.0.0.1:3569", + "mainnet": "access.mainnet.nodes.onflow.org:9000", + "testnet": "access.devnet.nodes.onflow.org:9000", + "testnetSecure": { + "host": "access-001.devnet30.nodes.onflow.org:9001", + "key": "ba69f7d2e82b9edf25b103c195cd371cf0cc047ef8884a9bbe331e62982d46daeebf836f7445a2ac16741013b192959d8ad26998aff12f2adc67a99e1eb2988d" + }, +} + +... +``` +### Emulators + +The default emulator CLI is automatically configured with name being `"default"` and values of +`serviceAccount`: `"emulator-account"` and `port`: `"3569"`. The default emulator configuration will not show up on +flow.json. + +To customize emulator values, add emulator section like the example below: + +```json +... + +"emulators": { + "custom-emulator": { + "port": 3600, + "serviceAccount": "emulator-account" + } +} + +... +``` \ No newline at end of file diff --git a/static/markdown/tools/flow-cli/flow.json/initialize-configuration.md b/static/markdown/tools/flow-cli/flow.json/initialize-configuration.md new file mode 100644 index 0000000000..1e0318bc88 --- /dev/null +++ b/static/markdown/tools/flow-cli/flow.json/initialize-configuration.md @@ -0,0 +1,102 @@ +--- +title: Initialize Configuration +description: How to initialize Flow configuration using CLI +sidebar_position: 1 +--- + +Flow CLI uses a state to operate which is called configuration (usually `flow.json` file). +Before using commands that require this configuration we must initialize the project by +using the init command. Read more about [state configuration here](./configuration.md). + +```shell +flow init +``` + +## Example Usage + +```shell +> flow init + +Configuration initialized +Service account: 0xf8d6e0586b0a20c7 + +Start emulator by running: 'flow emulator' +Reset configuration using: 'flow init --reset' + +``` + +### Error Handling + +Existing configuration will cause the error below. +You should initialize in an empty folder or reset configuration using `--reset` flag +or by removing the configuration file first. +```shell +❌ Command Error: configuration already exists at: flow.json, if you want to reset configuration use the reset flag +``` + +## Global Configuration + +Flow supports global configuration which is a `flow.json` file saved in your home +directory and loaded as the first configuration file wherever you execute the CLI command. + +Please be aware that global configuration has the lowest priority and is overwritten +by any other configuration file if they exist (if `flow.json` exist in your current +directory it will overwrite properties in global configuration, but only those which overlap). + +You can generate a global configuration using `--global` flag. + +Command example: `flow init --global`. + +Global flow configuration is saved as: +- MacOs: `~/flow.json` +- Linux: `~/flow.json` +- Windows: `C:\Users\$USER\flow.json` + +## Flags + +### Reset + +- Flag: `--reset` + +Using this flag will reset the existing configuration and create a new one. + +### Global + +- Flag: `--global` + +Using this flag will create a global Flow configuration. + +### Service Private Key + +- Flag: `--service-private-key` +- Valid inputs: a hex-encoded private key in raw form. + +Private key used on the default service account. + +### Service Key Signature Algorithm + +- Flag: `--service-sig-algo` +- Valid inputs: `"ECDSA_P256", "ECDSA_secp256k1"` +- Default: `"ECDSA_P256"` + +Specify the ECDSA signature algorithm for the provided public key. + +Flow supports the secp256k1 and P-256 curves. + +### Service Key Hash Algorithm + +- Flag: `--service-hash-algo` +- Valid inputs: `"SHA2_256", "SHA3_256"` +- Default: `"SHA3_256"` + +Specify the hashing algorithm that will be paired with the public key +upon account creation. + +### Log + +- Flag: `--log` +- Short Flag: `-l` +- Valid inputs: `none`, `error`, `debug` +- Default: `info` + +Specify the log level. Control how much output you want to see while command execution. \ No newline at end of file diff --git a/static/markdown/tools/flow-cli/flow.json/manage-configuration.md b/static/markdown/tools/flow-cli/flow.json/manage-configuration.md new file mode 100644 index 0000000000..c49de81f47 --- /dev/null +++ b/static/markdown/tools/flow-cli/flow.json/manage-configuration.md @@ -0,0 +1,36 @@ +--- +title: Manage Configuration +description: How to configure the Flow CLI +sidebar_position: 3 +--- + +Configuration should be managed by using `config add` +and `config remove` commands. Using add command will also +validate values that will be added to the configuration. + +```shell +flow config add +flow config remove +``` + +## Example Usage + +```shell +flow config add account + +Name: Admin +Address: f8d6e0586b0a20c7 +✔ ECDSA_P256 +✔ SHA3_256 +Private key: e382a0e494...9285809356 +Key index (Default: 0): 0 +``` + +### Configuration + +- Flag: `--config-path` +- Short Flag: `-f` +- Valid inputs: valid filename + +Specify a filename for the configuration files, you can provide multiple configuration +files by using `-f` flag multiple times. \ No newline at end of file diff --git a/static/markdown/tools/flow-cli/flow.json/security.md b/static/markdown/tools/flow-cli/flow.json/security.md new file mode 100644 index 0000000000..f136fae2d6 --- /dev/null +++ b/static/markdown/tools/flow-cli/flow.json/security.md @@ -0,0 +1,107 @@ +--- +title: Security +description: How to securely use CLI +sidebar_position: 4 +--- + +The managing of accounts and private keys is intrinsically dangerous. +We must take extra precautions to not expose private key data when using +the CLI. + +The Flow CLI provides several options to secure private account data. + +⚠️ Warning: please be careful when using private keys in configuration files. +Never commit private key data to source control. +If private key data must be kept in text, we suggest using a separate file +that is not checked into source control (e.g. excluded with `.gitignore`). + +### Private Account Configuration File +Storing an account key to a separate file which is not checked into source control (e.g. excluded with `.gitignore`) +can be the first step towards better security. + +#### Main configuration file +```json +... +"accounts": { + "my-testnet-account": { + "address": "3ae53cb6e3f42a79", + "key": { + "type": "file", + "location": "./my-testnet-account.key" + } + } +} +... +``` + +#### Separate account key file +⚠️ Put this file in `.gitignore` + +The `my-testnet-account.key` file only contains the hex-encoded private key. +``` +334232967f52bd75234ae9037dd4694c1f00baad63a10c35172bf65fbb8ad1111 +``` +--- + +#### Private configuration file + +⚠️ Put this file in `.gitignore`: + +```json +// flow.testnet.json +{ + "accounts": { + "my-testnet-account": { + "address": "3ae53cb6e3f42a79", + "key": "334232967f52bd75234ae9037dd4694c1f00baad63a10c35172bf65fbb8ad1111" + } + } +} +``` + +### Store Configuration in Environment Variables + +You can use environment variables for values that should be kept private (e.g. private keys, addresses). + +See example below: + +```shell +PRIVATE_KEY=key flow project deploy +``` + +```json +// flow.json +{ + ... + "accounts": { + "my-testnet-account": { + "address": "3ae53cb6e3f42a79", + "key": "$PRIVATE_KEY" + } + } + ... +} +``` + +### Private Dotenv File + +The CLI will load environment variables defined in the `.env` file in the active directory, if one exists. +These variables can be substituted inside the `flow.json`, +just like any other environment variable. + +⚠️ You should never commit `.env` to source control, +especially if it contains sensitive information +like a private key. + +Example `.env` file: +```bash +PRIVATE_KEY=123 +``` + +### Composing Multiple Configuration Files + +You can merge multiple configuration files like so: + +```shell +flow project deploy -f main.json -f private.json +``` \ No newline at end of file diff --git a/static/markdown/tools/flow-cli/get-flow-data/get-blocks.md b/static/markdown/tools/flow-cli/get-flow-data/get-blocks.md new file mode 100644 index 0000000000..931872f073 --- /dev/null +++ b/static/markdown/tools/flow-cli/get-flow-data/get-blocks.md @@ -0,0 +1,167 @@ +--- +title: Get Block +description: How to get a block from the command line +sidebar_position: 1 +--- + +The Flow CLI provides a command to fetch any block from the Flow network. + +```shell +flow blocks get +``` + +## Example Usage + +```shell +flow blocks get 12884163 --host access.mainnet.nodes.onflow.org:9000 --include transactions +``` + +### Example response + +```shell +Block ID 2fb7571a6ccf02f3ac42f27c14ce0a4cb119060e4fbd7af36fd51894465e7002 +Prent ID 1c5a6267ba9512e141e4e90630cb326cecfbf6113818487449efeb37fc98ca18 +Timestamp 2021-03-19 17:46:15.973305066 +0000 UTC +Height 12884163 +Status Sealed +Total Seals 2 +Total Collections 8 + Collection 0: 3e694588e789a72489667a36dd73104dea4579bcd400959d47aedccd7f930eeb + Transaction 0: acc2ae1ff6deb2f4d7663d24af6ab1baf797ec264fd76a745a30792f6882093b + Transaction 1: ae8bfbc85ce994899a3f942072bfd3455823b1f7652106ac102d161c17fcb55c + Transaction 2: 70c4d39d34e654173c5c2746e7bb3a6cdf1f5e6963538d62bad2156fc02ea1b2 + Transaction 3: 2466237b5eafb469c01e2e5f929a05866de459df3bd768cde748e068c81c57bf + Collection 1: e93f2bd988d66288c7e1ad991dec227c6c74b8039a430e43896ad94cf8feccce + Transaction 0: 4d790300722b646e7ed3e2c52675430d7ccf2efd1d93f106b53bc348df601af6 + Collection 2: c7d93b80ae55809b1328c686f6a8332e8e15083ab32f8b3105c4d910646f54bf + Transaction 0: 95c4efbb30f86029574d6acd7df04afe6108f6fd610d823dfd398c80cfa5e842 + Collection 3: 1a4f563b48aaa38f3a7e867c89422e0bd84887de125e8f48ba147f4ee58ddf0d + Transaction 0: fbcc99326336d4dbb4cbc01a3b9b85cfcdcdc071b3d0e01ee88ecd144444600b + Collection 4: 01000c7773cc3c22cba6d8917a2486dc7a1a1842dd7fb7c0e87e63c22bb14abe + Transaction 0: a75097639b434044de0122d3a28620e093f277fa715001e80a035568e118c59f + Collection 5: 6f2b08f9673545a2e61e954feb8d55d2a3ef2b3cef7a8d2f8de527bc42d92c28 + Transaction 0: 8ea63d397bd07a25db3f06fb9785dbf09bc652159f68a84c55ea2be606ada1e9 + Collection 6: 13b5c48252930824a8c6e846470763582cacdacb772c1e9c584adefced6724b2 + Transaction 0: 8ba57a92311367189a89a59bcb3c32192387fefca9bde493e087bc0d479186a8 + Transaction 1: 8ab1d99702ccf31b6f4b3acd2580dddd440f08bc07acab4884337c0c593a8f69 + Collection 7: bf90fdd2761b8f37565af60fc38165dd09edf0671fdd35b37f718a7eb45e804f + Transaction 0: b92a14c0802183719efed00363d31076d7e50f41a6207781cf34d39c822bbacb + +``` + +## Arguments + +### Query +- Name: `` +- Valid Input: Block ID, `latest` or block height + +Specify the block to retrieve by block ID or block height. + +## Arguments + +### Address +- Name: `address` +- Valid Input: Flow account address + +Flow [account address](../../../build/basics/accounts.md) (prefixed with `0x` or not). + +## Flags + +### Events + +- Flag: `--events` +- Valid inputs: Valid event name + +List events of this type for the block. + +### Include + +- Flag: `--include` +- Valid inputs: `transactions` + +Include additional values in the response. + +### Signer + +- Flag: `--signer` +- Valid inputs: the name of an account defined in the configuration (`flow.json`) + +Specify the name of the account that will be used to sign the transaction. + +### Host + +- Flag: `--host` +- Valid inputs: an IP address or hostname. +- Default: `127.0.0.1:3569` (Flow Emulator) + +Specify the hostname of the Access API that will be +used to execute the command. This flag overrides +any host defined by the `--network` flag. + +### Network Key + +- Flag: `--network-key` +- Valid inputs: A valid network public key of the host in hex string format + +Specify the network public key of the Access API that will be +used to create a secure GRPC client when executing the command. + +### Network + +- Flag: `--network` +- Short Flag: `-n` +- Valid inputs: the name of a network defined in the configuration (`flow.json`) +- Default: `emulator` + +Specify which network you want the command to use for execution. + +### Filter + +- Flag: `--filter` +- Short Flag: `-x` +- Valid inputs: a case-sensitive name of the result property. + +Specify any property name from the result you want to return as the only value. + +### Output + +- Flag: `--output` +- Short Flag: `-o` +- Valid inputs: `json`, `inline` + +Specify the format of the command results. + +### Save + +- Flag: `--save` +- Short Flag: `-s` +- Valid inputs: a path in the current filesystem. + +Specify the filename where you want the result to be saved + +### Log + +- Flag: `--log` +- Short Flag: `-l` +- Valid inputs: `none`, `error`, `debug` +- Default: `info` + +Specify the log level. Control how much output you want to see during command execution. + +### Configuration + +- Flag: `--config-path` +- Short Flag: `-f` +- Valid inputs: a path in the current filesystem. +- Default: `flow.json` + +Specify the path to the `flow.json` configuration file. +You can use the `-f` flag multiple times to merge +several configuration files. + +### Version Check + +- Flag: `--skip-version-check` +- Default: `false` + +Skip version check during start up to speed up process for slow connections. \ No newline at end of file diff --git a/static/markdown/tools/flow-cli/get-flow-data/get-collections.md b/static/markdown/tools/flow-cli/get-flow-data/get-collections.md new file mode 100644 index 0000000000..a10d9fb3f3 --- /dev/null +++ b/static/markdown/tools/flow-cli/get-flow-data/get-collections.md @@ -0,0 +1,117 @@ +--- +title: Get Collection +description: How to get a collection from the command line +sidebar_position: 3 +--- + +The Flow CLI provides a command to fetch any collection from the Flow network. + +```shell +flow collections get +``` + +## Example Usage + +```shell +flow collections get 3e694588e789a72489667a36dd73104dea4579bcd400959d47aedccd7f930eeb \ +--host access.mainnet.nodes.onflow.org:9000 +``` + +### Example response + +```shell +Collection ID 3e694588e789a72489667a36dd73104dea4579bcd400959d47aedccd7f930eeb: +acc2ae1ff6deb2f4d7663d24af6ab1baf797ec264fd76a745a30792f6882093b +ae8bfbc85ce994899a3f942072bfd3455823b1f7652106ac102d161c17fcb55c +70c4d39d34e654173c5c2746e7bb3a6cdf1f5e6963538d62bad2156fc02ea1b2 +2466237b5eafb469c01e2e5f929a05866de459df3bd768cde748e068c81c57bf + +``` + +## Arguments + +### Collection ID +- Name: `collection_id` +- Valid Input: SHA3-256 hash of the collection contents + +## Arguments + +## Flags + +### Host + +- Flag: `--host` +- Valid inputs: an IP address or hostname. +- Default: `127.0.0.1:3569` (Flow Emulator) + +Specify the hostname of the Access API that will be +used to execute the command. This flag overrides +any host defined by the `--network` flag. + +### Network Key + +- Flag: `--network-key` +- Valid inputs: A valid network public key of the host in hex string format + +Specify the network public key of the Access API that will be +used to create a secure GRPC client when executing the command. + +### Network + +- Flag: `--network` +- Short Flag: `-n` +- Valid inputs: the name of a network defined in the configuration (`flow.json`) +- Default: `emulator` + +Specify which network you want the command to use for execution. + +### Filter + +- Flag: `--filter` +- Short Flag: `-x` +- Valid inputs: a case-sensitive name of the result property. + +Specify any property name from the result you want to return as the only value. + +### Output + +- Flag: `--output` +- Short Flag: `-o` +- Valid inputs: `json`, `inline` + +Specify the format of the command results. + +### Save + +- Flag: `--save` +- Short Flag: `-s` +- Valid inputs: a path in the current filesystem. + +Specify the filename where you want the result to be saved + +### Log + +- Flag: `--log` +- Short Flag: `-l` +- Valid inputs: `none`, `error`, `debug` +- Default: `info` + +Specify the log level. Control how much output you want to see during command execution. + +### Configuration + +- Flag: `--config-path` +- Short Flag: `-f` +- Valid inputs: a path in the current filesystem. +- Default: `flow.json` + +Specify the path to the `flow.json` configuration file. +You can use the `-f` flag multiple times to merge +several configuration files. + +### Version Check + +- Flag: `--skip-version-check` +- Default: `false` + +Skip version check during start up to speed up process for slow connections. \ No newline at end of file diff --git a/static/markdown/tools/flow-cli/get-flow-data/get-events.md b/static/markdown/tools/flow-cli/get-flow-data/get-events.md new file mode 100644 index 0000000000..9cf3818667 --- /dev/null +++ b/static/markdown/tools/flow-cli/get-flow-data/get-events.md @@ -0,0 +1,215 @@ +--- +title: Get Events +description: How to get an event from the command line +sidebar_position: 2 +--- + +Use the event command to fetch a single or multiple events in a specific range of blocks. +You can provide start and end block height range, but also specify number of the latest blocks to +be used to search for specified event. Events are fetched concurrently by using multiple workers which +optionally you can also control by specifying the flags. + +```shell +flow events get +``` + +## Example Usage + +Get the event by name `A.0b2a3299cc857e29.TopShot.Deposit` from the last 20 blocks on mainnet. +```shell +> flow events get A.0b2a3299cc857e29.TopShot.Deposit --last 20 --network mainnet + + Events Block #12913388: + Index 2 + Type A.0b2a3299cc857e29.TopShot.Deposit + Tx ID 0a1e6cdc4eeda0e23402193d7ad5ba01a175df4c08f48fa7ac8d53e811c5357c + Values + id (UInt64) 3102159 + to ({}?) 24214cf0faa7844d + + Index 2 + Type A.0b2a3299cc857e29.TopShot.Deposit + Tx ID 1fa5e64dcdc8ed5dad87ba58207ee4c058feb38fa271fff659ab992dc2ec2645 + Values + id (UInt64) 5178448 + to ({}?) 26c96b6c2c31e419 + + Index 9 + Type A.0b2a3299cc857e29.TopShot.Deposit + Tx ID 262ab3996bdf98f5f15804c12b4e5d4e89c0fa9b71d57be4d7c6e8288c507c4a + Values + id (UInt64) 1530408 + to ({}?) 2da5c6d1a541971b + +... +``` + +Get two events `A.1654653399040a61.FlowToken.TokensDeposited` +and `A.1654653399040a61.FlowToken.TokensWithdrawn` in the block height range on mainnet. +```shell +> flow events get \ + A.1654653399040a61.FlowToken.TokensDeposited \ + A.1654653399040a61.FlowToken.TokensWithdrawn \ + --start 11559500 --end 11559600 --network mainnet + + Events Block #17015045: + Index 0 + Type A.1654653399040a61.FlowToken.TokensWithdrawn + Tx ID 6dcf60d54036acb52b2e01e69890ce34c3146849998d64364200e4b21e9ac7f1 + Values + - amount (UFix64): 0.00100000 + - from (Address?): 0x9e06eebf494e2d78 + + Index 1 + Type A.1654653399040a61.FlowToken.TokensWithdrawn + Tx ID 6dcf60d54036acb52b2e01e69890ce34c3146849998d64364200e4b21e9ac7f1 + Values + - amount (UFix64): 0.00100000 + - from (Never?): nil + + Events Block #17015047: + Index 0 + Type A.1654653399040a61.FlowToken.TokensWithdrawn + Tx ID 24979a3c0203f514f7f5822cc8ae7046e24f25d4a775bef697a654898fb7673e + Values + - amount (UFix64): 0.00100000 + - from (Address?): 0x18eb4ee6b3c026d2 + + Index 1 + Type A.1654653399040a61.FlowToken.TokensWithdrawn + Tx ID 24979a3c0203f514f7f5822cc8ae7046e24f25d4a775bef697a654898fb7673e + Values + - amount (UFix64): 0.00100000 + - from (Never?): nil +``` + +## Arguments + +### Event Name + +- Name: `event_name` +- Valid Input: String + +Fully-qualified identifier for the events. +You can provide multiple event names separated by a space. + +## Flags + +### Start + +- Flag: `--start` +- Valid inputs: valid block height + +Specify the start block height used alongside the end flag. +This will define the lower boundary of the block range. + +### End + +- Flag: `--end` +- Valid inputs: valid block height + +Specify the end block height used alongside the start flag. +This will define the upper boundary of the block range. + +### Last + +- Flag: `--last` +- Valid inputs: number +- Default: `10` + +Specify the number of blocks relative to the last block. Ignored if the +start flag is set. Used as a default if no flags are provided. + +### Batch + +- Flag: `--batch` +- Valid inputs: number +- Default: `25` + +Number of blocks each worker will fetch. + +### Workers + +- Flag: `--workers` +- Valid inputs: number +- Default: `10` + +Number of workers to use when fetching events concurrently. + +### Host + +- Flag: `--host` +- Valid inputs: an IP address or hostname. +- Default: `127.0.0.1:3569` (Flow Emulator) + +Specify the hostname of the Access API that will be +used to execute the command. This flag overrides +any host defined by the `--network` flag. + +### Network Key + +- Flag: `--network-key` +- Valid inputs: A valid network public key of the host in hex string format + +Specify the network public key of the Access API that will be +used to create a secure GRPC client when executing the command. + +### Network + +- Flag: `--network` +- Short Flag: `-n` +- Valid inputs: the name of a network defined in the configuration (`flow.json`) +- Default: `emulator` + +Specify which network you want the command to use for execution. + +### Filter + +- Flag: `--filter` +- Short Flag: `-x` +- Valid inputs: a case-sensitive name of the result property. + +Specify any property name from the result you want to return as the only value. + +### Output + +- Flag: `--output` +- Short Flag: `-o` +- Valid inputs: `json`, `inline` + +Specify the format of the command results. + +### Save + +- Flag: `--save` +- Short Flag: `-s` +- Valid inputs: a path in the current filesystem. + +Specify the filename where you want the result to be saved + +### Log + +- Flag: `--log` +- Short Flag: `-l` +- Valid inputs: `none`, `error`, `debug` +- Default: `info` + +Specify the log level. Control how much output you want to see during command execution. + +### Configuration + +- Flag: `--config-path` +- Short Flag: `-f` +- Valid inputs: a path in the current filesystem. +- Default: `flow.json` + +Specify the path to the `flow.json` configuration file. +You can use the `-f` flag multiple times to merge +several configuration files. + +### Version Check + +- Flag: `--skip-version-check` +- Default: `false` + +Skip version check during start up to speed up process for slow connections. \ No newline at end of file diff --git a/static/markdown/tools/flow-cli/get-flow-data/get-status.md b/static/markdown/tools/flow-cli/get-flow-data/get-status.md new file mode 100644 index 0000000000..82660779da --- /dev/null +++ b/static/markdown/tools/flow-cli/get-flow-data/get-status.md @@ -0,0 +1,98 @@ +--- +title: Network Status +description: How to get access node status from the command line +sidebar_position: 4 +--- + +The Flow CLI provides a command to get network status of specified Flow Access Node + +`flow status` + +## Example Usage + +```shell +> flow status --network testnet + +Status: 🟢 ONLINE +Network: testnet +Access Node: access.devnet.nodes.onflow.org:9000 +``` + +## Flags + +### Network + +- Flag: `--network` +- Short Flag: `-n` +- Valid inputs: the name of a network defined in the configuration (`flow.json`). + +Specify which network you want the command to use for execution. + +### Host + +- Flag: `--host` +- Valid inputs: an IP address or hostname. +- Default: `127.0.0.1:3569` (Flow Emulator) + +Specify the hostname of the Access API that will be +used to execute the command. This flag overrides +any host defined by the `--network` flag. + +### Network Key + +- Flag: `--network-key` +- Valid inputs: A valid network public key of the host in hex string format + +Specify the network public key of the Access API that will be +used to create a secure GRPC client when executing the command. + +### Filter + +- Flag: `--filter` +- Short Flag: `-x` +- Valid inputs: a case-sensitive name of the result property. + +Specify any property name from the result you want to return as the only value. + +### Output + +- Flag: `--output` +- Short Flag: `-o` +- Valid inputs: `json`, `inline` + +Specify the format of the command results. + +### Save + +- Flag: `--save` +- Short Flag: `-s` +- Valid inputs: a path in the current filesystem. + +Specify the filename where you want the result to be saved + +### Log + +- Flag: `--log` +- Short Flag: `-l` +- Valid inputs: `none`, `error`, `debug` +- Default: `info` + +Specify the log level. Control how much output you want to see during command execution. + +### Configuration + +- Flag: `--conf` +- Short Flag: `-f` +- Valid inputs: a path in the current filesystem. +- Default: `flow.json` + +Specify the path to the `flow.json` configuration file. +You can use the `-f` flag multiple times to merge +several configuration files. + +### Version Check + +- Flag: `--skip-version-check` +- Default: `false` + +Skip version check during start up to speed up process for slow connections. \ No newline at end of file diff --git a/static/markdown/tools/flow-cli/index.md b/static/markdown/tools/flow-cli/index.md new file mode 100644 index 0000000000..1afa652299 --- /dev/null +++ b/static/markdown/tools/flow-cli/index.md @@ -0,0 +1,30 @@ +--- +title: Flow CLI +sidebar_label: Flow CLI +sidebar_position: 3 +--- + +The **Flow Command Line Interface (CLI)** is a powerful tool that enables developers to seamlessly interact with the Flow blockchain across various environments, including testnet, mainnet, and local development using the Flow Emulator. Designed for ease of use, the Flow CLI simplifies common blockchain tasks such as managing accounts and contract dependencies, sending transactions, querying chain state, deploying smart contracts, and much more. + +With Flow CLI, developers can: + +- **Initialize Projects**: Quickly set up new Flow projects using the `flow init` command, which creates the necessary files and directories, sets up your project configuration, and installs any core contract dependencies. +- **Manage Contract Dependencies**: Use the [Dependency Manager](dependency-manager.md) to install and manage smart contract dependencies effortlessly, simplifying the integration of external contracts into your project. +- **Manage Accounts**: Create and manage Flow accounts, configure keys, and handle account-related operations. +- **Send Transactions**: Build, sign, and submit transactions to the Flow network, allowing for contract interaction and fund transfers. +- **Query Chain State**: Retrieve data from the Flow blockchain, including account balances, event logs, and the status of specific transactions. +- **Deploy Smart Contracts**: Easily deploy and update Cadence smart contracts on any Flow environment (emulator, testnet, or mainnet). +- **Use the Emulator:** Set up a local Flow blockchain instance with the Flow emulator to test and debug smart contracts in a development environment before deploying them on the network. +- **Interact with the [Flow Access API](/http-api)**: Automate complex workflows using configuration files and command-line scripting, which allows for greater flexibility in continuous integration (CI) or custom development tools. +- **Access Flow’s Tooling Ecosystem**: Integrate Flow CLI with other developer tools like the [Cadence Extension for VSCode](https://marketplace.visualstudio.com/items?itemName=onflow.cadence) to enhance your development experience. + +The Flow CLI is essential for developers looking to build, test, and maintain decentralized applications on the Flow blockchain efficiently, offering a feature-rich, user-friendly interface for both beginners and experienced blockchain developers. + +## Installation + +Follow [these steps](../flow-cli/install.md) to install the Flow CLI on +macOS, Linux, and Windows. + +## Create Your First Project + +To get started with creating your first Flow project and to learn more about how to use the Flow CLI super commands, please refer to the [Super Commands documentation](super-commands.md). These commands simplify the setup and development process, allowing you to focus on building your application without worrying about the underlying configurations. \ No newline at end of file diff --git a/static/markdown/tools/flow-cli/install.md b/static/markdown/tools/flow-cli/install.md new file mode 100644 index 0000000000..811b919ee4 --- /dev/null +++ b/static/markdown/tools/flow-cli/install.md @@ -0,0 +1,138 @@ +--- +title: Install Instructions +description: How to install the Flow command-line interface (CLI) +sidebar_position: 1 +--- + +The Flow CLI can be installed on macOS, Windows (7 or greater) and most Linux systems. + +> Note: If you need to install the pre-release version of the Flow CLI supporting Cadence 1.0, please refer to the [Cadence 1.0 migration guide instructions](https://cadence-lang.org/docs/cadence-migration-guide#install-cadence-10-cli). + +## macOS + +### Homebrew + +```sh +brew install flow-cli +``` + +### From a pre-built binary + +_This installation method only works on x86-64._ + +This script downloads and installs the appropriate binary for your system: + +```sh +sh -ci "$(curl -fsSL https://raw.githubusercontent.com/onflow/flow-cli/master/install.sh)" +``` + +To update, simply re-run the installation command above. + +It is currently not possible to install earlier versions of the Flow CLI with Homebrew. +## Linux + +### From a pre-built binary + +_This installation method only works on x86-64._ + +This script downloads and installs the appropriate binary for your system: + +```sh +sh -ci "$(curl -fsSL https://raw.githubusercontent.com/onflow/flow-cli/master/install.sh)" +``` + +To update, simply re-run the installation command above. + +### Install a specific version + +To install a specific version of Flow CLI newer than v0.42.0, append the version tag to the command (e.g. the command below installs CLI version v0.44.0). + +```sh +sh -ci "$(curl -fsSL https://raw.githubusercontent.com/onflow/flow-cli/master/install.sh)" -- v0.44.0 +``` + +To install a version older than v0.42.0, refer to [Installing versions before 0.42.0](#installing-versions-before-0420) below. + +## Windows + +### From a pre-built binary + +_This installation method only works on Windows 10, 8.1, or 7 (SP1, with [PowerShell 3.0](https://www.microsoft.com/en-ca/download/details.aspx?id=34595)), on x86-64._ + +1. Open PowerShell ([Instructions](https://docs.microsoft.com/en-us/powershell/scripting/install/installing-windows-powershell?view=powershell-7#finding-powershell-in-windows-10-81-80-and-7)) +2. In PowerShell, run: + + ```powershell + iex "& { $(irm 'https://raw.githubusercontent.com/onflow/flow-cli/master/install.ps1') }" + ``` + +To update, simply re-run the installation command above. + +# Upgrade the Flow CLI + +## macOS + +### Homebrew + +```sh +brew upgrade flow-cli +``` + +### From a pre-built binary + +_This update method only works on x86-64._ + +This script downloads and updates the appropriate binary for your system: + +```sh +sh -ci "$(curl -fsSL https://raw.githubusercontent.com/onflow/flow-cli/master/install.sh)" +``` + +## Linux + +### From a pre-built binary + +_This update method only works on x86-64._ + +This script downloads and updates the appropriate binary for your system: + +```sh +sh -ci "$(curl -fsSL https://raw.githubusercontent.com/onflow/flow-cli/master/install.sh)" +``` + +## Windows + +### From a pre-built binary + +_This update method only works on Windows 10, 8.1, or 7 (SP1, with [PowerShell 3.0](https://www.microsoft.com/en-ca/download/details.aspx?id=34595)), on x86-64._ + +1. Open PowerShell ([Instructions](https://docs.microsoft.com/en-us/powershell/scripting/install/installing-windows-powershell?view=powershell-7#finding-powershell-in-windows-10-81-80-and-7)) +2. In PowerShell, run: + + ```powershell + iex "& { $(irm 'https://raw.githubusercontent.com/onflow/flow-cli/master/install.ps1') }" + ``` + +# Uninstalling Flow CLI +To remove the flow CLI you can run the following command if it was previously installed using a pre-built binary. + +- macOS: `rm /usr/local/bin/flow` +- Linux: `rm ~/.local/bin/flow` +- Windows: `rm ~/Users/{user}/AppData/Flow/flow.exe` + +If you installed it using Hombrew you can remove it using: `brew uninstall flow-cli`. + +## Installing versions before 0.42.0 +If you want to install versions before v0.42.0 you have to use a different install command. + +**Linux/macOS** +``` +https://raw.githubusercontent.com/onflow/flow-cli/v0.41.3/install.ps1 + +sh -ci "$(curl -fsSL https://raw.githubusercontent.com/onflow/flow-cli/v0.41.3/install.sh)" -- v0.41.2 +``` + +**Windows** +``` +iex "& { $(irm 'https://raw.githubusercontent.com/onflow/flow-cli/master/install.ps1') }" +``` \ No newline at end of file diff --git a/static/markdown/tools/flow-cli/keys/decode-keys.md b/static/markdown/tools/flow-cli/keys/decode-keys.md new file mode 100644 index 0000000000..1a54978986 --- /dev/null +++ b/static/markdown/tools/flow-cli/keys/decode-keys.md @@ -0,0 +1,89 @@ +--- +title: Decode Public Keys +description: How to decode Flow public keys from the command line +sidebar_position: 2 +--- + +The Flow CLI provides a command to decode encoded public account keys. + +```shell +flow keys decode +``` + +## Example Usage + +### Decode RLP Encoded Public Key +```shell +> flow keys decode rlp f847b84084d716c14b051ad6b001624f738f5d302636e6b07cc75e4530af7776a4368a2b586dbefc0564ee28384c2696f178cbed52e62811bcc9ecb59568c996d342db2402038203e8 + +Public Key 84d716c1...bcc9ecb59568c996d342db24 +Signature algorithm ECDSA_P256 +Hash algorithm SHA3_256 +Weight 1000 +Revoked false +``` + +### Decode PEM Encoded Public Key From File +```shell +> flow keys decode pem --from-file key.pem + +Public Key d479b3c...c4615360039a6660a366a95f +Signature algorithm ECDSA_P256 +Hash algorithm UNKNOWN +Revoked false + +``` + +## Arguments + +### Encoding +- Valid inputs: `rlp`, `pem` + +First argument specifies a valid encoding of the public key provided. + +### Optional: Public Key +- Name: `encoded public key` +- Valid inputs: valid encoded key content + +Optional second argument provides content of the encoded public key. +If this argument is omitted the `--from-file` must be used instead. + +## Flags + +### From File + +- Flag: `--from-file` +- Valid inputs: valid filepath + +Provide file with the encoded public key. + +### Filter + +- Flag: `--filter` +- Short Flag: `-x` +- Valid inputs: a case-sensitive name of the result property. + +Specify any property name from the result you want to return as the only value. + +### Output + +- Flag: `--output` +- Short Flag: `-o` +- Valid inputs: `json`, `inline` + +Specify the format of the command results. + +### Save + +- Flag: `--save` +- Short Flag: `-s` +- Valid inputs: a path in the current filesystem. + +Specify the filename where you want the result to be saved + +### Version Check + +- Flag: `--skip-version-check` +- Default: `false` + +Skip version check during start up to speed up process for slow connections. \ No newline at end of file diff --git a/static/markdown/tools/flow-cli/keys/derive-keys.md b/static/markdown/tools/flow-cli/keys/derive-keys.md new file mode 100644 index 0000000000..27a903f76d --- /dev/null +++ b/static/markdown/tools/flow-cli/keys/derive-keys.md @@ -0,0 +1,69 @@ +--- +title: Derive Public Key +description: How to derive Flow public key from a private key from the command line +sidebar_position: 3 +--- + +The Flow CLI provides a command to derive Public Key from a Private Key. + +```shell +flow keys derive +``` + +## Example Usage + +### Derive Public Key from a Private Key +```shell +> flow keys derive c778170793026a9a7a3815dabed68ded445bde7f40a8c66889908197412be89f +``` + +### Example response + +```shell +> flow keys generate + +🔴️ Store Private Key safely and don't share with anyone! +Private Key c778170793026a9a7a3815dabed68ded445bde7f40a8c66889908197412be89f +Public Key 584245c57e5316d6606c53b1ce46dae29f5c9bd26e9e8...aaa5091b2eebcb2ac71c75cf70842878878a2d650f7 +``` + +## Arguments + +### Private Key +- Name: `private key` +- Valid inputs: valid private key content + +## Flags + +### Signature Algorithm + +- Flag: `--sig-algo` +- Valid inputs: `"ECDSA_P256", "ECDSA_secp256k1"` + +Specify the ECDSA signature algorithm for the key pair. + +Flow supports the secp256k1 and P-256 curves. + +### Filter + +- Flag: `--filter` +- Short Flag: `-x` +- Valid inputs: a case-sensitive name of the result property. + +Specify any property name from the result you want to return as the only value. + +### Output + +- Flag: `--output` +- Short Flag: `-o` +- Valid inputs: `json`, `inline` + +Specify the format of the command results. + +### Save + +- Flag: `--save` +- Short Flag: `-s` +- Valid inputs: a path in the current filesystem. + +Specify the filename where you want the result to be saved \ No newline at end of file diff --git a/static/markdown/tools/flow-cli/keys/generate-keys.md b/static/markdown/tools/flow-cli/keys/generate-keys.md new file mode 100644 index 0000000000..ddceb594b5 --- /dev/null +++ b/static/markdown/tools/flow-cli/keys/generate-keys.md @@ -0,0 +1,107 @@ +--- +title: Generate Keys +description: How to generate key pair from the command line +sidebar_position: 1 +--- + +The Flow CLI provides a command to generate ECDSA key pairs +that can be [attached to new or existing Flow accounts](../../../build/basics/accounts.md). + +```shell +flow keys generate +``` + +⚠️ Store private key safely and don't share with anyone! + +## Example Usage + +```shell +flow keys generate +``` + +### Example response + +```shell +> flow keys generate + +🔴️ Store Private Key safely and don't share with anyone! +Private Key c778170793026a9a7a3815dabed68ded445bde7f40a8c66889908197412be89f +Public Key 584245c57e5316d6606c53b1ce46dae29f5c9bd26e9e8...aaa5091b2eebcb2ac71c75cf70842878878a2d650f7 +``` + +## Flags + +### Seed + +- Flag: `--seed` +- Valid inputs: any string with length >= 32 + +Specify a UTF-8 seed string that will be used to generate the key pair. +Key generation is deterministic, so the same seed will always +result in the same key. + +If no seed is specified, the key pair will be generated using +a random 32 byte seed. + +⚠️ Using seed with production keys can be dangerous if seed was not generated +by using safe random generators. + +### Signature Algorithm + +- Flag: `--sig-algo` +- Valid inputs: `"ECDSA_P256", "ECDSA_secp256k1"` + +Specify the ECDSA signature algorithm for the key pair. + +Flow supports the secp256k1 and P-256 curves. + +### Filter + +- Flag: `--filter` +- Short Flag: `-x` +- Valid inputs: a case-sensitive name of the result property. + +Specify any property name from the result you want to return as the only value. + +### Output + +- Flag: `--output` +- Short Flag: `-o` +- Valid inputs: `json`, `inline` + +Specify the format of the command results. + +### Save + +- Flag: `--save` +- Short Flag: `-s` +- Valid inputs: a path in the current filesystem. + +Specify the filename where you want the result to be saved + +### Log + +- Flag: `--log` +- Short Flag: `-l` +- Valid inputs: `none`, `error`, `debug` +- Default: `info` + +Specify the log level. Control how much output you want to see during command execution. + +### Configuration + +- Flag: `--config-path` +- Short Flag: `-f` +- Valid inputs: a path in the current filesystem. +- Default: `flow.json` + +Specify the path to the `flow.json` configuration file. +You can use the `-f` flag multiple times to merge +several configuration files. + +### Version Check + +- Flag: `--skip-version-check` +- Default: `false` + +Skip version check during start up to speed up process for slow connections. \ No newline at end of file diff --git a/static/markdown/tools/flow-cli/lint.md b/static/markdown/tools/flow-cli/lint.md new file mode 100644 index 0000000000..1f86bfb83c --- /dev/null +++ b/static/markdown/tools/flow-cli/lint.md @@ -0,0 +1,33 @@ +--- +title: Cadence Linter +description: A static-analysis tool for finding potential issues in Cadence code +sidebar_position: 14 +--- + +The Cadence Linter is a static-analysis tool for finding potential issues in Cadence code. It is available in the Flow CLI & is designed to help developers write better code by identifying common mistakes and potential issues before they become problems. + +The linter will also check your code for any syntax or semantic errors, and provide suggestions for how to fix them. + +```shell +flow cadence lint [files] +``` + +## Example Usage + +```shell +flow cadence lint **/*.cdc +``` + +## Example Output + +```shell +test.cdc:27:6: semantic-error: cannot find variable in this scope: `abc` + +test.cdc:35:6: removal-hint: unnecessary force operator + +2 problems (1 error, 1 warning) +``` + +:::info +The Cadence Linter is also available in the [Cadence VSCode extension](../vscode-extension/index.md), which provides real-time feedback as you write your code. +::: \ No newline at end of file diff --git a/static/markdown/tools/flow-cli/scripts/execute-scripts.md b/static/markdown/tools/flow-cli/scripts/execute-scripts.md new file mode 100644 index 0000000000..88e9b66435 --- /dev/null +++ b/static/markdown/tools/flow-cli/scripts/execute-scripts.md @@ -0,0 +1,136 @@ +--- +title: Execute a Script +description: How to execute a Cadence script on Flow from the command line +sidebar_position: 6 +--- + +The Flow CLI provides a command to execute a Cadence script on +the Flow execution state with any Flow Access API. + +```shell +flow scripts execute [ ...] [flags] +``` + +## Example Usage + +```shell +# Execute a script on Flow Testnet +> flow scripts execute script.cdc "Hello" "World" + +"Hello World" +``` + +Script source code: +``` +access(all) fun main(greeting: String, who: String): String { + return greeting.concat(" ").concat(who) +} +``` + +## Arguments + +### Filename + +- Name: `filename` +- Valid inputs: a path in the current filesystem. + +The first argument is a path to a Cadence file containing the +script to be executed. + +### Arguments +- Name: `argument` +- Valid inputs: valid [cadence values](https://cadencelang.dev/docs/1.0/json-cadence-spec) + matching argument type in script code. + +Input arguments values matching corresponding types in the source code and passed in the same order. +You can pass a `nil` value to optional arguments by executing the flow script like this: `flow scripts execute script.cdc nil`. + +## Flags + +### Arguments JSON + +- Flag: `--args-json` +- Valid inputs: arguments in JSON-Cadence form. +- Example: `flow scripts execute script.cdc '[{"type": "String", "value": "Hello World"}]'` + +Arguments passed to the Cadence script in the Cadence JSON format. +Cadence JSON format contains `type` and `value` keys and is +[documented here](https://cadencelang.dev/docs/1.0/json-cadence-spec). + +### Host + +- Flag: `--host` +- Valid inputs: an IP address or hostname. +- Default: `127.0.0.1:3569` (Flow Emulator) + +Specify the hostname of the Access API that will be +used to execute the command. This flag overrides +any host defined by the `--network` flag. + +### Network Key + +- Flag: `--network-key` +- Valid inputs: A valid network public key of the host in hex string format + +Specify the network public key of the Access API that will be +used to create a secure GRPC client when executing the command. + +### Network + +- Flag: `--network` +- Short Flag: `-n` +- Valid inputs: the name of a network defined in the configuration (`flow.json`) +- Default: `emulator` + +Specify which network you want the command to use for execution. + +### Filter + +- Flag: `--filter` +- Short Flag: `-x` +- Valid inputs: a case-sensitive name of the result property. + +Specify any property name from the result you want to return as the only value. + +### Output + +- Flag: `--output` +- Short Flag: `-o` +- Valid inputs: `json`, `inline` + +Specify the format of the command results. + +### Save + +- Flag: `--save` +- Short Flag: `-s` +- Valid inputs: a path in the current filesystem. + +Specify the filename where you want the result to be saved + +### Log + +- Flag: `--log` +- Short Flag: `-l` +- Valid inputs: `none`, `error`, `debug` +- Default: `info` + +Specify the log level. Control how much output you want to see during command execution. + +### Configuration + +- Flag: `--config-path` +- Short Flag: `-f` +- Valid inputs: a path in the current filesystem. +- Default: `flow.json` + +Specify the path to the `flow.json` configuration file. +You can use the `-f` flag multiple times to merge +several configuration files. + +### Version Check + +- Flag: `--skip-version-check` +- Default: `false` + +Skip version check during start up to speed up process for slow connections. \ No newline at end of file diff --git a/static/markdown/tools/flow-cli/super-commands.md b/static/markdown/tools/flow-cli/super-commands.md new file mode 100644 index 0000000000..8bc53dd936 --- /dev/null +++ b/static/markdown/tools/flow-cli/super-commands.md @@ -0,0 +1,67 @@ +--- +title: Super Commands +description: How Flow Super Commands Work +sidebar_position: 2 +--- + +Flow CLI Super commands are set of commands that can be used during development of your dApp to greatly simplify the workflow. The result is you can focus on writing the contracts and the commands will take care of the rest. + +## Init +The initial command to start your new Flow project is flow init. It will ask you a few questions about how you'd like to configure your project and then create the necessary files and folders, set up the configuration file, and install any core contract dependencies you might need. + +During the initialization process, `flow init` will prompt you if you want to install any core smart contracts (e.g. `NonFungibleToken`) and set them up in your project. If you choose to install core contracts, the CLI will use the [Dependency Manager](dependency-manager.md) under the hood to automatically install any required smart contract dependencies. + +> Note: If you just want the `flow.json` configured without creating any folders or files, you can run `flow init --config-only`. + +Running the command: +``` +> flow init $PROJECT_NAME +``` + +Will create the following folders and files: +- `/contracts` folder should contain all your Cadence contracts, +- `/scripts` folder should contain all your Cadence scripts, +- `/transactions` folder should contain all your Cadence transactions, +- `/tests` folder should contain all your Cadence tests, +- `flow.json` is a configuration file for your project, which will be automatically maintained. + +### Using Scaffolds +Based on the purpose of your project you can select from a list of available scaffolds. +You can access the scaffolds by simply using the `--scaffold` flag like so: +``` +> flow init $PROJECT_NAME --scaffold +``` + +If you'd like to skip the interactive mode of selecting a scaffold, use the `--scaffold-id` flag with a known ID: + +``` +> flow init $PROJECT_NAME --scaffold-id=1 +``` + +The list of scaffolds will continuously grow, and you are welcome to contribute to that. +You can contribute by creating your own scaffold repository which can then be added to the scaffold +list by [following instructions here](https://github.com/onflow/flow-cli/blob/master/CONTRIBUTING.md#adding-a-scaffold). + +## Testing +`flow init` will also have created an example test file in the `/tests` folder. You can run the tests by using the `flow test` command. + +## Import Schema +You can simply import your contracts by name. We have introducted a new way to import your contracts. This will simply your workflow. + +The new import schema format looks like: +``` +import "{name of the contract}" +``` +Example: +``` +import "HelloWorld" +``` +This will automatically import the contract you have created in your project with the same name and +save the configuration in flow.json. It doesn't matter if the contract has been deployed on a non-default account. + +## Learn More + +To learn more about next steps following the initial setup, check out the following links: + +- [Depedency Manager](./dependency-manager.md): Lets you install and manage your contract dependencies with CLI commands. +- [Manage Configuration](./flow.json/manage-configuration.md): Learn how to manage your project configuration file. \ No newline at end of file diff --git a/static/markdown/tools/flow-cli/tests.md b/static/markdown/tools/flow-cli/tests.md new file mode 100644 index 0000000000..c5d83a4c08 --- /dev/null +++ b/static/markdown/tools/flow-cli/tests.md @@ -0,0 +1,227 @@ +--- +title: Running Cadence Tests +sidebar_label: Running Cadence Tests +description: How to run Cadence tests from the CLI +sidebar_position: 11 +--- + +The Flow CLI provides a straightforward command to execute Cadence tests, enabling developers to validate their scripts and smart contracts effectively. + +To run all tests in your project, simply use: + +```shell +flow test +``` + +The `flow test` command automatically discovers and runs all test scripts in your project that end with `_test.cdc`. + +> **Note:** The `test` command requires a properly initialized configuration. If you haven’t set up your Flow project yet, refer to the [flow init](flow.json/initialize-configuration.md) guide for assistance. + +## Prerequisites + +Before running your tests, ensure that your contracts are properly configured in your `flow.json` file, including any necessary testing aliases. + +### Setting Up Testing Aliases in Contracts + +If your tests involve deploying or interacting with contracts, you need to add your contracts to the `contracts` section in the `flow.json` configuration file. Specifically, include the contract name, source location, and an address alias for the `testing` environment. + +Example `flow.json` configuration: + +```json +{ + "contracts": { + "Counter": { + "source": "cadence/contracts/Counter.cdc", + "aliases": { + "testing": "0x0000000000000007" + } + } + }, + "networks": { + // ... your network configurations + }, + "accounts": { + // ... your account configurations + }, + "deployments": { + // ... your deployment configurations + } +} +``` + +For the `testing` alias, you can use one of the following addresses: + +- `0x0000000000000005` +- `0x0000000000000006` +- `0x0000000000000007` +- `0x0000000000000008` +- `0x0000000000000009` +- `0x000000000000000A` +- `0x000000000000000B` +- `0x000000000000000C` +- `0x000000000000000D` +- `0x000000000000000E` + +> **Note**: For more information on setting up contracts and aliases, refer to the [Flow CLI Configuration](flow.json/initialize-configuration.md) documentation. + +## Example Usage + +Assuming you have a test script named `test_script_test.cdc` in your project directory, which verifies the functionality of a Cadence script executed in the testing environment: + +```cadence +// test_script_test.cdc +import Test + +access(all) let blockchain = Test.newEmulatorBlockchain() + +access(all) fun testSumOfTwo() { + let scriptResult = blockchain.executeScript( + "access(all) fun main(a: Int, b: Int): Int { return a + b }", + [2, 3] + ) + + Test.expect(scriptResult, Test.beSucceeded()) + + let sum = scriptResult.returnValue! as! Int + Test.assertEqual(5, sum) +} +``` + +This script defines a single test case, `testSumOfTwo`, which checks if a Cadence script that adds two integers `(a + b)` works as expected. The test passes if the result matches the expected value of `5`. + +You can run all tests in your project using the CLI: + +```shell +$ flow test +``` + +The Flow CLI will discover all test scripts ending with `_test.cdc` and execute them. The results will be displayed in the terminal: + +```shell +Test results: +- PASS: test_script_test.cdc > testSumOfTwo +``` + +To learn more about writing tests in Cadence, visit the [Cadence Testing Framework](../../build/smart-contracts/testing.md) documentation. + +--- + +### Running Specific Tests + +If you wish to run a specific test script rather than all tests, you can provide the path to the test file: + +```shell +flow test path/to/your/test_script_test.cdc +``` + +This will execute only the tests contained in the specified file. + +--- + +## Flags + +The `flow test` command supports several flags that provide additional functionality for managing test execution and coverage reporting. + +### **Coverage Report** + +- **Flag:** `--cover` +- **Default:** `false` + +The `--cover` flag calculates the coverage of the code being tested, helping you identify untested parts of your scripts and contracts. + +```shell +$ flow test --cover +``` + +Sample output: + +```shell +Test results: +- PASS: test_script_test.cdc > testSumOfTwo +Coverage: 96.5% of statements +``` + +--- + +### Coverage Report Output File + +- **Flag:** `--coverprofile` +- **Valid Inputs:** A valid filename with extension `.json` or `.lcov` +- **Default:** `"coverage.json"` + +Use the `--coverprofile` flag to specify the output file for the coverage report. + +Example: + +```shell +$ flow test --cover --coverprofile="coverage.lcov" +``` + +The generated coverage file can then be inspected: + +```shell +$ cat coverage.lcov +``` + +### Coverage Code Type + +- **Flag:** `--covercode` +- **Valid Inputs:** `"all"` (default) or `"contracts"` +- **Default:** `"all"` + +The `--covercode` flag lets you limit the coverage report to specific types of code. Setting the value to `"contracts"` excludes scripts and transactions from the coverage analysis. + +```shell +$ flow test --cover --covercode="contracts" +``` + +Sample output when no contracts are present: + +```shell +Test results: +- PASS: test_script_test.cdc > testSumOfTwo +There are no statements to cover +``` + +> **Note:** In this example, the coverage report is empty because the `--covercode` flag is set to `"contracts"`, and the test script only contains scripts, not contracts. + +### Random Execution of Test Cases + +- **Flag:** `--random` +- **Default:** `false` + +Use the `--random` flag to execute test cases in a random order. This can help identify issues that may arise due to test dependencies or the order in which tests are run. + +```shell +flow test --random +``` + +### Seed for Random Execution + +- **Flag:** `--seed` +- **Default:** `0` + +Use the `--seed` flag to specify a seed value for the random execution order of test cases. This allows you to reproduce a specific random order by using the same seed value, which is helpful for debugging flaky tests. + +```shell +flow test --seed=12345 +``` + +> **Note:** If both `--random` and `--seed` are provided, the `--random` flag will be ignored, and the seed value from `--seed` will be used for randomization. + +--- + +### Run Specific Test by Name + +- **Flag:** `--name` +- **Default:** `""` (empty string) + +Use the `--name` flag to run only tests that match the given name. This is useful when you want to execute a specific test function within your test scripts. + +```shell +flow test --name=testSumOfTwo +``` + +This command will run only the test function named `testSumOfTwo` across all test scripts that contain it. + +To dive deeper into testing the functionality of your Cadence scripts and contracts, explore the [Cadence Testing Framework](https://cadence-lang.org/docs/testing-framework) documentation. \ No newline at end of file diff --git a/static/markdown/tools/flow-cli/transactions/build-transactions.md b/static/markdown/tools/flow-cli/transactions/build-transactions.md new file mode 100644 index 0000000000..b6570a7bbb --- /dev/null +++ b/static/markdown/tools/flow-cli/transactions/build-transactions.md @@ -0,0 +1,223 @@ +--- +title: Build a Transaction +description: How to build a Flow transaction from the command line +sidebar_position: 3 +--- + +The Flow CLI provides a command to build a transactions with options to specify +authorizer accounts, payer account and proposer account. + +The `build` command doesn't produce any signatures and instead +is designed to be used with the `sign` and `send-signed` commands. + +Use this functionality in the following order: +1. Use this command (`build`) to build the transaction. +2. Use the `sign` command to sign with each account specified in the build process. +3. Use the `send-signed` command to submit the signed transaction to the Flow network. + +```shell +flow transactions build [ ...] [flags] +``` + +## Example Usage + +```shell +> flow transactions build ./transaction.cdc "Meow" \ + --authorizer alice \ + --proposer bob \ + --payer charlie \ + --filter payload --save built.rlp + +ID e8c0a69952fbe50a66703985e220307c8d44b8fa36c76cbca03f8c43d0167847 +Payer e03daebed8ca0615 +Authorizers [f3fcd2c1a78f5eee] + +Proposal Key: + Address 179b6b1cb6755e31 + Index 0 + Sequence 1 + +No Payload Signatures + +No Envelope Signatures + +Arguments (1): + - Argument 0: {"type":"String","value":"Meow"} + +Code + +transaction(greeting: String) { + let guest: Address + + prepare(authorizer: &Account) { + self.guest = authorizer.address + } + + execute { + log(greeting.concat(",").concat(self.guest.toString())) + } +} + +Payload: +f9013df90138b8d17472616e...73616374696f6e286eeec0c0 +``` + +JSON arguments from a file example: +```shell +> flow transactions build tx1.cdc --args-json "$(cat args.json)" +``` + +## Arguments + +### Code Filename + +- Name: `filename` +- Valid inputs: Any filename and path valid on the system. + +The first argument is a path to a Cadence file containing the +transaction to be executed. + +### Arguments +- Name: `argument` +- Valid inputs: valid [cadence values](https://cadencelang.dev/docs/1.0/json-cadence-spec) + matching argument type in transaction code. + +Input arguments values matching corresponding types in the source code and passed in the same order. +For passing complex argument values see [send transaction](./send-transactions.md#example-usage) document. + +## Flags + +### Payer + +- Flag: `--payer` +- Valid Inputs: Flow address or account name from configuration. +- Default: service account + +Specify account address that will be paying for the transaction. +Read more about payers [here](../../../build/basics/transactions.md). + +### Proposer + +- Flag: `--proposer` +- Valid inputs: Flow address or account name from configuration. +- Default: service account + +Specify a name of the account that is proposing the transaction. +Account must be defined in flow configuration. + +### Proposer Key Index + +- Flag: `--proposer-key-index` +- Valid inputs: number of existing key index +- Default: 0 + +Specify key index for the proposer account. + +### Authorizer + +- Flag: `--authorizer` +- Valid Inputs: Flow address or account name from configuration. +- Default: service account + +Additional authorizer addresses to add to the transaction. +Read more about authorizers [here](../../../build/basics/transactions.md). + +### Arguments JSON + +- Flag: `--args-json` +- Valid inputs: arguments in JSON-Cadence form. +- Example: `flow transactions build ./tx.cdc '[{"type": "String", "value": "Hello World"}]'` + +Arguments passed to the Cadence transaction in Cadence JSON format. +Cadence JSON format contains `type` and `value` keys and is +[documented here](https://cadencelang.dev/docs/1.0/json-cadence-spec). + +### Gas Limit + +- Flag: `--gas-limit` +- Valid inputs: an integer greater than zero. +- Default: `1000` + +Specify the gas limit for this transaction. + +### Host + +- Flag: `--host` +- Valid inputs: an IP address or hostname. +- Default: `127.0.0.1:3569` (Flow Emulator) + +Specify the hostname of the Access API that will be +used to execute the commands. + +### Network Key + +- Flag: `--network-key` +- Valid inputs: A valid network public key of the host in hex string format + +Specify the network public key of the Access API that will be +used to create a secure GRPC client when executing the command. + +### Network + +- Flag: `--network` +- Short Flag: `-n` +- Valid inputs: the name of a network defined in the configuration (`flow.json`) +- Default: `emulator` + +Specify which network you want the command to use for execution. + +### Include Fields + +- Flag: `--include` +- Valid inputs: `code`, `payload`, `signatures` + +Specify fields to include in the result output. Applies only to the text output. + +### Filter + +- Flag: `--filter` +- Short Flag: `-x` +- Valid inputs: case-sensitive name of the result property. + +Specify any property name from the result you want to return as the only value. + +### Output + +- Flag: `--output` +- Short Flag: `-o` +- Valid inputs: `json`, `inline` + +Specify in which format you want to display the result. + +### Save + +- Flag: `--save` +- Short Flag: `-s` +- Valid inputs: valid filename + +Specify the filename where you want the result to be saved. + +### Log + +- Flag: `--log` +- Short Flag: `-l` +- Valid inputs: `none`, `error`, `debug` +- Default: `info` + +Specify the log level. Control how much output you want to see while command execution. + +### Configuration + +- Flag: `--config-path` +- Short Flag: `-f` +- Valid inputs: valid filename + +Specify a filename for the configuration files, you can provide multiple configuration +files by using `-f` flag multiple times. + +### Version Check + +- Flag: `--skip-version-check` +- Default: `false` + +Skip version check during start up to speed up process for slow connections. \ No newline at end of file diff --git a/static/markdown/tools/flow-cli/transactions/complex-transactions.md b/static/markdown/tools/flow-cli/transactions/complex-transactions.md new file mode 100644 index 0000000000..99c3539ac0 --- /dev/null +++ b/static/markdown/tools/flow-cli/transactions/complex-transactions.md @@ -0,0 +1,195 @@ +--- +title: Build a Complex Transaction +description: How to build and send a complex Flow transaction from the command line +sidebar_position: 4 +--- + +**Simple Transactions** + +Sending a transaction using the Flow CLI can simply be +achieved by using the [send command documented here](./send-transactions.md). + +**Complex Transactions** + +If you would like to build more complex transactions the Flow CLI provides +commands to build, sign and send transactions allowing you to specify different +authorizers, signers and proposers. + +The process of sending a complex transactions includes three steps: +1. [build a transaction](./build-transactions.md) +2. [sign the built transaction](./sign-transaction.md) +3. [send signed transaction](./send-signed-transactions.md) + +Read more about each command flags and arguments in the above links. + +## Examples +We will describe common examples for complex transactions. All examples are using an [example configuration](./complex-transactions.md#configuration). + +### Single payer, proposer and authorizer +The simplest Flow transaction declares a single account as the proposer, payer and authorizer. + +Build the transaction: +```shell +> flow transactions build tx.cdc + --proposer alice + --payer alice + --authorizer alice + --filter payload --save tx1 +``` +Sign the transaction: +```shell +> flow transactions sign tx1 --signer alice + --filter payload --save tx2 +``` +Submit the signed transaction: +```shell +> flow transactions send-signed tx2 +``` +Transaction content (`tx.cdc`): +``` +transaction { + prepare(signer: &Account) {} + execute { ... } +} +``` + +### Single payer and proposer, multiple authorizers +A transaction that declares same payer and proposer but multiple authorizers each required to sign the transaction. Please note that the order of signing is important, and [the payer must sign last](../../../build/basics/transactions.md#payer-signs-last). + +Build the transaction: +```shell +> flow transactions build tx.cdc + --proposer alice + --payer alice + --authorizer bob + --authorizer charlie + --filter payload --save tx1 +``` +Sign the transaction with authorizers: +```shell +> flow transactions sign tx1 --signer bob + --filter payload --save tx2 +``` +```shell +> flow transactions sign tx2 --signer charlie + --filter payload --save tx3 +``` +Sign the transaction with payer: +```shell +> flow transactions sign tx3 --signer alice + --filter payload --save tx4 +``` +Submit the signed transaction: +```shell +> flow transactions send-signed tx4 +``` +Transaction content (`tx.cdc`): +``` +transaction { + prepare(bob: &Account, charlie: &Account) {} + execute { ... } +} +``` + +### Different payer, proposer and authorizer +A transaction that declares different payer, proposer and authorizer each signing separately. +Please note that the order of signing is important, and [the payer must sign last](../../../build/basics/transactions.md#payer-signs-last). + +Build the transaction: +```shell +> flow transactions build tx.cdc + --proposer alice + --payer bob + --authorizer charlie + --filter payload --save tx1 +``` +Sign the transaction with proposer: +```shell +> flow transactions sign tx1 --signer alice + --filter payload --save tx2 +``` +Sign the transaction with authorizer: +```shell +> flow transactions sign tx2 --signer charlie + --filter payload --save tx3 +``` +Sign the transaction with payer: +```shell +> flow transactions sign tx3 --signer bob + --filter payload --save tx4 +``` +Submit the signed transaction: +```shell +> flow transactions send-signed tx4 +``` +Transaction content (`tx.cdc`): +``` +transaction { + prepare(charlie: &Account) {} + execute { ... } +} +``` + +### Single payer, proposer and authorizer but multiple keys +A transaction that declares same payer, proposer and authorizer but the signer account has two keys with half weight, required to sign with both. + +Build the transaction: +```shell +> flow transactions build tx.cdc + --proposer dylan1 + --payer dylan1 + --authorizer dylan1 + --filter payload --save tx1 +``` +Sign the transaction with the first key: +```shell +> flow transactions sign tx1 --signer dylan1 + --filter payload --save tx2 +``` +Sign the transaction with the second key: +```shell +> flow transactions sign tx2 --signer dylan2 + --filter payload --save tx3 +``` +Submit the signed transaction: +```shell +> flow transactions send-signed tx3 +``` +Transaction content (`tx.cdc`): +``` +transaction { + prepare(signer: &Account) {} + execute { ... } +} +``` + +### Configuration +This is an example configuration using mock values: +```json +{ + ... + "accounts": { + "alice": { + "address": "0x1", + "key": "111...111" + }, + "bob": { + "address": "0x2", + "key": "222...222" + }, + "charlie": { + "address": "0x3", + "key": "333...333" + }, + "dylan1": { + "address": "0x4", + "key": "444...444" + }, + "dylan2": { + "address": "0x4", + "key": "555...555" + } + } + ... +} +``` \ No newline at end of file diff --git a/static/markdown/tools/flow-cli/transactions/decode-transactions.md b/static/markdown/tools/flow-cli/transactions/decode-transactions.md new file mode 100644 index 0000000000..87cd36b5f3 --- /dev/null +++ b/static/markdown/tools/flow-cli/transactions/decode-transactions.md @@ -0,0 +1,77 @@ +--- +title: Build a Complex Transaction +description: How to decode a Flow transaction from the command line +sidebar_position: 7 +--- + +The Flow CLI provides a command to decode a transaction +from RLP in a file. It uses same transaction format as get command + +```shell +flow transactions decode +``` + +## Example Usage + +```shell +> flow transactions decode ./rlp-file.rlp + +ID c1a52308fb906358d4a33c1f1d5fc458d3cfea0d570a51a9dea915b90d678346 +Payer 83de1a7075f190a1 +Authorizers [83de1a7075f190a1] + +Proposal Key: + Address 83de1a7075f190a1 + Index 1 + Sequence 1 + +No Payload Signatures + +Envelope Signature 0: 83de1a7075f190a1 +Signatures (minimized, use --include signatures) + +Code (hidden, use --include code) + +Payload (hidden, use --include payload) +``` + +## Arguments + +### Filename + +- Name: `` +- Valid Input: file name. + +The first argument is the filename containing the transaction RLP. + +## Flags + +### Include Fields + +- Flag: `--include` +- Valid inputs: `code`, `payload`, `signatures` + +Specify fields to include in the result output. Applies only to the text output. + +### Output + +- Flag: `--output` +- Short Flag: `-o` +- Valid inputs: `json`, `inline` + +Specify the format of the command results. + +### Save + +- Flag: `--save` +- Short Flag: `-s` +- Valid inputs: a path in the current filesystem. + +Specify the filename where you want the result to be saved + +### Version Check + +- Flag: `--skip-version-check` +- Default: `false` + +Skip version check during start up to speed up process for slow connections. \ No newline at end of file diff --git a/static/markdown/tools/flow-cli/transactions/get-transactions.md b/static/markdown/tools/flow-cli/transactions/get-transactions.md new file mode 100644 index 0000000000..d80a01852d --- /dev/null +++ b/static/markdown/tools/flow-cli/transactions/get-transactions.md @@ -0,0 +1,170 @@ +--- +title: Get a Transaction +description: How to get a Flow transaction from the command line +sidebar_position: 2 +--- + +The Flow CLI provides a command to fetch a transaction +that was previously submitted to an Access API. + +```shell +flow transactions get +``` + +## Example Usage + +```shell +> flow transactions get 40bc4b100c1930c61381c22e0f4c10a7f5827975ee25715527c1061b8d71e5aa --network mainnet + +Status ✅ SEALED +ID 40bc4b100c1930c61381c22e0f4c10a7f5827975ee25715527c1061b8d71e5aa +Payer 18eb4ee6b3c026d2 +Authorizers [18eb4ee6b3c026d2] + +Proposal Key: + Address 18eb4ee6b3c026d2 + Index 11 + Sequence 17930 + +Payload Signature 0: 18eb4ee6b3c026d2 +Payload Signature 1: 18eb4ee6b3c026d2 +Envelope Signature 0: 18eb4ee6b3c026d2 +Signatures (minimized, use --include signatures) + +Events: + Index 0 + Type A.1654653399040a61.FlowToken.TokensWithdrawn + Tx ID 40bc4b100c1930c61381c22e0f4c10a7f5827975ee25715527c1061b8d71e5aa + Values + - amount (UFix64): 0.00100000 + - from ({}?): 18eb4ee6b3c026d2 + + Index 1 + Type A.1654653399040a61.FlowToken.TokensDeposited + Tx ID 40bc4b100c1930c61381c22e0f4c10a7f5827975ee25715527c1061b8d71e5aa + Values + - amount (UFix64): 0.00100000 + - to ({}?): 5068e27f275c546c + + Index 2 + Type A.18eb4ee6b3c026d2.PrivateReceiverForwarder.PrivateDeposit + Tx ID 40bc4b100c1930c61381c22e0f4c10a7f5827975ee25715527c1061b8d71e5aa + Values + - amount (UFix64): 0.00100000 + - to ({}?): 5068e27f275c546c + +Code (hidden, use --include code) + +Payload (hidden, use --include payload) +``` + +## Arguments + +### Transaction ID + +- Name: `` +- Valid Input: transaction ID. + +The first argument is the ID (hash) of the transaction. + +## Flags + +### Include Fields + +- Flag: `--include` +- Valid inputs: `code`, `payload`, `signatures` + +Specify fields to include in the result output. Applies only to the text output. + +### Wait for Seal + +- Flag: `--sealed` +- Default: `false` + +Indicate whether to wait for the transaction to be sealed +before displaying the result. + +### Exclude Fields + +- Flag: `--exclude` +- Valid inputs: `events` + +Specify fields to exclude from the result output. Applies only to the text output. + +### Host + +- Flag: `--host` +- Valid inputs: an IP address or hostname. +- Default: `127.0.0.1:3569` (Flow Emulator) + +Specify the hostname of the Access API that will be +used to execute the command. This flag overrides +any host defined by the `--network` flag. + +### Network Key + +- Flag: `--network-key` +- Valid inputs: A valid network public key of the host in hex string format + +Specify the network public key of the Access API that will be +used to create a secure GRPC client when executing the command. + +### Network + +- Flag: `--network` +- Short Flag: `-n` +- Valid inputs: the name of a network defined in the configuration (`flow.json`) +- Default: `emulator` + +Specify which network you want the command to use for execution. + +### Filter + +- Flag: `--filter` +- Short Flag: `-x` +- Valid inputs: a case-sensitive name of the result property. + +Specify any property name from the result you want to return as the only value. + +### Output + +- Flag: `--output` +- Short Flag: `-o` +- Valid inputs: `json`, `inline` + +Specify the format of the command results. + +### Save + +- Flag: `--save` +- Short Flag: `-s` +- Valid inputs: a path in the current filesystem. + +Specify the filename where you want the result to be saved + +### Log + +- Flag: `--log` +- Short Flag: `-l` +- Valid inputs: `none`, `error`, `debug` +- Default: `info` + +Specify the log level. Control how much output you want to see during command execution. + +### Configuration + +- Flag: `--config-path` +- Short Flag: `-f` +- Valid inputs: a path in the current filesystem. +- Default: `flow.json` + +Specify the path to the `flow.json` configuration file. +You can use the `-f` flag multiple times to merge +several configuration files. + +### Version Check + +- Flag: `--skip-version-check` +- Default: `false` + +Skip version check during start up to speed up process for slow connections. \ No newline at end of file diff --git a/static/markdown/tools/flow-cli/transactions/send-signed-transactions.md b/static/markdown/tools/flow-cli/transactions/send-signed-transactions.md new file mode 100644 index 0000000000..4acbc9d557 --- /dev/null +++ b/static/markdown/tools/flow-cli/transactions/send-signed-transactions.md @@ -0,0 +1,148 @@ +--- +title: Send Signed Transaction +description: How to send a signed Flow transaction from the command line +sidebar_position: 6 +--- + +The Flow CLI provides a command to send signed transactions to +any Flow Access API. + +Use this functionality in the following order: +1. Use the `build` command to build the transaction. +2. Use the `sign` command to sign with each account specified in the build process. +3. Use this command (`send-signed`) to submit the signed transaction to the Flow network. + +```shell +flow transactions send-signed +``` + +## Example Usage + +```shell +> flow transactions send-signed ./signed.rlp + +Status ✅ SEALED +ID 528332aceb288cdfe4d11d6522aa27bed94fb3266b812cb350eb3526ed489d99 +Payer f8d6e0586b0a20c7 +Authorizers [f8d6e0586b0a20c7] + +Proposal Key: + Address f8d6e0586b0a20c7 + Index 0 + Sequence 0 + +No Payload Signatures + +Envelope Signature 0: f8d6e0586b0a20c7 +Signatures (minimized, use --include signatures) + +Events: None + +Code (hidden, use --include code) + +Payload (hidden, use --include payload) + +``` + +## Arguments + +### Signed Code Filename +- Name: `signed transaction filename` +- Valid inputs: Any filename and path valid on the system. + +The first argument is a path to a Cadence file containing the +transaction to be executed. + +## Flags + +### Include Fields + +- Flag: `--include` +- Valid inputs: `code`, `payload` + +Specify fields to include in the result output. Applies only to the text output. + +### Exclude Fields + +- Flag: `--exclude` +- Valid inputs: `events` + +Specify fields to exclude from the result output. Applies only to the text output. + +### Filter + +- Flag: `--filter` +- Short Flag: `-x` +- Valid inputs: a case-sensitive name of the result property. + +Specify any property name from the result you want to return as the only value. + +### Host + +- Flag: `--host` +- Valid inputs: an IP address or hostname. +- Default: `127.0.0.1:3569` (Flow Emulator) + +Specify the hostname of the Access API that will be +used to execute the command. This flag overrides +any host defined by the `--network` flag. + +### Network Key + +- Flag: `--network-key` +- Valid inputs: A valid network public key of the host in hex string format + +Specify the network public key of the Access API that will be +used to create a secure GRPC client when executing the command. + +### Network + +- Flag: `--network` +- Short Flag: `-n` +- Valid inputs: the name of a network defined in the configuration (`flow.json`) +- Default: `emulator` + +Specify which network you want the command to use for execution. + +### Output + +- Flag: `--output` +- Short Flag: `-o` +- Valid inputs: `json`, `inline` + +Specify the format of the command results. + +### Save + +- Flag: `--save` +- Short Flag: `-s` +- Valid inputs: a path in the current filesystem. + +Specify the filename where you want the result to be saved + +### Log + +- Flag: `--log` +- Short Flag: `-l` +- Valid inputs: `none`, `error`, `debug` +- Default: `info` + +Specify the log level. Control how much output you want to see during command execution. + +### Configuration + +- Flag: `--config-path` +- Short Flag: `-f` +- Valid inputs: a path in the current filesystem. +- Default: `flow.json` + +Specify the path to the `flow.json` configuration file. +You can use the `-f` flag multiple times to merge +several configuration files. + +### Version Check + +- Flag: `--skip-version-check` +- Default: `false` + +Skip version check during start up to speed up process for slow connections. \ No newline at end of file diff --git a/static/markdown/tools/flow-cli/transactions/send-transactions.md b/static/markdown/tools/flow-cli/transactions/send-transactions.md new file mode 100644 index 0000000000..5bc8f1e9bc --- /dev/null +++ b/static/markdown/tools/flow-cli/transactions/send-transactions.md @@ -0,0 +1,238 @@ +--- +title: Send a Transaction +description: How to send a Flow transaction from the command line +sidebar_position: 1 +--- + +The Flow CLI provides a command to sign and send transactions to +any Flow Access API. + +```shell +flow transactions send [ ...] [flags] +``` + +## Example Usage + +```shell +> flow transactions send ./tx.cdc "Hello" + +Status ✅ SEALED +ID b04b6bcc3164f5ee6b77fa502c3a682e0db57fc47e5b8a8ef3b56aae50ad49c8 +Payer f8d6e0586b0a20c7 +Authorizers [f8d6e0586b0a20c7] + +Proposal Key: + Address f8d6e0586b0a20c7 + Index 0 + Sequence 0 + +No Payload Signatures + +Envelope Signature 0: f8d6e0586b0a20c7 +Signatures (minimized, use --include signatures) + +Events: None + +Code (hidden, use --include code) + +Payload (hidden, use --include payload) + +``` + +Multiple arguments example: +```shell +> flow transactions send tx1.cdc Foo 1 2 10.9 0x1 '[123,222]' '["a","b"]' +``` +Transaction code: +``` +transaction(a: String, b: Int, c: UInt16, d: UFix64, e: Address, f: [Int], g: [String]) { + prepare(authorizer: &Account) {} +} +``` + +In the above example, the `flow.json` file would look something like this: + +```json +{ + "accounts": { + "my-testnet-account": { + "address": "a2c4941b5f3c7151", + "key": "12c5dfde...bb2e542f1af710bd1d40b2" + } + } +} +``` + +JSON arguments from a file example: +```shell +> flow transactions send tx1.cdc --args-json "$(cat args.json)" +``` + +## Arguments + +### Code Filename +- Name: `code filename` +- Valid inputs: Any filename and path valid on the system. + +The first argument is a path to a Cadence file containing the +transaction to be executed. + +### Arguments +- Name: `argument` +- Valid inputs: valid [cadence values](https://cadencelang.dev/docs/1.0/json-cadence-spec) + matching argument type in transaction code. + +Input arguments values matching corresponding types in the source code and passed in the same order. +You can pass a `nil` value to optional arguments by sending the transaction like this: `flow transactions send tx.cdc nil`. + +## Flags + +### Include Fields + +- Flag: `--include` +- Valid inputs: `code`, `payload` + +Specify fields to include in the result output. Applies only to the text output. + +### Code + +- Flag: `--code` + +⚠️ No longer supported: use filename argument. + +### Results + +- Flag: `--results` + +⚠️ No longer supported: all transactions will provide result. + +### Exclude Fields + +- Flag: `--exclude` +- Valid inputs: `events` + +Specify fields to exclude from the result output. Applies only to the text output. + +### Signer + +- Flag: `--signer` +- Valid inputs: the name of an account defined in the configuration (`flow.json`) + +Specify the name of the account that will be used to sign the transaction. + +### Proposer + +- Flag: `--proposer` +- Valid inputs: the name of an account defined in the configuration (`flow.json`) + +Specify the name of the account that will be used as proposer in the transaction. + +### Payer + +- Flag: `--payer` +- Valid inputs: the name of an account defined in the configuration (`flow.json`) + +Specify the name of the account that will be used as payer in the transaction. + +### Authorizer + +- Flag: `--authorizer` +- Valid inputs: the name of a single or multiple comma-separated accounts defined in the configuration (`flow.json`) + +Specify the name of the account(s) that will be used as authorizer(s) in the transaction. If you want to provide multiple authorizers separate them using commas (e.g. `alice,bob`) + +### Arguments JSON + +- Flag: `--args-json` +- Valid inputs: arguments in JSON-Cadence form. +- Example: `flow transactions send ./tx.cdc '[{"type": "String", "value": "Hello World"}]'` + +Arguments passed to the Cadence transaction in Cadence JSON format. +Cadence JSON format contains `type` and `value` keys and is +[documented here](https://cadencelang.dev/docs/1.0/json-cadence-spec). + +### Gas Limit + +- Flag: `--gas-limit` +- Valid inputs: an integer greater than zero. +- Default: `1000` + +Specify the gas limit for this transaction. + +### Host + +- Flag: `--host` +- Valid inputs: an IP address or hostname. +- Default: `127.0.0.1:3569` (Flow Emulator) + +Specify the hostname of the Access API that will be +used to execute the command. This flag overrides +any host defined by the `--network` flag. + +### Network Key + +- Flag: `--network-key` +- Valid inputs: A valid network public key of the host in hex string format + +Specify the network public key of the Access API that will be +used to create a secure GRPC client when executing the command. + +### Network + +- Flag: `--network` +- Short Flag: `-n` +- Valid inputs: the name of a network defined in the configuration (`flow.json`) +- Default: `emulator` + +Specify which network you want the command to use for execution. + +### Filter + +- Flag: `--filter` +- Short Flag: `-x` +- Valid inputs: a case-sensitive name of the result property. + +Specify any property name from the result you want to return as the only value. + +### Output + +- Flag: `--output` +- Short Flag: `-o` +- Valid inputs: `json`, `inline` + +Specify the format of the command results. + +### Save + +- Flag: `--save` +- Short Flag: `-s` +- Valid inputs: a path in the current filesystem. + +Specify the filename where you want the result to be saved + +### Log + +- Flag: `--log` +- Short Flag: `-l` +- Valid inputs: `none`, `error`, `debug` +- Default: `info` + +Specify the log level. Control how much output you want to see during command execution. + +### Configuration + +- Flag: `--config-path` +- Short Flag: `-f` +- Valid inputs: a path in the current filesystem. +- Default: `flow.json` + +Specify the path to the `flow.json` configuration file. +You can use the `-f` flag multiple times to merge +several configuration files. + +### Version Check + +- Flag: `--skip-version-check` +- Default: `false` + +Skip version check during start up to speed up process for slow connections. \ No newline at end of file diff --git a/static/markdown/tools/flow-cli/transactions/sign-transaction.md b/static/markdown/tools/flow-cli/transactions/sign-transaction.md new file mode 100644 index 0000000000..dfbadac60b --- /dev/null +++ b/static/markdown/tools/flow-cli/transactions/sign-transaction.md @@ -0,0 +1,168 @@ +--- +title: Sign a Transaction +description: How to sign a Flow transaction from the command line +sidebar_position: 5 +--- + +The Flow CLI provides a command to sign transactions with options to specify +authorizer accounts, payer accounts and proposer accounts. + +Use this functionality in the following order: +1. Use the `build` command to build the transaction. +2. Use this command (`sign`) to sign with each account specified in the build process. +3. Use the `send-signed` command to submit the signed transaction to the Flow network. + +```shell +flow transactions sign +``` + +## Example Usage + +```shell +> flow transactions sign ./built.rlp --signer alice \ + --filter payload --save signed.rlp + +Hash b03b18a8d9d30ff7c9f0fdaa80fcaab242c2f36eedb687dd9b368326311fe376 +Payer f8d6e0586b0a20c7 +Authorizers [f8d6e0586b0a20c7] + +Proposal Key: + Address f8d6e0586b0a20c7 + Index 0 + Sequence 6 + +No Envelope Signatures + +Payload Signature 0: + Address f8d6e0586b0a20c7 + Signature b5b1dfed2a899037...164e1b224a7ac924018e7033b68b0df86769dd54 + Key Index 0 + +Arguments (1): + - Argument 0: {"type":"String","value":"Meow"} + +Code + +transaction(greeting: String) { + let guest: Address + + prepare(authorizer: &Account) { + self.guest = authorizer.address + } + + execute { + log(greeting.concat(",").concat(self.guest.toString())) + } +} + +Payload: +f90184f...a199bfd9b837a11a0885f9104b54014750f5e3e5bfe4a5795968b0df86769dd54c0 +``` + +## Arguments + +### Built Transaction Filename or Remote Server URL +- Name: `built transaction filename | --from-remote-url ` +- Valid inputs: Any filename and path valid on the system or --from-remote-url flag and fully qualified remote server url. + +Specify the filename containing valid transaction payload that will be used for signing. +To be used with the `flow transaction build` command. + +When --from-remote-url flag is used the value needs to be a fully qualified url to transaction RLP +Example: `flow transaction sign --from-remote-url https://fully/qualified/url --signer alice` +## Flags + +### From Remote Url +- Flag: `--from-remote-url` +- Valid input: `http(s)://fully/qualified/server/url` + +Specify this flag with a fully qualified url to transaction RLP. The RLP will be fetched from server then signed. The resulting signed RLP is then posted to the remote url. This feature is to support protocol level multiple signature transaction coordination between multiple signers. +Note: --yes flag is not supported and will fail `sign` command when this flag is used. This forces the user to verify the cadence code. + +### Include Fields + +- Flag: `--include` +- Valid inputs: `code`, `payload`, `signatures` + +Specify fields to include in the result output. Applies only to the text output. + +### Signer + +- Flag: `--signer` +- Valid inputs: the name of an account defined in the configuration (`flow.json`) + +Specify the name of the account that will be used to sign the transaction. + +### Host +- Flag: `--host` +- Valid inputs: an IP address or hostname. +- Default: `127.0.0.1:3569` (Flow Emulator) + +Specify the hostname of the Access API that will be +used to execute the commands. + +### Network Key + +- Flag: `--network-key` +- Valid inputs: A valid network public key of the host in hex string format + +Specify the network public key of the Access API that will be +used to create a secure GRPC client when executing the command. + +### Network + +- Flag: `--network` +- Short Flag: `-n` +- Valid inputs: the name of a network defined in the configuration (`flow.json`) +- Default: `emulator` + +Specify which network you want the command to use for execution. + +### Filter + +- Flag: `--filter` +- Short Flag: `-x` +- Valid inputs: case-sensitive name of the result property. + +Specify any property name from the result you want to return as the only value. + +### Output + +- Flag: `--output` +- Short Flag: `-o` +- Valid inputs: `json`, `inline` + +Specify in which format you want to display the result. + +### Save + +- Flag: `--save` +- Short Flag: `-s` +- Valid inputs: valid filename + +Specify the filename where you want the result to be saved. + +### Log + +- Flag: `--log` +- Short Flag: `-l` +- Valid inputs: `none`, `error`, `debug` +- Default: `info` + +Specify the log level. Control how much output you want to see while command execution. + +### Configuration + +- Flag: `--conf` +- Short Flag: `-f` +- Valid inputs: valid filename + +Specify a filename for the configuration files, you can provide multiple configuration +files by using `-f` flag multiple times. + +### Version Check + +- Flag: `--skip-version-check` +- Default: `false` + +Skip version check during start up to speed up process for slow connections. \ No newline at end of file diff --git a/static/markdown/tools/flow-cli/utils/signature-generate.md b/static/markdown/tools/flow-cli/utils/signature-generate.md new file mode 100644 index 0000000000..3f90f70aa3 --- /dev/null +++ b/static/markdown/tools/flow-cli/utils/signature-generate.md @@ -0,0 +1,90 @@ +--- +title: Generate a Signature +description: How to generate a new signature from the command line +--- + +Generate a signature using the private key of the signer account. + +```shell +flow signatures generate +``` + +⚠️ _Make sure the account you want to use for signing is saved in the `flow.json` configuration. +The address of the account is not important, just the private key._ + +## Example Usage + +```shell +> flow signatures generate 'The quick brown fox jumps over the lazy dog' --signer alice + +Signature b33eabfb05d374b...f09929da96f5beec167fd1f123ec +Message The quick brown fox jumps over the lazy dog +Public Key 0xc92a7c...042c4025d241fd430242368ce662d39636987 +Hash Algorithm SHA3_256 +Signature Algorithm ECDSA_P256 +``` + +## Arguments + +### Message +- Name: `message` + +Message used for signing. + +## Flags + +### Signer + +- Flag: `--signer` +- Valid inputs: the name of an account defined in the configuration (`flow.json`) + +Specify the name of the account that will be used to sign the transaction. + +### Filter + +- Flag: `--filter` +- Short Flag: `-x` +- Valid inputs: case-sensitive name of the result property. + +Specify any property name from the result you want to return as the only value. + +### Output + +- Flag: `--output` +- Short Flag: `-o` +- Valid inputs: `json`, `inline` + +Specify in which format you want to display the result. + +### Save + +- Flag: `--save` +- Short Flag: `-s` +- Valid inputs: valid filename + +Specify the filename where you want the result to be saved. + +### Log + +- Flag: `--log` +- Short Flag: `-l` +- Valid inputs: `none`, `error`, `debug` +- Default: `info` + +Specify the log level. Control how much output you want to see while command execution. + +### Configuration + +- Flag: `--config-path` +- Short Flag: `-f` +- Valid inputs: valid filename + +Specify a filename for the configuration files, you can provide multiple configuration +files by using `-f` flag multiple times. + +### Version Check + +- Flag: `--skip-version-check` +- Default: `false` + +Skip version check during start up to speed up process for slow connections. \ No newline at end of file diff --git a/static/markdown/tools/flow-cli/utils/signature-verify.md b/static/markdown/tools/flow-cli/utils/signature-verify.md new file mode 100644 index 0000000000..dd5fdee488 --- /dev/null +++ b/static/markdown/tools/flow-cli/utils/signature-verify.md @@ -0,0 +1,102 @@ +--- +title: Verify Signature +description: How to verify a signature from the command line +--- + +Verify validity of a signature based on provided message and public key of the signature creator. + +```shell +flow signatures verify +``` + +## Example Usage + +```shell +> flow signatures verify + 'The quick brown fox jumps over the lazy dog' + b1c9eff5d829fdeaf2dad6308fc8033e3b8875bc185ef804ce5d0d980545ef5be0f98b47afc979d12272d257ce13c4b490e431bfcada485cb1d2e3f209be8d07 + 0xc92a7c72a78f8f046a79f8a5fe1ef72424258a55eb869f13e6133301d64ad025d3362d5df9e7c82289637af1431042c4025d241fd430242368ce662d39636987 + +Valid true +Message The quick brown fox jumps over the lazy dog +Signature b1c9eff5d829fdeaf2...7ce13c4b490eada485cb1d2e3f209be8d07 +Public Key c92a7c72a78...1431042c4025d241fd430242368ce662d39636987 +Hash Algorithm SHA3_256 +Signature Algorithm ECDSA_P256 +``` + +## Arguments + +### Message +- Name: `message` + +Message data used for creating the signature. + +### Signature +- Name: `signature` + +Message signature that will be verified. + +### Public Key +- Name: `public key` + +Public key of the private key used for creating the signature. + +## Flags + +### Public Key Signature Algorithm + +- Flag: `--sig-algo` +- Valid inputs: `"ECDSA_P256", "ECDSA_secp256k1"` + +Specify the ECDSA signature algorithm of the key pair used for signing. + +Flow supports the secp256k1 and P-256 curves. + +### Public Key Hash Algorithm + +- Flag: `--hash-algo` +- Valid inputs: `"SHA2_256", "SHA3_256"` +- Default: `"SHA3_256"` + +Specify the hash algorithm of the key pair used for signing. + +### Filter + +- Flag: `--filter` +- Short Flag: `-x` +- Valid inputs: case-sensitive name of the result property. + +Specify any property name from the result you want to return as the only value. + +### Output + +- Flag: `--output` +- Short Flag: `-o` +- Valid inputs: `json`, `inline` + +Specify in which format you want to display the result. + +### Save + +- Flag: `--save` +- Short Flag: `-s` +- Valid inputs: valid filename + +Specify the filename where you want the result to be saved. + +### Log + +- Flag: `--log` +- Short Flag: `-l` +- Valid inputs: `none`, `error`, `debug` +- Default: `info` + +Specify the log level. Control how much output you want to see while command execution. + +### Version Check + +- Flag: `--skip-version-check` +- Default: `false` + +Skip version check during start up to speed up process for slow connections. \ No newline at end of file diff --git a/static/markdown/tools/flow-cli/utils/snapshot-save.md b/static/markdown/tools/flow-cli/utils/snapshot-save.md new file mode 100644 index 0000000000..69a2e9c17d --- /dev/null +++ b/static/markdown/tools/flow-cli/utils/snapshot-save.md @@ -0,0 +1,79 @@ +--- +title: Snapshot Save +description: How to save a protocol snapshot from the command line +--- + +The FLOW CLI provides a command to save the latest finalized protocol state snapshot + +```shell +flow snapshot save +``` + +## Example Usage + +```shell +flow snapshot save /tmp/snapshot.json --network testnet +``` + +### Example response +```shell +snapshot saved: /tmp/snapshot.json +``` + +## Arguments + +### Output Path +- Name: `output path` +- Valid Input: any valid string path + +Output path where the protocol snapshot JSON file will be saved. + +## Flags + +### Host +- Flag: `--host` +- Valid inputs: an IP address or hostname. +- Default: `127.0.0.1:3569` (Flow Emulator) + +Specify the hostname of the Access API that will be +used to execute the commands. + +### Network Key + +- Flag: `--network-key` +- Valid inputs: A valid network public key of the host in hex string format + +Specify the network public key of the Access API that will be +used to create a secure GRPC client when executing the command. + +### Network + +- Flag: `--network` +- Short Flag: `-n` +- Valid inputs: the name of a network defined in the configuration (`flow.json`) +- Default: `emulator` + +Specify which network you want the command to use for execution. + +### Filter + +- Flag: `--filter` +- Short Flag: `-x` +- Valid inputs: case-sensitive name of the result property. + +Specify any property name from the result you want to return as the only value. + +### Output + +- Flag: `--output` +- Short Flag: `-o` +- Valid inputs: `json`, `inline` + +Specify in which format you want to display the result. + +### Version Check + +- Flag: `--skip-version-check` +- Default: `false` + +Skip version check during start up to speed up process for slow connections. \ No newline at end of file diff --git a/static/markdown/tools/flow-cli/utils/tools.md b/static/markdown/tools/flow-cli/utils/tools.md new file mode 100644 index 0000000000..4acf2c1df8 --- /dev/null +++ b/static/markdown/tools/flow-cli/utils/tools.md @@ -0,0 +1,74 @@ +--- +title: Development Tools +description: How to start development tools using the Flow CLI +--- + +The Flow CLI integrates different development tools, which can now be easily started +and managed from a single place. + +Currently the CLI supports starting: +- [Flow Development Wallet](https://github.com/onflow/fcl-dev-wallet) + +## Flow Development Wallet + +The Flow Dev Wallet is a mock Flow wallet that simulates the protocols used by FCL to interact with the Flow blockchain on behalf of simulated user accounts. + +**Be sure you have the emulator running before starting this command** +_You can start it using the `flow emulator` command_. + +```shell +flow dev-wallet +``` +_⚠️ This project implements an FCL compatible +interface, but should **not** be used as a reference for +building a production grade wallet._ + +After starting dev-wallet, you can set your fcl config to use it like below: + +```javascript + + +fcl.config() + // Point App at Emulator + .put("accessNode.api", "http://localhost:8080") + // Point FCL at dev-wallet (default port) + .put("discovery.wallet", "http://localhost:8701/fcl/authn") +``` +You can read more about setting up dev-wallet at [Flow Dev Wallet Project](https://github.com/onflow/fcl-dev-wallet) + +## Flags + +### Port + +- Flag: `--port` +- Valid inputs: Number +- Default: `8701` + +Port on which the dev wallet server will listen on. + +### Emulator Host + +- Flag: `--emulator-host` +- Valid inputs: a hostname +- Default: `http://localhost:8080` + +Specifies the host configuration for dev wallet + +### Configuration + +- Flag: `--config-path` +- Short Flag: `-f` +- Valid inputs: valid filename + +Specify a filename for the configuration files, you can provide multiple configuration +files by using `-f` flag multiple times. + +Specify a filename for the configuration files, you can provide multiple configuration +files by using `-f` flag multiple times. + +### Version Check + +- Flag: `--skip-version-check` +- Default: `false` + +Skip version check during start up to speed up process for slow connections. \ No newline at end of file diff --git a/static/markdown/tools/flow-dev-wallet/index.md b/static/markdown/tools/flow-dev-wallet/index.md new file mode 100644 index 0000000000..1f72551f97 --- /dev/null +++ b/static/markdown/tools/flow-dev-wallet/index.md @@ -0,0 +1,232 @@ +--- +title: Flow Dev Wallet +sidebar_label: Flow Dev Wallet +sidebar_position: 5 +--- + +The Flow Dev Wallet is a mock Flow wallet that simulates the protocols used by [FCL](../clients/fcl-js/index.md) to interact with the Flow blockchain on behalf of simulated user accounts. + +:::warning[IMPORTANT] + +This project implements an FCL compatible +interface, but should **not** be used as a reference for +building a production grade wallet. + +This project should only be used in aid of local +development against a locally run instance of the Flow +blockchain like the Flow emulator, and should never be used in +conjunction with Flow Mainnet, Testnet, or any +other instances of Flow. + +::: + +:::info + +To see a full list of Flow compatible wallets visit [Wallets page](../../ecosystem/wallets.md) + +::: + +## Getting Started + +Before using the dev wallet, you'll need to start the Flow emulator. + +### Install the `flow-cli` + +The Flow emulator is bundled with the Flow CLI. Instructions for installing the CLI can be found here: [flow-cli/install/](../flow-cli/install.md) + +### Create a `flow.json` file + +Run this command to create `flow.json` file (typically in your project's root directory): + +```sh +flow init --config-only +``` + +### Start the Emulator + +Start the Emulator and deploy the contracts by running the following command from the directory containing `flow.json` in your project: + +```sh +flow emulator start +flow project deploy --network emulator +``` + +## Configuring Your JavaScript Application + +The Flow Dev Wallet is designed to be used with [`@onflow/fcl`](https://github.com/onflow/fcl-js) version `1.0.0` or higher. The FCL package can be installed with: `npm install @onflow/fcl` or `yarn add @onflow/fcl`. + +To use the dev wallet, configure FCL to point to the address of a locally running [Flow emulator](#start-the-emulator) and the dev wallet endpoint. + +```javascript + + +fcl + .config() + // Point App at Emulator REST API + .put('accessNode.api', 'http://localhost:8888') + // Point FCL at dev-wallet (default port) + .put('discovery.wallet', 'http://localhost:8701/fcl/authn'); +``` + +:::info + +For a full example refer to [Authenticate using FCL snippet](https://academy.ecdao.org/en/snippets/fcl-authenticate) + +::: + +### Test harness + +It's easy to use this FCL harness app as a barebones +app to interact with the dev-wallet during development: + +Navigate to http://localhost:8701/harness + +### Wallet Discovery + +[Wallet Discovery](../clients/fcl-js/discovery.md) offers a convenient modal and mechanism to authenticate users and connects to all wallets available in the Flow ecosystem. + +The following code from [Emerald Academy](https://academy.ecdao.org/en/snippets/fcl-authenticate) can be added to your React app to enable Wallet Discovery: + +```javascript + + + +const fclConfigInfo = { + emulator: { + accessNode: 'http://127.0.0.1:8888', + discoveryWallet: 'http://localhost:8701/fcl/authn', + discoveryAuthInclude: [], + }, + testnet: { + accessNode: 'https://rest-testnet.onflow.org', + discoveryWallet: 'https://fcl-discovery.onflow.org/testnet/authn', + discoveryAuthnEndpoint: + 'https://fcl-discovery.onflow.org/api/testnet/authn', + // Adds in Dapper + Ledger + discoveryAuthInclude: ['0x82ec283f88a62e65', '0x9d2e44203cb13051'], + }, + mainnet: { + accessNode: 'https://rest-mainnet.onflow.org', + discoveryWallet: 'https://fcl-discovery.onflow.org/authn', + discoveryAuthnEndpoint: 'https://fcl-discovery.onflow.org/api/authn', + // Adds in Dapper + Ledger + discoveryAuthInclude: ['0xead892083b3e2c6c', '0xe5cd26afebe62781'], + }, +}; + +const network = 'emulator'; + +config({ + 'walletconnect.projectId': 'YOUR_PROJECT_ID', // your WalletConnect project ID + 'app.detail.title': 'Emerald Academy', // the name of your DApp + 'app.detail.icon': 'https://academy.ecdao.org/favicon.png', // your DApps icon + 'app.detail.description': 'Emerald Academy is a DApp for learning Flow', // a description of your DApp + 'app.detail.url': 'https://academy.ecdao.org', // the URL of your DApp + 'flow.network': network, + 'accessNode.api': fclConfigInfo[network].accessNode, + 'discovery.wallet': fclConfigInfo[network].discoveryWallet, + 'discovery.authn.endpoint': fclConfigInfo[network].discoveryAuthnEndpoint, + // adds in opt-in wallets like Dapper and Ledger + 'discovery.authn.include': fclConfigInfo[network].discoveryAuthInclude, + 'discovery.authn.exclude': ['0x1234567890abcdef'], // excludes chosen wallets by address +}); + +export default function App() { + const [user, setUser] = useState({ loggedIn: false, addr: '' }); + + // So that the user stays logged in + // even if the page refreshes + useEffect(() => { + currentUser.subscribe(setUser); + }, []); + + return ( +
    + + +

    {user.loggedIn ? `Welcome, ${user.addr}!` : 'Please log in.'}

    +
    + ); +} +``` + +### Account/Address creation + +You can [create a new account](https://cadence-lang.org/docs/language/accounts#account-creation) by using the `&Account` constructor. When you do this, make sure to specify which account will pay for the creation fees by setting it as the payer. + +The account you choose to pay these fees must have enough money to cover the cost. If it doesn't, the process will stop and the account won't be created. + +```cadence +transaction(publicKey: String) { + prepare(signer: &Account) { + let key = PublicKey( + publicKey: publicKey.decodeHex(), + signatureAlgorithm: SignatureAlgorithm.ECDSA_P256 + ) + let account = Account(payer: signer) + account.keys.add( + publicKey: key, + hashAlgorithm: HashAlgorithm.SHA3_256, + weight: 1000.0 + ) + } +} +``` + +To create a new Flow account refer to these resources + +- [Create an Account with FCL snippet](https://academy.ecdao.org/en/snippets/fcl-create-account) +- [Create an Account in Cadence snippet](https://academy.ecdao.org/en/snippets/cadence-create-account) + +### Get Flow Balance + +Retrieving the token balance of a specific account involves writing a script to pull data from onchain. The user may have both locked tokens as well as unlocked so to retrieve the total balance we would aggregate them together. + +```javascript + + +const CODE = ` +import "FungibleToken" +import "FlowToken" +import "LockedTokens" + +access(all) fun main(address: Address): UFix64 { + let account = getAccount(address) + let unlockedVault = account + .capabilities.get<&FlowToken.Vault>(/public/flowTokenBalance) + .borrow() + ?? panic("Could not borrow Balance reference to the Vault" + .concat(" at path /public/flowTokenBalance!") + .concat(" Make sure that the account address is correct ") + .concat("and that it has properly set up its account with a FlowToken Vault.")) + + let unlockedBalance = unlockedVault.balance + let lockedAccountInfoCap = account + .capabilities.get + <&LockedTokens.TokenHolder> + (LockedTokens.LockedAccountInfoPublicPath) + if !(lockedAccountInfoCap!.check()) { + return unlockedBalance + } + let lockedAccountInfoRef = lockedAccountInfoCap!.borrow()! + let lockedBalance = lockedAccountInfoRef.getLockedAccountBalance() + return lockedBalance + unlockedBalance +}`; +export const getTotalFlowBalance = async (address) => { + return await fcl.decode( + await fcl.send([fcl.script(CODE), fcl.args([fcl.arg(address, t.Address)])]), + ); +}; +``` + +## Contributing + +Releasing a new version of Dev Wallet is as simple as tagging and creating a release, a Github Action will then build a bundle of the Dev Wallet that can be used in other tools (such as CLI). If the update of the Dev Wallet is required in the CLI, a seperate update PR on the CLI should be created. For more information, please visit the [fcl-dev-wallet GitHub repository](https://github.com/onflow/fcl-dev-wallet). + +## More + +Additionally, consider exploring these resources: + +- [Guide to Creating a Fungible Token on Flow](../../build/guides/fungible-token.md) +- [Tutorial on Fungible Tokens](https://cadence-lang.org/docs/tutorial/fungible-tokens) +- [Faucets](../../ecosystem/faucets.md) \ No newline at end of file diff --git a/static/markdown/tools/index.md b/static/markdown/tools/index.md new file mode 100644 index 0000000000..2aa219b7fa --- /dev/null +++ b/static/markdown/tools/index.md @@ -0,0 +1,46 @@ +--- +sidebar_position: 12 +title: Tools +description: Essential tools for the Flow blockchain ecosystem +--- + + + + + + + !isSamePath(item.href, useLocation().pathname)), + { + type: 'link', + label: 'Flowser', + href: 'https://flowser.dev/', + description: 'Flowser combines all the tools for local development and gives you a clear UI to inspect the local Flow network.', + customProps: { + icon: 'https://flowser.dev/icon.png', + author: { + name: 'Flowser', + profileImage: + 'https://flowser.dev/icon.png', + }, + twitterLink: 'https://twitter.com/onflowser', + githubLink: 'https://github.com/onflowser/flowser' + } + }, + { + type: 'link', + label: 'Overflow', + href: 'https://github.com/bjartek/overflow', + description: 'Overflow is a Go-based DSL for testing and running interactive stories', + customProps: { + icon: '', + author: { + name: 'bjartek', + profileImage: + 'https://avatars.githubusercontent.com/u/10621?v=4', + }, + discordLink: 'https://discord.gg/t6GEtHnWFh', + githubLink: 'https://github.com/bjartek/overflow' + } + }, +]}/> \ No newline at end of file diff --git a/static/markdown/tools/kit/index.md b/static/markdown/tools/kit/index.md new file mode 100644 index 0000000000..3be39d2c3f --- /dev/null +++ b/static/markdown/tools/kit/index.md @@ -0,0 +1,343 @@ +--- +title: '@onflow/kit' +description: React hooks for interacting with the Flow blockchain. +sidebar_position: 1 +--- + +# @onflow/kit + +:::warning + +🚧 This library is currently in alpha and is subject to change. + +::: + +`@onflow/kit` is a lightweight React utility library that simplifies interacting with the Flow blockchain. It provides a collection of hooks, similar to those in other popular web3 libraries, that make it easier to build frontends that understand blockchain interactions. **In the future**, it will also provided components designed to make authentication, script execution, transactions, event subscriptions, and network configuration seamless in React apps. + +## 🔌 Included React Hooks + +- [`useCurrentFlowUser`](#usecurrentflowuser) - Authenticate and manage the current Flow user +- [`useFlowAccount`](#useflowaccount) - Fetch Flow account details by address +- [`useFlowBlock`](#useflowblock) - Query latest or specific Flow blocks +- [`useFlowConfig`](#useflowconfig) - Access the current Flow configuration +- [`useFlowEvents`](#useflowevents) - Subscribe to Flow events in real-time +- [`useFlowQuery`](#useflowquery) - Execute Cadence scripts with optional arguments +- [`useFlowMutate`](#useflowmutate) - Send transactions to the Flow blockchain +- [`useFlowTransaction`](#useflowtransaction) - Track transaction status updates + +## Installation + +```bash +npm install @onflow/kit +``` + +## Usage + +### Wrapping Your App With `FlowProvider` + +Begin by wrapping your application with the `FlowProvider` to initialize FCL configuration. This sets up FCL and maps its configuration keys to a strictly typed format for your hooks. + +```tsx + + + + + +function Root() { + return ( + + + + ); +} + +export default Root; +``` + +If you're using [Next.js], put this in `layout.tsx`. Adapt as appropriate for other frontend frameworks. + +--- + +## Hooks + +:::info + +Many of these hooks are built using [`@tanstack/react-query`](https://tanstack.com/query/latest), which provides powerful caching, revalidation, and background refetching features. As a result, you’ll see return types like `UseQueryResult` and `UseMutationResult` throughout this section. Other types—such as `Account`, `Block`, and `CurrentUser`—are from the [Flow Client Library (FCL) TypeDefs](https://github.com/onflow/fcl-js/blob/master/packages/typedefs/src/index.ts). Refer to their respective documentation for full type definitions and usage patterns. + +::: + +### `useCurrentFlowUser` + +```tsx + +``` + +#### Returns: + +- `user: CurrentUser` - The current user object from FCL +- `authenticate: () => Promise` - Triggers wallet authentication +- `unauthenticate: () => void` - Logs the user out + +```tsx +function AuthComponent() { + const { user, authenticate, unauthenticate } = useCurrentFlowUser(); + + return ( +
    + {user.loggedIn ? ( + <> +

    Logged in as {user.addr}

    + + + ) : ( + + )} +
    + ); +} +``` + +--- + +### `useFlowAccount` + +```tsx + +``` + +#### Parameters: + +- `address?: string` - Flow address (with or without `0x` prefix) + +#### Returns: `UseQueryResult` + +```tsx +function AccountDetails() { + const { + data: account, + isLoading, + error, + refetch, + } = useFlowAccount('0x1cf0e2f2f715450'); + + if (isLoading) return

    Loading account...

    ; + if (error) return

    Error fetching account: {error.message}

    ; + if (!account) return

    No account data

    ; + + return ( +
    +

    Account: {account.address}

    +

    Balance: {account.balance}

    +
    {account.code}
    + +
    + ); +} +``` + +--- + +### `useFlowBlock` + +```tsx + +``` + +#### Parameters (mutually exclusive): + +- `{}` - Latest block (default) +- `{ sealed: true }` - Latest sealed block +- `{ id: string }` - Block by ID +- `{ height: number }` - Block by height + +#### Returns: `UseQueryResult` + +```tsx +function LatestBlock() { + const { data: block, isLoading, error } = useFlowBlock(); + if (isLoading) return

    Loading...

    ; + if (error) return

    Error: {error.message}

    ; + if (!block) return

    No block data.

    ; + + return ( +
    +

    Block {block.height}

    +

    ID: {block.id}

    +
    + ); +} +``` + +--- + +### `useFlowConfig` + +```tsx + +``` + +#### Returns: `FlowConfig` + +```tsx +function MyComponent() { + const config = useFlowConfig(); + + return ( +
    +

    Current network: {config.flowNetwork}

    +

    Current access node: {config.accessNodeUrl}

    +
    + ); +} +``` + +--- + +### `useFlowEvents` + +```tsx + +``` + +#### Parameters: + +- `eventNameOrFilter`: string | EventFilter +- `options: { onEvent: (event) => void, onError?: (error) => void }` + +#### Example: + +```tsx +function EventListener() { + useFlowEvents('A.0xDeaDBeef.SomeContract.SomeEvent', { + onEvent: (event) => console.log('New event:', event), + onError: (error) => console.error('Error:', error), + }); + + return
    Listening for events...
    ; +} +``` + +--- + +### `useFlowQuery` + +```tsx + +``` + +#### Parameters: + +- `cadence: string` - Cadence script to run +- `args?: (arg, t) => unknown[]` - Function returning FCL arguments +- `enabled?: boolean` - Defaults to `true` + +#### Returns: `UseQueryResult` + +```tsx +function QueryExample() { + const { data, isLoading, error, refetch } = useFlowQuery({ + cadence: ` + pub fun main(a: Int, b: Int): Int { + return a + b + } + `, + args: (arg, t) => [arg(1, t.Int), arg(2, t.Int)], + }); + + if (isLoading) return

    Loading query...

    ; + if (error) return

    Error: {error.message}

    ; + + return ( +
    +

    Result: {data}

    + +
    + ); +} +``` + +--- + +### `useFlowMutate` + +```tsx + +``` + +#### Returns: `UseMutationResult` + +- `mutate`: A function to send the transaction +- `data`: Transaction ID +- `error`: Any error +- `isPending`: Boolean status + +```tsx +function CreatePage() { + const { mutate, isPending, error, data: txId } = useFlowMutate(); + + const sendTransaction = () => { + mutate({ + cadence: `transaction() { + prepare(acct: &Account) { + log(acct.address) + } + }`, + args: (arg, t) => [], + proposer: fcl.currentUser, + payer: fcl.currentUser, + authorizations: [], + limit: 100, + }); + }; + + return ( +
    + + {isPending &&

    Sending transaction...

    } + {error &&

    Error: {error.message}

    } + {txId &&

    Transaction ID: {txId}

    } +
    + ); +} +``` + +--- + +### `useFlowTransaction` + +```tsx + +``` + +#### Parameters: + +- `txId: string` - Transaction ID to subscribe to + +#### Returns: + +- `transactionStatus: TransactionStatus | null` +- `error: Error | null` + +```tsx +function TransactionComponent() { + const txId = 'your-transaction-id-here'; + const { transactionStatus, error } = useFlowTransaction(txId); + + if (error) return
    Error: {error.message}
    ; + + return
    Status: {transactionStatus?.statusString}
    ; +} +``` \ No newline at end of file diff --git a/static/markdown/tools/vscode-extension/index.md b/static/markdown/tools/vscode-extension/index.md new file mode 100644 index 0000000000..86376bea89 --- /dev/null +++ b/static/markdown/tools/vscode-extension/index.md @@ -0,0 +1,79 @@ +--- +title: Cadence VS Code Extension +sidebar_position: 4 +--- + +This extension integrates [Cadence](https://cadence-lang.org/docs), the resource-oriented smart contract programming language of [Flow](https://www.onflow.org/), into [Visual Studio Code](https://code.visualstudio.com/). +It provides features like syntax highlighting, type checking, code completion, etc. + +Note that most editing features (type checking, code completion, etc.) are implemented in the [Cadence Language Server](https://github.com/onflow/cadence-tools/tree/master/languageserver). + +## Features + +- Syntax highlighting (including in Markdown code fences) +- Run the emulator, submit transactions, scripts from the editor + +## Installation + +To install the extension, ensure you have the [VS Code IDE installed](https://code.visualstudio.com/docs/setup/mac). +Then, you can install the Cadence extension from the [VS Code Marketplace](https://marketplace.visualstudio.com/items?itemName=onflow.cadence). + +## Developing the Extension + +### Prerequisites + +- Must have Typescript installed globally: `npm i -g typescript` + +### Getting Started + +- Run the Typescript watcher: `tsc -watch -p ./` +- Launch the extension by pressing `F5` in VSCode +- Manually reload the extension host when you make changes to TypeScript code + +### Configuration for Extension Host if Missing (`launch.json`): + +``` +{ + "version": "0.2.0", + "configurations": [ + { + "type": "extensionHost", + "request": "launch", + "name": "Launch Extension", + "runtimeExecutable": "${execPath}", + "args": ["--extensionDevelopmentPath=${workspaceFolder}"], + "outFiles": ["${workspaceFolder}/out/**/*.js"] + } + ] +} + +``` + +### Building + +If you are building the extension from source, you need to build both the +extension itself and the Flow CLI (if you don't already have a version installed). +Unless you're developing the extension or need access to unreleased features, +you should use the Flow CLI install option (above). It's much easier! + +If you haven't already, install dependencies. + +```shell script +npm install +``` + +Next, build and package the extension. + +```shell script +npm run package +``` + +This will result in a `.vsix` file containing the packaged extension. + +Install the packaged extension. + +```shell script +code --install-extension cadence-*.vsix +``` + +Restart VS Code and the extension should be installed! \ No newline at end of file diff --git a/static/markdown/tools/wallet-provider-spec/authorization-function.md b/static/markdown/tools/wallet-provider-spec/authorization-function.md new file mode 100644 index 0000000000..aa632772d9 --- /dev/null +++ b/static/markdown/tools/wallet-provider-spec/authorization-function.md @@ -0,0 +1,131 @@ +# Authorization Function + +## Overview + +An Authorization Function is a function which enables the JS-SDK and FCL to know which Flow account fulfills which signatory role in a transaction and how to recieve a signature on behalf of the supplied account. + +## How to Use an Authorization Function + +An authorization function is a function that you may use in place of an authorization in the Flow JS-SDK and FCL. An authorization is a concept that is used when denoting a proposer, payer or authorizer for a transaction. An authorization can either be a data structure represenating an authorization, or a function which when called returns an authorization called an Authorization Function. In this document we discuss the latter. + +To use an Authorization Function, you specify that Authorization Function as the authorization for a proposer, payer or authorizer for a transaction. + +> `fcl.currentUser().authorization` which is aliased to `fcl.authz` is itself an authorization function. It tells the underlying js-sdk the current users flow account will be used for the signatory role and supplies a signing function that enables the application to request a signature from the users wallet. + +Example 1: +```javascript + + +const myAuthorizationFunction = ... // An Authorization Function + +const response = fcl.send([ + fcl.transaction`transaction() { prepare(acct: &Account) {} execute { log("Hello, Flow!") } }`, + fcl.proposer(myAuthorizationFunction), + fcl.payer(myAuthorizationFunction), + fcl.authorizers([ myAuthorizationFunction ]) +]) +``` + +The builder functions, `fcl.proposer`, `fcl.payer` and `fcl.authorizations` each consume the Authorization Function and set it as the resolve field on the internal Account object it creates. + +During the resolve phase of the Flow JS-SDK and FCL, when [`resolveAccounts`](https://github.com/onflow/fcl-js/blob/master/packages/sdk/src/resolve/resolve.js#L58) is called, the resolve field on each internal Account object is called, which means each Authorization Function is called appropriately and the account is _resolved_ into the data structure the authorizationFunction returns. These accounts are then deduped based on the a mix of the `addr`, `keyId` and `tempId` so that only a single signature request happens per `address` `keyId` pair. When [`resolveSignatures`](https://github.com/onflow/fcl-js/blob/master/packages/sdk/src/resolve/resolve.js#L62) is called the signing function for each `address` `keyId` pair is called returning a composite signature for each signatory role. + +## How to Create An Authorization Function + +Fortunately, creating an Authorization Function is relatively straight forward. + +An Authorization Function needs to be able to do at minimum two things. +- Who will sign -- Know which account is going to sign and the keyId of the key it will use to sign +- How they sign -- Know how to get a signature for the supplied account and key from the first piece. + +The Authorization Function has a concept of an account. An account represent a possible signatory for the transaction, it includes the who is signing as well as the how it will be signed. The Authorization Function is passed an empty Account and needs to return an Account, your job when making an Authorization Function is mostly to fill in this Account with the information so that the account you want to sign things can. + +Lets say we knew up front the account, keyId and had a function that could sign things. + +```javascript +const ADDRESS = "0xba1132bc08f82fe2" +const KEY_ID = 1 // this account on testnet has three keys, we want the one with an index of 1 (has a weight of 1000) +const sign = msg => { /* ... returns signature (for the key above) for supplied message ... */ } +``` + +Our Authorization Function becomes about filling things in: + +Example 2: +```javascript +const authorizationFunction = async (account) => { + // authorization function need to return an account + return { + ...account, // bunch of defaults in here, we want to overload some of them though + tempId: `${ADDRESS}-${KEY_ID}`, // tempIds are more of an advanced topic, for 99% of the times where you know the address and keyId you will want it to be a unique string per that address and keyId + addr: ADDRESS, // the address of the signatory + keyId: Number(KEY_ID), // this is the keyId for the accounts registered key that will be used to sign, make extra sure this is a number and not a string + signingFunction: async signable => { + // Singing functions are passed a signable and need to return a composite signature + // signable.message is a hex string of what needs to be signed. + return { + addr: ADDRESS, // needs to be the same as the account.addr + keyId: Number(KEY_ID), // needs to be the same as account.keyId, once again make sure its a number and not a string + signature: sign(signable.message), // this needs to be a hex string of the signature, where signable.message is the hex value that needs to be signed + } + } + } +} +``` + +## Async stuff + +Both the Authorization Function, and the accounts Signing Function can be asynchronous. This means both of these functions can go and get the information needed elsewhere. Say each of your users had a `userId`. From this `userId` say you had an api call that could return the corresponding address and key that is needed for the Authorization Functions account. You could also have another endpoint that when posted the signable (includes what needs to be signed) and the `userId` it can return with the composite signature if your api decides its okay to sign (the signable has all sorts of info to help you decide). An authorization function that can do that could look something like this. + +Example 3: +```javascript +const getAccount = (userId) => fetch(`/api/user/${userId}/account`).then(d => d.json()) +const getSignature = (userId, signable) = fetch(`/api/user/${userId}/sign`, { + method: "POST", + headers: { "Content-Type": "application/json"}, + body: JSON.stringify(signable), +}) + +function authz (userId) { + return async function authorizationFunction (account) { + const {addr, keyId} = await getAccount(userId) + + return { + ...account, + tempId: `${addr}-${keyId}`, + addr: addr, + keyId: Number(keyId), + signingFunction: signable => { + return getSignature(userId, signable) + } + } + } +} +``` +The above **Example 3** is the same as **Example 2**, but the information is gathered during the execution of the authorization function based on the supplied user id. + +## How to create a Signing Function + +Creating a signing function is also relatively simple! + +To create a signing function you specify a function which consumes a payload and returns a signature data structure. + +Example 3: +```javascript +const signingFunction = ({ + message, // The encoded string which needs to be used to produce the signature. + addr, // The address of the Flow Account this signature is to be produced for. + keyId, // The keyId of the key which is to be used to produce the signature. + roles: { + proposer, // A Boolean representing if this signature to be produced for a proposer. + authorizer, // A Boolean representing if this signature to be produced for a authorizer. + payer, // A Boolean representing if this signature to be produced for a payer. + }, + voucher, // The raw transactions information, can be used to create the message for additional safety and lack of trust in the supplied message. +}) => { + return { + addr, // The address of the Flow Account this signature was produced for. + keyId, // The keyId for which key was used to produce the signature. + signature: produceSignature(message) // The hex encoded string representing the signature of the message. + } +} +``` \ No newline at end of file diff --git a/static/markdown/tools/wallet-provider-spec/custodial.md b/static/markdown/tools/wallet-provider-spec/custodial.md new file mode 100644 index 0000000000..bc7f8aa353 --- /dev/null +++ b/static/markdown/tools/wallet-provider-spec/custodial.md @@ -0,0 +1,361 @@ +# Introduction + +A Wallet Provider handles Authentications and Authorizations. They play a very important role of being the place the users control their information and approve transactions. + +One of FCLs core ideals is for the user to be in control of their data, a wallet provider is where many users will do just that. + +FCL has been built in a way that it doesn't need to know any intimate details about a wallet provider up front, they can be discovered when the users wishes to let the dapp know about them. This gives us a concept we have been calling Bring Your Own Identity. + +# Identity + +Conceptually, FCL thinks of identity in two ways: Public and Private. + +Public identity will be stored on chain as a resource, it will be publicly available to anyone that knows the Flow Address for the account. + +In FCL getting a users public identity will be as easy as: + +```javascript + + +const identity = await user(flowAddress).snapshot() +// ^ +// `------ The public identity for `flowAddress` + +const unsub = user(flowAddress).subscribe(identity => console.log(identity)) +// ^ +// `------- The public identity for `flowAddress` +``` + +Private identity will be stored by the Wallet Provider, it will only be available to the currentUser. + +In FCL getting the currentUsers identity will fetch both the public and the private identities, merging the private into the public. + +Private info needs to be requested via scopes before the challenge step, more on that later. +We highly recommend Wallet Providers let the user see what scopes are being requested, and decide what scopes to share with the dapp. + +Consumers of identities in FCL should always assume all data is optional, and should store as little as possible, FCL will make sure the users always see the latest. + +```javascript + + +config.put("challenge.scope", "email") // request the email scope + +const unsub = currentUser().subscribe(identity => console.log(identity)) +// ^ +// `------- The private identity for the currentUser + +authenticate() // trigger the challenge step (authenticate the user via a wallet provider) +``` + +# Identity Data + +- All information in Identities are optional and may not be there. +- All values can be stored on chain, but most probably shouldn't be. + +We would love to see Wallet Providers enable the user to control the following info publicly, sort of a public profile starter kit if you will. + +FCL will always publicly try to fetch these fields when asked for a users information and it will be up to the Wallet provider to make sure they are there and keep them up to date if the user wants to change them. + +- **`name`** -- A human readable name/alias/nym for a dapp users display name +- **`avatar`** -- A fully qualified url to a smaller image used to visually represent the dapp user +- **`cover`** -- A fully qualified url to a bigger image, could be used by the dapp for personalization +- **`color`** -- A 6 character hex color, could be used by the dapp for personalization +- **`bio`** -- A small amount of text that a user can use to express themselves + +If we can give dapp developers a solid foundation of usable information that is in the direct control of the users from the very start, which we belive the above fields would do, our hopes are they can rely more on the chain and will need to store less in their own database. + +Private data on the other hand has more use cases than general data. It is pretty easy to imagine ordering something and needing information like contact details and where to ship something. + +Eventually we would love to see that sort of thing handled completely on-chain, securely, privately and safely, but in the interm it probably means storing a copy of data in a database when its needed, and allowed by a user. + +The process of a dapp receiving private data is as follows: + +1. The dapp requests the scopes they want up front `fcl.config().put("challenge.scope", "email+shippingAddress")`. +2. The User authenticates `fcl.authenticate()` and inside the Wallet Providers authentication process decides its okay for the dapp to know both the `email` and the `shippingAddress`. The User should be able to decide which information to share, if any at all. +3. When the dapp needs the information they can request it from FCLs current cache of data, if it isnt there the dapp needs to be okay with that and adjust accodingly. + +Below are the scopes we are thinking of supporting privately: +FCL will only publicly and privately try to fetch these when specified up front by a dapp. + +- **`email`** +- **`fullName`** +- **`phone`** +- **`textMessage`** +- **`address`** +- **`shippingAddress`** +- **`location`** +- **`publicKey`** + +All of the above are still subject to change as it is still early days, we would like to work closely with Wallet Providers to produce a robust, detailed and consitent spec regarding scopes. Feedback and thoughts are always welcome. + +# Authentication Challenge + +Authentication can happen one of two ways: + +- Iframe Flow +- Redirection Flow + +As a Wallet Provider you will be expected to register a URL endpoint (and some other information) with a handshake service (FCL will be launching with one in which registration happens on chain and is completely open source (Apache-2.0 lincense)). +This registered URL will be what is shown inside the iFrame or where the dapp users will be redirected. +For the remainder of this documentation we will refere to it as the _Authentication Endpoint_ and pair it with the `GET https://provider.com/flow/authentication` route. + +The Authentication Endpoint will receive the following data as query params: + +- `l6n` _(required)_ -- location (origin) of dapp +- `nonce` _(required)_ -- a random string supplied by the FCL +- `scope` _(optional)_ -- the scopes requested by the dapp +- `redirect` _(optional)_ -- where to redirect once the authentication challenge is complete + +``` +GET https://provider.com/flow/authenticate + ?l6n=https%3A%2F%2Fdapp.com + &nonce=asdfasdfasdf + &scope=email+shippingAddress + &redirect=https%3A%2F%2Fdapp.com%2Fflow%2Fcallback + +The values will use javascripts `encodeURIComponent` function and scopes will be `+` deliminated. +``` + +We can tell that this challenge is using the Redirect Flow because of the inclusion of the redirect query param. +The Iframe Flow will still need to be supported as it will be the default flow for dapps. + +At this point its on the Wallet Provider to do their magic and be confident enough that the user is who they say they are. +The user should then be shown in some form what the dapp is requesting via the scopes and allow them to opt in or out of anything they want. +Once the Wallet Provider is ready to hand back control to the dapp and FCL it needs to complete the challenge by redirecting or emiting a javascript `postMessage` event. + +Redirecting will look like this: + +``` +GET https://dapp.com/flow/callback # supplied by the redirect query param above + ?l6n=https%3A%2F%2Fdapp.com # the l6n supplied by FCL above + &nonce=asdfasdfasdf # the nonce supplied by FCL above + &addr=0xab4U9KMf # address for the users flow account (if available) -- will be used to fetch public identity information and hooks + &padder=0xhMgqTff86 # address for the Wallet Providers account -- will be used to fetch provider information + &code=afseasdfsadf # a token supplied to FCL from the Wallet Provider, FCL will use this token when requesting private information and hooks, can be any url safe value + &exp=1650400809517 # when the code expires, a value of `0` will be considered as never expires + &hks==https%3A%2F%2Fprovider.com%2Fhooks # a URL where FCL can request the private information and hooks +``` + +Iframe will look like this: + +```javascript +parent.postMessage( + { + type: "FCL::CHALLENGE::RESPONSE", // used by FCL to know what kind of message this is + addr: "0xab4U9KMf", + paddr: "0xhMgqTff86", + code: "afseasdfsadf", + exp: 1650400809517, + hks: "https://provider.com/hooks", + nonce: "asdfasdfasdf", + l6n: decodeURIComponent(l6n), + }, + decodeURIComponent(l6n) +) +``` + +FCL should now have everything it needs to collect the Public, Private and Wallet Provider Info. +The Wallet Provider info will be on chain so its not something that needs to be worried about here by the Wallet Provider. +What does need to be worried about handling the hooks request which was supplied to FCL via the `hks` value in the challenge response `https://provider.hooks`. + +The hooks request will be to the `hks` value supplied in the challenge response. The request will also include the code as a query param + +``` +GET https://povider.com/hooks + ?code=afseasdfsadf +``` + +This request needs to happen for a number of reasons. + +- If it fails FCL knows something is wrong and will attempt to re-authenticate. +- If is succeeds FCL knows that the code it has is valid. +- It creates a direct way for FCL to "verify" the user against the Wallet Provider. +- It gives FCL a direct way to get Private Identity Information and Hooks. +- The code can be passed to the backend to create a back-channel between the backend and the Wallet Provider. + +When users return to a dapp, if the code FCL stored hasnt expired, FCL will make this request again in order to stay up to date with the latest informtaion. FCL may also intermitently request this information before some critial actions. + +The hooks request should respond with the following JSON + +```javascript +const privateHooks = { + addr: "0xab4U9KMf", // the flow address this user is using for the dapp + keyId: 3, // the keyId the user wants to use when authorizing transaction + identity: { // the identity information fcl always wants if its there, will be deep merged into public info + name: "Bob the Builder", + avatar: "https://avatars.onflow.org/avatar/0xab4U9KMf.svg" + cover: "https://placekittens.com/g/900/300", + color: "cccc00", + bio: "", + }, + scoped: { // the private info request in the original challenge + email: "bob@bob.bob", // the user said it was okay for the dapp to know the email + shippingAddress: null, // the user said it was NOT okay for the dapp to know the shippingAddress + }, + provider: { + addr: "0xhMgqTff86", // the flow address for the wallet provider (used in the identity composite id) + pid: 2345432, // the wallet providers internal id for the user (used in the identity composite id) + name: "Super Wallet", + icon: "https://provider.com/assets/icon.svg", + authn: "https://provider.com/flow/authenticate", + } +} +``` + +When FCL requested the Public info from the chain it is expecting something like this. +It will be on the Wallet Provider to keep this information up to date. + +```javascript +const publicHooks = { + addr: "0xab4U9KMf", + keyId: 2, + identity: { + name: "Bob the Builder", + avatar: "https://avatars.onflow.org/avatar/0xab4U9KMf.svg" + cover: "https://placekittens.com/g/900/300", + color: "cccc00", + bio: "", + }, + authorizations: [ + { + id: 345324539, + addr: "0xhMgqTff86", + method: "HTTP/POST", + endpoint: "https://provider.com/flow/authorize", + data: { + id: 2345432 + } + } + ] +} +``` + +At this point FCL can be fairly confident who the currentUser is and is ready to initiate transactions the user can authorize. + +# Authorization + +FCL will broadcast authorization requests to the Public and Private authorization hooks it knows for a User, in a process we call Asynchronous Remote Signing. + +The core concepts to this idea are: + +- Hooks tell FCL where to send authorization requests (Wallet Provider) +- Wallet Provider responds imediately with: + - a back-channel where FCL can request the results of the authorization + - some optional local hooks ways the currentUser can authorize +- FCL will trigger the local hooks if they are for the currentUser +- FCL will poll the back-channel requesting updates until an approval or denial is given + +Below is the public authorization hook we received during the challenge above. + +```javascript + { + id: 345324539, + addr: "0xhMgqTff86", + method: "HTTP/POST", + endpoint: "https://provider.com/flow/authorize", + data: { + id: 2345432 + } + } +``` + +FCL will take that hook and do the following post requeset: + +``` +POST https://provider.com/flow/authorize + ?id=2345432 +--- +{ + message: "...", // what needs to be signed (needs to be convered from hex to binary before signing) + addr: "0xab4U9KMf", // the flow address that needs to sign + keyId: 3, // the flow account keyId for the private key that needs to sign + roles: { + proposer: true, // this accounts sequence number will be used in the transaction + authorizer: true, // this transaction can "move" and "modify" the accounts resources directly + payer: true, // this transaction will be paid for by this account (also signifies that they are signing an envelopeMessage instead of a payloadMessage) + }, + interaction: {...} // needed to recreate the message if the Wallet Provider wants to verify the message. +} +``` + +FCL ise expecting something like this in response: + +```javascript +{ + status: "PENDING", + reason: null, + compositeSignature: null, + authorizationUpdates: { + method: "HTTP/POST", + endpoint: "https://provider.com/flow/authorizations/4323", + }, + local: [ + { + method: "BROWSER/IFRAME", + endpoint: "https://provider.com/authorizations/4324", + width: "300", + height: "600", + background: "#ff0066" + } + ] +} +``` + +That local hook will be consumed by FCL, rendering an iframe with the endpoint as the src. If the user is already authenticated this screen could show them the Wallet Providers transaction approval process directly. +Because FCL isnt relying on any communication to or from the Iframe it can lock it down as much as possible, and remove it once the authorization is complete. +While displaying the local hook, it will request the status of the authorization from the `authorizationUpdates` hook. + +``` +POST https://provider.com/flow/authorizations/4323 +``` + +Expecting a response that has the same structure as the origin but without the local hooks: + +```javascript +{ + status: "PENDING", + reason: "", + compositeSignature: null, + authorizationUpdates: { + method: "HTTP/POST", + endpoint: "https://provider.com/flow/authorizations/4323", + }, +} +``` + +FCL will then follow the new `authorizationUpdates` hooks until the status changes to `"APPROVED"` or `"DECLINED"`. +If the authorization is declined it should include a reason if possible. + +```javascript +{ + status: "DECLINED", + reason: "They said no", +} +``` + +If the authorization is approved it should include a composite signature: + +```javascript +{ + status: "APPROVED", + compositeSignature: { + addr: "0xab4U9KMf", // the flow address that needs to sign + keyId: 3, // the flow account keyId for the private key that needs to sign + signature: "..." // binary signature of message encoded as hex + } +} +``` + +FCl can now submit the transaction to the Flow blockchain. + +# TL;DR Wallet Provider + +Register Provider with FCL Handshake and implement 5 Endpoints. + +- `GET flow/authenticate` -> `parent.postMessage(..., l6n)` +- `GET flow/hooks?code=___` -> `{ ...identityAndHooks }` +- `POST flow/authorize` -> `{ status, reason, compositeSignature, authorizationUpdates, local }` +- `POST authorizations/:authorization_id` +- `GET authorizations/:authorization_id` + +![diagram showing current fcl authn and authz flow](./assets/fcl-ars-auth-v3.2.png) \ No newline at end of file diff --git a/static/markdown/tools/wallet-provider-spec/index.md b/static/markdown/tools/wallet-provider-spec/index.md new file mode 100644 index 0000000000..ea88ad432f --- /dev/null +++ b/static/markdown/tools/wallet-provider-spec/index.md @@ -0,0 +1,1006 @@ +--- +title: Wallet Provider Spec +sidebar_title: Draft v4 +sidebar_position: 8 +--- + +## Status + +- **Last Updated:** June 20th 2022 +- **Stable:** Yes +- **Risk of Breaking Change:** Medium +- **Compatibility:** `>= @onflow/fcl@1.0.0-alpha.0` + +## Definitions + +This document is written with the perspective that _you_ who are reading this right now are an FCL Wallet Developer. All references to _you_ in this doc are done with this perspective in mind. + +# Overview + +Flow Client Library (FCL) approaches the idea of blockchain wallets on Flow in a different way than how wallets may be supported on other blockchains. For example, with FCL, a wallet is not necessarily limited to being a browser extension or even a native application on a users device. FCL offers wallet developers the flexibility and freedom to build many different types of applications. Since wallet applications can take on many forms, we needed to create a way for these varying applications to be able to communicate and work together. + +FCL acts in many ways as a protocol to facilitate communication and configuration between the different parties involved in a blockchain application. An _Application_ can use FCL to _authenticate_ users, and request _authorizations_ for transactions, as well as mutate and query the _Blockchain_. An application using FCL offers its _Users_ a way to connect and select any number of Wallet Providers and their Wallet Services. A selected _Wallet_ provides an Application's instance of FCL with configuration information about itself and its Wallet Services, allowing the _User_ and _Application_ to interact with them. + +In the following paragraphs we'll explore ways in which you can integrate with FCL by providing implementations of various FCL services. + +The following services will be covered: + +- Authentication (Authn) Service +- Authorization (Authz) Service +- User Signature Service +- Pre-Authz Service + +# Service Methods + +FCL Services are your way as a Wallet Provider of configuring FCL with information about what your wallet can do. FCL uses what it calls `Service Methods` to perform your supported FCL services. Service Methods are the ways FCL can talk to your wallet. Your wallet gets to decide which of these service methods each of your supported services use to communicate with you. + +Sometimes services just configure FCL and that's it. An example of this can be seen with the Authentication Service and the OpenID Service. +With those two services you are simply telling FCL "here is a bunch of info about the current user". (You will see that those two services both have a `method: "DATA"` field in them. +Currently these are the only two cases that can be a data service.) + +Other services can be a little more complex. For example, they might require a back and forth communication between FCL and the Service in question. +Ultimately we want to do this back and forth via a secure back-channel (https requests to servers), **but in some situations that isn't a viable option, so there is also a front-channel option**. +Where possible, you should aim to provide a back-channel support for services, and only fall back to a front-channel if absolutely necessary. + +Back-channel communications use `method: "HTTP/POST"`, while front-channel communications use `method: "IFRAME/RPC"`, `method: "POP/RPC"`, `method: "TAB/RPC` and `method: "EXT/RPC"`. + +| Service Method | Front | Back | +| -------------- | ----- | ---- | +| HTTP/POST | ⛔ | ✅ | +| IFRAME/RPC | ✅ | ⛔ | +| POP/RPC | ✅ | ⛔ | +| TAB/RPC | ✅ | ⛔ | +| EXT/RPC | ✅ | ⛔ | + +It's important to note that regardless of the method of communication, the data that is sent back and forth between the parties involved is the same. + +# Protocol schema definitions + +In this section we define the schema of objects used in the protocol. While they are JavaScript objects, only features supported by JSON should be used. (Meaning that conversion of an object to and from JSON should not result in any loss.) + +For the schema definition language we choose TypeScript, so that the schema closely resembles the actual type definitions one would use when making an FCL implementation. + +**Note that currently there are no official type definitions available for FCL. If you are using TypeScript, you will have to create your own type definitions (possibly based on the schema definitions presented in this document).** + +## Common definitions + +In this section we introduce some common definitions that the individual object definitions will be deriving from. + +First, let us define the kinds of FCL objects available: + +```typescript +type ObjectType = + | 'PollingResponse' + | 'Service' + | 'Identity' + | 'ServiceProvider' + | 'AuthnResponse' + | 'Signable' + | 'CompositeSignature' + | 'OpenID'; +``` + +The fields common to all FCL objects then can be defined as follows: + +```typescript +interface ObjectBase { + f_vsn: Version; + f_type: ObjectType; +} +``` + +The `f_vsn` field is usually `1.0.0` for this specification, but some exceptions will be defined by passing a different `Version` type parameter to `ObjectBase`. + +All FCL objects carry an `f_type` field so that their types can be identified at runtime. + +## FCL objects + +In this section we will define the FCL objects with each `ObjectType`. + +We also define the union of them to mean any FCL object: + +```typescript +type FclObject = + | PollingResponse + | Service + | Identity + | ServiceProvider + | AuthnResponse + | Signable + | CompositeSignature + | OpenID; +``` + +### `PollingResponse` + +```typescript +interface PollingResponse extends ObjectBase { + f_type: 'PollingResponse'; + status: 'APPROVED' | 'DECLINED' | 'PENDING' | 'REDIRECT'; + reason: string | null; + data?: FclObject; + updates?: FclObject; + local?: FclObject; +} +``` + +Each response back to FCL must be "wrapped" in a `PollingResponse`. The `status` field determines the meaning of the response: + +- An `APPROVED` status means that the request has been approved. The `data` field should be present. +- A `DECLINED` status means that the request has been declined. The `reason` field should contain a human readable reason for the refusal. +- A `PENDING` status means that the request is being processed. More `PENDING` responses may follow, but eventually a non-pending status should be returned. The `updates` and `local` fields may be present. +- The `REDIRECT` status is reserved, and should not be used by wallet services. + +In summary, zero or more `PENDING` responses should be followed by a non-pending response. It is entirely acceptable for your service to immediately return an `APPROVED` Polling Response, skipping a `PENDING` state. + +See also [PollingResponse](https://github.com/onflow/fcl-js/blob/master/packages/fcl-core/src/normalizers/service/polling-response.js). + +Here are some examples of valid `PollingResponse` objects: + +```javascript +// APPROVED +{ + f_type: "PollingResponse", + f_vsn: "1.0.0", + status: "APPROVED", + data: ___, // what the service needs to send to FCL +} + +// Declined +{ + f_type: "PollingResponse", + f_vsn: "1.0.0", + status: "DECLINED", + reason: "Declined by user." +} + +// Pending - Simple +{ + f_type: "PollingResponse", + f_vsn: "1.0.0", + status: "PENDING", + updates: { + f_type: "Service", + f_vsn: "1.0.0", + type: "back-channel-rpc", + endpoint: "https://____", // where post request will be sent + method: "HTTP/POST", + data: {}, // will be included in the request's body + params: {}, // will be included in the request's url + } +} + +// Pending - First Time with Local +{ + f_type: "PollingResponse", + f_vsn: "1.0.0", + status: "PENDING", + updates: { + f_type: "Service", + f_vsn: "1.0.0", + type: "back-channel-rpc", + endpoint: "https://____", // where post request will be sent + method: "HTTP/POST", + data: {}, // included in body of request + params: {}, // included as query params on endpoint + }, + local: { + f_type: "Service", + f_vsn: "1.0.0", + endpoint: "https://____", // the iframe that will be rendered, + method: "VIEW/IFRAME", + data: {}, // sent to frame when ready + params: {}, // included as query params on endpoint + } +} +``` + +A `PollingResponse` can alternatively be constructed using `WalletUtils` when sending `"APPROVED"` or `"DECLINED"` responses. + +```javascript + + +// Approving a PollingResponse +// Example using an AuthnResponse as the PollingResponse data +WalletUtils.approve({ + f_type: "AuthnResponse", + f_vsn: "1.0.0" + ... +}) + +// Rejecting a PollingResponse +// Supplies a reason for declining +const reason = "User declined to authenticate." +WalletUtils.decline(reason) +``` + +### `Service` + +```typescript +type ServiceType = + | 'authn' + | 'authz' + | 'user-signature' + | 'pre-authz' + | 'open-id' + | 'back-channel-rpc' + | 'authn-refresh'; + +type ServiceMethod = + | 'HTTP/POST' + | 'IFRAME/RPC' + | 'POP/RPC' + | 'TAB/RPC' + | 'EXT/RPC' + | 'DATA'; + +interface Service extends ObjectBase { + f_type: 'Service'; + type: ServiceType; + method: ServiceMethod; + uid: string; + endpoint: string; + id: string; + identity: Identity; + provider?: ServiceProvider; + data?: FclObject; +} +``` + +The meaning of the fields is as follows. + +- `type`: The type of this service. +- `method`: The service method this service uses. `DATA` means that the purpose of this service is just to provide the information in this `Service` object, and no active communication services are provided. +- `uid`: A unique identifier for the service. A common scheme for deriving this is to use `'wallet-name#${type}'`, where `${type}` refers to the type of this service. +- `endpoint`: Defines where to communicate with the service. + - When `method` is `EXT/RPC`, this can be an arbitrary unique string, and the extension will need to use it to identify its own services. A common scheme for deriving the `endpoint` is to use `'ext:${address}'`, where `${address}` refers to the wallet's address. (See `ServiceProvider` for more information.) +- `id`: The wallet's internal identifier for the user. If no other identifier is used, simply the user's flow account address can be used here. +- `identity`: Information about the identity of the user. +- `provider`: Information about the wallet. +- `data`: Additional information used with a service of type `open-id`. + +See also: + +- [authn](https://github.com/onflow/fcl-js/blob/master/packages/fcl-core/src/normalizers/service/authn.js) +- [authz](https://github.com/onflow/fcl-js/blob/master/packages/fcl-core/src/normalizers/service/authz.js) +- [user-signature](https://github.com/onflow/fcl-js/blob/master/packages/fcl-core/src/normalizers/service/user-signature.js) +- [pre-authz](https://github.com/onflow/fcl-js/blob/master/packages/fcl-core/src/normalizers/service/pre-authz.js) +- [open-id](https://github.com/onflow/fcl-js/blob/master/packages/fcl-core/src/normalizers/service/open-id.js) +- [back-channel-rpc](https://github.com/onflow/fcl-js/blob/master/packages/fcl-core/src/normalizers/service/back-channel-rpc.js) + +### `Identity` + +This object is used to define the identity of the user. + +```typescript +interface Identity extends ObjectBase { + f_type: 'Identity'; + address: string; + keyId?: number; +} +``` + +The meaning of the fields is as follows. + +- `address`: The flow account address of the user. +- `keyId`: The id of the key associated with this account that will be used for signing. + +### `ServiceProvider` + +This object is used to communicate information about a wallet. + +```typescript +interface ServiceProvider extends ObjectBase { + f_type: 'ServiceProvider'; + address: string; + name?: string; + description?: string; + icon?: string; + website?: string; + supportUrl?: string; + supportEmail?: string; +} +``` + +The meaning of the fields is as follows. + +- `address`: A flow account address owned by the wallet. It is unspecified what this will be used for. +- `name`: The name of the wallet. +- `description`: A short description for the wallet. +- `icon`: An image URL for the wallet's icon. +- `website`: The wallet's website. +- `supportUrl`: A URL the user can use to get support with the wallet. +- `supportEmail`: An e-mail address the user can use to get support with the wallet. + +### `AuthnResponse` + +This object is used to inform FCL about the services a wallet provides. + +```typescript +interface AuthnResponse extends ObjectBase { + f_type: 'AuthnResponse'; + addr: string; + services: Service[]; +} +``` + +The meaning of the fields is as follows. + +- `addr`: The flow account address of the user. +- `services`: The list of services provided by the wallet. + +### `Signable` + +```typescript +interface Signable extends ObjectBase<'1.0.1'> { + f_type: 'Signable'; + addr: string; + keyId: number; + voucher: { + cadence: string; + refBlock: string; + computeLimit: number; + arguments: { + type: string; + value: unknown; + }[]; + proposalKey: { + address: string; + keyId: number; + sequenceNum: number; + }; + payer: string; + authorizers: string[]; + }; +} +``` + +The `WalletUtils.encodeMessageFromSignable` function can be used to calculate the message that needs to be signed. + +### `CompositeSignature` + +```typescript +interface CompositeSignature extends ObjectBase { + f_type: 'CompositeSignature'; + addr: string; + keyId: number; + signature: string; +} +``` + +See also [CompositeSignature](https://github.com/onflow/fcl-js/blob/master/packages/fcl-core/src/normalizers/service/composite-signature.js). + +### `OpenID` + +TODO + +## Miscellaneous objects + +### `Message` + +```typescript +type MessageType = + | 'FCL:VIEW:READY' + | 'FCL:VIEW:READY:RESPONSE' + | 'FCL:VIEW:RESPONSE' + | 'FCL:VIEW:CLOSE'; + +type Message = { + type: MessageType; +}; +``` + +A message that indicates the status of the protocol invocation. + +This type is sometimes used as part of an _intersection type_. For example, the type `Message & PollingResponse` means a `PollingResponse` extended with the `type` field from `Message`. + +### `ExtensionServiceInitiationMessage` + +```typescript +type ExtensionServiceInitiationMessage = { + service: Service; +}; +``` + +This object is used to invoke a service when the `EXT/RPC` service method is used. + +## See also + +- [local-view](https://github.com/onflow/fcl-js/blob/master/packages/fcl-core/src/normalizers/service/local-view.js) +- [frame](https://github.com/onflow/fcl-js/blob/master/packages/fcl-core/src/normalizers/service/frame.js) + +# Service Methods + +## IFRAME/RPC (Front Channel) + +`IFRAME/RPC` is the easiest to explain, so we will start with it: + +- An iframe is rendered (comes from the `endpoint` in the service). +- The rendered iframe adds a listener and sends the `"FCL:VIEW:READY"` message. This can be simplified `WalletUtils.ready(callback)` +- FCL will send the data to be dealt with: + - Where `body` is the stuff you care about, `params` and `data` are additional information you can provide in the service object. +- The wallet sends back an `"APPROVED"` or `"DECLINED"` post message. (It will be a `f_type: "PollingResponse"`, which we will get to in a bit). This can be simplified using `WalletUtils.approve` and `WalletUtils.decline` + - If it's approved, the polling response's data field will need to be what FCL is expecting. + - If it's declined, the polling response's reason field should say why it was declined. + +```javascript +export const WalletUtils.approve = data => { + sendMsgToFCL("FCL:VIEW:RESPONSE", { + f_type: "PollingResponse", + f_vsn: "1.0.0", + status: "APPROVED", + reason: null, + data: data, + }) +} + +export const WalletUtils.decline = reason => { + sendMsgToFCL("FCL:VIEW:RESPONSE", { + f_type: "PollingResponse", + f_vsn: "1.0.0", + status: "DECLINED", + reason: reason, + data: null, + }) +} +``` + +```mermaid +graph LR + Start1(Start) + --Bot 启动--> check1[检查群内的非 Authing 用户] + --> addUser[添加 Authing 用户并消息提醒绑定手机号] + --> End1(End) +``` + +![IFRAME/RPC Diagram](https://raw.githubusercontent.com/onflow/fcl-js/master/packages/fcl-core/assets/service-method-diagrams/iframe-rpc.png) + +## POP/RPC | TAB/RPC (Front Channel) + +`POP/RPC` and `TAB/RPC` work in an almost entirely similar way to `IFRAME/RPC`, except instead of rendering the `method` in an iframe, we render it in a popup or new tab. The same communication protocol between the rendered view and FCL applies. + +![POP/RPC Diagram](https://raw.githubusercontent.com/onflow/fcl-js/master/packages/fcl-core/assets/service-method-diagrams/pop-rpc.png) + +![TAB/RPC Diagram](https://raw.githubusercontent.com/onflow/fcl-js/master/packages/fcl-core/assets/service-method-diagrams/tab-rpc.png) + +## HTTP/POST (Back Channel) + +`HTTP/POST` initially sends a post request to the `endpoint` specified in the service, which should immediately return a `f_type: "PollingResponse"`. + +Like `IFRAME/RPC`, `POP/RPC` or `TAB/RPC`, our goal is to eventually get an `APPROVED` or `DECLINED` polling response, and technically this endpoint could return one of those immediately. + +But more than likely that isn't the case and it will be in a `PENDING` state (`PENDING` is not available to `IFRAME/RPC`, `POP/RPC` or `TAB/RPC`). +When the polling response is `PENDING` it requires an `updates` field that includes a service, `BackChannelRpc`, that FCL can use to request an updated `PollingResponse` from. +FCL will use that `BackChannelRpc` to request a new `PollingResponse` which itself can be `APPROVED`, `DECLINED` or `PENDING`. +If it is `APPROVED` FCL will return, otherwise if it is `DECLINED` FCL will error. However, if it is `PENDING`, it will use the `BackChannelRpc` supplied in the new `PollingResponse` updates field. It will repeat this cycle until it is either `APPROVED` or `DECLINED`. + +There is an additional optional feature that `HTTP/POST` enables in the first `PollingResponse` that is returned. +This optional feature is the ability for FCL to render an iframe, popup or new tab, and it can be triggered by supplying a service `type: "VIEW/IFRAME"`, `type: "VIEW/POP"` or `type: "VIEW/TAB"` and the `endpoint` that the wallet wishes to render in the `local` field of the `PollingResponse`. This is a great way for a wallet provider to switch to a webpage if displaying a UI is necessary for the service it is performing. + +![HTTP/POST Diagram](https://raw.githubusercontent.com/onflow/fcl-js/master/packages/fcl-core/assets/service-method-diagrams/http-post.png) + +## EXT/RPC (Front Channel) + +`EXT/RPC` is used to enable and communicate between FCL and an installed web browser extension. (Though this specification is geared towards Chromium based browsers, it should be implementable in any browser with similar extension APIs available. From now on we will be using the word _Chrome_ to refer to Chromium based browsers.) + +An implementation of `EXT/RPC` needs to somehow enable communication between the application and the extension context. Implementing this is a bit more complex and usually relies on 3 key scripts to allow message passing between an installed extension and FCL. The separation of contexts enforced by Chrome and the availability of different Chrome APIs within those contexts require these scripts to be set up in a particular sequence so that the communication channels needed by FCL's `EXT/RPC` service method will work. + +The following is an overview of these scripts and the functionality they need to support FCL: + +- `background.js`: Used to launch the extension popup with `chrome.windows.create` if selected by the user from Discovery or set directly via `fcl.config.discovery.wallet` +- `content.js`: Used to proxy messages between the application to the extension via `chrome.runtime.sendMessage`. +- `script.js`: Injected by `content.js` into the application's HTML page. It appends the extension authn service to the `window.fcl_extensions` array on page load. This allows FCL to confirm installation and send extension details to Discovery or launch your wallet as the default wallet. + +An example and guide showing how to build an FCL compatible wallet extension on Flow can be found [here](https://github.com/onflow/wallet-extension-example). + +Once the extension is enabled (for example when the user selects it through the discovery service), the following communication protocol applies. (The term _send_ should specifically refer to using `window.postMessage` in the application context, as this is the only interface between the application and the extension. Note that since `window.postMessage` broadcasts messages to all message event handlers, care should be taken by each party to filter only the messages targeted at them.) + +- An `ExtensionServiceInitiationMessage` object is sent by FCL. It is the extension's responsibility to inspect the `endpoint` field of the service, and only activate itself (e.g. by opening a popup) if it is the provider of this service. +- The extension should respond by sending a `Message` with type `FCL:VIEW:READY`. (Usually this message will originate from the extension popup, and be relayed to the application context.) +- FCL will send a `Message` with type `FCL:VIEW:READY:RESPONSE`. Additional fields specific to the service (such as `body`, `params` or `data`) are usually present. See the section on the specific service for a description of these fields. +- The wallet sends back a `Message & PollingResponse` with type `FCL:VIEW:RESPONSE` with either an `APPROVED` or `DECLINED` status. + - If it's approved, the polling response's data field will need to be what FCL is expecting. + - If it's declined, the polling response's reason field should say why it was declined. + +The extension can send a `Message` with type `FCL:VIEW:CLOSE` at any point during this protocol to indicate an interruption. This will halt FCL's current routine. On the other hand, once a `PollingResponse` with either an `APPROVED` or `DECLINED` status was sent, the protocol is considered finished, and the extension should not send any further messages as part of this exchange. + +Conversely, when FCL sends a new `ExtensionServiceInitiationMessage`, the previous routine is interrupted. (This is the case even when the new service invocation is targeted at a different extension.) + +Note that as a consequence of the above restrictions, only single service invocation can be in progress at a time. + +Here is a code example for how an extension popup might send its response: + +```javascript +chrome.tabs.sendMessage(tabs[0].id, { + f_type: 'PollingResponse', + f_vsn: '1.0.0', + status: 'APPROVED', + reason: null, + data: { + f_type: 'AuthnResponse', + f_vsn: '1.0.0', + addr: address, + services: services, + }, +}); +``` + +![EXT/RPC Diagram](https://raw.githubusercontent.com/onflow/fcl-js/master/packages/fcl-core/assets/service-method-diagrams/ext-rpc.png) + +## `data` and `params` + +`data` and `params` are information that the wallet can provide in the service config that FCL will pass back to the service. + +- `params` will be added onto the `endpoint` as query params. +- `data` will be included in the body of the `HTTP/POST` request or in the `FCL:VIEW:READY:RESPONSE` for a `IFRAME/RPC`, `POP/RPC`, `TAB/RPC` or `EXT/RPC`. + +# Authentication Service + +In the following examples, we'll walk you through the process of building an authentication service. + +In FCL, wallets are configured by passing in a wallet provider's authentication URL or extension endpoint as the `discovery.wallet` config variable. + +You will need to make and expose a webpage or API hosted at an authentication endpoint that FCL will use. + +```javascript +// IN APPLICATION +// configuring fcl to point at a wallet looks like this + + +config({ + 'discovery.wallet': 'url-or-endpoint-fcl-will-use-for-authentication', // FCL Discovery endpoint, wallet provider's authentication URL or extension endpoint + 'discovery.wallet.method': 'IFRAME/RPC', // Optional. Available methods are "IFRAME/RPC", "POP/RPC", "TAB/RPC", "EXT/RPC" or "HTTP/POST", defaults to "IFRAME/RPC". +}); +``` + +If the method specified is `IFRAME/RPC`, `POP/RPC` or `TAB/RPC`, then the URL specified as `discovery.wallet` will be rendered as a webpage. If the configured method is `EXT/RPC`, `discovery.wallet` should be set to the extension's `authn` `endpoint`. Otherwise, if the method specified is `HTTP/POST`, then the authentication process will happen over HTTP requests. (While authentication can be accomplished using any of those service methods, this example will use the `IFRAME/RPC` service method.) + +Once the Authentication webpage is rendered, the extension popup is enabled, or the API is ready, you then need to tell FCL that it is ready. You will do this by sending a message to FCL, and FCL will send back a message with some additional information that you can use about the application requesting authentication on behalf of the user. + +The following example is using the `IFRAME/RPC` method. Your authentication webpage will likely resemble the following code: + +```javascript +// IN WALLET AUTHENTICATION FRAME + + +function callback(data) { + if (typeof data != "object") return + if (data.type !== "FCL:VIEW:READY:RESPONSE") return + + ... // Do authentication things ... + + // Send back AuthnResponse + WalletUtils.sendMsgToFCL("FCL:VIEW:RESPONSE", { + f_type: "PollingResponse", + f_vsn: "1.0.0", + status: "APPROVED", + data: { + f_type: "AuthnResponse", + f_vsn: "1.0.0" + ... + } + }) + + // Alternatively be sent using WalletUtils.approve (or WalletUtils.decline) + // which will wrap AuthnResponse in a PollingResponse + WalletUtils.approve({ + f_type: "AuthnResponse", + f_vsn: "1.0.0" + ... + }) +} +// add event listener first +WalletUtils.onMsgFromFCL("FCL:VIEW:READY:RESPONSE", callback) + +// tell fcl the wallet is ready +WalletUtils.sendMsgToFCL("FCL:VIEW:READY") + +// alternatively adds "FCL:VIEW:READY:RESPONSE" listener and sends "FCL:VIEW:READY" +WalletUtils.ready(callback) +``` + +During authentication, the application has a chance to request to you what they would like you to send back to them. These requests are included in the `FCL:VIEW:READY:RESPONSE` message sent to the wallet from FCL. + +An example of such a request is the OpenID service. The application can request for example that you to send them the email address of the current user. The application requesting this information does not mean you need to send it. It's entirely optional for you to do so. However, some applications may depend on you sending the requested information back, and should you decline to do so it may cause the application to not work. + +In the config they can also tell you a variety of things about them, such as the name of their application or a url for an icon of their application. You can use these pieces of information to customize your wallet's user experience should you desire to do so. + +Your wallet having a visual distinction from the application, but still a seamless and connected experience is our goal here. + +Whether your authentication process happens using a webpage with the `IFRAME/RPC`, `POP/RPC` or `TAB/RPC` methods, via an enabled extension using the `EXT/RPC` method, or using a backchannel to an API with the `HTTP/POST` method, the handshake is the same. The same messages are sent in all methods, however the transport mechanism changes. For `IFRAME/RPC`, `POP/RPC`, `TAB/RPC` or `EXT/RPC` methods, the transport is `window.postMessage()`, with the `HTTP/POST` method, the transport is HTTP post messages. + +As always, you must never trust anything you receive from an application. Always do your due-diligence and be alert as you are the user's first line of defense against potentially malicious applications. + +### Authenticate your User + +It's important that you are confident that the user is who the user claims to be. + +Have them provide enough proof to you that you are okay with passing their details back to FCL. +Using Blocto as an example, an authentication code is sent to the email a user enters at login. +This code can be used as validation and is everything Blocto needs to be confident in the user's identity. + +### Once you know who your User is + +Once you're confident in the user's identity, we can complete the authentication process. + +The authentication process is complete once FCL receives back a response that configures FCL with FCL Services for the current user. This response is extremely important to FCL. At its core it tells FCL who the user is, and then via the included services it tells FCL how the user authenticated, how to request transaction signatures, how to get a personal message signed and the user's email and other details if requested. In the future it may also include many more things! + +You can kind of think of FCL as a plugin system. But since those plugins exist elsewhere outside of FCL, FCL needs to be configured with information on how to communicate with them. + +What you are sending back to FCL is everything that it needs to communicate with the plugins that you are supplying. +Your wallet is like a plugin to FCL, and these details tell FCL how to use you as a plugin. + +Here is an example of an authentication response: + +```javascript +// IN WALLET AUTHENTICATION FRAME + + +WalletUtils.approve({ + f_type: "AuthnResponse", + f_vsn: "1.0.0", + addr: "0xUSER", // The user's flow address + + services: [ // All the stuff that configures FCL + + // Authentication Service - REQUIRED + { + f_type: "Service", // It's a service! + f_vsn: "1.0.0", // Follows the v1.0.0 spec for the service + type: "authn", // the type of service it is + method: "DATA", // It's data! + uid: "amazing-wallet#authn", // A unique identifier for the service + endpoint: "your-url-that-fcl-will-use-for-authentication", // should be the same as was passed into the config + id: "0xUSER", // the wallet's internal id for the user, use flow address if you don't have one + // The User's Info + identity: { + f_type: "Identity", // It's an Identity! + f_vsn: "1.0.0", // Follows the v1.0.0 spec for an identity + address: "0xUSER", // The user's address + keyId: 0, // OPTIONAL - The User's KeyId they will use + }, + // The Wallet's Info + provider: { + f_type: "ServiceProvider", // It's a Service Provider + f_vsn: "1.0.0", // Follows the v1.0.0 spec for service providers + address: "0xWallet", // A flow address owned by the wallet + name: "Amazing Wallet", // OPTIONAL - The name of your wallet. ie: "Dapper Wallet" or "Blocto Wallet" + description: "The best wallet", // OPTIONAL - A short description for your wallet + icon: "https://___", // OPTIONAL - Image url for your wallet's icon + website: "https://___", // OPTIONAL - Your wallet's website + supportUrl: "https://___", // OPTIONAL - An url the user can use to get support from you + supportEmail: "help@aw.com", // OPTIONAL - An email the user can use to get support from you + }, + }, + + // Authorization Service + { + f_type: "Service", + f_vsn: "1.0.0", + type: "authz", + uid: "amazing-wallet#authz", + ... + // We will cover this at length in the authorization section of this guide + }, + + // User Signature Service + { + f_type: "Service", + f_vsn: "1.0.0", + type: "user-signature", + uid: "amazing-wallet#user-signature", + ... + // We will cover this at length in the user signature section of this guide + }, + + // OpenID Service + { + f_type: "Service", + f_vsn: "1.0.0", + type: "open-id", + uid: "amazing-wallet#open-id", + method: "DATA", + data: { // only include data that was request, ideally only if the user approves the sharing of data, everything is optional + f_type: "OpenID", + f_vsn: "1.0.0", + profile: { + name: "Jeff", + family_name: "D", // icky underscored names because of OpenID Connect spec + given_name: "Jeffrey", + middle_name: "FakeMiddleName", + nickname: "JeffJeff", + preferred_username: "Jeff", + profile: "https://www.jeff.jeff/", + picture: "https://avatars.onflow.org/avatar/jeff", + website: "https://www.jeff.jeff/", + gender: "male", + birthday: "1900-01-01", // can use 0000 for year if year is not known + zoneinfo: "America/Vancouver", + locale: "en", + updated_at: "1625588304427" + }, + email: { + email: "jeff@jeff.jeff", + email_verified: false, + } + }, + } + ] +}) +``` + +### Stopping an Authentication Process + +From any frame, you can send a `FCL:VIEW:CLOSE` post message to FCL, which will halt FCL's current routine and close the frame. + +```javascript + + +WalletUtils.sendMsgToFCL('FCL:VIEW:CLOSE'); +``` + +# Authorization Service + +Authorization services are depicted with with a `type: "authz"`, and a `method` of either `HTTP/POST`, `IFRAME/RPC`, `POP/RPC`, `TAB/RPC` or `EXT/RPC`. +They are expected to eventually return a `f_type: "CompositeSignature"`. + +An authorization service is expected to know the Account and the Key that will be used to sign the transaction at the time the service is sent to FCL (during authentication). + +```javascript +{ + f_type: "Service", + f_vsn: "1.0.0", + type: "authz", // say it's an authorization service + uid: "amazing-wallet#authz", // standard service uid + method: "HTTP/POST", // can also be `IFRAME/RPC` or `POP/RPC` + endpoint: "https://____", // where to talk to the service + identity: { + f_type: "Identity", + f_vsn: "1.0.0", + address: "0xUser", // the address that the signature will be for + keyId: 0, // the key for the address that the signature will be for + }, + data: {}, + params: {}, +} +``` + +FCL will use the `method` provided to request an array of composite signature from authorization service (Wrapped in a `PollingResponse`). +The authorization service will be sent a `Signable`. +The service is expected to construct an encoded message to sign from `Signable.voucher`. +It then needs to hash the encoded message, and prepend a required [transaction domain tag](https://github.com/onflow/fcl-js/blob/master/packages/sdk/src/encode/encode.ts#L18-L21). +Finally it signs the payload with the user/s keys, producing a signature. +This signature, as a HEX string, is sent back to FCL as part of the `CompositeSignature` which includes the user address and keyID in the data property of a `PollingResponse`. + +```elixir +signature = + signable.voucher + |> encode + |> hash + |> tag + |> sign + |> convert_to_hex +``` + +The eventual response back from the authorization service should resolve to something like this: + +```javascript +{ + f_type: "PollingResponse", + f_vsn: "1.0.0", + status: "APPROVED", + data: { + f_type: "CompositeSignature", + f_vsn: "1.0.0", + addr: "0xUSER", + keyId: 0, + signature: "signature as hex value" + } +} +``` + +A `CompositeSignature` can alternatively be constructed using `WalletUtils` + +```javascript + + +WalletUtils.CompositeSignature(addr: String, keyId: Number, signature: Hex) + +``` + +# User Signature Service + +User Signature services are depicted with a `type: "user-signature"` and a `method` of either `HTTP/POST`, `IFRAME/RPC`, `POP/RPC`, `TAB/RPC` or `EXT/RPC`. +They are expected to eventually return an array of `f_type: "CompositeSignature"`. + +The User Signature service is a stock/standard service. + +```javascript +{ + f_type: "Service", + f_vsn: "1.0.0", + type: "user-signature", // say it's an user-signature service + uid: "amazing-wallet#user-signature", // standard service uid + method: "HTTP/POST", // can also be `IFRAME/RPC` + endpoint: "https://___", // where to talk to the service + data: {}, + params: {}, +} +``` + +FCL will use the `method` provided to request an array of composite signatures from the user signature service (Wrapped in a `PollingResponse`). +The user signature service will be sent a `Signable`. +The service is expected to tag the `Signable.message` and then sign it with enough keys to produce a full weight. +The signatures need to be sent back to FCL as HEX strings in an array of `CompositeSignatures`. + +```javascript +// Pseudocode: +// For every required signature + + +const encoded = WalletUtils.encodeMessageFromSignable(signable, signerAddress); +const taggedMessage = tagMessage(encoded); // Tag the message to sign +const signature = signMessage(taggedMessage); // Sign the message +const hexSignature = signatureToHex(signature); // Convert the signature to hex, if required. + +return hexSignature; +``` + +The eventual response back from the user signature service should resolve to something like this: + +```javascript +{ + f_type: "PollingResponse", + f_vsn: "1.0.0", + status: "APPROVED", + data: [ + { + f_type: "CompositeSignature", + f_vsn: "1.0.0", + addr: "0xUSER", + keyId: 0, + signature: "signature as hex value" + }, + { + f_type: "CompositeSignature", + f_vsn: "1.0.0", + addr: "0xUSER", + keyId: 1, + signature: "signature as hex value" + } + ] +} +``` + +# Pre Authz Service + +This is a strange one, but extremely powerful. This service should be used when a wallet is responsible for an account that's signing as multiple roles of a transaction, and wants the ability to change the accounts on a per role basis. + +Pre Authz Services are depicted with a `type: "pre-authz"` and a `method` of either `HTTP/POST`, `IFRAME/RPC`, `POP/RPC`, `TAB/RPC` or `EXT/RPC`. +They are expected to eventually return a `f_type: "PreAuthzResponse"`. + +The Pre Authz Service is a stock/standard service. + +```javascript +{ + f_type: "Service", + f_vsn: "1.0.0", + type: "pre-authz", // say it's a pre-authz service + uid: "amazing-wallet#pre-authz", // standard service uid + method: "HTTP/POST", // can also be IFRAME/RPC, POP/RPC, TAB/RPC + endpoint: "https://___", // where to talk to the service + data: {}, + params: {}, +} +``` + +FCL will use the `method` provided to request a `PreAuthzReponse` (Wrapped in a `PollingResponse`). +The Authorizations service will be sent a `PreSignable`. +The pre-authz service is expected to look at the `PreSignable` and determine the breakdown of accounts to be used. +The pre-authz service is expected to return `Authz` services for each role it is responsible for. +A pre-authz service can only supply roles it is responsible for. +If a pre-authz service is responsible for multiple roles, but it wants the same account to be responsible for all the roles, it will need to supply an Authz service per role. + +The eventual response back from the pre-authz service should resolve to something like this: + +```javascript +{ + f_type: "PollingResponse", + f_vsn: "1.0.0", + status: "APPROVED", + data: { + f_type: "PreAuthzResponse", + f_vsn: "1.0.0", + proposer: { // A single Authz Service + f_type: "Service", + f_vsn: "1.0.0", + type: "authz", + ... + }, + payer: [ // An array of Authz Services + { + f_type: "Service", + f_vsn: "1.0.0", + type: "authz", + ... + } + ], + authorization: [ // An array of Authz Services (it's singular because it only represents a singular authorization) + { + f_type: "Service", + f_vsn: "1.0.0", + type: "authz", + ... + } + ], + } +} +``` + +# Authentication Refresh Service + +Since synchronization of a user's session is important to provide a seamless user experience when using an app and transacting with the Flow Blockchain, a way to confirm, extend, and refresh a user session can be provided by the wallet. + +Authentication Refresh Services should include a `type: "authn-refresh"`, `endpoint`, and supported `method` (`HTTP/POST`, `IFRAME/RPC`, `POP/RPC`, or `EXT/RPC`). + +FCL will use the `endpoint` and service `method` provided to request updated authentication data. +The `authn-refresh` service should refresh the user's session if necessary and return updated authentication configuration and user session data. + +The service is expected to return a `PollingResponse` with a new `AuthnResponse` as data. If user input is required, a `PENDING` `PollingResponse` can be returned with a `local` view for approval/re-submission of user details. + +The Authentication Refresh Service is a stock/standard service. + +```javascript + { + "f_type": "Service", + "f_vsn": "1.0.0", + "type": "authn-refresh", + "uid": "uniqueDedupeKey", + "endpoint": "https://rawr", + "method": "HTTP/POST", // "HTTP/POST", // HTTP/POST | IFRAME/RPC | HTTP/RPC + "id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", // wallet's internal id for the user + "data": {}, // included in body of request + "params": {}, // included as query params on endpoint url + } +``` + +The provided `data` and `params` should include all the wallet needs to identify and re-authenticate the user if necessary. + +The eventual response back from the `authn-refresh` service should resolve to an `AuthnResponse` and look something like this: + +```javascript +{ + f_type: "PollingResponse", + f_vsn: "1.0.0", + status: "APPROVED", + data: { + f_type: "AuthnResponse", + f_vsn: "1.0.0", + addr: "0xUSER", + services: [ + // Authentication Service - REQUIRED + { + f_type: "Service", + f_vsn: "1.0.0", + type: "authn", + ... + }, + // Authorization Service + { + f_type: "Service", + f_vsn: "1.0.0", + type: "authz", + ... + }, + // Authentication Refresh Service + { + f_type: "Service", + f_vsn: "1.0.0", + type: "authn-refresh", + ... + } + // Additional Services + ], + } +} +``` \ No newline at end of file diff --git a/static/markdown/tools/wallet-provider-spec/provable-authn.md b/static/markdown/tools/wallet-provider-spec/provable-authn.md new file mode 100644 index 0000000000..21b2f3ab67 --- /dev/null +++ b/static/markdown/tools/wallet-provider-spec/provable-authn.md @@ -0,0 +1,89 @@ +# Provable Authn + +In order to improve UX/DX and encourage seamless integration with App backends and services, `fcl.authenticate` has been upgraded. + +Additional data is sent in the body of `FCL:VIEW:READY:RESPONSE`. This data includes what the wallet needs to build a message for signing with the user’s private key/s. +The signature can be returned as part of an optional `account-proof` service with the `FCL:VIEW:RESPONSE`. + +When provided by the wallet, this **signature** and additional **account-proof data** is available to the App via `fcl.currentUser` services. The service data can be used to recreate the message, and verify the signature on the Flow Blockchain. + +For example, it can be sent to the App’s backend and after validating the signature and the other account-proof data, it can safely associate the included account address to a user and log them in. + +--- + +## TL;DR Wallet Provider + +1. Wallet receives Authn `FCL:VIEW:READY:RESPONSE` request and parses out the `appIdentifier`, and `nonce`. +2. The wallet authenticates the user however they choose to do, and determines the user's account `address` +3. Wallet prepares and signs the message: + - Encodes the `appIdentifier`, `nonce`, and `address` along with the `"FCL-ACCOUNT-PROOF-V0.0"` domain separation tag, [using the encoding scheme described below](#account-proof-message-encoding). + - Signs the message with the `signatureAlgorithm` and `hashAlgorithm` specified on user's key. **It is highly recommended that the wallet display the message data and receive user approval before signing.** +4. Wallet sends back this new service and data along with the other service configuration when completing Authn. + +### Account Proof Message Encoding + +The account proof message is encoded as follows: + +```text +MESSAGE = + USER_DOMAIN_TAG || + RLP_ENCODE([ + APP_IDENTIFIER, + ADDRESS, + NONCE + ]) +``` + +with the following values: + +- `ACCOUNT_PROOF_DOMAIN_TAG` is the constant `"FCL-ACCOUNT-PROOF-V0.0"`, encoded as UTF-8 byte array and right-padded with zero bytes to a length of 32 bytes. +- `APP_IDENTIFIER` is an arbitrary length string. +- `ADDRESS` is a byte array containing the address bytes, left-padded with zero bytes to a length of 8 bytes. +- `NONCE` is an byte array with a minimum length of 32 bytes. + +`RLP_ENCODE` is a function that performs [RLP encoding](https://eth.wiki/fundamentals/rlp) and returns the encoded value as bytes. + +### JavaScript Signing Example + +```javascript +// Using WalletUtils + + +const message = WalletUtils.encodeAccountProof( + appIdentifier, // A human readable string to identify your application during signing + address, // Flow address of the user authenticating + nonce, // minimum 32-btye nonce +) + +sign(privateKey, message) + +// Without using FCL WalletUtils +const ACCOUNT_PROOF_DOMAIN_TAG = rightPaddedHexBuffer( + Buffer.from("FCL-ACCOUNT-PROOF-V0.0").toString("hex"), + 32 +) +const message = rlp([appIdentifier, address, nonce]) +const prependUserDomainTag = (message) => ACCOUNT_PROOF_DOMAIN_TAG + message + +sign(privateKey, prependUserDomainTag(message)) +``` + +```json +// Authentication Proof Service +{ + f_type: "Service", // Its a service! + f_vsn: "1.0.0", // Follows the v1.0.0 spec for the service + type: "account-proof", // the type of service it is + method: "DATA", // Its data! + uid: "awesome-wallet#account-proof", // A unique identifier for the service + data: { + f_type: "account-proof", + f_vsn: "1.0.0" + // The user's address (8 bytes, i.e 16 hex characters) + address: "0xf8d6e0586b0a20c7", + // Nonce signed by the current account-proof (minimum 32 bytes in total, i.e 64 hex characters) + nonce: "75f8587e5bd5f9dcc9909d0dae1f0ac5814458b2ae129620502cb936fde7120a", + signatures: [CompositeSignature], + } +} +``` \ No newline at end of file diff --git a/static/markdown/tools/wallet-provider-spec/user-signature.md b/static/markdown/tools/wallet-provider-spec/user-signature.md new file mode 100644 index 0000000000..adf23216f3 --- /dev/null +++ b/static/markdown/tools/wallet-provider-spec/user-signature.md @@ -0,0 +1,103 @@ +# User Signature + +## Status + +- **Last Updated:** June 1st 2021 +- **Stable:** Yes +- **Risk of Breaking Change:** Low +- **Compatibility:** `>= @onflow/fcl@0.0.71` + +# Overview and Introduction + +**Personally sign data via FCL Compatible Wallets** + +**FCL** now incldues **`signUserMessage()`** which allows for the sending of unencrypted message data to a connected wallet provider or service to be signed with a user's private key. + +An application or service can verify a signature against a user's public key on the **Flow Blockchain**, providing proof a user controls the account's private key. + +**Use Cases** + +- **Authentication**: Cryptographically verify the ownership of a **Flow** account by signing a piece of data using a private key +- **Improved Application Login** + - **Increased security**: Arguably more secure than proof of ownership by email/password + - **Simplified UX**: No application password required + - **Increased privacy**: No email or third party authentication service needed +- **Message Validation**: Assuring that a message sent or received has not been tampered with +- **Multisig contracts** +- **Decentralised exchanges** +- **Meta transactions** + +# Config and Authentication + +As a prerequisite, **FCL** is configured to point to the Wallet Provider's Authentication Endpoint. No additional configuration is required. + +> During development (and on mainnet) FCL can be configured to use the wallet directly by +> setting the **Wallet Discovery Url** to the wallet provider's **Authentication Endpoint** +> by configuring fcl like this `config().put("discovery.wallet", "https://my-awesome-wallet-provider.com/fcl/authenticate")`. + +Common Configuration Keys and additional info can be found here [How to Configure FCL](../clients/fcl-js/configure-fcl.md#common-configuration-keys) + +1. A user initiates authentication with the wallet provider via application UI +2. The wallet confirms a user's identity and sends back information used to configure **FCL** for future user actions in the application +3. Included in the authentication response should be the provider's [Key Services](#) including a **`user-signature`** service for use with **`signUserMessage()`** + +# User Signature Service + +A [user-signature service](https://github.com/onflow/fcl-js/blob/master/packages/fcl-core/src/normalizers/service/user-signature.js) is a standard service, with methods for **IFRAME/RPC** or **HTTP/POST**. + +The `user-signature` service receives a signable message from **FCL** and returns a standard [PollingResponse](https://github.com/onflow/fcl-js/blob/master/packages/fcl-core/src/normalizers/service/polling-response.js#L5) with an array of [CompositeSignatures](https://github.com/onflow/fcl-js/blob/master/packages/fcl-core/src/normalizers/service/composite-signature.js#L4) or `null` as the data. + +A status of **Approved** needs to have an array of composite signatures as data. + +A status of **Declined** needs to include a reason why. + +A **Pending** status needs to include an updates service and can include a local. +A service using the **`IFRAME/RPC`** method can only respond with approved or declined, as pending is not valid for iframes. + +When `signUserMessage()` is called by the application, **FCL** uses the service method to decide how to send the signable to the wallet. + +The Wallet is responsible for prepending the signable with the correct `UserDomainTag`, hashing, and signing the message. + +# Signing Sequence + +1. Application sends message to signing service. **FCL expects a hexadecimal string** +3. Wallet/Service tags the message with required `UserDomainTag` (see below), hashes, and signs using the `signatureAlgorithm` specified on account key +2. Wallet makes available a Composite Signature consisting of `addr`, `keyId`, and `signature` **as a hex string** + +### UserDomainTag +The **`UserDomainTag`** is the prefix of all signed user space payloads. + +Before hashing and signing the message, the wallet must add a specified DOMAIN TAG. + +> currently **"FLOW-V0.0-user"** + +A domain tag is encoded as **UTF-8 bytes, right padded to a total length of 32 bytes**, prepended to the message. + +The signature can now be verified on the Flow blockchain. The following illustrates an example using `fcl.verifyUserSignatures` + +```javascript +/** + * Verify a valid signature/s for an account on Flow. + * + * @param {string} msg - A message string in hexadecimal format + * @param {Array} compSigs - An array of Composite Signatures + * @param {string} compSigs[].addr - The account address + * @param {number} compSigs[].keyId - The account keyId + * @param {string} compSigs[].signature - The signature to verify + * @return {bool} + * + * @example + * + * const isValid = await fcl.verifyUserSignatures( + * Buffer.from('FOO').toString("hex"), + * [{f_type: "CompositeSignature", f_vsn: "1.0.0", addr: "0x123", keyId: 0, signature: "abc123"}] + * ) + */ +``` + +## TL;DR Wallet Provider + +- Register with **FCL** and provide signing service endpoint. No further configuration is needed. +- On receipt of message, prompt user to approve or decline +- Prepend `UserDomainTag`, hash and sign the message with the signatureAlgorithm specified on user's key +- Return a standard `PollingResponse` with an array of `CompositeSignatures` as data or `null` and `reason` if declined \ No newline at end of file diff --git a/static/markdown/tutorials/ai-plus-flow/agentkit-flow-guide.md b/static/markdown/tutorials/ai-plus-flow/agentkit-flow-guide.md new file mode 100644 index 0000000000..5f1d57bff8 --- /dev/null +++ b/static/markdown/tutorials/ai-plus-flow/agentkit-flow-guide.md @@ -0,0 +1,324 @@ +--- +title: Build Custom AI Agents on Flow with AgentKit +description: Learn how to configure and deploy AI agents on the Flow testnet using AgentKit, Langchain, and the EVM-compatible Flow environment. +sidebar_label: Using AgentKit on Flow +sidebar_position: 4 +--- + +# Getting Started with AgentKit on Flow + +AgentKit is an ecosystem-agnostic modular developer toolkit that lets you rapidly build, deploy, and iterate on AI agents using pre-configured environments and ready-to-use templates. + +In this guide, you'll set up your own custom agent running on **Flow's EVM-compatible testnet**, powered by **Langchain** and **Anthropic's Claude** LLM. + +--- + +## Quickstart - Starting From Scratch + +Open your terminal and run: + +```bash +npm create onchain-agent@latest +``` + +Follow the interactive setup: + +1. Type `y` to proceed, then press **Enter**. +2. Select your framework: **Langchain** +3. Choose your network: **EVM** +4. Set the custom Chain ID: + - `545` for **Flow Testnet** + - `747` for **Flow Mainnet** +5. JSON-RPC endpoint: + ```txt + https://testnet.evm.nodes.onflow.org + ``` + +--- + +## Project Setup + +Once your scaffold is ready: + +```bash +cd onchain-agent +npm install +``` + +Now open the project in your preferred IDE (e.g. Cursor). + +### Environment Configuration + +1. Create a `.env.local` file (or edit the one generated). +2. Add your API keys (we'll use **Anthropic** here). + +> You can also use OpenAI, DeepSeek, or any other supported LLM. + +### Get Your Anthropic API Key + +- Head to [Anthropic Console](https://console.anthropic.com/dashboard) +- Create an account and **purchase credits** +- Click **Create Key**, name it, and copy the API key +- Add this to your `.env.local`: + +```env +ANTHROPIC_API_KEY=your_api_key_here +``` + +### Wallet Setup with MetaMask + +1. Add [Flow Testnet](https://developers.flow.com/evm/using) to MetaMask +2. Use the [Faucet](https://faucet.flow.com/fund-account) to fund your wallet +3. Get your private key: + - Click the `...` menu in MetaMask > **Account Details** + - Enter your password, copy the private key +4. Add it to `.env.local`: + +```env +PRIVATE_KEY=your_private_key_here +``` + +Your `.env.local` should look something like this: + +```env +PRIVATE_KEY=... +ANTHROPIC_API_KEY=... +``` + +Now run: + +```bash +mv .env.local .env +npm run dev +``` + +Visit your local server: + +``` +http://localhost:3000 +``` + +--- + +## Configure Your LLM + +If your agent doesn't respond yet — no worries! You still need to configure your **LLM and client libraries**. + +### Choose a Model + +Langchain supports many LLMs ([full list here](https://python.langchain.com/docs/integrations/llms/)). + +For this example, we'll use **Anthropic's `claude-3-5-haiku-20241022`**, a lightweight and affordable model. Alternatively, [DeepSeek](https://deepseek.com/) is highly recommended for budget-friendly usage. + +### Update `create-agent.ts` + +Change the default model from OpenAI: + +```ts +const llm = new ChatOpenAI({ model: 'gpt-4o-mini' }); +``` + +To Anthropic: + +```ts + + +const llm = new ChatAnthropic({ model: 'claude-3-5-haiku-20241022' }); +``` + +Install the package: + +```bash +npm install @langchain/anthropic +``` + +--- + +## Configure Flow and Viem Wallet + +### Update the Faucet Provider Logic + +Change this: + +```ts +const canUseFaucet = walletProvider.getNetwork().networkId == 'base-sepolia'; +``` + +To: + +```ts +const canUseFaucet = walletProvider.getNetwork().networkId == 'flow-testnet'; +``` + +### Add Flow Context Message to Agent + +This gives your agent context about the Flow testnet: + +```ts +const flowContextMessage = canUseFaucet + ? ` + You are now operating on the Flow blockchain testnet using a Viem wallet. Flow is a fast, decentralized, and + developer-friendly blockchain designed for NFTs, games, and apps. + + Key facts about Flow: + - Flow uses a proof-of-stake consensus mechanism + - The native token is FLOW + - Flow has a unique multi-role architecture for high throughput + - The testnet is EVM-compatible (works with MetaMask + Viem) + - RPC URL: https://testnet.evm.nodes.onflow.org + - Chain ID: 545 + + Your wallet address is \${await walletProvider.getAddress()}. +` + : ''; +``` + +Then inject it into the agent message modifier: + +```ts +agent = createReactAgent({ + llm, + tools, + checkpointSaver: memory, + messageModifier: ` + You are a helpful agent interacting with the Flow blockchain testnet using a Viem wallet. + Flow testnet supports EVM, so you can use Ethereum-compatible tools. + \${flowContextMessage} + + Before your first action, check the wallet details. If you see a 5XX error, ask the user to try again later. + If a task is unsupported, let the user know and point them to CDP SDK + AgentKit at: + https://docs.cdp.coinbase.com or https://developers.flow.com. + + Be concise, helpful, and avoid repeating tool descriptions unless asked. + `, +}); +``` + +--- + +## You're Done! + +You now have a working AI agent connected to Flow testnet using AgentKit! + +You can send faucet tokens to your wallet and start testing smart contract interactions or on-chain workflows. + +--- + +## Starter Project + +Want to skip the setup? + +> [Fork the Flow AgentKit Starter](https://github.com/Aliserag/flow-agentkit-starter) + +This starter includes all necessary config to start building immediately on Flow. + +--- + +## Adding AgentKit to an Existing Project + +Already have a project and want to add AgentKit? Follow these steps to integrate it into your existing codebase: + +### Install the Package + +Run this command in your project's root directory: + +```bash +npm install onchain-agent@latest +``` + +This will: + +- Download and install the latest version of the `onchain-agent` package +- Add it to the dependencies section of your `package.json` +- Update your `node_modules` folder accordingly + +### Configure Environment + +1. Create or update your `.env` file with the necessary API keys: + +```env +PRIVATE_KEY=your_wallet_private_key +ANTHROPIC_API_KEY=your_anthropic_api_key +# Or other LLM API keys +``` + +2. Configure your RPC endpoints for Flow: + +```env +FLOW_TESTNET_RPC_URL=https://testnet.evm.nodes.onflow.org +FLOW_MAINNET_RPC_URL=https://mainnet.evm.nodes.onflow.org +``` + +### Integrate AgentKit in Your Code + +Import and configure AgentKit in your application: + +```ts +// Import AgentKit components + + + +// Set up your Flow wallet provider +const walletClient = createWalletClient({ + transport: http('https://testnet.evm.nodes.onflow.org'), + chain: { + id: 545, // Flow Testnet + name: 'Flow Testnet', + }, + account: yourPrivateKey, +}); + +// Configure the LLM +const llm = new ChatAnthropic({ + model: 'claude-3-5-haiku-20241022', +}); + +// Create your agent +const agent = createReactAgent({ + llm, + tools: yourSelectedTools, + // Additional configuration +}); + +// Use the agent in your application +// ... +``` + +### Add Specialized Tools (Optional) + +To add specialized blockchain tools to your agent: + +```ts + + +// Configure Viem tools for Flow +const viemTools = viem.createTools({ + chain: { + id: 545, + name: 'Flow Testnet', + }, + transport: http('https://testnet.evm.nodes.onflow.org'), +} as ViemToolConfig); + +// Add these tools to your agent +const agent = createReactAgent({ + llm, + tools: [ + ...viemTools, + // Other tools + ], +}); +``` + +--- + +## Resources + +- [AgentKit Docs](https://docs.cdp.coinbase.com/agentkit) +- [Flow EVM Guide](https://developers.flow.com/evm/using) +- [Langchain LLM Integrations](https://python.langchain.com/docs/integrations/llms/) +- [Anthropic Model Comparison](https://docs.anthropic.com/en/docs/about-claude/models/all-models#model-comparison-table) + +--- + +Happy hacking on Flow! \ No newline at end of file diff --git a/static/markdown/tutorials/ai-plus-flow/chatgpt/index.md b/static/markdown/tutorials/ai-plus-flow/chatgpt/index.md new file mode 100644 index 0000000000..0dd8b6b87e --- /dev/null +++ b/static/markdown/tutorials/ai-plus-flow/chatgpt/index.md @@ -0,0 +1,112 @@ +--- +title: Use Flow Knowledge Base in ChatGPT +sidebar_label: Use ChatGPT +sidebar_position: 2 +keywords: + - ChatGPT + - AI + - OpenAI + - Flow documentation + - Cadence documentation + - Flow development + - Flow tools + - Flow IDE + - Flow setup + - Flow configuration + - Flow AI assistance +--- + +# Use Flow Knowledge Base in ChatGPT + +[ChatGPT] is an AI assistant developed by [OpenAI] that can help with tasks such as writing, coding, and answering questions. It adapts to context and user input to provide relevant, conversational responses. ChatGPT can be integrated into developer tools or workflows to assist with documentation, debugging, and productivity. + +This guide walks you through creating a **Custom GPT** using ChatGPT that can reference the [Flow Data Sources] file to answer questions. + +
    + +
    + +:::warning + +You'll need a [ChatGPT Plus subscription] to use the **Custom GPT** feature. + +::: + +## 📍 Step 1: Open the "Explore GPTs" Section + +1. Log in to [ChatGPT]. +2. In the sidebar on the left, click **Explore GPTs**. + +![explore gpts](explore-gpts.png) + +--- + +## 📍 Step 2: Click "Create a GPT" + +1. In the **Explore GPTs** screen, click the **"Create"** button in the top-right corner. + +![create](create.png) + +--- + +## 📍 Step 3: Walk Through the GPT Builder + +ChatGPT will now guide you through a conversation to set up your custom GPT. First, drag and drop the [Flow Data Sources All Merged] file into the prompt. + +### Suggested Prompt + +```text +I want to make a GPT called FlowGPT that uses the linked file as it's primary source. This file changes, so it should reference the live file at least once a day: https://github.com/onflow/Flow-Data-Sources/blob/main/merged_docs/all_merged.md +``` + +--- + +## 📍 Step 4: Configure the GPT's Name and Instructions + +ChatGPT may ask you to customize or verify: + +- **Name and description** of your GPT +- **Instructions**: Tell it how to behave and what to prioritize (e.g., always reference the uploaded document) +- **Capabilities**: Enable file browsing, code interpreter, or DALL·E if needed + +We've found it helpful to suggest: + +```text +Please imagine you are a fast and smart junior developer who is eager to help and has memorized all the information in the linked file +``` + +Please let us know if you find any other useful customization prompts! + +--- + +## 📍 Step 5: Test Your GPT + +Once the GPT is built, you'll be taken to a preview chat window. Test it by asking a few questions based on your uploaded document. + +--- + +## 📍 Step 6: Save and Publish (Optional) + +When you're ready: + +- Click **"Update & Save"** to finalize +- You can choose to keep it **private** or make it **public** + +--- + +## ✅ That's it! + +You've now created a custom GPT that references your uploaded file as a primary source. You can update the file or instructions later if needed. + +[ChatGPT]: https://chatgpt.com/ +[OpenAI]: https://openai.com/ +[ChatGPT Plus subscription]: https://chat.openai.com +[Flow Data Sources]: ../flow-data-sources.md +[Flow Data Sources All Merged]: https://github.com/onflow/Flow-Data-Sources/blob/main/merged_docs/all_merged.md \ No newline at end of file diff --git a/static/markdown/tutorials/ai-plus-flow/cursor/index.md b/static/markdown/tutorials/ai-plus-flow/cursor/index.md new file mode 100644 index 0000000000..23fe03e77d --- /dev/null +++ b/static/markdown/tutorials/ai-plus-flow/cursor/index.md @@ -0,0 +1,92 @@ +--- +title: Use Flow Knowledge Base in Cursor +sidebar_label: Use Cursor AI +sidebar_position: 1 +keywords: + - Cursor + - AI + - Flow documentation + - Cadence documentation + - Flow development + - Flow tools + - Flow IDE + - Flow setup + - Flow configuration + - Flow AI assistance +--- + +# Use Flow Knowledge Base in Cursor + +[Cursor] is an AI code editor that makes it easy to write code while building Flow apps. Let's walk through how to setup Cursor for the best possible experience when writing applications on Flow. + +
    + +
    + +## Installation + +Adding Flow docs lets you interact with our docs directly and get the most accurate answers to your questions. + +1. Go to Cursor Settings > Features > Docs and click "+ Add new doc". + +![Cursor Settings](./images//use-cursor-1.png) + +1. Set Flow Docs: + +- Enter the URL of the Flow docs: `https://developers.flow.com/tools` and press Enter. + - Note: This **will index all** the docs. We're investigating why you need `/tools` + - Cursor will automatically detect the Flow docs and index them for you. + - Ensure the name is `Flow`, and click "Confirm" to add the docs. + +![Cursor Settings](./images//use-cursor-2.png) + +1. Set Cadence Docs: + +- Click "+ Add new doc" again, now enter the URL of the Cadence docs: `https://cadence-lang.org/docs/` and press Enter. +- Same process as before, ensure the name is `Cadence`, and click "Confirm" to add the docs. + +1. Add [Flow Data Sources]: + Click "+ Add new doc" one more time and enter the URL of our massive, auto-generated file with the most current data and practices for Flow and Cadence: `https://github.com/onflow/Flow-Data-Sources/blob/main/merged_docs/all_merged.md` and press Enter. + +- Enter `Flow Data Sources`, and click "Confirm" to add the doc. +- **Caution**: This file is very large. For older development machines, you may wish to use the [essentials merged] file instead. + +1. Now wait for Cursor to index the docs. You can check the progress in the Docs section of the settings. After the indexing is complete, you can start using the docs in Cursor. + +## Using Flow Docs in Cursor + +You can then reference the Flow docs in your prompt with the `@Flow`, `@Cadence`or `@Flow Data Sources` docs. + +![Cursor Settings](./images//use-cursor-3.png) + +## Best Practices + +When using Cursor with Flow documentation: + +- Use `@Flow` when asking questions about Flow-specific concepts, tools, or ecosystem +- Use `@Cadence` when asking questions about Cadence programming language syntax or features +- Use `@Flow Data Sources` when asking about complex questions, difficult tasks, or anything that the first two sources didn't provide a satisfactory result +- Be specific in your prompts to get more accurate and relevant answers +- Combine both `@Flow` and `@Cadence` when working on cross-VM applications +- Use the documentation to verify AI-generated code and ensure best practices + +## Troubleshooting + +If you encounter any issues: + +1. Ensure all three sources are properly indexed +2. Try refreshing the documentation if answers seem outdated +3. Check your internet connection as Cursor needs to access the documentation +4. Verify the URLs are correct in your settings +5. Contact Cursor support if issues persist + +[Cursor]: https://www.cursor.com/ +[Flow Data Sources]: ../flow-data-sources.md +[essentials merged]: https://github.com/onflow/Flow-Data-Sources/blob/main/merged_docs/essentials_merged.md \ No newline at end of file diff --git a/static/markdown/tutorials/ai-plus-flow/eliza/build-plugin.md b/static/markdown/tutorials/ai-plus-flow/eliza/build-plugin.md new file mode 100644 index 0000000000..479d95d5d9 --- /dev/null +++ b/static/markdown/tutorials/ai-plus-flow/eliza/build-plugin.md @@ -0,0 +1,179 @@ +--- +title: Eliza Plugin Guide +description: Learn how to build Eliza plugins for your AI Agent on Flow +sidebar_position: 2 +keywords: + - AI + - AI Agent + - Eliza + - Eliza on Flow + - Plugin + - Flow Development + - Quickstart +--- + +# Eliza Plugin Development Guide + +Plugins are a powerful way to extend the functionality of your Eliza AI agents. This guide will walk you through the process of creating custom plugins that can enhance your agent's capabilities, from simple utilities to complex integrations with external services. You'll learn how to leverage the plugin system to create modular and reusable components for your AI agents. + +## Learning Objectives + +By the end of this tutorial, you will be able to: + +- Create a new plugin repository from the template +- Understand the plugin development workflow +- Implement custom actions and services +- Integrate plugins with your Eliza agent +- Register and publish plugins to the Eliza Plugin Registry +- Use dependency injection for better plugin architecture + +## Prerequisites + +Before getting started with Eliza, ensure you have: + +- [Node.js 23+] (using [nvm] is recommended) +- [pnpm 9+] +- Git for version control +- A code editor ([VS Code], [Cursor] or [VSCodium] recommended) +- [Flow-cli] for Flow blockchain interaction. + +> **Note for Windows Users:** [WSL 2] is required. + +## Quickstart + +Please follow the [Quickstart Guide] to set up your development environment. + +## Plugin Development + +### Create a Plugin repository from Template + +Visit [Eliza Plugin Template] and click on the "Use this template" button to create a new repository. + +Or you can create a new empty repository and copy the files from some examples at [Eliza Plugins] organization. + +> Note: Flow's Eliza plugin template is using Dependency Injection(`@elizaos-plugins/plugin-di`), you can learn more about the Dependency Injection in the [plugin's README.md]. It allows you can use `Class` instead of `Object` for your `Actions`, `Providers`, `Services`, and etc. **If you don't want to use it, you can follow the other examples in Eliza Plugins organiazation.** + +### Add the Plugin repository to your Eliza project + +Let's say you created a repository named `username/plugin-foo`. + +Use submodules to add the plugin repository to your Eliza project. + +```bash +git submodule add https://github.com/username/plugin-foo.git packages/plugin-foo +``` + +Change the package's name in the plugin's `package.json` to `@elizaos-plugins/plugin-foo`. + +```json +{ + "name": "@elizaos-plugins/plugin-foo", +} +``` + +Add the plugin to agent's `package.json` + +```bash +pnpm add @elizaos-plugins/plugin-foo@'workspace:*' --filter ./agent +``` + +Check the `agent/package.json` to ensure the plugin is added, you should see something like this: + +```json +{ + "dependencies": { + "@elizaos-plugins/plugin-foo": "workspace:*" + } +} +``` + +### Build the Plugin + +Build the plugin using the following command: + +```bash +pnpm build --filter ./packages/plugin-foo + +# Or build all packages +pnpm build +``` + +### Add Plugin to the `character.json` you want to use + +Let's say you want to add the plugin to the `sample` character which is `characters/sample.character.json`. + +```json +{ + "name": "Sample", + "plugins": [ + "@elizaos-plugins/plugin-foo" + ] +} +``` + +:::warning + +If you are using Dependency Injection(`@elizaos-plugins/plugin-di`) in your plugin, remember to add it to the `postProcessors` field. And **`clients` field is deprecated** in the latest version of Eliza, so if you want to add clients you also need to use `plugins` field. + +::: + +```json +{ + "name": "Sample", + "plugins": [ + "@elizaos-plugins/plugin-foo", + "@elizaos-plugins/client-discord" + ], + "postProcessors": [ + "@elizaos-plugins/plugin-di" + ] +} +``` + +### Run the Eliza Agent with your Plugin + +Run the Eliza agent to test the plugin. + +```bash +pnpm start --character="characters/sample.character.json" + +# Or with more debug logs +pnpm start:debug --character="characters/sample.character.json" +``` + +### Interact with the Agent + +Now, you're ready to start a conversation with your agent. + +Open a new terminal window and run the client's http server. + +```bash +pnpm start:client +``` + +## Plugin Registration + +You need to register your plugin in the [Eliza Plugin Registry] to make it available for other users. + +Please follow the guide there, modify the [index.json] and submit a PR to the registry repository. + +## Conclusion + +In this tutorial, you've learned how to develop custom plugins for Eliza. You've gained experience with creating plugin repositories, implementing custom actions and services, integrating plugins with agents, and using dependency injection for better architecture. + +Eliza's plugin system provides a powerful way to extend the functionality of your AI agents. With the knowledge gained from this tutorial, you can now develop more sophisticated plugins, create reusable components, and share your work through the plugin registry. + +[Node.js 23+]: https://docs.npmjs.com/downloading-and-installing-node-js-and-npm +[nvm]: https://github.com/nvm-sh/nvm +[pnpm 9+]: https://pnpm.io/installation +[VS Code]: https://code.visualstudio.com/ +[Cursor]: https://cursor.com/ +[VSCodium]: https://vscodium.com +[Flow-cli]: https://developers.flow.com/tools/flow-cli +[WSL 2]: https://learn.microsoft.com/en-us/windows/wsl/install-manual +[Quickstart Guide]: ./index.md +[Eliza Plugin Template]: https://github.com/onflow/eliza-plugin-template +[Eliza Plugins]: https://github.com/elizaos-plugins +[plugin's README.md]: https://github.com/fixes-world/plugin-di +[Eliza Plugin Registry]: https://github.com/elizaos-plugins/registry +[index.json]: https://github.com/elizaos-plugins/registry/blob/main/index.json \ No newline at end of file diff --git a/static/markdown/tutorials/ai-plus-flow/eliza/index.md b/static/markdown/tutorials/ai-plus-flow/eliza/index.md new file mode 100644 index 0000000000..b4cba38fe5 --- /dev/null +++ b/static/markdown/tutorials/ai-plus-flow/eliza/index.md @@ -0,0 +1,257 @@ +--- +title: Eliza on Flow +description: Learn how to build AI Agent on Flow with Eliza +sidebar_position: 4 +keywords: + - AI + - AI Agent + - Eliza + - Eliza on Flow + - Flow Development + - Quickstart +--- + +# Quickstart Guide to build AI Agent on Flow with Eliza + +Eliza is a powerful framework for building AI agents that can interact with users through natural language. This tutorial will guide you through setting up and deploying an AI agent on the Flow blockchain using Eliza. You'll learn how to create intelligent agents that can understand and respond to user queries, while leveraging Flow's secure and scalable infrastructure. + +## Learning Objectives + +By the end of this tutorial, you will be able to: + +- Set up the Eliza development environment +- Configure and deploy an AI agent on Flow +- Create and customize character configurations +- Integrate different AI models with your agent +- Interact with your AI agent through a web interface +- Add and develop custom plugins for extended functionality + +## Prerequisites + +Before getting started with Eliza, ensure you have: + +- [Node.js 23+] (using [nvm] is recommended) +- [pnpm 9+] +- Git for version control +- A code editor ([VS Code], [Cursor] or [VSCodium] recommended) +- [Flow-cli] for Flow blockchain interaction. + +> **Note for Windows Users:** [WSL 2] is required. + +## Installation + +ElizaOnFlow is a Flow-dedicated Eliza wrapper, so: + +- The plugins from this repository are also compatible with the origin [Eliza]. +- You can also use any plugins from original Eliza in this repository. + +Clone the repository + +```bash +# The ElizaOnFlow is a wrapper with origin Eliza as submodule +git clone --recurse-submodules https://github.com/onflow/elizaOnFlow.git + +# Enter directory +cd elizaOnFlow + +# Please checkout the main branch which is using the latest release of origin Eliza +git checkout main +``` + +Or, If you want to use the origin Eliza, please run: + +```bash +# Eliza's characters folder is a submodule +git clone --recurse-submodules https://github.com/elizaOs/eliza.git + +# Enter directory +cd eliza + +# Checkout the latest release +git checkout $(git describe --tags --abbrev=0) +``` + +If you already cloned without submodules, please run: + +```bash +# Fetch submodules +git submodule update --init --recursive +``` + +Install dependencies + +```bash +pnpm install --no-frozen-lockfile +``` + +:::warning + +Please only use the `--no-frozen-lockfile` option when you're initially instantiating the repo or are bumping the version of a package or adding a new package to your package.json. This practice helps maintain consistency in your project's dependencies and prevents unintended changes to the lockfile. + +::: + +If you are using ElizaOnFlow, you need to install Flow Cadence contracts dependencies to ensure `*.cdc` be correctly linted by Cadence extension. + +Install Flow Cadence contracts dependencies: + +```bash +flow deps install +``` + +Build all packages: + +```bash +pnpm build +``` + +## Configure Environment + +Copy .env.example to .env and fill in the appropriate values. + +```bash +cp .env.example .env +``` + +:::danger + +In normal development, it's a best practice to use a `.env` to protect API keys and other sensitive information. When working with crypto, it's **critical** to be disciplined and always use them, even in test projects or tutorials. If you expose a wallet key, you might lose everything in that wallet immediately, or someone might watch it for years and rug you the day you put something valuable there. + +::: + +Edit `.env` and add your values. Do NOT add this file to version control. + +### Choose Your Model + +Eliza supports multiple AI models and you set which model to use inside the character JSON file. +But remember, once you chosed a model, you need to set up the relevant configuration. + +Check full list of supported LLMs in origin Eliza: [Models.ts] + +Suggested models: + +- Use API to access LLM providers + - OpenAI: set modelProvider as `openai`, and set `OPENAI_API_KEY` in `.env` + - Deepseek: set modelProvider as `deepseek`, and set `DEEPSEEK_API_KEY` in `.env` + - Grok: set modelProvider as `grok`, and set `GROK_API_KEY` in `.env` +- Use local inference + - Ollama: set modelProvider as `ollama`, and set `OLLAMA_MODEL` in `.env` to the model name you are using in ollama. + +> To choose model, you need to set in charactor configuration. For example: OPENAI, please set `modelProvider: "openai"` in charactor JSON file or `modelProvider: ModelProviderName.OPENAI` in `charactor.ts` + +### Setup Agent's Flow Account + +Create a new Flow account for the Agent. Learn more: [doc] + +```bash +flow accounts create +``` + +> If you are using Testnet, you can get free tokens from [Flow Faucet] + +Set Flow blockchain configuration in `.env` with new generated Flow account. + +```bash +FLOW_ADDRESS= +FLOW_PRIVATE_KEY= +FLOW_NETWORK= # Default: mainnet +FLOW_ENDPOINT_URL= # Default: +``` + +For testnet, please check Flow's [Networks] for more information. + +## Create Your First Agent + +### Create a Character File + +Check out the `deps/eliza/characters/` directory for a number of character files to try out. +Additionally you can override Eliza's `defaultCharacter` by editting `charactor.ts` which will be default used if no character json provided. + +Copy one of the example character files and make it your own + +```bash +cp characters/scooby.character.json characters/sample.character.json +``` + +📝 [Character Documentation] + +### **Start the Agent** + +Inform it which character you want to run: + +```bash +pnpm start --character="characters/sample.character.json" +``` + +Or you can use `pnpm start:debug` for more debugging logs: + +```bash +pnpm start:debug --character="characters/sample.character.json" +``` + +You can load multiple characters with a comma-separated list: + +```bash +pnpm start --characters="characters/sample.character.json, characters/scooby.character.json" +``` + +### Add / Develop Plugins + +run `npx elizaos plugins list` to get a list of available plugins or visit [Eliza Plugins Registry] + +run `npx elizaos plugins add @elizaos-plugins/plugin-NAME` to install the plugin into your instance + +To create a new plugin **for your own business**, you can refer to the [plugin development guide]. + +#### Additional Requirements + +You may need to install Sharp. If you see an error when starting up, try installing it with the following command: + +```bash +pnpm install --include=optional sharp +``` + +### **Interact with the Agent** + +Now you're ready to start a conversation with your agent. + +Open a new terminal window and run the client's http server. + +```bash +pnpm start:client +``` + +Once the client is running, you'll see a message like this: + +```bash +➜ Local: http://localhost:5173/ +``` + +Simply click the link or open your browser to `http://localhost:5173/`. You'll see the chat interface connect to the system, and you can begin interacting with your character. + +## Common Issues & Solutions + +Please check the orgin Eliza's [Common Issues & Solutions] + +## Conclusion + +In this tutorial, you've learned how to build and deploy an AI agent on the Flow blockchain using Eliza. You've gained hands-on experience with setting up the development environment, configuring agents, creating character configurations, integrating AI models, and developing custom plugins. + +The Eliza framework provides a powerful way to create intelligent agents that can understand and respond to user queries while leveraging Flow's secure and scalable infrastructure. By completing this tutorial, you now have the foundation to build more sophisticated AI agents and create unique user experiences through character customization and plugin development. + +[Node.js 23+]: https://docs.npmjs.com/downloading-and-installing-node-js-and-npm +[nvm]: https://github.com/nvm-sh/nvm +[pnpm 9+]: https://pnpm.io/installation +[VS Code]: https://code.visualstudio.com/ +[Cursor]: https://cursor.com/ +[VSCodium]: https://vscodium.com +[Flow-cli]: https://developers.flow.com/tools/flow-cli +[WSL 2]: https://learn.microsoft.com/en-us/windows/wsl/install-manual +[Eliza]: https://github.com/elizaOs/eliza +[Models.ts]: https://github.com/elizaOS/eliza/blob/main/packages/core/src/models.ts +[doc]: https://developers.flow.com/tools/flow-cli/accounts/create-accounts +[Flow Faucet]: https://faucet.flow.com/ +[Networks]: https://developers.flow.com/networks/flow-networks +[Character Documentation]: https://elizaos.github.io/eliza/docs/core/characterfile/ +[Eliza Plugins Registry]: https://elizaos.github.io/registry +[plugin development guide]: build-plugin.md +[Common Issues & Solutions]: https://elizaos.github.io/eliza/docs/quickstart/#common-issues--solutions \ No newline at end of file diff --git a/static/markdown/tutorials/ai-plus-flow/flow-data-sources.md b/static/markdown/tutorials/ai-plus-flow/flow-data-sources.md new file mode 100644 index 0000000000..820bf54d64 --- /dev/null +++ b/static/markdown/tutorials/ai-plus-flow/flow-data-sources.md @@ -0,0 +1,68 @@ +--- +title: Flow Data Sources +sidebar_label: Flow Data Sources +sidebar_position: 3 +keywords: + - Flow Data Sources + - AI knowledge base + - Flow documentation + - Cadence documentation + - Flow development + - Flow tools + - Flow AI assistance + - RAG + - Retrieval-Augmented Generation +--- + +# Flow Data Sources + +Flow Data Sources is a comprehensive repository that automatically aggregates and formats Flow ecosystem content into Markdown files optimized for AI ingestion. This resource serves as a centralized knowledge base for AI tools, chatbots, and RAG (Retrieval-Augmented Generation) pipelines. + +## Overview + +The repository contains Python scripts that: + +- Crawl Flow-related documentation sites, GitHub repositories, and discussions +- Convert HTML content to Markdown format +- Extract code examples from GitHub repositories +- Capture community discussions and Q&A content +- Merge all content into consolidated files for easy consumption + +## Key Features + +- **Daily Updates**: Content is automatically refreshed to ensure the latest information +- **Structured Format**: All content is converted to Markdown for consistent processing +- **Comprehensive Coverage**: Includes official documentation, code examples, and community discussions +- **Optimized for AI**: Designed specifically for AI tools, chatbots, and RAG pipelines +- **Output Options**: + - `all_merged.md`: Complete content + - `essentials_merged.md`: Streamlined version only including official documentation and sample codes. + - `cadence_docs_merged.md`: Streamlined version only including Cadence related documentation and sample codes. + +## How to Use + +Flow Data Sources can be integrated with: + +- **ChatGPT Plugins**: Enhance Q&A capabilities with Flow-specific knowledge +- **Custom Chatbots**: Power Discord/Telegram bots with accurate Flow information +- **RAG Systems**: Index content in vector databases for semantic search +- **Development Tools**: Provide context-aware assistance in IDEs like Cursor + +## Accessing the Content + +The merged documentation files are available at: + +- [All Merged Content][all-merged] +- [Essentials Only][essentials-merged] +- [Cadence Only][cadence-merged] + +For integration with AI tools like Cursor or ChatGPT, use the appropriate URL as described in the respective tutorials: + +- [Use Flow Knowledge Base in Cursor][cursor] - Learn how to set up Cursor with Flow knowledge bases +- [Use Flow Knowledge Base in ChatGPT][chatgpt] - Create a custom GPT that understands Flow and Cadence + +[all-merged]: https://github.com/onflow/Flow-Data-Sources/blob/main/merged_docs/all_merged.md +[essentials-merged]: https://github.com/onflow/Flow-Data-Sources/blob/main/merged_docs/essentials_merged.md +[cadence-merged]: https://github.com/onflow/Flow-Data-Sources/blob/main/merged_docs/cadence_docs_merged.md +[cursor]: ./cursor/index.md +[chatgpt]: ./chatgpt/index.md \ No newline at end of file diff --git a/static/markdown/tutorials/ai-plus-flow/index.md b/static/markdown/tutorials/ai-plus-flow/index.md new file mode 100644 index 0000000000..74b2cb7c74 --- /dev/null +++ b/static/markdown/tutorials/ai-plus-flow/index.md @@ -0,0 +1,69 @@ +--- +title: AI Plus Flow +description: Learn how to leverage AI tools to enhance your Flow development experience +sidebar_position: 2 +keywords: + - AI + - ChatGPT + - Cursor + - AgentKit + - Flow documentation + - Cadence documentation + - Flow development + - Flow tools + - Flow IDE + - Flow setup + - Flow configuration + - Flow AI assistance +--- + +# AI Plus Flow + +Artificial Intelligence tools can significantly enhance your Flow development experience by providing intelligent assistance, code generation, and documentation access. This tutorial series will guide you through integrating various AI tools with Flow development to boost your productivity and code quality. + +## What You'll Learn + +In this tutorial series, you'll discover how to: + +- Configure AI-powered development environments for Flow +- Access Flow documentation directly from AI assistants +- Generate Cadence and Solidity code with AI assistance +- Debug and troubleshoot Flow applications with AI support +- Leverage AI for testing and optimization +- Build AI agents that interact with Flow using AgentKit + +## Tutorials + +- [Use Flow Knowledge Base in Cursor] - Learn how to set up Cursor with Flow knowledge bases to get intelligent assistance while developing Flow applications. +- [Use Flow Knowledge Base in ChatGPT] - Create a custom GPT that understands Flow and Cadence to provide accurate answers to your development questions. +- [Flow Data Sources] - Learn about this comprehensive resource and how to integrate it with various AI platforms. +- [Eliza on Flow] - Learn how to build AI Agent on Flow with Eliza +- [Build AI Agents with AgentKit] - Learn how to create AI agents that can interact with Flow using AgentKit. + +## Best Practices + +When using AI tools with Flow development: + +- Always verify AI-generated code against Flow documentation +- Use specific prompts that reference Flow concepts and terminology +- Combine AI assistance with your own understanding of Flow architecture +- Keep your AI tools updated with the latest Flow documentation +- Test AI-generated code thoroughly before deploying to production +- Consider the security implications of AI agents interacting with your contracts + +## Next Steps + +After completing these tutorials, you'll be equipped to leverage AI tools effectively in your Flow development workflow. Consider exploring our other tutorial series to deepen your understanding of Flow development: + +- [Cross-VM Apps][cross-vm-apps] - Build applications that integrate Flow EVM and Cadence +- [Native VRF][native-vrf] - Implement verifiable random functions in your applications +- [Token Launch][token-launch] - Create and launch tokens on Flow + +[Use Flow Knowledge Base in Cursor]: ./cursor/index.md +[Use Flow Knowledge Base in ChatGPT]: ./chatgpt/index.md +[Flow Data Sources]: ./flow-data-sources.md +[Eliza on Flow]: ./eliza/index.md +[Build AI Agents with AgentKit]: ./agentkit-flow-guide.md +[cross-vm-apps]: ../cross-vm-apps/introduction.md +[native-vrf]: ../native-vrf/index.md +[token-launch]: ../token-launch/index.md \ No newline at end of file diff --git a/static/markdown/tutorials/cross-vm-apps/add-to-wagmi.md b/static/markdown/tutorials/cross-vm-apps/add-to-wagmi.md new file mode 100644 index 0000000000..1424f4dcef --- /dev/null +++ b/static/markdown/tutorials/cross-vm-apps/add-to-wagmi.md @@ -0,0 +1,515 @@ +--- +title: Update Existing wagmi App +description: Learn how to integrate Flow Cadence with your existing wagmi/RainbowKit app to enable batch transactions and other Cadence features. +sidebar_position: 1 +keywords: + - hybrid apps + - cross-vm apps + - FCL + - wagmi + - RainbowKit + - Flow EVM + - Flow Cadence + - cross-VM + - multi-call + - batch transactions + - web3 + - dapp development + - wallet integration + - smart contracts + - blockchain development + - supercharge your EVM app with Cadence +--- + +# Add Flow Cadence to Your wagmi App + +This tutorial demonstrates how to enhance your existing wagmi/RainbowKit application with Flow Cadence capabilities. By integrating the Flow Client Library (FCL) with your EVM stack, you can unlock powerful features like batch transactions with a single signature. + +## Video Overview + +
    + +
    + +## Objectives + +After completing this guide, you'll be able to: + +- Add FCL to your existing wagmi/RainbowKit application +- Configure FCL to work alongside your EVM wallet connections +- Implement batch transactions that execute multiple EVM calls in a single Cadence transaction +- Display both Cadence and EVM addresses in your application + +## Prerequisites + +### Next.js and Modern Frontend Development + +This tutorial uses [Next.js]. You don't need to be an expert, but it's helpful to be comfortable with development using a current React framework. You'll be on your own to select and use a package manager, manage Node versions, and other frontend environment tasks. If you don't have your own preference, you can just follow along with us and use [npm]. + +### Solidity and Cadence Smart Contract Development + +Apps using the hybrid approach can interact with both [Cadence] and [Solidity] smart contracts. You don't need to be an expert in either of these, but it's helpful to be familiar with how smart contracts work in at least one of these languages. + +### Onchain App Frontends + +We're assuming you're familiar with [wagmi], [viem], and [RainbowKit]. If you're coming from the Cadence, you might want to take a quick look at the getting started guides for these platforms. They're all excellent and will rapidly get you up to speed on how the EVM world commonly connects their apps to their contracts. + +## Create an App + +Start by creating an app using [RainbowKit]'s scaffold: + +```bash +npm init @rainbow-me/rainbowkit@latest +``` + +## Install Required Dependencies + +Continue by adding the necessary Flow dependencies to your project: + +```bash +npm install @onflow/fcl @onflow/fcl-rainbowkit-adapter +``` + +These packages provide: + +- `@onflow/fcl`: The Flow Client Library for interacting with the Cadence VM +- `@onflow/fcl-rainbowkit-adapter`: An adapter that allows RainbowKit to work with FCL-compatible wallets + +## Step 2: Configure FCL in Your wagmi Setup + +Update your wagmi configuration (`src/wagmi.ts`) to include FCL: + +```typescript +'use client'; + +import { + flowWallet, + walletConnectWallet, +} from '@onflow/fcl-rainbowkit-adapter'; + + + + + +fcl.config({ + 'accessNode.api': 'https://rest-testnet.onflow.org', + 'discovery.wallet': 'https://fcl-discovery.onflow.org/mainnet/authn', + 'walletconnect.projectId': '9b70cfa398b2355a5eb9b1cf99f4a981', +}); + +const connectors = connectorsForWallets( + [ + { + groupName: 'Recommended', + wallets: [flowWallet(), walletConnectWallet], + }, + ], + { + appName: 'RainbowKit demo', + projectId: '9b70cfa398b2355a5eb9b1cf99f4a981', + }, +); + +export const config = createConfig({ + chains: [flowTestnet], + connectors, + ssr: true, + transports: { + [flowTestnet.id]: http(), + }, +}); +``` + +## Step 3: Add the Batch Transaction Utility + +Create a custom hook in `src/hooks/useBatchTransactions.ts` to handle batch transactions. This utility allows you to execute multiple EVM transactions in a single Cadence transaction: + +```typescript + + + + + +// Define the interface for each EVM call. +export interface EVMBatchCall { + address: string; // The target EVM contract address (as a string) + abi: Abi; // The contract ABI fragment (as JSON) + functionName: string; // The name of the function to call + args?: readonly unknown[]; // The function arguments + gasLimit?: bigint; // The gas limit for the call + value?: bigint; // The value to send with the call +} + +export interface CallOutcome { + status: 'passed' | 'failed' | 'skipped'; + hash?: string; + errorMessage?: string; +} + +export type EvmTransactionExecutedData = { + hash: string[]; + index: string; + type: string; + payload: string[]; + errorCode: string; + errorMessage: string; + gasConsumed: string; + contractAddress: string; + logs: string[]; + blockHeight: string; + returnedData: string[]; + precompiledCalls: string[]; + stateUpdateChecksum: string; +}; + +// Helper to encode our ca lls using viem. +// Returns an array of objects with keys "address" and "data" (hex-encoded string without the "0x" prefix). +export function encodeCalls( + calls: EVMBatchCall[], +): Array> { + return calls.map((call) => { + const encodedData = encodeFunctionData({ + abi: call.abi, + functionName: call.functionName, + args: call.args, + }); + + return [ + { key: 'to', value: call.address }, + { key: 'data', value: fcl.sansPrefix(encodedData) ?? '' }, + { key: 'gasLimit', value: call.gasLimit?.toString() ?? '15000000' }, + { key: 'value', value: call.value?.toString() ?? '0' }, + ]; + }) as any; +} + +const EVM_CONTRACT_ADDRESSES = { + testnet: '0x8c5303eaa26202d6', + mainnet: '0xe467b9dd11fa00df', +}; + +// Takes a chain id and returns the cadence tx with addresses set +const getCadenceBatchTransaction = (chainId: number) => { + const isMainnet = chainId === 0x747; + const evmAddress = isMainnet + ? EVM_CONTRACT_ADDRESSES.mainnet + : EVM_CONTRACT_ADDRESSES.testnet; + + return ` +import EVM from ${evmAddress} + +transaction(calls: [{String: AnyStruct}], mustPass: Bool) { + + let coa: auth(EVM.Call) &EVM.CadenceOwnedAccount + + prepare(signer: auth(BorrowValue) & Account) { + let storagePath = /storage/evm + self.coa = signer.storage.borrow(from: storagePath) + ?? panic("No CadenceOwnedAccount (COA) found at ".concat(storagePath.toString())) + } + + execute { + for i, call in calls { + let to = call["to"] as! String + let data = call["data"] as! String + let gasLimit = call["gasLimit"] as! UInt64 + let value = call["value"] as! UInt + + let result = self.coa.call( + to: EVM.addressFromString(to), + data: data.decodeHex(), + gasLimit: gasLimit, + value: EVM.Balance(attoflow: value) + ) + + if mustPass { + assert( + result.status == EVM.Status.successful, + message: "Call index ".concat(i.toString()).concat(" to ").concat(to) + .concat(" with calldata ").concat(data).concat(" failed: ") + .concat(result.errorMessage) + ) + } + } + } +} +`; +}; + +// Custom hook that returns a function to send a batch transaction +export function useBatchTransaction() { + const { chain } = useAccount(); + + const cadenceTx = chain?.id ? getCadenceBatchTransaction(chain.id) : null; + + const [isPending, setIsPending] = useState(false); + const [isError, setIsError] = useState(false); + const [txId, setTxId] = useState(''); + const [results, setResults] = useState([]); + + async function sendBatchTransaction( + calls: EVMBatchCall[], + mustPass: boolean = true, + ) { + // Reset state + setIsPending(true); + setIsError(false); + setTxId(''); + setResults([]); + + try { + if (!cadenceTx) { + throw new Error('No current chain found'); + } + + const encodedCalls = encodeCalls(calls); + + const txId = await fcl.mutate({ + cadence: cadenceTx, + args: (arg, t) => [ + // Pass encodedCalls as an array of dictionaries with keys (String, String) + arg( + encodedCalls, + t.Array( + t.Dictionary([ + { key: t.String, value: t.String }, + { key: t.String, value: t.String }, + { key: t.String, value: t.UInt64 }, + { key: t.String, value: t.UInt }, + ] as any), + ), + ), + // Pass mustPass=true to revert the entire transaction if any call fails + arg(true, t.Bool), + ], + limit: 9999, + }); + + setTxId(txId); + + // The transaction may revert if mustPass=true and one of the calls fails, + // so we catch that error specifically. + let txResult; + try { + txResult = await fcl.tx(txId).onceExecuted(); + } catch (txError) { + // If we land here, the transaction likely reverted. + // We can return partial or "failed" outcomes for all calls. + setIsError(true); + setResults( + calls.map(() => ({ + status: 'failed' as const, + hash: undefined, + errorMessage: 'Transaction reverted', + })), + ); + setIsPending(false); + return; + } + + // Filter for TransactionExecuted events + const executedEvents = txResult.events.filter((e: any) => + e.type.includes('TransactionExecuted'), + ); + + // Build a full outcomes array for every call. + // For any call index where no event exists, mark it as "skipped". + const outcomes: CallOutcome[] = calls.map((_, index) => { + const eventData = executedEvents[index] + ?.data as EvmTransactionExecutedData; + if (eventData) { + return { + hash: bytesToHex( + Uint8Array.from( + eventData.hash.map((x: string) => parseInt(x, 10)), + ), + ), + status: eventData.errorCode === '0' ? 'passed' : 'failed', + errorMessage: eventData.errorMessage, + }; + } else { + return { + status: 'skipped', + }; + } + }); + + setResults(outcomes); + setIsPending(false); + } catch (error: any) { + setIsError(true); + setIsPending(false); + } + } + + return { sendBatchTransaction, isPending, isError, txId, results }; +} +``` + +## Step 4: Implement the UI + +Now, update your application's `page.tsx` to use the batch transaction utility. Update + +```tsx +'use client'; + + + + + + + +import { + EVMBatchCall, + useBatchTransaction, +} from '../hooks/useBatchTransaction'; + +function Page() { + const coa = useAccount(); + const [flowAddress, setFlowAddress] = useState(null); + const { sendBatchTransaction, isPending, isError, txId, results } = + useBatchTransaction(); + + useEffect(() => { + const unsub = fcl.currentUser().subscribe((user: CurrentUser) => { + setFlowAddress(user.addr ?? null); + }); + return () => unsub(); + }, []); + + // Define a "real" calls array to demonstrate a batch transaction. + // In this example, we call two functions on a token contract: + // 1. deposit() to wrap FLOW (e.g., WFLOW) + // 2. approve() to allow a spender to spend tokens. + const calls: EVMBatchCall[] = [ + { + // Call deposit() function (wrap FLOW) on the token contract. + address: '0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e', // Replace with your actual token contract address. + abi: [ + { + inputs: [], + name: 'deposit', + outputs: [], + stateMutability: 'payable', + type: 'function', + }, + ], + functionName: 'deposit', + args: [], // deposit takes no arguments; value is passed with the call. + }, + { + // Call approve() function (ERC20 style) on the same token contract. + address: '0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e', // Replace with your actual token contract address if needed. + abi: [ + { + inputs: [ + { name: 'spender', type: 'address' }, + { name: 'value', type: 'uint256' }, + ], + name: 'approve', + outputs: [{ name: '', type: 'bool' }], + stateMutability: 'nonpayable', + type: 'function', + }, + ], + functionName: 'approve', + args: [ + '0x2E2Ed0Cfd3AD2f1d34481277b3204d807Ca2F8c2', // Spender address. + BigInt('1000000000000000000'), // Approve 1 token (assuming 18 decimals). + ], + }, + ]; + + return ( + <> +
    + +
    +

    Flow Address: {flowAddress}

    +

    EVM Address: {coa?.address}

    +
    + + {

    {JSON.stringify({ isPending, isError, txId, results })}

    } + + + ); +} + +export default Page; +``` + +## Step 5: Test Your Application + +1. Start your development server: + + ```bash + npm run dev + ``` + +2. Connect your wallet using the RainbowKit `ConnectButton` + + - Make sure to use a Cadence-compatible wallet like Flow Wallet + +3. Click the "Send Batch Transaction" button + + - You'll be prompted to approve the Cadence transaction + - This transaction will execute multiple EVM calls in a single atomic operation + +4. Observe the results + - The Cadence transaction ID will be displayed + - The results of each EVM transaction will be shown + +## How It Works + +When you call `sendBatchTransaction`, the following happens: + +1. A Cadence transaction is created that includes all your EVM calls +2. The transaction is executed using FCL's `mutate` function +3. The Cadence transaction calls each EVM transaction in sequence +4. If any transaction fails and `mustPass` is true, the entire batch is rolled back +5. The results of each EVM transaction are returned + +This approach gives you several advantages: + +- **Atomic Operations**: All transactions succeed or fail together +- **Single Signature**: Users only need to sign one transaction +- **Gas Efficiency**: Reduced gas costs compared to separate transactions +- **Simplified UX**: Users don't need to approve multiple transactions + +## Conclusion + +You've successfully integrated Flow Cadence with your wagmi/rainbowkit application! This integration allows you to leverage the power of Cadence while maintaining the familiar EVM development experience. + +## Reference Implementation + +For a complete reference implementation, check out the [FCL + RainbowKit + wagmi Integration Demo] repository. + +[Cadence]: https://cadence-lang.org/docs +[Next.js]: https://nextjs.org/docs/app/getting-started/installation +[npm]: https://www.npmjs.com/ +[create an issue]: https://github.com/onflow/docs/issues/new/choose +[Cadence]: https://cadence-lang.org +[Solidity]: https://soliditylang.org/ +[native VRF]: ../../evm/guides/vrf.md +[structure and call EVM transactions]: ./batched-evm-transactions.md +[FLIP 316]: https://github.com/onflow/flips/pull/317 +[Flow Client Library (FCL)]: ../../tools/clients/fcl-js +[wagmi]: https://wagmi.sh/ +[viem]: https://viem.sh/ +[RainbowKit]: https://www.rainbowkit.com/ +[wallet]: ../../ecosystem/wallets.md +[Discord]: https://discord.com/channels/613813861610684416/1162086721471647874 +[FCL + RainbowKit + wagmi Integration Demo]: https://github.com/jribbink/cross-vm-app +[FCL-JS]: https://github.com/onflow/fcl-js +[Testnet Cadence Flowscan]: https://testnet.flowscan.io +[Cadence Owned Accounts]: ../../build/basics/accounts.md +[Testnet EVM Flowscan]: https://evm-testnet.flowscan.io \ No newline at end of file diff --git a/static/markdown/tutorials/cross-vm-apps/batched-evm-transactions.md b/static/markdown/tutorials/cross-vm-apps/batched-evm-transactions.md new file mode 100644 index 0000000000..427058c40c --- /dev/null +++ b/static/markdown/tutorials/cross-vm-apps/batched-evm-transactions.md @@ -0,0 +1,739 @@ +--- +title: Batched EVM Transactions Using Cadence +sidebar_label: Batched EVM Transactions +sidebar_position: 6 +--- + +Integrating Cadence into EVM applications on Flow enables developers to leverage the best of both worlds. This guide +demonstrates how to batch EVM transactions using Cadence, allowing applications to embed multiple EVM transactions in a +single Cadence transaction while conditioning final execution on the success of all EVM transactions. + +This feature can supercharge your EVM application by unlocking experiences otherwise impossible on traditional EVM +platforms. + +## Objectives + +After completing this guide, you'll be able to + +- Construct a Cadence transaction that executes several EVM transactions such that if any EVM transaction fails, the + entire set will revert +- Read and write from smart contract functions on [EVM Flowscan] +- Run a Cadence transaction from the browser using [Flow Runner] +- Install conceptual understanding of Cadence X EVM interactions +- Inspect multiple EVM transactions embedded in a Cadence transaction with [Flowscan] block explorer +- Write code that interacts with the EVM via a CadenceOwnedAccount (COA) + +## Prerequisites + +Before you dive in, make sure you have the following configured: + +- [MetaMask] installed in your browser with an active account +- [Flow Wallet extension] installed in your browser with an active account +- Both wallets funded with Testnet FLOW. See the [Faucet guide] for more information. + +## Overview + +For the purposes of demonstration, this walkthrough will focus on relatively simple EVM operations in addition to first +creating a [Cadence-controlled EVM account (COA)]. Specifically, we will: + +- Wrap FLOW as WFLOW +- Approve an ERC721 to transfer WFLOW in exchange for an NFT mint +- Mint an ERC721 token - this ERC721 has a 50% chance of failing (using [onchain VRF] to determine success) + +These operations let us focus on the **core concepts** of this guide: + +1. **Batching EVM transactions** using Cadence +2. **Conditioning execution** on the results of those EVM transactions. + +However, using these same principles, you'll have the power to address more complex use cases. For instance, replace +wrapping FLOW with a DEX swap. Or instead of minting an ERC721, purchase an NFT listing from a marketplace. Combine +these two and suddenly you can purchase NFTs with any ERC20 token, all in a single Cadence transaction, reverting +everything if a single step fails. + +The point is, while a simple use case, this guide will give you the tools to build much more complex and interesting +applications. So let's get started! + +## Components + +As mentioned in the [Overview], this guide involves three main actions: + +- Wrapping FLOW as WFLOW +- Approving an ERC721 to transfer WFLOW in exchange for an NFT mint +- Minting an ERC721 token + +Before interacting with these contracts, let's dig bit more into the components of this guide. + +### Wrap FLOW as WFLOW + +On Flow EVM, FLOW is the native currency and similar to other EVM platforms, the native currency is not accessible as an +ERC20 token. To interact with ERC20 contracts, you need to wrap FLOW as WFLOW (Wrapped FLOW). This is Flow's equivalent +of WETH on Ethereum. + +:::tip + +You can find WFLOW deployed to `0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e` on Flow [Testnet] & [Mainnet] and source +code in the [`@onflow/flow-sol-utils` repository]. + +::: + +### Approve ERC721 Transfer + +Our example `MaybeMintERC721` contract accepts WFLOW in exchange for minting an NFT. However, the contract cannot move +WFLOW without your permission. To allow the contract to move your WFLOW, you must approve the contract to transfer +enough of your WFLOW to mint the NFT. + +### Mint ERC721 Token + +Finally, we'll mint an ERC721 token using the `MaybeMintERC721` contract. This contract has a 50% chance of failing, +simulating a real-world scenario where purchasing an NFT might fail - say a listing was purchased before your +transaction was processed. + +Importantly, if this transaction fails, we want to revert the entire sequence of transactions. After all, you wrapped +FLOW to WFLOW and approved the ERC721 transfer specifically to mint this NFT. If the mint fails, you want to unwind +everything. As we'll see shortly, this is where batching EVM transactions using Cadence is extremely powerful. + +## Interacting with the Contracts + +Before taking the easy route, let's first interact with the contracts individually to better understand the process and +status quo user experience. Realistically, this is your only option for completing the whole process on other EVM +platforms. + +:::tip + +Recall in [Prerequisites] that you need to have both [MetaMask] and [Flow Wallet extension] installed and funded with +Testnet FLOW. Make sure you've done so before proceeding. + +::: + +### Using MetaMask + +#### 1. Wrap FLOW + +Our first action will be to wrap enough FLOW to cover the cost of minting the `MaybeMintERC721` token. To do this, we'll +interact with the `WFLOW` contract on Testnet. There are a number of ways we could interact with this contract - Remix +IDE, Foundry's CLI, Hardhat, etc. - but for the purposes of this guide, we'll use the [Flowscan EVM block explorer]. + +Navigate to the WFLOW Testnet contract on Flowscan: [WFLOW]. Ensure you're on the `Write Contract` tab which allows you +to interact with the contract's mutating functions. + +Before you can interact with the contract, you need to connect your MetaMask wallet to the [Flowscan EVM block +explorer]. Click the `Connect` button in the top right corner and follow the prompts to connect your MetaMask wallet. + +:::warning + +There are two **separate** block explorers for Flow - one for Cadence activity and another for EVM activity. This is +unique to Flow and is due to the fact that Cadence & EVM are separate runtimes, with EVM effectively emulated within +Cadence. This orientation - that of EVM running within Cadence - means that the Cadence-side explorer has visibility to +EVM transactions embedded within a Cadence transaction. + +Practically, this means that any transactions ran using a Flow native account can be viewed on the Cadence explorer +while any transactions run using an EVM account can be viewed on the EVM explorer. + +::: + +![Connect wallet to Flowscan](./flowscan-connect.png) + +Once connected, you should see your address in the top right corner and above the contract's functions. + +Now we can wrap FLOW. Click on the `deposit` method which will drop down an input field for the amount of FLOW you want +to wrap. The mint amount for the `MaybeMintERC721` contract is 1 whole FLOW which in EVM terms is `1e18 wei` - `wei` +being the smallest unit of an EVM's native currency (inherited from Ethereum's units - more on Ether units [here]). + +As shown below, put `1 000 000 000 000 000 000` in the input field for `deposit`. + +![Deposit 1 FLOW to WFLOW contract](./wflow-deposit.png) + +You can now click the `Write` button to submit the transaction. Once MetaMask prompts you to sign the transaction, click +`Confirm` and give it a few seconds to process. + +
    +![Confirm WFLOW deposit in MetaMask](./wflow-deposit-confirm.png) +
    + +Once confirmed, you should be able to see WFLOW balance in your tokens list in MetaMask - if not, you can click on +`Import Tokens` and paste the WFLOW contract address found on the Flowscan page and refresh your list. + +
    +![WFLOW in MetaMask](./wflow-in-metamask-tokens.png) +
    + +#### 2. Approve WFLOW Transfer + +Now that you have your WFLOW, you'll need to approve the `MaybeMintERC721` contract to transfer your WFLOW. From the +same WFLOW page in Flowscan, click on the `approve` method. This time, you'll need to input the `MaybeMintERC721` +contract address - `0x2E2Ed0Cfd3AD2f1d34481277b3204d807Ca2F8c2` - and the amount of WFLOW you want to approve - again `1 +000 000 000 000 000 000` WFLOW. + +![Approve MaybeMintERC721 for 1 WFLOW in Flowscan](./wflow-approve.png) + +Click `Write` to submit the transaction. To be clear, this does not complete a transfer, but allows the +`MaybeMintERC721` contract to transfer your WFLOW on your behalf which will execute in the next step. + +#### 3. Mint ERC721 Token + +Finally, we'll attempt to mint the ERC721 token using the `MaybeMintERC721` contract. Navigate to the `MaybeMintERC721` +contract on Flowscan: [MaybeMintERC721]. + +Again, you'll be met with the contract functions on the `Write Contract` tab. Click on the `mint` function which takes +no arguments - just click on `Write` and then `Confirm` in the resulting MetaMask window. + +This contract has a 50% chance of failing on mint using onchain randomness. If it fails, simply mint again until it +succeeds. + +On success, you can click on your NFTs in MetaMask to see your newly minted token. + +
    +![MaybeMintERC721 in MetaMask NFT list](./maybe-mint-in-metamask.png) +
    + +#### Recap + +This process is cumbersome and requires multiple transactions, each of which could fail. Given the intent of the process - +minting an NFT - if this were a case where the NFT was a limited edition or time-sensitive, you'd be left with WFLOW +wrapped and approved for transfer, but no NFT and would need to manually unwind the process. + +Or you could just use Cadence to batch these transactions and revert everything if the mint fails. Let's do that. + +### Using Flow Wallet + +Before diving into the "how", let's execute the batched version of everything we just did using Flow Wallet. This will +give you a sense of the power of Cadence and the Flow blockchain. + +The transaction below, like all Cadence transactions, is scripted, allowing us to execute a series of actions. It may +look like a lot at first, but we will break it down step by step in the following sections. + +
    + +wrap_and_mint.cdc + +```cadence +// TESTNET IMPORTS +import FungibleToken from 0x9a0766d93b6608b7 +import FlowToken from 0x7e60df042a9c0868 +import EVM from 0x8c5303eaa26202d6 + +/// This transaction demonstrates how multiple EVM calls can be batched in a single Cadence transaction via +/// CadenceOwnedAccount (COA), performing the following actions: +/// +/// 1. Configures a COA in the signer's account if needed +/// 2. Funds the signer's COA with enough FLOW to cover the WFLOW cost of minting an ERC721 token +/// 3. Wraps FLOW as WFLOW - EVM call 1 +/// 4. Approves the example MaybeMintERC721 contract which accepts WFLOW to move the mint amount - EVM call 2 +/// 5. Attempts to mint an ERC721 token - EVM call 3 +/// +/// Importantly, the transaction is reverted if any of the EVM interactions fail returning the account to the original +/// state before the transaction was executed across Cadence & EVM. +/// +/// For more context, see https://github.com/onflow/batched-evm-exec-example +/// +/// @param wflowAddressHex: The EVM address hex of the WFLOW contract as a String +/// @param maybeMintERC721AddressHex: The EVM address hex of the ERC721 contract as a String +/// +transaction(wflowAddressHex: String, maybeMintERC721AddressHex: String) { + + let coa: auth(EVM.Call) &EVM.CadenceOwnedAccount + let mintCost: UFix64 + let wflowAddress: EVM.EVMAddress + let erc721Address: EVM.EVMAddress + + prepare(signer: auth(SaveValue, BorrowValue, IssueStorageCapabilityController, PublishCapability, UnpublishCapability) &Account) { + /* COA configuration & assigment */ + // + let storagePath = /storage/evm + let publicPath = /public/evm + // Configure a COA if one is not found in storage at the default path + if signer.storage.type(at: storagePath) == nil { + // Create & save the CadenceOwnedAccount (COA) Resource + let newCOA <- EVM.createCadenceOwnedAccount() + signer.storage.save(<-newCOA, to: storagePath) + + // Unpublish any existing Capability at the public path if it exists + signer.capabilities.unpublish(publicPath) + // Issue & publish the public, unentitled COA Capability + let coaCapability = signer.capabilities.storage.issue<&EVM.CadenceOwnedAccount>(storagePath) + signer.capabilities.publish(coaCapability, at: publicPath) + } + + // Assign the COA reference to the transaction's coa field + self.coa = signer.storage.borrow(from: storagePath) + ?? panic("A CadenceOwnedAccount (COA) Resource could not be found at path ".concat(storagePath.toString()) + .concat(" - ensure the COA Resource is created and saved at this path to enable EVM interactions")) + + /* Fund COA with cost of mint */ + // + // Borrow authorized reference to signer's FlowToken Vault + let sourceVault = signer.storage.borrow( + from: /storage/flowTokenVault + ) ?? panic("The signer does not store a FlowToken Vault object at the path " + .concat("/storage/flowTokenVault. ") + .concat("The signer must initialize their account with this vault first!")) + // Withdraw from the signer's FlowToken Vault + self.mintCost = 1.0 + let fundingVault <- sourceVault.withdraw(amount: self.mintCost) as! @FlowToken.Vault + // Deposit the mint cost into the COA + self.coa.deposit(from: <-fundingVault) + + /* Set the WFLOW contract address */ + // + // View the cannonical WFLOW contract at: + // https://evm-testnet.flowscan.io/address/0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e + self.wflowAddress = EVM.addressFromString(wflowAddressHex) + + /* Assign the ERC721 EVM Address */ + // + // Deserialize the provided ERC721 hex string to an EVM address + self.erc721Address = EVM.addressFromString(maybeMintERC721AddressHex) + } + + pre { + self.coa.balance().inFLOW() >= self.mintCost: + "CadenceOwnedAccount holds insufficient FLOW balance to mint - " + .concat("Ensure COA has at least ".concat(self.mintCost.toString()).concat(" FLOW")) + } + + execute { + /* Wrap FLOW in EVM as WFLOW */ + // + // Encode calldata & set value + let depositCalldata = EVM.encodeABIWithSignature("deposit()", []) + let value = EVM.Balance(attoflow: 0) + value.setFLOW(flow: self.mintCost) + // Call the WFLOW contract, wrapping the sent FLOW + let wrapResult = self.coa.call( + to: self.wflowAddress, + data: depositCalldata, + gasLimit: 15_000_000, + value: value + ) + assert( + wrapResult.status == EVM.Status.successful, + message: "Wrapping FLOW as WFLOW failed: ".concat(wrapResult.errorMessage) + ) + + /* Approve the ERC721 address for the mint amount */ + // + // Encode calldata approve(address,uint) calldata, providing the ERC721 address & mint amount + let approveCalldata = EVM.encodeABIWithSignature( + "approve(address,uint256)", + [self.erc721Address, UInt256(1_000_000_000_000_000_000)] + ) + // Call the WFLOW contract, approving the ERC721 address to move the mint amount + let approveResult = self.coa.call( + to: self.wflowAddress, + data: approveCalldata, + gasLimit: 15_000_000, + value: EVM.Balance(attoflow: 0) + ) + assert( + approveResult.status == EVM.Status.successful, + message: "Approving ERC721 address on WFLOW contract failed: ".concat(approveResult.errorMessage) + ) + + /* Attempt to mint ERC721 */ + // + // Encode the mint() calldata + let mintCalldata = EVM.encodeABIWithSignature("mint()", []) + // Call the ERC721 contract, attempting to mint + let mintResult = self.coa.call( + to: self.erc721Address, + data: mintCalldata, + gasLimit: 15_000_000, + value: EVM.Balance(attoflow: 0) + ) + // If mint fails, all other actions in this transaction are reverted + assert( + mintResult.status == EVM.Status.successful, + message: "Minting ERC721 token failed: ".concat(mintResult.errorMessage) + ) + } +} + +``` + +
    + +You can run the transaction at the following link using the community-developed Flow Runner tool: [`wrap_and_mint.cdc`]. + +This transaction takes two arguments: + +- WFLOW contract address: `0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e` +- MaybeMintERC721 contract address: `0x2E2Ed0Cfd3AD2f1d34481277b3204d807Ca2F8c2` + +Before running, ensure that the network section - bottom right corner - displays Testnet. If not, click and select +`Testnet` as your network and refresh. Once you've confirmed you're Flow Runner is targeting Testnet, copy these +addresses and paste them into the respective fields on the Flow Runner page. Click `Run` on the top left and follow the +prompts to connect your Flow Wallet and sign the transaction. + +:::warning + +Although we are running a manual transaction for the purposes of this walkthrough, you should always be careful to +review the transaction details before signing and submitting. + +::: + +Again, since the ERC721 has a 50% chance of failing, you may need to run the transaction multiple times until it +succeeds. However note that if the mint fails, the entire transaction will revert, unwinding the wrapped FLOW and +approval. + +Again, since the ERC721 has a 50% chance of failure and the success of the transaction is conditioned on successfully +minting, your transaction may fail. If it does fail, importantly the entire transaction reverts, unwinding the wrapped +FLOW deposit and approval - the wrapping and approval transactions **do not execute** in the event of mint failure! This +is the main takeaway of this guide, that you embed a whole sequence of EVM transactions into one atomic operation using +Cadence and if the primary intent (or intents) does not execute, everything else is reverted as well. + +In our case, you'll want to submit a transaction until one succeeds. Once you submit a successful transaction, you'll +see a transaction ID with event logs in the Flow Runner output. Let's take a closer look at the transaction and its +results in the Flowscan block explorer. + +![Flow Runner output on successful transaction execution](./flow-runner-successful-output.png) + +Copy your transaction ID and go to the Flowscan Testnet Cadence block explorer: [Flowscan Cadence]. + +Pasting your transaction ID into the search bar will show you the transaction details, including the Cadence script, +execution status, and event logs. Click on the `EVM` tab to view the EVM transactions batched in the Cadence +transaction. + +![Embedded EVM transactions on Flowscan](./evm-embed-flowscan.png) + +Clicking on the transactions will open up the EVM transaction in Flowscan's EVM block explorer. If you view the EVM +transactions in order, you'll notice that they aggregate the same actions we took manually in the MetaMask section, but +this time in a single Cadence transaction! + +## Breaking it Down + +Now that we can relate to the pain of manually executing these transactions and we've seen the magic you can work with +Cadence, let's understand what's going on under the hood. + +To recap, our Cadence transaction does the following, reverting if any step fails: + +1. Wraps FLOW as WFLOW +2. Approves the `MaybeMintERC721` contract to move WFLOW +3. Attempts to mint a `MaybeMintERC721` token + +But how does our Flow account interact with EVM from the Cadence runtime? As you'll recall from the [Interacting with +COA](./interacting-with-coa.md) guide, we use a Cadence-owned account (COA) to interact with EVM contracts from Cadence. + +A COA is a [resource] providing an interface through which Cadence can interact with the EVM runtime. This is +importantly **_in addition_** to the traditional routes you'd normally access normal EVMs - e.g. via the JSON-RPC API. +And with this interface, we can take advantage of all of the benefits of Cadence - namely here scripted transactions and +conditional execution. + +So in addition to the above steps, our transaction first configures a COA in the signer's account if one doesn't already +exist. It then funds the COA with enough FLOW to cover the mint cost, sourcing funds from the signing Flow account's +Cadence Vault. Finally, it wraps FLOW as WFLOW, approves the ERC721 contract to move the mint amount, and attempts to +mint the ERC721 token. + +Let's see what each step looks like in the transaction code. + +### COA Configuration + +The first step in our transaction is to configure a COA in the signer's account if one doesn't already exist. This is +done by creating a new COA resource and saving it to the signer account's storage. A public Capability on the COA is +then issued and published on the signer's account, allowing anyone to deposit FLOW into the COA, affecting its EVM +balance. + +```cadence +/* COA configuration & assignment */ +// +let storagePath = /storage/evm +let publicPath = /public/evm +// Configure a COA if one is not found in storage at the default path +if signer.storage.type(at: storagePath) == nil { + // Create & save the CadenceOwnedAccount (COA) Resource + let newCOA <- EVM.createCadenceOwnedAccount() + signer.storage.save(<-newCOA, to: storagePath) + + // Unpublish any existing Capability at the public path if it exists + signer.capabilities.unpublish(publicPath) + // Issue & publish the public, unentitled COA Capability + let coaCapability = signer.capabilities.storage.issue<&EVM.CadenceOwnedAccount>(storagePath) + signer.capabilities.publish(coaCapability, at: publicPath) +} + +// Assign the COA reference to the transaction's coa field +self.coa = signer.storage.borrow(from: storagePath) + ?? panic("A CadenceOwnedAccount (COA) Resource could not be found at path ".concat(storagePath.toString()) + .concat(" - ensure the COA Resource is created and saved at this path to enable EVM interactions")) +``` + +At the end of this section, the transaction now has an reference authorized with the `EVM.Call` [entitlement] to use in +the `execute` block which can be used call into EVM. + +You can run a transaction that does just this step here: [`setup_coa.cdc`] + +Since you ran the all-in-one transaction previously, your account already has a COA configured in which case the linked +transaction won't do anything. You can lookup your Testnet account's EVM address with the script below to confirm you +have a COA configured. Simply input your Testnet Flow address and click `Run`. + + + +### Funding the COA + +Next, we fund the COA with enough FLOW to cover the mint cost. This is done by withdrawing FLOW from the signer's +FlowToken Vault and depositing it into the COA. + +```cadence +/* Fund COA with cost of mint */ +// +// Borrow authorized reference to signer's FlowToken Vault +let sourceVault = signer.storage.borrow( + from: /storage/flowTokenVault + ) ?? panic("The signer does not store a FlowToken Vault object at the path " + .concat("/storage/flowTokenVault. ") + .concat("The signer must initialize their account with this vault first!")) +// Withdraw from the signer's FlowToken Vault +self.mintCost = 1.0 +let fundingVault <- sourceVault.withdraw(amount: self.mintCost) as! @FlowToken.Vault +// Deposit the mint cost into the COA +self.coa.deposit(from: <-fundingVault) +``` + +Taking a look at the full transaction, we can see an explicit check that the COA has enough FLOW to cover the mint cost +before proceeding into the transaction's `execute` block. + +```cadence +pre { + self.coa.balance().inFLOW() >= self.mintCost: + "CadenceOwnedAccount holds insufficient FLOW balance to mint - " + .concat("Ensure COA has at least ".concat(self.mintCost.toString()).concat(" FLOW")) +} +``` + +This isn't absolutely necessary as successive steps would fail on this condition, but helps provide enhanced error +messages in the event of insufficient funds. + +You can run the above block in a transaction here which will move 1 FLOW from your account's Cadence FLOW balance to +your account's EVM balance, depositing it directly to your pre-configured COA: [`fund_coa.cdc`] + +After running the linked transaction, you can check your COA's FLOW balance with the script below, just enter your COA's +EVM address (which you can get from the previous script). The resulting balance should be 1.0 (unless you've funded your +COA prior to this walkthrough). + + + +### Setting our EVM Contract Targets + +The last step in our transaction's `prepare` block is to deserialize the provided WFLOW and ERC721 contract addresses +from hex strings to EVM addresses. + +```cadence +/* Set the WFLOW contract address */ +// +// View the cannonical WFLOW contract at: +// https://evm-testnet.flowscan.io/address/0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e +self.wflowAddress = EVM.addressFromString(wflowAddressHex) + +/* Assign the ERC721 EVM Address */ +// +// Deserialize the provided ERC721 hex string to an EVM address +self.erc721Address = EVM.addressFromString(maybeMintERC721AddressHex) +``` + +### Wrapping FLOW as WFLOW + +Next, we're on to the first EVM interaction - wrapping FLOW as WFLOW. This is done by encoding the `deposit()` function +call and setting the call value to the mint cost. The COA then calls the WFLOW contract with the encoded calldata, gas +limit, and value. + +```cadence +/* Wrap FLOW in EVM as WFLOW */ +// +// Encode calldata & set value +let depositCalldata = EVM.encodeABIWithSignature("deposit()", []) +let value = EVM.Balance(attoflow: 0) +value.setFLOW(flow: self.mintCost) +// Call the WFLOW contract, wrapping the sent FLOW +let wrapResult = self.coa.call( + to: self.wflowAddress, + data: depositCalldata, + gasLimit: 15_000_000, + value: value +) +assert( + wrapResult.status == EVM.Status.successful, + message: "Wrapping FLOW as WFLOW failed: ".concat(wrapResult.errorMessage) +) +``` + +Setting the value of the call transmits FLOW along with the call to the contract, accessible in solidity as `msg.value`. + +:::tip + +You'll notice a general pattern among all EVM calls in this transaction: + +1. Encoding the calldata +2. Calling the contract +3. Asserting the call was successful + +Here we're just interested in a successful call, but we could access return data if it were expected and relevant for +our Cadence transaction. This returned data is accessible from the `data` field on the `EVM.Result` object returned from +`coa.call(...)`. This data would then be decoded using `EVM.decodeABI(...)`. More on this in later guides. + +::: + +You can run the above code as a transaction here: [`wrap_flow.cdc`] + +After running the transaction, your COA should have a WFLOW balance of 1.0 WFLOW. Confirm your WFLOW balance by running +the script below, providing your Flow account address, the WFLOW address of `0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e` +and your COA's EVM address (retrieved from a previous script): + + + +Since Solidity does not support decimal precision, the returned balance will look like a large number. In the case of +WFLOW, we can recover the decimals by shifting the decimal place 18 digits to the left. Your account should have `1` +WFLOW or `1000000000000000000` as returned. + +:::warning + +Note that the number of places to shift varies by ERC20 implementation -- the default value is 18, but it's not safe to +assume this value. You can check a token's decimal places by calling `ERC20.decimals()(uint8)`. + +::: + +### Approving the ERC721 Contract + +Once the FLOW is wrapped as WFLOW, we approve the ERC721 contract to move the mint amount. This is done by encoding the +`approve(address,uint256)` calldata and calling the WFLOW contract with the encoded calldata. + +```cadence +/* Approve the ERC721 address for the mint amount */ +// +// Encode calldata approve(address,uint) calldata, providing the ERC721 address & mint amount +let approveCalldata = EVM.encodeABIWithSignature( + "approve(address,uint256)", + [self.erc721Address, UInt256(1_000_000_000_000_000_000)] + ) +// Call the WFLOW contract, approving the ERC721 address to move the mint amount +let approveResult = self.coa.call( + to: self.wflowAddress, + data: approveCalldata, + gasLimit: 15_000_000, + value: EVM.Balance(attoflow: 0) +) +assert( + approveResult.status == EVM.Status.successful, + message: "Approving ERC721 address on WFLOW contract failed: ".concat(approveResult.errorMessage) +) +``` + +You can run this approval using the transaction, passing the WFLOW address of +`0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e` and MaybeMintERC721 address of `0x2E2Ed0Cfd3AD2f1d34481277b3204d807Ca2F8c2` +: [`approve_maybe_mint_erc721.cdc`] + +The linked transaction will perform the approval step, authorizing the ERC721 to transfer WFLOW to cover the mint cost +when `mint()` is called. Confirm the contract allowance by running the script below. Pass your Flow address, WFLOW +address, ERC721 address, and your COA's EVM address. + + + +The result is the amount of your WFLOW balance the ERC721 is allowed to transfer, which after the transaction should be +`1` WFLOW, or `1000000000000000000` as returned. + +### Minting the ERC721 Token + +Finally, we attempt to mint the ERC721 token. This is done by encoding the `mint()` calldata and calling the ERC721 +contract with the encoded calldata. If the mint fails, the entire transaction is reverted. + +```cadence +/* Attempt to mint ERC721 */ +// +// Encode the mint() calldata +let mintCalldata = EVM.encodeABIWithSignature("mint()", []) +// Call the ERC721 contract, attempting to mint +let mintResult = self.coa.call( + to: self.erc721Address, + data: mintCalldata, + gasLimit: 15_000_000, + value: EVM.Balance(attoflow: 0) +) +// If mint fails, all other actions in this transaction are reverted +assert( + mintResult.status == EVM.Status.successful, + message: "Minting ERC721 token failed: ".concat(mintResult.errorMessage) +) +``` + +You can run the minting transaction here, passing the ERC721 address of `0x2E2Ed0Cfd3AD2f1d34481277b3204d807Ca2F8c2`: +[`mint.cdc`] + +Again, this transaction may fail. But if you executed all the prior stepwise transactions according to the walkthrough, +you can try again until the mint succeeds. Recall that you can view your transaction details using Cadence [Flowscan] +which will also let you view the embedded EVM transactions in the `EVM` tab. Try it out, and see if you can figure out +how to get your minted NFT's URI with the script below. + + + +### Recap + +All of the stepwise transactions you just executed are compiled in the first Cadence transaction we ran. Hopefully, +going through the process step by step illuminates the power and flexibility of Cadence, allowing you to write +transactions as simple or as complex as you want. + +While lengthy transactions can be intimidating and even a bit verbose at times, the flexibility afforded by the language +means you are only limited by your imagination. Cadence transactions allow you to support the most streamlined of +experiences, incorporating as many contracts as needed to support your use case. + +## Conclusion + +In this guide, we've demonstrated how to batch EVM transactions using Cadence, allowing you to conditionally execute +multiple EVM transactions in a single Cadence transaction. While this guide focused on relatively simple EVM operations, +the principles can be applied to much more complex and interesting applications. + +In the process, you learned how to: + +- Read and write from smart contract functions on EVM Flowscan +- Run a Cadence transaction from the browser using [Flow Runner] +- Execute batched EVM transactions via a COA in a Cadence transaction +- Condition final transaction execution on success of all EVM transactions +- Inspect multiple EVM transactions embedded in a Cadence transaction with [Flowscan] block explorer + +The biggest takeaway here isn't the specific actions taken in this walkthrough, but the overarching concept that you can +use **Cadence as an orchestration layer** to **extend existing EVM contracts**, creating unique user experiences with +the power **to differentiate your Web3 application**. + +With these basics in hand, you're ready to start building more complex applications that leverage the power of Cadence +and the Flow blockchain. How will you use these features to build Web3's next killer app? + +## Further Reading + +Now that you've experienced the power of Cadence and EVM interactions firsthand, we recommend checking out the following +guides to deepen your understanding: + +- [How Flow EVM Works] - Learn more about the Flow EVM and how it differs from traditional EVM platforms +- [Interacting with COAs] - Get a fuller picture of how Cadence interacts with EVM contracts via Cadence-owned accounts +- [Cadence Transactions] - Learn more about the Cadence transaction model + +Ready to level up your Cadence skills? Take a look at [these Cadence tutorials]. + + + +[EVM Flowscan]: https://evm.flowscan.io/ +[Flow Runner]: https://run.dnz.dev/ +[Flowscan]: https://www.flowscan.io/ +[MetaMask]: https://metamask.io/download/ +[Flow Wallet extension]: https://wallet.flow.com/download +[Faucet guide]: ../../ecosystem/faucets.md +[Cadence-controlled EVM account (COA)]: ./interacting-with-coa.md +[onchain VRF]: ../../evm/guides/vrf.md +[Overview]: #overview +[Testnet]: https://evm-testnet.flowscan.io/token/0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e?tab=contract +[Mainnet]: https://evm.flowscan.io/token/0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e?tab=contract +[`@onflow/flow-sol-utils` repository]: https://github.com/onflow/flow-sol-utils +[Prerequisites]: #prerequisites +[Flowscan EVM block explorer]: https://www.evm-testnet.flowscan.io/ +[WFLOW]: https://evm-testnet.flowscan.io/token/0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e?tab=write_contract +[here]: https://docs.soliditylang.org/en/v0.8.28/units-and-global-variables.html#ether-units +[MaybeMintERC721]: https://evm-testnet.flowscan.io/address/0x2E2Ed0Cfd3AD2f1d34481277b3204d807Ca2F8c2?tab=write_contract +[`wrap_and_mint.cdc`]: https://run.dnz.dev/snippet/c99b25e04a2d1f28 +[Flowscan Cadence]: https://testnet.flowscan.io/ +[resource]: https://cadence-lang.org/docs/solidity-to-cadence#resources +[entitlement]: https://cadence-lang.org/docs/language/access-control#entitlements +[How Flow EVM Works]: ../../evm/how-it-works.md +[Interacting with COAs]: ./interacting-with-coa.md +[Cadence Transactions]: ../../build/basics/transactions.md +[these Cadence tutorials]: https://cadence-lang.org/docs/tutorial/first-steps +[`setup_coa.cdc`]: https://run.dnz.dev/snippet/4ec75e1f4165fa05 +[`fund_coa.cdc`]: https://run.dnz.dev/snippet/0e7370601bd9123b +[`wrap_flow.cdc`]: https://run.dnz.dev/snippet/9dbfb784da5300fb +[`approve_maybe_mint_erc721.cdc`]: https://run.dnz.dev/snippet/1b503d82f9a2c5a7 +[`mint.cdc`]: https://run.dnz.dev/snippet/fd7c4dda536d006e \ No newline at end of file diff --git a/static/markdown/tutorials/cross-vm-apps/direct-calls.md b/static/markdown/tutorials/cross-vm-apps/direct-calls.md new file mode 100644 index 0000000000..8a67e39fe4 --- /dev/null +++ b/static/markdown/tutorials/cross-vm-apps/direct-calls.md @@ -0,0 +1,98 @@ +--- +title: Direct Calls from Cadence to Flow EVM +sidebar_label: Direct Calls to Flow EVM +sidebar_position: 5 +--- + +Direct calls from Cadence to Flow EVM are essential for enabling Cadence smart contracts to interact seamlessly with the EVM environment hosted on the Flow blockchain. These calls facilitate a range of functionalities including state queries and transaction initiations, allowing Cadence contracts to leverage EVM-based tools and assets. + +## Making Direct Calls + +### Accessing Flow EVM + +To interact with Flow EVM, Cadence contracts must first import `EVM` from its service address: + +```js +import EVM from +``` + +Next, create an `EVMAddress` with a sequence of 20 bytes representing the EVM address: + +```js +let addr = EVM.EVMAddress(bytes: bytes) +``` + +Once you have access to an `EVMAddress`, you can query various pieces of state information such as: + +- `balance() EVM.Balance` provides the balance of the address. It returns a balance object rather than a basic type to avoid errors when converting from flow to atto-flow. +- `nonce() UInt64` retrieves the nonce associated with the address. +- `code(): [UInt8]` fetches the code at the address; it returns the smart contract code if applicable, and is empty otherwise. + +```cadence +import EVM from + +access(all) +fun main(bytes: [UInt8; 20]): EVM.Balance { + let addr = EVM.EVMAddress(bytes: bytes) + let bal = addr.balance() + return bal +} +``` + +Alternatively, you can use the EVM contract's native deserialization to access the balance provided a hex string representing the address: + +```cadence +import EVM from + +access(all) +fun main(addressHex: String): UFix64 { + let addr = EVM.addressFromString(addressHex) + return addr.balance().inFLOW() +} +``` + +### Sending Transactions to Flow EVM + +To send transactions to Flow EVM, use the `run` function which executes RLP-encoded transactions. RLP (Recursive Length Prefix) encoding is used to efficiently encode data into a byte-array format, suitable for Ethereum-based environments. Here's an example of wrapping and sending a transaction: + +```cadence +import EVM from + +transaction(rlpEncodedTransaction: [UInt8], coinbaseBytes: [UInt8; 20]) { + + prepare(signer: &Account) { + let coinbase = EVM.EVMAddress(bytes: coinbaseBytes) + let result = EVM.run(tx: rlpEncodedTransaction, coinbase: coinbase) + assert( + runResult.status == EVM.Status.successful, + message: "tx was not executed successfully." + ) + } +} +``` + +Using `run` restricts an EVM block to a single EVM transaction, while a future `batchRun` will offer the capability to execute multiple EVM transactions in a batch. + +### Handling Transaction Responses + +Handling responses correctly is crucial to manage the state changes or errors that occur during `EVM` transactions: + +When calling `EVM.run`, it's important to understand that this method does not revert the outer Flow transaction. Developers must therefore carefully handle the response based on the `result.Status` of the EVM transaction execution. There are three main outcomes to consider: + +- `Status.invalid`: This status indicates that the transaction or call failed at the validation step, such as due to a nonce mismatch. Transactions with this status are not executed or included in a block, meaning no state change occurs. +- `Status.failed`: This status is assigned when the transaction has technically succeeded in terms of being processable, but the EVM reports an error as the outcome, such as running out of gas. Importantly, a failed transaction or call is still included in a block. Attempting to resubmit a failed transaction will result in an `invalid` status on the second try due to a now incorrect nonce. +- `Status.successful`: This status is given when the transaction or call is successfully executed and no errors are reported by the EVM. + +For scenarios where transaction validity is critical, developers may choose to use the `mustRun` variation, which reverts the transaction in the case of a validation failure, providing an added layer of error handling. + +### Understanding Gas Usage in EVM Transactions + +Direct calls to Flow EVM require gas, it's important to understand how gas usage is calculated and billed. During the execution of methods that interact with the EVM: + +- **Gas Aggregation**: The gas used by each call is aggregated throughout the transaction. +- **Gas Adjustment**: The total gas used is then adjusted based on a multiplier. This multiplier is determined by the network and can be adjusted by the service account to reflect operational costs and network conditions. +- **Payment of Gas Fees**: The adjusted total gas amount is added to the overall computation fees of the Flow transaction. These fees are paid by the transaction initiator, commonly referred to as the payer. + +## Keep Learning + +For more information and a deeper dive into the `EVMAddress`, `Result`, and `Status` objects, see [the contract here](https://github.com/onflow/flow-go/blob/master/fvm/evm/stdlib/contract.cdc). \ No newline at end of file diff --git a/static/markdown/tutorials/cross-vm-apps/index.md b/static/markdown/tutorials/cross-vm-apps/index.md new file mode 100644 index 0000000000..fb935c2d72 --- /dev/null +++ b/static/markdown/tutorials/cross-vm-apps/index.md @@ -0,0 +1,37 @@ +--- +title: Cross-VM Apps +description: A series of tutorials on building cross-VM applications that integrate Flow EVM with Flow Cadence. +sidebar_position: 3 +keywords: + - hybrid apps + - cross-vm apps + - Flow EVM + - Flow Cadence + - tutorials + - COAs + - batched transactions + - VM bridge + - cross-VM bridge +--- + +# Cross-VM App Tutorials + +This series covers how to build cross-VM applications that integrate Flow EVM with Flow Cadence, unlocking new capabilities by combining both environments. + +## Tutorials + +- **[Batched Transactions]** - Learn how to use FCL with wagmi and RainbowKit to create a cross-VM app. +- **[Add Flow Cadence to Your wagmi App]** - Learn how to integrate Flow Cadence with your existing wagmi/RainbowKit application to enable batch transactions and other Cadence features. +- **[Interacting with COAs]** - Learn how to create and interact with Cadence Owned Accounts (COAs) to control EVM accounts from Cadence. +- **[Batched EVM Transactions]** - Discover how to batch multiple EVM transactions into a single Cadence transaction. +- **[Cross-VM Bridge]** - Explore how to bridge fungible and non-fungible tokens between Cadence and EVM environments. + +## More Coming Soon + +Stay tuned—more tutorials and advanced guides are on the way! + +[Batched Transactions]: ./introduction.md +[Interacting with COAs]: ./interacting-with-coa.md +[Batched EVM Transactions]: ./batched-evm-transactions.md +[Cross-VM Bridge]: ./vm-bridge.md +[Add Flow Cadence to Your wagmi App]: ./add-to-wagmi.md \ No newline at end of file diff --git a/static/markdown/tutorials/cross-vm-apps/interacting-with-coa.md b/static/markdown/tutorials/cross-vm-apps/interacting-with-coa.md new file mode 100644 index 0000000000..583c906286 --- /dev/null +++ b/static/markdown/tutorials/cross-vm-apps/interacting-with-coa.md @@ -0,0 +1,633 @@ +--- +title: Interacting with COAs from Cadence +sidebar_label: Interacting with COAs +sidebar_position: 4 +--- + +[Cadence Owned Accounts (COAs)](../../evm/accounts.md#cadence-owned-accounts) are EVM accounts owned by a Cadence resource and +are used to interact with Flow EVM from Cadence. + +COAs expose two interfaces for interaction: one on the Cadence side and one on the EVM side. In this guide, we will +focus on how to interact with COAs with Cadence. + +In this guide we will walk through some basic examples creating and interacting with a COA in Cadence. Your specific +usage of the COA resource will depend on your own application's requirements (e.g. the COA resource may not live +directly in `/storage/evm` as in these examples, but may instead be a part of a more complex resource structure). + +## COA Interface + +To begin, we can take a look at a simplified version of the `EVM` contract, highlighting parts specific to COAs. + +You can learn more about the `EVM` contract [here](../../build/core-contracts/13-evm.md) and the full contract code can +be found on [GitHub](https://github.com/onflow/flow-go/tree/master/fvm/evm/stdlib/contract.cdc). + +```cadence EVM.cdc +access(all) +contract EVM { + //... + access(all) + resource CadenceOwnedAccount: Addressable { + /// The EVM address of the cadence owned account + /// -> could be used to query balance, code, nonce, etc. + access(all) + view fun address(): EVM.EVMAddress + + /// Get balance of the cadence owned account + /// This balance + access(all) + view fun balance(): EVM.Balance + + /// Deposits the given vault into the cadence owned account's balance + access(all) + fun deposit(from: @FlowToken.Vault) + + /// The EVM address of the cadence owned account behind an entitlement, acting as proof of access + access(EVM.Owner | EVM.Validate) + view fun protectedAddress(): EVM.EVMAddress + + /// Withdraws the balance from the cadence owned account's balance + /// Note that amounts smaller than 10nF (10e-8) can't be withdrawn + /// given that Flow Token Vaults use UFix64s to store balances. + /// If the given balance conversion to UFix64 results in + /// rounding error, this function would fail. + access(EVM.Owner | EVM.Withdraw) + fun withdraw(balance: EVM.Balance): @FlowToken.Vault + + /// Deploys a contract to the EVM environment. + /// Returns the address of the newly deployed contract + access(EVM.Owner | EVM.Deploy) + fun deploy( + code: [UInt8], + gasLimit: UInt64, + value: Balance + ): EVM.EVMAddress + + /// Calls a function with the given data. + /// The execution is limited by the given amount of gas + access(EVM.Owner | EVM.Call) + fun call( + to: EVMAddress, + data: [UInt8], + gasLimit: UInt64, + value: Balance + ): EVM.Result + } + + // Create a new CadenceOwnedAccount resource + access(all) + fun createCadenceOwnedAccount(): @EVM.CadenceOwnedAccount + // ... +} +``` + +## Importing the EVM Contract + +The `CadenceOwnedAccount` resource is a part of the `EVM` system contract, so to use any of these functions, you will +need to begin by importing the `EVM` contract into your Cadence code. + +To import the `EVM` contract into your Cadence code using the simple import syntax, you can use the following format +(learn more about configuring contracts in `flow.json` +[here](../../tools/flow-cli/flow.json/configuration.md#contracts)): + +```cadence +// This assumes you are working in the in the Flow CLI, FCL, or another tool that supports this syntax +// The contract address should be configured in your project's `flow.json` file +import "EVM" +// ... +``` + +However, if you wish to use manual address imports instead, you can use the following format: + +```cadence +// Must use the correct address based on the network you are interacting with +import EVM from 0x1234 +// ... +``` + +To find the deployment addresses of the `EVM` contract, you can refer to the [EVM contract +documentation](../../build/core-contracts/13-evm.md). + +## Creating a COA + +To create a COA, we can use the `createCadenceOwnedAccount` function from the `EVM` contract. This function takes no +arguments and returns a new `CadenceOwnedAccount` resource which represents this newly created EVM account. + +For example, we can create this COA in a transaction, saving it to the user's storage and publishing a public capability +to its reference: + +```cadence create_coa.cdc +import "EVM" + +// Note that this is a simplified example & will not handle cases where the COA already exists +transaction() { + prepare(signer: auth(SaveValue, IssueStorageCapabilityController, PublishCapability) &Account) { + let storagePath = /storage/evm + let publicPath = /public/evm + + // Create account & save to storage + let coa: @EVM.CadenceOwnedAccount <- EVM.createCadenceOwnedAccount() + signer.storage.save(<-coa, to: storagePath) + + // Publish a public capability to the COA + let cap = signer.capabilities.storage.issue<&EVM.CadenceOwnedAccount>(storagePath) + signer.capabilities.publish(cap, at: publicPath) + } +} +``` + +## Getting the EVM Address of a COA + +To get the EVM address of a COA, you can use the `address` function from the `EVM` contract. This function returns the +EVM address of the COA as an `EVM.Address` struct. This struct is used to represent addresses within Flow EVM and can +also be used to query the balance, code, nonce, etc. of an account. + +For our example, we could query the address of the COA we just created with the following script: + +```cadence get_coa_address.cdc +import "EVM" + +access(all) +fun main(address: Address): EVM.EVMAddress { + // Get the desired Flow account holding the COA in storage + let account = getAuthAccount(address) + + // Borrow a reference to the COA from the storage location we saved it to + let coa = account.storage.borrow<&EVM.CadenceOwnedAccount>( + from: /storage/evm + ) ?? panic("Could not borrow reference to the signer's CadenceOwnedAccount (COA). " + .concat("Ensure the signer account has a COA stored in the canonical /storage/evm path")) + + // Return the EVM address of the COA + return coa.address() +} +``` + +If you'd prefer the hex representation of the address, you instead return using the `EVMAddress.toString()` function: + +```cadence +return coa.address().toString() +``` + +The above will return the EVM address as a string; however note that Cadence does not prefix hex strings with `0x`. + +## Getting the Flow Balance of a COA + +Like any other Flow EVM or Cadence account, COAs possess a balance of FLOW tokens. To get the current balance of our +COA, we can use the COA's `balance` function. It will return a `EVM.Balance` struct for the account - these are used to +represent balances within Flow EVM. + +This script will query the current balance of our newly created COA: + +```cadence get_coa_balance.cdc +import "EVM" + +access(all) +fun main(address: Address): EVM.Balance { + // Get the desired Flow account holding the COA in storage + let account = getAuthAccount(address) + + // Borrow a reference to the COA from the storage location we saved it to + let coa = account.storage.borrow<&EVM.CadenceOwnedAccount>( + from: /storage/evm + ) ?? panic("Could not borrow reference to the signer's CadenceOwnedAccount (COA). " + .concat("Ensure the signer account has a COA stored in the canonical /storage/evm path")) + + // Get the current balance of this COA + return coa.balance() +} +``` + +You can also easily get the `UFix64` FLOW balance of any EVM address with this script: + +```cadence get_coa_balance_as_ufix64.cdc +import "EVM" + +access(all) +fun main(addressHex: String): UFix64 { + let addr = EVM.addressFromString(addressHex) + return addr.balance().inFLOW() +} +``` + +The above script is helpful if you already know the COA address and can provide the hex representation directly. + +## Depositing and Withdrawing Flow Tokens + +Tokens can be seamlessly transferred between the Flow EVM and Cadence environment using the `deposit` and `withdraw` +functions provided by the COA resource. Anybody with a valid reference to a COA may deposit Flow tokens into a it, +however only someone with the `Owner` or `Withdraw` entitlements can withdraw tokens. + +### Depositing Flow Tokens + +The `deposit` function takes a `FlowToken.Vault` resource as an argument, representing the tokens to deposit. It will +transfer the tokens from the vault into the COA's balance. + +This transaction will withdraw Flow tokens from a user's Cadence vault and deposit them into their COA: + +```cadence deposit_to_coa.cdc +import "EVM" +import "FungibleToken" +import "FlowToken" + +transaction(amount: UFix64) { + let coa: &EVM.CadenceOwnedAccount + let sentVault: @FlowToken.Vault + + prepare(signer: auth(BorrowValue) &Account) { + // Borrow the public capability to the COA from the desired account + // This script could be modified to deposit into any account with a `EVM.CadenceOwnedAccount` capability + self.coa = signer.capabilities.borrow<&EVM.CadenceOwnedAccount>(/public/evm) + ?? panic("Could not borrow reference to the signer's CadenceOwnedAccount (COA). " + .concat("Ensure the signer account has a COA stored in the canonical /storage/evm path")) + + // Withdraw the balance from the COA, we will use this later to deposit into the receiving account + let vaultRef = signer.storage.borrow( + from: /storage/flowTokenVault + ) ?? panic("Could not borrow reference to the owner's FlowToken Vault") + self.sentVault <- vaultRef.withdraw(amount: amount) as! @FlowToken.Vault + } + + execute { + // Deposit the withdrawn tokens into the COA + self.coa.deposit(from: <-self.sentVault) + } +} +``` + +:::info + +This is a basic example which only transfers tokens between a single user's COA & Flow account. It can be easily +modified to transfer these tokens between any arbitrary accounts. + +You can also deposit tokens directly into other types of EVM accounts using the `EVM.EVMAddress.deposit` function. See +the [EVM contract documentation](../../build/core-contracts/13-evm.md) for more information. + +::: + +### Withdrawing Flow Tokens + +The `withdraw` function takes a `EVM.Balance` struct as an argument, representing the amount of Flow tokens to withdraw, +and returns a `FlowToken.Vault` resource with the withdrawn tokens. + +We can run the following transaction to withdraw Flow tokens from a user's COA and deposit them into their Flow vault: + +```cadence withdraw_from_coa.cdc +import "EVM" +import "FungibleToken" +import "FlowToken" + +transaction(amount: UFix64) { + let sentVault: @FlowToken.Vault + let receiver: &{FungibleToken.Receiver} + + prepare(signer: auth(BorrowValue) &Account) { + // Borrow a reference to the COA from the storage location we saved it to with the `EVM.Withdraw` entitlement + let coa = signer.storage.borrow( + from: /storage/evm + ) ?? panic("Could not borrow reference to the signer's CadenceOwnedAccount (COA). " + .concat("Ensure the signer account has a COA stored in the canonical /storage/evm path")) + + // We must create a `EVM.Balance` struct to represent the amount of Flow tokens to withdraw + let withdrawBalance = EVM.Balance(attoflow: 0) + withdrawBalance.setFLOW(flow: amount) + + // Withdraw the balance from the COA, we will use this later to deposit into the receiving account + self.sentVault <- coa.withdraw(balance: withdrawBalance) as! @FlowToken.Vault + + // Borrow the public capability to the receiving account (in this case the signer's own Vault) + // This script could be modified to deposit into any account with a `FungibleToken.Receiver` capability + self.receiver = signer.capabilities.borrow<&{FungibleToken.Receiver}>(/public/flowTokenReceiver)! + } + + execute { + // Deposit the withdrawn tokens into the receiving vault + self.receiver.deposit(from: <-self.sentVault) + } +} +``` + +:::info + +This is a basic example which only transfers tokens between a single user's COA & Flow account. It can be easily +modified to transfer these tokens between any arbitrary accounts. + +::: + +## Direct Calls to Flow EVM + +To interact with smart contracts on the EVM, you can use the `call` function provided by the COA resource. This function +takes the EVM address of the contract you want to call, the data you want to send, the gas limit, and the value you want +to send. It will return a `EVM.Result` struct with the result of the call - you will need to handle this result in your +Cadence code. + +This transaction will use the signer's COA to call a contract method with the defined signature and args at a given EVM +address, executing with the provided gas limit and value: + +```cadence call.cdc +import "EVM" + +/// Calls the function with the provided signature and args at the target contract address using +/// the defined gas limit and transmitting the provided value. +transaction(evmContractHex: String, signature: String, args: [AnyStruct], gasLimit: UInt64, flowValue: UInt) { + let coa: auth(EVM.Call) &EVM.CadenceOwnedAccount + + prepare(signer: auth(BorrowValue) &Account) { + // Borrow an entitled reference to the COA from the storage location we saved it to + self.coa = signer.storage.borrow( + from: /storage/evm + ) ?? panic("Could not borrow reference to the signer's CadenceOwnedAccount (COA). " + .concat("Ensure the signer account has a COA stored in the canonical /storage/evm path")) + } + + execute { + // Deserialize the EVM address from the hex string + let contractAddress = EVM.addressFromString(evmContractHex) + // Construct the calldata from the signature and arguments + let calldata = EVM.encodeABIWithSignature( + signature, + args + ) + // Define the value as EVM.Balance struct + let value = EVM.Balance(attoflow: flowValue) + // Call the contract at the given EVM address with the given data, gas limit, and value + // These values could be configured through the transaction arguments or other means + // however, for simplicity, we will hardcode them here + let result: EVM.Result = self.coa.call( + to: contractAddress, + data: calldata, + gasLimit: gasLimit, + value: value + ) + + // Revert the transaction if the call was not successful + // Note: a failing EVM call will not automatically revert the Cadence transaction + // and it is up to the developer to use this result however it suits their application + assert( + result.status == EVM.Status.successful, + message: "EVM call to ".concat(evmContractHex) + .concat(" and signature ").concat(signature) + .concat(" failed with error code ").concat(result.errorCode.toString()) + .concat(": ").concat(result.errorMessage) + ) + } +} +``` + +:::info + +Notice that the calldata is encoded in the scope of the transaction. While developers can encode the calldata +outside the scope of the transaction and pass the encoded data as an argument, doing so compromises the +human-readability of Cadence transactions. + +It's encouraged to either define transactions for each COA call and encoded the hardcoded EVM signature and arguments, +or to pass in the human-readable arguments and signature and encode the calldata within the transaction. This ensures a +more interpretable and therefore transparent transaction. + +::: + +### Transferring FLOW in EVM + +Similar to transferring ETH and other native value in other EVMs, you'll want to call to the target EVM address with +empty calldata and providing the transfer value. + +```cadence transfer_evm_flow.cdc +import "EVM" + +/// Transfers FLOW to another EVM address from the signer's COA +/// +/// @param to: the serialized EVM address of the recipient +/// @param amount: the amount of FLOW to send +transaction(to: String, amount: UInt) { + + let recipient: EVM.EVMAddress + let recipientPreBalance: UInt + let coa: auth(EVM.Call) &EVM.CadenceOwnedAccount + + prepare(signer: auth(BorrowValue) &Account) { + self.recipient = EVM.addressFromString(to) + self.recipientPreBalance = self.recipient.balance().attoflow + self.coa = signer.storage.borrow(from: /storage/evm) + ?? panic("Could not borrow reference to the signer's CadenceOwnedAccount (COA). " + .concat("Ensure the signer account has a COA stored in the canonical /storage/evm path")) + } + + execute { + let res = self.coa.call( + to: self.recipient, + data: [], + gasLimit: 100_000, + value: EVM.Balance(attoflow: amount) + ) + + assert( + res.status == EVM.Status.successful, + message: "Failed to transfer FLOW to EVM address with error code ".concat(res.errorCode.toString()) + .concat(": ").concat(res.errorMessage) + ) + } + + post { + self.recipient.balance().attoflow == self.recipientPreBalance + amount: + "Expected final balance ".concat((self.recipientPreBalance + amount).toString()) + .concat(" but found actual balance ").concat(self.recipient.balance().attoflow.toString()) + .concat(" after deposit of ").concat(amount.toString()) + } +} +``` + +### Transfer ERC20 + +Below is an example transaction demonstrating the common ERC20 transfer. A similar pattern can be used for other +arbitrary EVM calls. + +```cadence erc20_transfer_from.cdc +import "EVM" + +/// Transfers ERC20 tokens from the signer's COA to the named recipient in the amount provided +/// +/// @param erc20AddressHex: the serialized EVM address of the ERC20 contract +/// @param to: the serialized EVM address of the recipient +/// @param amount: the amount of tokens to send +transaction(erc20AddressHex: String, to: String, amount: UInt256) { + let coa: auth(EVM.Call) &EVM.CadenceOwnedAccount + + prepare(signer: auth(BorrowValue) &Account) { + // Borrow an entitled reference to the COA from the canonical storage location + self.coa = signer.storage.borrow( + from: /storage/evm + ) ?? panic("Could not borrow reference to the signer's CadenceOwnedAccount (COA). " + .concat("Ensure the signer account has a COA stored in the canonical /storage/evm path")) + } + + execute { + // Encode the calldata for the ERC20 transfer + let calldata = EVM.encodeABIWithSignature( + "transfer(address,uint256)", // function signature + [EVM.addressFromString(to), amount] // function args + ) + // Call the contract at the given ERC20 address with encoded calldata and 0 value + let result: EVM.Result = self.coa.call( + to: EVM.addressFromString(erc20AddressHex), // deserialized address + data: calldata, // encoded calldata + gasLimit: 100_000, // 100k gas should cover most erc20 transfers + value: EVM.Balance(attoflow: UInt(0)) // no value required in most cases + ) + + // Revert the transaction if the call was not successful + // Note: a failing EVM call will not automatically revert the Cadence transaction + // and it is up to the developer to use this result however it suits their application + assert( + result.status == EVM.Status.successful, + message: "ERC20.transfer call failed with error code: ".concat(result.errorCode.toString()) + .concat(": ").concat(result.errorMessage) + ) + } +} +``` + +### Transfer ERC721 + +Following on from above, the example transaction below demonstrates a common ERC721 transfer. + +```cadence erc721_transfer.cdc +import "EVM" + +/// Transfers an ERC721 token from the signer's COA to the named recipient +/// +/// @param erc721AddressHex: the serialized EVM address of the ERC721 contract +/// @param to: the serialized EVM address of the recipient +/// @param id: the token ID to send from the signer's COA to the recipient +transaction(erc721AddressHex: String, to: String, id: UInt256) { + let coa: auth(EVM.Call) &EVM.CadenceOwnedAccount + + prepare(signer: auth(BorrowValue) &Account) { + // Borrow an entitled reference to the COA from the canonical storage location + self.coa = signer.storage.borrow( + from: /storage/evm + ) ?? panic("Could not borrow reference to the signer's CadenceOwnedAccount (COA). " + .concat("Ensure the signer account has a COA stored in the canonical /storage/evm path")) + } + + execute { + let calldata = EVM.encodeABIWithSignature( + "safeTransferFrom(address,address,uint256)", + [self.coa.address(), EVM.addressFromString(to), id] + ) + // Call the contract at the given ERC721 address with encoded calldata and 0 value + let result: EVM.Result = self.coa.call( + to: EVM.addressFromString(erc721AddressHex), // deserialized address + data: calldata // previously encoded calldata + gasLimit: 100_000, // 100k gas should cover most erc721 transfers + value: EVM.Balance(attoflow: UInt(0)) // no value required in most cases + ) + + // Revert the transaction if the call was not successful + // Note: a failing EVM call will not automatically revert the Cadence transaction + // and it is up to the developer to use this result however it suits their application + assert( + result.status == EVM.Status.successful, + message: "ERC721.safeTransferFrom call failed with error code: ".concat(result.errorCode.toString()) + .concat(": ").concat(result.errorMessage) + ) + } +} +``` + +#### Bulk Transfer ERC721 + +As covered in the [Batched EVM transactions walkthrough](./batched-evm-transactions.md), you can script multiple EVM +calls in a single Cadence transaction. Compared to the single ERC721 transfer, bulk sending multiple tokens isn't much +more code and allows for greater utility out of a single transaction. Below is an example of a bulk ERC721 token +transfer. + +```cadence erc721_bulk_transfer.cdc +import "EVM" + +/// Bulk transfers ERC721 tokens from the signer's COA to the named recipient. All tokens must be from +/// the same collection and sent to the same recipient. +/// +/// @param erc721AddressHex: the serialized EVM address of the ERC721 contract +/// @param to: the serialized EVM address of the recipient +/// @param ids: an array of IDs to send from the signer's COA to the recipient +transaction(erc721AddressHex: String, to: String, ids: [UInt256]) { + let coa: auth(EVM.Call) &EVM.CadenceOwnedAccount + + prepare(signer: auth(BorrowValue) &Account) { + // Borrow an entitled reference to the COA from the canonical storage location + self.coa = signer.storage.borrow( + from: /storage/evm + ) ?? panic("Could not borrow reference to the signer's CadenceOwnedAccount (COA). " + .concat("Ensure the signer account has a COA stored in the canonical /storage/evm path")) + } + + execute { + // Iterate over provided IDs. Note the whole transaction fails if a single transfer fails, + // so ownership validation is recommended before executing. Alternatively, you could remove + // the assertion on success below and continue iteration on call failure. + for id in ids { + let calldata = EVM.encodeABIWithSignature( + "safeTransferFrom(address,address,uint256)", + [self.coa.address(), EVM.addressFromString(to), id] + ) + // Call the contract at the given ERC721 address with encoded calldata and 0 value + let result: EVM.Result = self.coa.call( + to: EVM.addressFromString(erc721AddressHex), // deserialized address + data: calldata // previously encoded calldata + gasLimit: 100_000, // 100k gas should cover most erc721 transfers + value: EVM.Balance(attoflow: UInt(0)) // no value required in most cases + ) + + // Revert the transaction if the transfer was not successful + // Note: a failing EVM call will not automatically revert the Cadence transaction + // and it is up to the developer to use this result however it suits their application + assert( + result.status == EVM.Status.successful, + message: "ERC721.safeTransferFrom call failed on id ".concat(id.toString()) + .concat(" with error code: ").concat(result.errorCode.toString()) + .concat(": ").concat(result.errorMessage) + ) + } + } +} +``` + +## Deploying a Contract to Flow EVM + +To deploy a contract to the EVM, you can use the `deploy` function provided by the COA resource. This function takes the +contract code, gas limit, and value you want to send. It will return the EVM address of the newly deployed contract. + +This transaction will deploy a contract with the given code using the signer's COA: + +```cadence deploy_evm_contract.cdc +import "EVM" + +transaction(bytecode: String) { + let coa: auth(EVM.Deploy) &EVM.CadenceOwnedAccount + + prepare(signer: auth(BorrowValue) &Account) { + // Borrow an entitled reference to the COA from the storage location we saved it to + self.coa = signer.storage.borrow( + from: /storage/evm + ) ?? panic("Could not borrow reference to the signer's CadenceOwnedAccount (COA). " + .concat("Ensure the signer account has a COA stored in the canonical /storage/evm path")) + } + + execute { + // Deploy the contract with the given compiled bytecode, gas limit, and value + self.coa.deploy( + code: bytecode.decodeHex(), + gasLimit: 15_000_000, // can be adjusted as needed, hard coded here for simplicity + value: EVM.Balance(attoflow: 0) + ) + } +} +``` + +## More Information + +For more information about Cadence Owned Accounts, see [Flow EVM Accounts](../../evm/accounts.md). + +Other useful snippets for interacting with COAs can be found [here](https://fw-internal-doc.gitbook.io/evm). + +Check out the [Batched EVM Transactions walkthrough](./batched-evm-transactions.md) for details on transaction batching +using Cadence. \ No newline at end of file diff --git a/static/markdown/tutorials/cross-vm-apps/introduction.md b/static/markdown/tutorials/cross-vm-apps/introduction.md new file mode 100644 index 0000000000..702a680692 --- /dev/null +++ b/static/markdown/tutorials/cross-vm-apps/introduction.md @@ -0,0 +1,832 @@ +--- +title: Batched Tx From Scaffold +description: Learn how to use FCL with wagmi and rainbowkit to create a cross-vm app - one that is simultaneously connected to Flow EVM and Flow Cadence. +sidebar_position: 0 +keywords: + - hybrid apps + - cross-vm apps + - FCL + - wagmi + - RainbowKit + - viem + - Flow EVM + - Flow Cadence + - cross-VM + - multi-call + - batch transactions + - web3 + - dapp development + - wallet integration + - smart contracts + - blockchain development + - supercharge your EVM app with Cadence +--- + +Ever since the launch of Flow EVM, it's been possible to _supercharge_ your EVM apps by using Flow Cadence features and contracts. Some benefits, such as [native VRF] and inexpensive gas without compromising security are built in and either easy or automatic to use. Others, such as the ability to use [Cadence] to [structure and call EVM transactions], are powerful but complicated to configure and use. They also require developers to manage concurrent connections to both networks. + +[FLIP 316] improves the [Flow Client Library (FCL)] to support cross-VM functionality between Flow EVM and Flow Cadence. + +For EVM developers, this means that you can use the familiar [wagmi], [viem], and [RainbowKit] stack you're used to, add FCL, and get features like **multi-call write** with one signature for users with a Cadence-compatible [wallet]. + +In this tutorial, you'll learn how to create [Click to Mint], a simple game that allows players to mint an ERC-20 token by clicking a button. With the power of Flow, they can also click a button, and **complete 10 separate transactions with just one approval!** + +![Click to Mint](click-to-mint.png) + +:::warning + +The FCL functionality described in this tutorial is in alpha. Some steps may change. We'll keep the tutorial updated, but please [create an issue] or let us know on [Discord] if something isn't working for you. + +::: + +## Objectives + +After completing this guide, you'll be able to: + +- Build an app that seamlessly integrates Flow Cadence and Flow EVM connections +- Add Cadence features to your [Rainbowkit]/[wagmi]/[viem] app +- Utilize [Flow Client Library (FCL)] to enable multi-call contract writes to Flow EVM + +## Prerequisites + +### Next.js and Modern Frontend Development + +This tutorial uses [Next.js]. You don't need to be an expert, but it's helpful to be comfortable with development using a current React framework. You'll be on your own to select and use a package manager, manage Node versions, and other frontend environment tasks. If you don't have your own preference, you can just follow along with us and use [npm]. + +### Solidity and Cadence Smart Contract Development + +Apps using the hybrid approach can interact with both [Cadence] and [Solidity] smart contracts. You don't need to be an expert in either of these, but it's helpful to be familiar with how smart contracts work in at least one of these languages. + +### Onchain App Frontends + +We're assuming you're familiar with [wagmi], [viem], and [RainbowKit]. If you're coming from the Cadence, you might want to take a quick look at the getting started guides for these platforms. They're all excellent and will rapidly get you up to speed on how the EVM world commonly connects their apps to their contracts. + +## Getting Started + +For this tutorial, we'll be starting from a fork of the [FCL + RainbowKit + Wagmi Integration Demo] built by the team. + +Fork the repo so you can push your work freely to your own copy, then follow the setup instructions. + +## Project Overview + +Open the cross-vm app scaffold in your editor, run it, and view the site in your browser: + +```bash +npm run dev +``` + +You'll see: + +![Hybrid App Demo](hybrid-app-demo.png) + +Connect with a Cadence-compatible [wallet]. + +:::warning + +In a production app, you'll want to manage this process carefully. Non-Cadence EVM wallets may be able to connect, but they will **not** be able to use any Cadence features. + +::: + +## Send Batch Transactions + +The first demo built into this scaffold is **multi-call contract write**. + +On Flow, this isn't an unstable experimental feature - it's a demonstration of the power of EVM + Cadence. + +Click `Send Batch Transaction Example` and approve the transaction. You'll see three lines appear on the page, similar to: + +``` +{"isPending":false,"isError":false,"txId":"b3c2b8c86e68177af04324152d45d9de9c2a118ff8f090476b3a07e0c9554912","results":[{"hash":"0x46e923a08d9008632e3782ea512c4c590d4650ba58b3e8b49628f58e6adddaa9","status":"passed","errorMessage":""},{"hash":"0x52c82dc689cd5909519f8a90d0a1ec2e74192d7603fd3b5d33f7f4d54a618a84","status":"passed","errorMessage":""}]} +``` + +:::tip + +Currently, the Flow wallet sponsors all gas for all transactions signed with the wallet on both testnet **and mainnet!** + +::: + +### Cadence Parent Transaction + +The first line is the transaction id of the Flow Cadence transaction that calls **both** of the EVM transactions. Search for it in [Testnet Cadence Flowscan]. + +Cadence transactions are more complicated than those in Solidity contracts. Rather than being restricted to running functions present on the contract, they can run arbitrary code as long as the caller has access to all of the resources required by the transaction. + +You can see the code of the transaction in the `Script` tab, but we've included it here for convenience: + +```cadence +import EVM from 0x8c5303eaa26202d6 + +transaction(calls: [{String: AnyStruct}], mustPass: Bool) { + + let coa: auth(EVM.Call) &EVM.CadenceOwnedAccount + + // Borrow a reference to the EVM account that has the ability to sign transactions + prepare(signer: auth(BorrowValue) & Account) { + let storagePath = /storage/evm + self.coa = signer.storage.borrow(from: storagePath) + ?? panic("No CadenceOwnedAccount (COA) found at ".concat(storagePath.toString())) + } + + // Iterate through the list of provided EVM transactions + execute { + for i, call in calls { + let to = call["to"] as! String + let data = call["data"] as! String + let gasLimit = call["gasLimit"] as! UInt64 + let value = call["value"] as! UInt + + let result = self.coa.call( + to: EVM.addressFromString(to), + data: data.decodeHex(), + gasLimit: gasLimit, + value: EVM.Balance(attoflow: value) + ) + + if mustPass { + assert( + result.status == EVM.Status.successful, + message: "Call index ".concat(i.toString()).concat(" to ").concat(to) + .concat(" with calldata ").concat(data).concat(" failed: ") + .concat(result.errorMessage) + ) + } + } + } +``` + +In this case, it's checking that the caller of the Cadence transaction has permission to control to the EVM account, which is built in for [Cadence Owned Accounts]. The `execute` phase then iterates through the EVM transactions and uses the Cadence accounts own permissions to sign the EVM transactions. + +The loop also handles a check for the optional flag to cancel all of the transactions if any one of them fails. **In other words, you could set up a 20 transaction arbitrage attempt and unwind everything if it fails at any step!** + +### EVM Child Transactions + +The next two lines show the transaction hashes for the EVM transactions. You can view this in [Testnet EVM Flowscan] by searching for the transaction hashes, the same as any other. + +Look up both transactions. + +The first is calling the `deposit()` function to wrap FLOW and move it to EVM. + +The second is calling the ERC-20 `approve()` function to give another address the authority to spend those tokens. + +For the demo, the code for this is hard-coded into `src/app/page.tsx`: + +```tsx +const calls: EVMBatchCall[] = [ + { + // Call deposit() function (wrap FLOW) on the token contract. + address: '0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e', // Replace with your actual token contract address. + abi: [ + { + inputs: [], + name: 'deposit', + outputs: [], + stateMutability: 'payable', + type: 'function', + }, + ], + functionName: 'deposit', + args: [], // deposit takes no arguments; value is passed with the call. + }, + { + // Call approve() function (ERC20 style) on the same token contract. + address: '0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e', // Replace with your actual token contract address if needed. + abi: [ + { + inputs: [ + { name: 'spender', type: 'address' }, + { name: 'value', type: 'uint256' }, + ], + name: 'approve', + outputs: [{ name: '', type: 'bool' }], + stateMutability: 'nonpayable', + type: 'function', + }, + ], + functionName: 'approve', + args: [ + '0x2E2Ed0Cfd3AD2f1d34481277b3204d807Ca2F8c2', // Spender address. + BigInt('1000000000000000000'), // Approve 1 token (assuming 18 decimals). + ], + }, +]; +``` + +It's called with the `useBatchTransaction` hook via the `sendBatchTransaction(calls)` function. + +## Code Evaluator + +The demo also has an embedded code evaluator that you can use to experiment with snippets of code from `fcl` or `wagmi`. + +For example: + +```tsx +const user = await fcl.currentUser().snapshot(); +return user.addr; +``` + +Will return your Cadence address. This snippet: + +```tsx +const block = await fcl.block(); +return block.height; +``` + +Returns the current Cadence VM block number. + +## Calling Your Own Contract + +Next, we'll update the starter to connect to and call functions in our own contract. For this, we'll use a simple [Button Clicker Contract]. You can deploy your own copy, or use the one deployed at [`0xA7Cf2260e501952c71189D04FAd17c704DFB36e6`]. + +## Set Up Contract Imports + +:::info + +The following steps assume deployment with Hardhat Ignition. If you are using a different deployment method, import the contract address and abi as appropriate. + +::: + +In your fork of the app, add a folder called `contracts` to the `src` folder. In it, copy over ['deployed_addresses.json`] from `ignition/deployments/chain-545` in the Button Clicker repo, and `ignition/deployments/chain-545/ClickTokenModule#ClickToken.json`. + +Next, create a folder called `constants` and add a file called `contracts.ts` to it. + +In it, import the contract artifact and addresses file, and create export a constant with this information. + +```tsx + + + +export const clickToken = { + abi: ClickToken.abi, + address: deployedAddresses['ClickTokenModule#ClickToken'] as `0x${string}`, +}; +``` + +## Build Traditional Functionality + +This isn't a wagmi tutorial, so we'll give you some components to speed up the process. Add a folder called `components` inside `src` and add the following files. + +`TheButton.tsx` + +```tsx +'use client'; + + + + +interface theButtonProps { + // eslint-disable-next-line + writeContract: Function; + awaitingResponse: boolean; + setAwaitingResponse: (value: boolean) => void; +} + +export default function TheButton({ + writeContract, + awaitingResponse, + setAwaitingResponse, +}: theButtonProps) { + const account = useAccount(); + + function handleClick() { + setAwaitingResponse(true); + writeContract({ + abi: clickToken.abi, + address: clickToken.address, + functionName: 'mintTo', + args: [account.address], + gas: 45000, + }); + } + + return ( + <> + {!awaitingResponse && ( + + )} + {awaitingResponse && ( + + )} + + ); +} +``` + +`TopTenDisplay.tsx` + +```tsx + + + + + + +type scoreBoardEntry = { + user: string; + value: bigint; +}; + +interface TopTenDisplayProps { + reloadScores: boolean; + setReloadScores: (value: boolean) => void; +} + +export default function TopTenDisplay({ + reloadScores, + setReloadScores, +}: TopTenDisplayProps) { + const [scores, setScores] = useState([]); + + const account = useAccount(); + const queryClient = useQueryClient(); + + const { data: scoresData, queryKey: getAllScoresQueryKey } = useReadContract({ + abi: clickToken.abi, + address: clickToken.address as `0x${string}`, + functionName: 'getAllScores', + }); + + useEffect(() => { + if (scoresData) { + const sortedScores = scoresData as scoreBoardEntry[]; + // Sort scores in descending order + sortedScores.sort((a, b) => Number(b.value) - Number(a.value)); + + setScores(sortedScores); + } + }, [scoresData]); + + useEffect(() => { + if (reloadScores) { + console.log('Reloading scores...'); + queryClient.invalidateQueries({ queryKey: getAllScoresQueryKey }); + setReloadScores(false); + } + }, [reloadScores]); + + function renderAddress(address: string) { + return address?.slice(0, 5) + '...' + address?.slice(-3); + } + + function renderTopTen() { + if (scores.length === 0 || !account) { + return ( +
      +
    1. Loading...
    2. +
    + ); + } + // Only display the top 10 scores. If the user is in the top 10, bold the item with their score. If not, show it at the bottom with their ranking number + const topTen = scores.length > 10 ? scores.slice(0, 10) : scores; + // myRank is my address's position in the array of scores, +1. If it's not present, my rank is the length of the array + const myRank = + scores.findIndex((entry) => entry.user === account?.address) + 1 || + scores.length + 1; + + const topTenList = topTen.map((entry, index) => { + return ( +
  • + {entry.user === account.address ? ( + + {index + 1} -- {renderAddress(entry.user)} --{' '} + {formatUnits(entry.value, 18)} + + ) : ( + <> + {index + 1} -- {renderAddress(entry.user)} --{' '} + {formatUnits(entry.value, 18)} + + )} +
  • + ); + }); + + // Append my score if myRank is > 10 + if (account?.address && (myRank > 10 || myRank > scores.length)) { + topTenList.push( +
  • + + {myRank} -- {renderAddress(account.address.toString())} --{' '} + {myRank > scores.length + ? 0 + : formatUnits(scores[myRank - 1].value, 18)} + +
  • , + ); + } + + return
      {topTenList}
    ; + } + + return ( +
    +

    Top 10 Scores

    + {renderTopTen()} +
    + ); +} +``` + +`Content.tsx` + +```tsx +'use client'; + + + +import { + useWaitForTransactionReceipt, + useWriteContract, + useAccount, +} from 'wagmi'; + + +export default function Content() { + const [reload, setReload] = useState(false); + const [awaitingResponse, setAwaitingResponse] = useState(false); + + const account = useAccount(); + + const { data, writeContract, error: writeError } = useWriteContract(); + + const { data: receipt, error: receiptError } = useWaitForTransactionReceipt({ + hash: data, + }); + + useEffect(() => { + if (receipt) { + console.log('Transaction receipt:', receipt); + setReload(true); + setAwaitingResponse(false); + } + }, [receipt]); + + useEffect(() => { + if (writeError) { + console.error(writeError); + setAwaitingResponse(false); + } + }, [writeError]); + + useEffect(() => { + if (receiptError) { + console.error(receiptError); + setAwaitingResponse(false); + } + }, [receiptError]); + + return ( +
    + {account.address && ( +
    + +
    + )} +
    + {} +
    + ); +} +``` + +Then, import and add `` to `page.tsx`: + +```tsx +return ( + <> +
    + +
    +

    Flow Address: {flowAddress}

    +

    EVM Address: {coa?.address}

    +
    + + {

    {JSON.stringify({ isPending, isError, txId, results })}

    } + + +); +``` + +You'll now see the button and scoreboard from the contract. Test it out and earn a few points! + +![scores](scores.png) + +## Supercharge your EVM App With Cadence + +Now let's supercharge it. With the power of Cadence, you can use multi-call write and give your users way more tokens with a single click and single signature! + +For the first pass, we'll skip some organization best practices. + +Import `clickToken` into `page.tsx` and update `calls` to instead call the `mint` function from the Button Clicker contract. + +```tsx +const calls: EVMBatchCall[] = [ + { + address: clickToken.address, + abi: clickToken.abi as Abi, + functionName: 'mintTo', + args: [coa?.address], + }, +]; +``` + +Try clicking the `Send Batch Transaction Example` button again. You'll have to **manually refresh** the page when the EVM transaction hash appears to see the score update. We haven't wired in the query invalidation yet. + +Next, use some JavaScript to put 10 copies of the transaction call into the array: + +```tsx +const calls: EVMBatchCall[] = Array.from({ length: 10 }, () => ({ + address: clickToken.address, + abi: clickToken.abi as Abi, + functionName: 'mintTo', + args: [coa?.address], +})); +``` + +Click the button again and **manually** refresh page once the transaction hashes appear. + +**You just minted 10 tokens from 10 transactions with one signature!** + +## Improve the UI/UX + +While we've got the batched transactions feature working, we've got a few flaws in the user experience that we'll need to resolve, and we should make this a bit nicer looking. + +### Install Tailwind + +:::warning + +We initially tried getting an AI friend to install this for us and it got very confused. Next.js and Tailwind have both had a lot of change recently. As a result, the LLMs don't seem to have caught up just yet. + +Do this part the old-fashioned way. + +::: + +The components we borrowed already use [Tailwind], so install it: + +```bash +npm install tailwindcss @tailwindcss/postcss postcss +``` + +Then, in the root of the project, add `postcss.config.mjs` and add: + +```tsx +const config = { + plugins: { + '@tailwindcss/postcss': {}, + }, +}; +export default config; +``` + +Then, add the following to the top of `src/styles/global.css`: + +```css +@import 'tailwindcss'; +``` + +Run the app and make sure you see some styling. It won't look nice yet. We'll help you reorganize the components and hook up state monitoring, but it will be up to you to style the app how you'd like. You can check out the [reference repo] for inspiration, but it's far from perfect or beautiful. + +### Update State Display + +The first thing we'll need to fix is that the user has to refresh the window manually to see the results of the batched transaction in the scoreboard. Start by moving the functionality in `page.tsx` into a new component, called `SuperButton.tsx`. Note that we're mimicking the pattern in `TheButton.tsx` where the blockchain state is managed in `Content.tsx` and we're passing in the relevant information and functions as props: + +```tsx +'use client'; + + + + + + +interface SuperButtonProps { + flowAddress: string | null; + awaitingResponse: boolean; + setAwaitingResponse: (value: boolean) => void; + sendBatchTransaction: (calls: EVMBatchCall[]) => void; + isPending: boolean; + isError: boolean; + txId: string; + results: CallOutcome[]; +} + +export default function SuperButton({ + flowAddress, + awaitingResponse, + setAwaitingResponse, + sendBatchTransaction, + isPending, + isError, + txId, + results, +}: SuperButtonProps) { + const account = useAccount(); + + const calls: EVMBatchCall[] = Array.from({ length: 10 }, () => ({ + address: clickToken.address, + abi: clickToken.abi as Abi, + functionName: 'mintTo', + args: [account?.address], + })); + + function handleClick() { + setAwaitingResponse(true); + sendBatchTransaction(calls); + } + + return ( +
    +
    + With the{' '} + + Flow Wallet + + , you can sign 10 mint transactions at once! +
    + {!awaitingResponse && ( + + )} + {awaitingResponse && ( + + )} + {

    {JSON.stringify({ isPending, isError, txId, results })}

    } +
    + ); +} +``` + +You should end up with a vastly simplified `page.tsx`: + +```tsx + + +function Page() { + return ( + <> + + + ); +} + +export default Page; +``` + +Next, update `Content.tsx`. First, add the decomposition of the `useBatchTransactions` hook that used to be in `page.tsx`. You'll keep blockchain-state-related code here, in a similar pattern to `useWriteTransaction`. + +```tsx + +``` + +```tsx +const { sendBatchTransaction, isPending, isError, txId, results } = + useBatchTransaction(); +``` + +You'll also need to move the `useEffect` that subscribes to the current user on the Cadence side: + +```tsx +useEffect(() => { + const unsub = fcl.currentUser().subscribe((user: CurrentUser) => { + setFlowAddress(user.addr ?? null); + }); + return () => unsub(); +}, []); +``` + +Then, update the `useEffect` that waits for a `receipt` to also trigger if `results` is updated with the result of a batched transaction: + +```tsx +useEffect(() => { + if (receipt || results.length > 0) { + console.log('Transaction receipt:', receipt); + setReload(true); + setAwaitingResponse(false); + } +}, [receipt, results]); +``` + +Finally, reorganize the `return` into two side-by-side cards and put the new component in the right card: + +```tsx +return ( +
    +
    + +
    +

    Flow Address: {flowAddress}

    +

    EVM Address: {account?.address}

    +
    +
    +
    + {account.address && ( +
    + +
    + )} +
    +
    + +
    + {} +
    +); +``` + +### Testing + +Run the app and make sure it's working as expected, even if in a rather ugly fashion. + +### Add UI Hints + +With this kind of app, you're likely to have two types of users. Those that have upgraded to the [Flow Wallet] can take advantage of advanced features such as batched transactions, and those who haven't cannot. + +It's up to you do design a comprehensive strategy for your app, but here, we can at least let users know what's going on. Add some explainer text, and configure the button to show an appropriate message and disable itself if the wallet won't support it. + +```tsx +
    + With the Flow Wallet, you can sign 10 mint transactions at once! +
    + +``` + +### Styling + +It's up to you to make the app pretty. If you need inspiration, you can always check the [reference repo]. + +## Conclusion + +In this tutorial, you reviewed the demo starter for building hybrid applications that utilize a common EVM stack and integrate with Flow Cadence. You then added functionality to interface with another contract that mints ERC-20 tokens. Finally, you supercharged your app by using the power of Cadence for EVM multi-call contract writes. + +Now that you have completed the tutorial, you should be able to: + +- Build an app that seamlessly integrates Flow Cadence and Flow EVM connections +- Add Cadence features to your [Rainbowkit]/[wagmi]/[viem] app +- Utilize [Flow Client Library (FCL)] to enable multi-call contract writes to Flow EVM + + + +[Cadence]: https://cadence-lang.org/docs +[Next.js]: https://nextjs.org/docs/app/getting-started/installation +[npm]: https://www.npmjs.com/ +[Click to Mint]: https://clicktomint.vercel.app/ +[create an issue]: https://github.com/onflow/docs/issues/new/choose +[Cadence]: https://cadence-lang.org +[Solidity]: https://soliditylang.org/ +[native VRF]: ../../evm/guides/vrf.md +[structure and call EVM transactions]: ./batched-evm-transactions.md +[FLIP 316]: https://github.com/onflow/flips/pull/317 +[Flow Client Library (FCL)]: ../../tools/clients/fcl-js +[wagmi]: https://wagmi.sh/ +[viem]: https://viem.sh/ +[RainbowKit]: https://www.rainbowkit.com/ +[wallet]: ../../ecosystem/wallets.md +[Discord]: https://discord.com/channels/613813861610684416/1162086721471647874 +[FCL + RainbowKit + Wagmi Integration Demo]: https://github.com/jribbink/cross-vm-app +[FCL-JS]: https://github.com/onflow/fcl-js +[Testnet Cadence Flowscan]: https://testnet.flowscan.io +[Cadence Owned Accounts]: ../../build/basics/accounts.md +[Testnet EVM Flowscan]: https://evm-testnet.flowscan.io +[Button Clicker Contract]: https://github.com/briandoyle81/button-clicker-contract/blob/main/contracts/ClickToken.sol +[`0xA7Cf2260e501952c71189D04FAd17c704DFB36e6`]: https://evm-testnet.flowscan.io/address/0xA7Cf2260e501952c71189D04FAd17c704DFB36e6?tab=contract +[Tailwind]: https://tailwindcss.com/ +[reference repo]: https://github.com/briandoyle81/cross-vm-app-1/tree/main \ No newline at end of file diff --git a/static/markdown/tutorials/cross-vm-apps/vm-bridge.md b/static/markdown/tutorials/cross-vm-apps/vm-bridge.md new file mode 100644 index 0000000000..905cf0b9ff --- /dev/null +++ b/static/markdown/tutorials/cross-vm-apps/vm-bridge.md @@ -0,0 +1,312 @@ +--- +title: Cross-VM Bridge +sidebar_label: Cross-VM Bridge +sidebar_position: 7 +--- + +# Cross-VM Bridge + +Flow provides the [Cross-VM Bridge](https://www.github.com/onflow/flow-evm-bridge) which enables the movement of +fungible and non-fungible tokens between Cadence & EVM. The Cross-VM Bridge is a contract-based protocol enabling the +automated and atomic bridging of tokens from Cadence into EVM with their corresponding ERC-20 and ERC-721 token types. +In the opposite direction, it supports bridging of arbitrary ERC-20 and ERC-721 tokens from EVM to Cadence as their +corresponding FT or NFT token types. + +The Cross-VM Bridge internalizes the capabilities to deploy new token contracts in either VM state as needed, resolving +access to, and maintaining links between associated contracts. It additionally automates account and contract calls to +enforce source VM asset burn or lock, and target VM token mint or unlock. + +Developers wishing to use the Cross-VM Bridge will be required to use a Cadence transaction. Cross-VM bridging +functionality is not currently available natively in Flow EVM. By extension, this means that the EVM account bridging +from EVM to Cadence must be a [`CadenceOwnedAccount` (COA)](./interacting-with-coa.md) as this is the only EVM account +type that can be controlled from the Cadence runtime. + +This [FLIP](https://github.com/onflow/flips/pull/233) outlines the architecture and implementation of the VM bridge. +This document will focus on how to use the Cross-VM Bridge and considerations for fungible and non-fungible token +projects deploying to either Cadence or EVM. + +## Deployments + +The core bridge contracts can be found at the following addresses: + +| Contracts | Testnet | Mainnet | +| ------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- | +| All Cadence Bridge contracts | [`0xdfc20aee650fcbdf`](https://contractbrowser.com/account/0xdfc20aee650fcbdf/contracts) | [`0x1e4aa0b87d10b141`](https://contractbrowser.com/account/0x1e4aa0b87d10b141/contracts) | +| `FlowEVMBridgeFactory.sol` | [`0xf8146b4aef631853f0eb98dbe28706d029e52c52`](https://evm-testnet.flowscan.io/address/0xF8146B4aEF631853F0eB98DBE28706d029e52c52) | [`0x1c6dea788ee774cf15bcd3d7a07ede892ef0be40`](https://evm.flowscan.io/address/0x1C6dEa788Ee774CF15bCd3d7A07ede892ef0bE40) | +| `FlowEVMBridgeDeploymentRegistry.sol` | [`0x8781d15904d7e161f421400571dea24cc0db6938`](https://evm-testnet.flowscan.io/address/0x8781d15904d7e161f421400571dea24cc0db6938) | [`0x8fdec2058535a2cb25c2f8cec65e8e0d0691f7b0`](https://evm.flowscan.io/address/0x8FDEc2058535A2Cb25C2f8ceC65e8e0D0691f7B0) | +| `FlowEVMBridgedERC20Deployer.sol` | [`0x4d45CaD104A71D19991DE3489ddC5C7B284cf263`](https://evm-testnet.flowscan.io/address/0x4d45CaD104A71D19991DE3489ddC5C7B284cf263) | [`0x49631Eac7e67c417D036a4d114AD9359c93491e7`](https://evm.flowscan.io/address/0x49631Eac7e67c417D036a4d114AD9359c93491e7) | +| `FlowEVMBridgedERC721Deployer.sol` | [`0x1B852d242F9c4C4E9Bb91115276f659D1D1f7c56`](https://evm-testnet.flowscan.io/address/0x1B852d242F9c4C4E9Bb91115276f659D1D1f7c56) | [`0xe7c2B80a9de81340AE375B3a53940E9aeEAd79Df`](https://evm.flowscan.io/address/0xe7c2B80a9de81340AE375B3a53940E9aeEAd79Df) | + +And below are the bridge escrow's EVM addresses. These addresses are COAs and are stored stored in the same Flow account +as you'll find the Cadence contracts (see above). + +| Network | Address | +| ------- | ---------------------------------------------------------------------------------------------------------------------------------- | +| Testnet | [`0x0000000000000000000000023f946ffbc8829bfd`](https://evm-testnet.flowscan.io/address/0x0000000000000000000000023f946FFbc8829BFD) | +| Mainnet | [`0x00000000000000000000000249250a5c27ecab3b`](https://evm.flowscan.io/address/0x00000000000000000000000249250a5C27Ecab3B) | + +## Interacting With the Bridge + +:::info + +All bridging activity in either direction is orchestrated via Cadence on COA EVM accounts. This means that all bridging +activity must be initiated via a Cadence transaction, not an EVM transaction regardless of the directionality of the +bridge request. For more information on the interplay between Cadence and EVM, see [How Flow EVM +Works](../../evm/how-it-works.md). + +::: + +### Overview + +The Flow EVM bridge allows both fungible and non-fungible tokens to move atomically between Cadence and EVM. In the +context of EVM, fungible tokens are defined as ERC20 tokens, and non-fungible tokens as ERC721 tokens. In Cadence, +fungible tokens are defined by contracts implementing +[the `FungibleToken` interface](https://github.com/onflow/flow-ft/blob/master/contracts/FungibleToken.cdc) +and non-fungible tokens implement +[the `NonFungibleToken` interface](https://github.com/onflow/flow-nft/blob/master/contracts/NonFungibleToken.cdc). + +Like all operations on Flow, there are native fees associated with both computation and storage. To prevent spam and +sustain the bridge account's storage consumption, fees are charged for both onboarding assets and bridging assets. In +the case where storage consumption is expected, fees are charged based on the storage consumed at the current network +storage rate. + +### Onboarding + +Since a contract must define the asset in the target VM, an asset must be "onboarded" to the bridge before requests can +be fulfilled. + +Moving from Cadence to EVM, onboarding can occur on the fly, deploying a template contract in the same transaction as +the asset is bridged to EVM if the transaction so specifies. + +Moving from EVM to Cadence, however, requires that onboarding occur in a separate transaction due to the fact that a +Cadence contract is initialized at the end of a transaction and isn't available in the runtime until after the +transaction has executed. + +Below are transactions relevant to onboarding assets: + +
    +onboard_by_type.cdc + +```cadence onboard_by_type.cdc +!from https://www.github.com/onflow/flow-evm-bridge/blob/main/cadence/transactions/bridge/onboarding/onboard_by_type.cdc +``` + +
    + +
    +onboard_by_evm_address.cdc + +```cadence onboard_by_evm_address.cdc +!from https://www.github.com/onflow/flow-evm-bridge/blob/main/cadence/transactions/bridge/onboarding/onboard_by_evm_address.cdc +``` + +
    + +### Bridging + +Once an asset has been onboarded, either by its Cadence type or EVM contract address, it can be bridged in either +direction, referred to by its Cadence type. For Cadence-native assets, this is simply its native type. For EVM-native +assets, this is in most cases a templated Cadence contract deployed to the bridge account, the name of which is derived +from the EVM contract address. For instance, an ERC721 contract at address `0x1234` would be onboarded to the bridge as +`EVMVMBridgedNFT_0x1234`, making its type identifier `A..EVMVMBridgedNFT_0x1234.NFT`. + +To get the type identifier for a given NFT, you can use the following code: + +```cadence +// Where `nft` is either a @{NonFungibleToken.NFT} or &{NonFungibleToken.NFT} +nft.getType().identifier +``` + +You may also retrieve the type associated with a given EVM contract address using the following script: + +
    + +get_associated_type.cdc + +```cadence get_associated_type.cdc +!from https://github.com/onflow/flow-evm-bridge/blob/main/cadence/scripts/bridge/get_associated_type.cdc +``` + +
    + +Alternatively, given some onboarded Cadence type, you can retrieve the associated EVM address using the following +script: + +
    + +get_associated_address.cdc + +```cadence get_associated_address.cdc +!from https://github.com/onflow/flow-evm-bridge/blob/main/cadence/scripts/bridge/get_associated_evm_address.cdc +``` + +
    + +#### NFTs + +Any Cadence NFTs bridging to EVM are escrowed in the bridge account and either minted in a bridge-deployed ERC721 +contract or transferred from escrow to the calling COA in EVM. On the return trip, NFTs are escrowed in EVM - owned by +the bridge's COA - and either unlocked from escrow if locked or minted from a bridge-owned NFT contract. + +Below are transactions relevant to bridging NFTs: + +
    + +bridge_nft_to_evm.cdc + +```cadence bridge_nft_to_evm.cdc +!from https://www.github.com/onflow/flow-evm-bridge/blob/main/cadence/transactions/bridge/nft/bridge_nft_to_evm.cdc +``` + +
    + +
    + +bridge_nft_from_evm.cdc + +```cadence bridge_nft_from_evm.cdc +!from https://www.github.com/onflow/flow-evm-bridge/blob/main/cadence/transactions/bridge/nft/bridge_nft_from_evm.cdc +``` + +
    + +#### Fungible Tokens + +Any Cadence fungible tokens bridging to EVM are escrowed in the bridge account only if they are Cadence-native. If the +bridge defines the tokens, they are burned. On the return trip the pattern is similar, with the bridge burning +bridge-defined tokens or escrowing them if they are EVM-native. In all cases, if the bridge has authority to mint on one +side, it must escrow on the other as the native VM contract is owned by an external party. + +With fungible tokens in particular, there may be some cases where the Cadence contract is not deployed to the bridge +account, but the bridge still follows a mint/burn pattern in Cadence. These cases are handled via +[`TokenHandler`](https://github.com/onflow/flow-evm-bridge/blob/main/cadence/contracts/bridge/interfaces/FlowEVMBridgeHandlerInterfaces.cdc) +implementations. Also know that moving $FLOW to EVM is built into the `EVMAddress` object so any requests bridging $FLOW +to EVM will simply leverage this interface; however, moving $FLOW from EVM to Cadence must be done through the COA +resource. + +Below are transactions relevant to bridging fungible tokens: + +
    + +bridge_tokens_to_evm.cdc + +```cadence bridge_tokens_to_evm.cdc +!from https://www.github.com/onflow/flow-evm-bridge/blob/main/cadence/transactions/bridge/tokens/bridge_tokens_to_evm.cdc +``` + +
    + +
    + +bridge_tokens_from_evm.cdc + +```cadence bridge_tokens_from_evm.cdc +!from https://www.github.com/onflow/flow-evm-bridge/blob/main/cadence/transactions/bridge/tokens/bridge_tokens_from_evm.cdc +``` + +
    + +## Prep Your Assets for Bridging + +### Context + +To maximize utility to the ecosystem, this bridge is permissionless and open to any fungible or non-fungible token as +defined by the respective Cadence standards and limited to ERC20 and ERC721 Solidity standards. Ultimately, a project +does not have to do anything for users to be able to bridge their assets between VMs. However, there are some +considerations developers may take to enhance the representation of their assets in non-native VMs. These largely relate +to asset metadata and ensuring that bridging does not compromise critical user assumptions about asset ownership. + +### EVMBridgedMetadata + +Proposed in [@onflow/flow-nft/pull/203](https://github.com/onflow/flow-nft/pull/203), the `EVMBridgedMetadata` view +presents a mechanism to both represent metadata from bridged EVM assets as well as enable Cadence-native projects to +specify the representation of their assets in EVM. Implementing this view is not required for assets to be bridged, but +the bridge does default to it when available as a way to provide projects greater control over their EVM asset +definitions within the scope of ERC20 and ERC721 standards. + +The interface for this view is as follows: + +```cadence +access(all) struct URI: MetadataViews.File { + /// The base URI prefix, if any. Not needed for all URIs, but helpful + /// for some use cases For example, updating a whole NFT collection's + /// image host easily + access(all) let baseURI: String? + /// The URI string value + /// NOTE: this is set on init as a concatenation of the baseURI and the + /// value if baseURI != nil + access(self) let value: String + + access(all) view fun uri(): String + +} + +access(all) struct EVMBridgedMetadata { + access(all) let name: String + access(all) let symbol: String + + access(all) let uri: {MetadataViews.File} +} +``` + +This uri value could be a pointer to some offchain metadata if you expect your metadata to be static. Or you could +couple the `uri()` method with the utility contract below to serialize the onchain metadata on the fly. Alternatively, +you may choose to host a metadata proxy which serves the requested token URI content. + +### SerializeMetadata + +The key consideration with respect to metadata is the distinct metadata storage patterns between ecosystem. It's +critical for NFT utility that the metadata be bridged in addition to the representation of the NFTs ownership. However, +it's commonplace for Cadence NFTs to store metadata onchain while EVM NFTs often store an onchain pointer to metadata +stored offchain. In order for Cadence NFTs to be properly represented in EVM platforms, the metadata must be bridged in +a format expected by those platforms and be done in a manner that also preserves the atomicity of bridge requests. The +path forward on this was decided to be a commitment of serialized Cadence NFT metadata into formats popular in the EVM +ecosystem. + +For assets that do not implement `EVMBridgedMetadata`, the bridge will attempt to serialize the metadata of the asset as +a JSON data URL string. This is done via the [`SerializeMetadata` +contract](https://github.com/onflow/flow-evm-bridge/blob/main/cadence/contracts/utils/SerializeMetadata.cdc) which +serializes metadata values into a JSON blob compatible with the OpenSea metadata standard. The serialized metadata is +then committed as the ERC721 `tokenURI` upon bridging Cadence-native NFTs to EVM. Since Cadence NFTs can easily update +onchain metadata either by field or by the ownership of sub-NFTs, this serialization pattern enables token URI updates +on subsequent bridge requests. + +### Opting Out + +It's also recognized that the logic of some use cases may actually be compromised by the act of bridging, particularly +in such a unique partitioned runtime environment. Such cases might include those that do not maintain ownership +assumptions implicit to ecosystem standards. + +For instance, an ERC721 implementation may reclaim a user's assets after a month of inactivity. In such a case, bridging +that ERC721 to Cadence would decouple the representation of ownership of the bridged NFT from the actual ownership in +the defining ERC721 contract after the token had been reclaimed - there would be no NFT in escrow for the bridge to +transfer on fulfillment of the NFT back to EVM. In such cases, projects may choose to opt-out of bridging, but +**importantly must do so before the asset has been onboarded to the bridge**. + +For Solidity contracts, opting out is as simple as extending the [`BridgePermissions.sol` abstract +contract](https://github.com/onflow/flow-evm-bridge/blob/main/solidity/src/interfaces/BridgePermissions.sol) which +defaults `allowsBridging()` to `false`. The bridge explicitly checks for the implementation of `IBridgePermissions` and +the value of `allowsBridging()` to validate that the contract has not opted out of bridging. + +Similarly, Cadence contracts can implement the [`IBridgePermissions.cdc` contract +interface](https://github.com/onflow/flow-evm-bridge/blob/main/cadence/contracts/bridge/interfaces/IBridgePermissions.cdc). +This contract has a single method `allowsBridging()` with a default implementation returning `false`. Again, the bridge +explicitly checks for the implementation of `IBridgePermissions` and the value of `allowsBridging()` to validate that +the contract has not opted out of bridging. Should you later choose to enable bridging, you can simply override the +default implementation and return `true`. + +In both cases, `allowsBridging()` gates onboarding to the bridge. Once onboarded - **a permissionless operation anyone +can execute** - the value of `allowsBridging()` is irrelevant and assets can move between VMs permissionlessly. + +## Under the Hood + +For an in-depth look at the high-level architecture of the bridge, see [FLIP +#237](https://github.com/onflow/flips/blob/main/application/20231222-evm-vm-bridge.md) + +### Additional Resources + +For the current state of Flow EVM across various task paths, see the following resources: + +- [Flow EVM Equivalence forum post](https://forum.flow.com/t/evm-equivalence-on-flow-proposal-and-path-forward/5478) +- [EVM Integration FLIP #223](https://github.com/onflow/flips/pull/225/files) +- [Gateway & JSON RPC FLIP #235](https://github.com/onflow/flips/pull/235) \ No newline at end of file diff --git a/static/markdown/tutorials/flowtobooth/image-gallery.md b/static/markdown/tutorials/flowtobooth/image-gallery.md new file mode 100644 index 0000000000..e9d2b201f6 --- /dev/null +++ b/static/markdown/tutorials/flowtobooth/image-gallery.md @@ -0,0 +1,1118 @@ +--- +title: Build a Fully-Onchain Image Gallery +description: Learn how to store images up to approximately 32kb onchain, on Flow EVM, easily - free with the Flow wallet, or sub-cent with any other wallet. +sidebar_position: 1 +keywords: + [ + Flow, + EVM, + Flow EVM, + storage, + Solidity, + Next.js, + React, + onchain storage, + base64, + image gallery, + smart contract, + blockchain, + gas efficiency, + web3, + dapp, + tutorial, + onchain app, + ] +--- + +# Build a Fully-Onchain Image Gallery + +:::info + +The [FlowtoBooth] tutorial series teaches you how to build a **fun benchmark app** and provides inspiration for the greater scope of possibilities building on Flow thanks to gas being so much less expensive. + +It is **not a production best-practice**. While everything in these tutorials works, you'll run into the following problems at production scale: + +- RPC Providers will likely rate-limit you for reading this much data at once +- NFT marketplaces may not display the images, likely due to the above +- 256\*256 images are huge by blockchain data standards, but too small for modern devices + +::: + +If you search for resources on how to store images of any significant size onchain, you'll be told it's either prohibitively expensive or even completely impossible. The reason for this is two-fold - first the size limit for data on transactions is about 40kb. Second, saving 40kb takes almost all of the 30 million gas limit on most blockchains. + +The former constraint is immutable (though many chains are slowly increasing this limit), which limits the app to images about 256\*256 pixels in size. The latter is heavily dependent on which chain you choose. + +At current gas prices on most chains, using all 30 million gas in a block costs **several dollars** - or potentially **thousands** on ETH mainnet. At current prices on Flow, spending 30 million gas costs **less than a penny**, usually 1 or 2 tenths of a cent. + +Much more computation is available at prices you or your users will be willing to pay for regular interactions. Including, but not limited to: + +- Airdropping hundreds of NFTs with one transaction, for pennies +- Generation of large mazes +- Generating large amounts of random numbers (with free [native VRF]) +- Extensive string manipulation onchain +- Simple game AI logic + +In this tutorial, we'll build a smart contract that can store and retrieve images onchain. We'll also build a simple frontend to interact with the contract on Flow and another chain. + +![stage-1](stage-1.png) + +## Objectives + +After completing this guide, you'll be able to: + +- Construct a composable onchain image gallery that can be used permissionlessly by onchain apps and other contracts to store and retrieve images +- Build an onchain app that can interact with this contract to save and display images +- Compare the price of spending 30 million gas on Flow with the price on other chains + +## Prerequisites + +### Next.js and Modern Frontend Development + +This tutorial uses [Next.js]. You don't need to be an expert, but it's helpful to be comfortable with development using a current React framework. You'll be on your own to select and use a package manager, manage Node versions, and other frontend environment tasks. + +### Solidity + +You don't need to be an expert, but you should be comfortable writing code in [Solidity]. You can use [Hardhat], [Foundry], or even [Remix]. + +## Build an Image Gallery Contract + +Start a new smart contract project in the toolchain of your choice and install the [OpenZeppelin] contracts. + +In your project, stub out a new contract for your image gallery that inherits from the [Ownable] contract: + +```solidity +// ImageGallery.sol + +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.28; + +import "@openzeppelin/contracts/access/Ownable.sol"; + +contract ImageGallery is Ownable { + constructor(address _owner) Ownable(_owner) {} +} +``` + +We're passing the original owner of the contract as an argument in the constructor to give greater flexibility for ownership when this contract is deployed. + +### Set Up Storage for Images + +We'll store the images in a simple `struct` that holds the image as a `base64` encoded `string`and also contains a `string` for the description. Doing so allows the image to be directly used in html and makes it easier to test the contract directly with a block explorer, but has the downside of making the images 33% bigger. Another format would be more efficient. + +These will be held in array: + +```solidity +struct Image { + string description; + string base64EncodedImage; +} + +Image[] public images; +``` + +### Construct Functions to Add and Delete Images + +Next, add a function that accepts a `_description` and `_base64EncodedImage` and adds them to the array. + +```solidity +function addImage( + string memory _description, + string memory _base64EncodedImage +) public onlyOwner { + images.push(Image(_description, _base64EncodedImage)); +} +``` + +Then, add one to delete the image at a given index: + +```solidity +function deleteImage(uint256 index) public onlyOwner { + if (index >= images.length) { + revert ImageIndexOutOfBounds(index, images.length); + } + for (uint256 i = index; i < images.length - 1; i++) { + images[i] = images[i + 1]; + } + images.pop(); +} +``` + +:::warning + +If the array gets big enough that calling `deleteImage` takes more than 30 million gas, it will brick this function. A safer and more gas-efficient method is to use a `mapping` with a counter as the index, and handling for the case where an index is empty. + +We're doing it this way to provide a way to delete accidentally uploaded images without making things too complex. + +::: + +### Retrieval Functions + +Finally, add functions to get one image, get all of the images, and get the number of images in the collection. + +```solidity +function getImages() public view returns (Image[] memory) { + return images; +} + +function getImage(uint256 index) public view returns (Image memory) { + if (index >= images.length) { + revert ImageIndexOutOfBounds(index, images.length); + } + return images[index]; +} + +function getImageCount() public view returns (uint256) { + return images.length; +} +``` + +### Final Contract + +After completing the above, you'll end up with a contract similar to: + +```solidity +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.28; + +import "@openzeppelin/contracts/access/Ownable.sol"; + +contract ImageGallery is Ownable { + struct Image { + string description; + string base64EncodedImage; + } + + Image[] public images; + + error ImageIndexOutOfBounds(uint256 index, uint256 length); + + constructor(address _owner) Ownable(_owner) {} + + function addImage( + string memory _description, + string memory _base64EncodedImage + ) public onlyOwner { + images.push(Image(_description, _base64EncodedImage)); + } + + function deleteImage(uint256 index) public onlyOwner { + if (index >= images.length) { + revert ImageIndexOutOfBounds(index, images.length); + } + for (uint256 i = index; i < images.length - 1; i++) { + images[i] = images[i + 1]; + } + images.pop(); + } + + function getImages() public view returns (Image[] memory) { + return images; + } + + function getImage(uint256 index) public view returns (Image memory) { + if (index >= images.length) { + revert ImageIndexOutOfBounds(index, images.length); + } + return images[index]; + } + + function getImageCount() public view returns (uint256) { + return images.length; + } +} + +``` + +### Create a Factory + +The image gallery contract you've just constructed is intended to be a utility for other contracts and apps to use freely. You don't want just one gallery for everyone, you need to give the ability for any app or contract to create and deploy private galleries freely. + +Build a factory to deploy image galleries: + +```solidity +pragma solidity ^0.8.28; + +import "@openzeppelin/contracts/access/Ownable.sol"; +import "./ImageGallery.sol"; + +contract ImageGalleryFactory { + event ImageGalleryCreated(address indexed owner, address gallery); + + function createImageGallery(address _owner) public { + ImageGallery gallery = new ImageGallery(_owner); + emit ImageGalleryCreated(_owner, address(gallery)); + } +} +``` + +### Tracking Factories + +Some app designs may need multiple galleries for each user. For example, you might want to be able to give users the ability to collect images in separate galleries for separate topics, dates, or events, similar to how many photo apps work on smartphones. + +To facilitate this feature, update your contract to keep track of which galleries have been created by which users. You'll end up with: + +```solidity +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.28; + +import "@openzeppelin/contracts/access/Ownable.sol"; +import "./ImageGallery.sol"; + +contract ImageGalleryFactory { + event ImageGalleryCreated(address indexed owner, address gallery); + + mapping(address => address[]) userToGalleries; + + function createImageGallery(address _owner) public { + ImageGallery gallery = new ImageGallery(_owner); + emit ImageGalleryCreated(_owner, address(gallery)); + userToGalleries[_owner].push(address(gallery)); + } + + function getGalleries( + address _owner + ) public view returns (address[] memory) { + return userToGalleries[_owner]; + } +} +``` + +### Testing the Factory + +Write appropriate unit tests, then deploy and verify the factory on Flow Testnet. + +If you need help, check out: + +- Deploy and Verify with [Hardhat] +- Deploy and Verify with [Foundry] +- Deploy and Verify with [Remix] + +Navigate to [evm-testnet.flowscan.io], search for your contract, and navigate to the `contracts` tab, then `Read/Write contract`. You'll see something similar to: + +![Factory on Flowscan](factory-on-flowscan.png) + +`Connect` your wallet. Use the [Flow Wallet] if you want automatically sponsored gas on both mainnet and testnet, or use the [Flow Faucet] to grab some testnet funds if you prefer to use another wallet. + +Expand the `createImageGallery` function, click the `self` button, and then `Write` the function. + +![createImageGallery](create-image-gallery.png) + +Approve the transaction and wait for it to complete. Then, call `getGalleries` for your address to find the address of the gallery you've created. + +### Testing the Image Gallery + +Search for the address of your image gallery contract. It `won't` be verified, but if you're using our exact contract, you will see a message from Flowscan that a verified contract with the same bytecode was found in the Blockscout DB. Click the provided link to complete the verification process. + +:::info + +The easiest way to get an ABI for the image gallery is to deploy one. You can do that now if you like. + +::: + +If you're following along, but used your own contract, simply deploy and verify one copy of the contract directly, refresh the page, then complete the above. + +You could test `addImage` with a random string, but it's better to use a base64-encoded image. Search for and navigate to one of the many online tools that will base64 encode images. + +:::danger + +Most sites of this nature are free tools created by helpful programmers and are funded with ads, donations, or the generosity of the creator. But you never know who made them or what they're caching. + +**Never** upload or convert sensitive data on a free site. + +::: + +Use the tool to convert an image that is ~30kb or smaller. Copy the string and paste it into the field in `addImage`. You can also add a `description`, but the bytes used will count towards the ~40kb limit. + +![addImage](add-image.png) + +Click `Write` and approve the transaction. Take note of the cost! You've saved an image onchain forever for just a little bit of gas! + +Once the transaction goes through, call `getImage` with `0` as the index to retrieve your description and base64-encoded image. + +Paste your image string as the `src` for an `img` tag in an html snippet to confirm it worked. + +```html +
    + +
    +``` + +## Building the Frontend + +Now that your contracts are sorted and working, it's time to build an app to interact with it. We'll use [Next.js] for this, but the components we provide will be adaptable to other React frameworks. + +Run: + +```bash +npx create-next-app +``` + +We're using the default options. + +Next, install [rainbowkit], [wagmi], and their related dependencies: + +```bash +npm install @rainbow-me/rainbowkit wagmi viem@2.x @tanstack/react-query +``` + +### Provider Setup + +Add a file called `providers` inside the `app` folder. In it, add your config and providers for [wagmi] and [rainbowkit]. You'll need to [add the Flow Wallet] as a custom wallet. It's not included by default because it has special features that aren't compatible with other blockchains. + +```tsx +'use client'; + + + + + + + + + +const projectId = '51407fcf066d74968d9a1a4c6da0d994'; // Replace with your actual project ID + +export interface MyWalletOptions { + projectId: string; +} + +const flowWallet = ({ projectId }: MyWalletOptions): Wallet => ({ + id: 'flow-wallet', + name: 'Flow Wallet', + iconUrl: 'https://lilico.app/logo_mobile.png', + iconBackground: '#41CC5D', + downloadUrls: { + android: + 'https://play.google.com/store/apps/details?id=com.flowfoundation.wallet', + ios: 'https://apps.apple.com/ca/app/flow-wallet-nfts-and-crypto/id6478996750', + chrome: + 'https://chromewebstore.google.com/detail/flow-wallet/hpclkefagolihohboafpheddmmgdffjm', + qrCode: 'https://link.lilico.app', + }, + mobile: { + getUri: (uri: string) => uri, + }, + qrCode: { + getUri: (uri: string) => uri, + instructions: { + learnMoreUrl: 'https://wallet.flow.com', + steps: [ + { + description: + 'We recommend putting Flow Wallet on your home screen for faster access to your wallet.', + step: 'install', + title: 'Open the Flow Wallet app', + }, + { + description: + 'You can find the scan button on home page, a connection prompt will appear for you to connect your wallet.', + step: 'scan', + title: 'Tap the scan button', + }, + ], + }, + }, + extension: { + instructions: { + learnMoreUrl: 'https://wallet.flow.com', + steps: [ + { + description: + 'We recommend pinning Flow Wallet to your taskbar for quicker access to your wallet.', + step: 'install', + title: 'Install the Flow Wallet extension', + }, + { + description: + 'Be sure to back up your wallet using a secure method. Never share your secret phrase with anyone.', + step: 'create', + title: 'Create or Import a Wallet', + }, + { + description: + 'Once you set up your wallet, click below to refresh the browser and load up the extension.', + step: 'refresh', + title: 'Refresh your browser', + }, + ], + }, + }, + createConnector: getWalletConnectConnector({ projectId }), +}); + +const connectors = connectorsForWallets( + [ + { + groupName: 'Recommended', + wallets: [flowWallet], + }, + ], + { + appName: 'Onchain Image Gallery', + projectId: projectId, + }, +); + +const wagmiConfig = createConfig({ + connectors, + chains: [flowTestnet], + ssr: true, + transports: { + [flowTestnet.id]: http(), + }, +}); + +export default function Providers({ children }: { children: React.ReactNode }) { + const queryClient = new QueryClient(); + + return ( + + + {children} + + + ); +} +``` + +### Add the Connect Button + +Open `page.tsx` and clear out the default content. Replace it with a message about what your app does and add the [rainbowkit] `Connect` button. Don't forget to import rainbowkit's css file and the `ConnectButton` component: + +```tsx +import '@rainbow-me/rainbowkit/styles.css'; + + + +export default function Home() { + return ( +
    +
    +

    Image Gallery

    +

    + A decentralized image gallery built on Flow blockchain. All images + saved directly onchain. +

    +

    + A fun benchmark, not best practice for production! +

    +

    + Free with gas sponsored by Flow with the Flow wallet. Sub-cent to save + an image with other wallets. +

    + +
    +
    + ); +} +``` + +Test the app and make sure you can connect your wallet. + +### Import Your Contracts + +Next, you'll need to get your contract ABI and address into your frontend. If you're using Hardhat, you can use the artifacts produced by the Ignition deployment process. If you're using Foundry or Remix, you can adapt this process to the format of artifacts produced by those toolchains. + +:::tip + +If you didn't deploy the Image Gallery contract, do so now to generate an artifact containing the ABI. + +::: + +Add a folder in `app` called `contracts`. Copy the following files from your smart contract project, located in the `ignition` and `ignition/deployments/chain-545` folders: + +- `deployed_addresses.json` +- `ImageGallery#ImageGallery.json` +- `ImageGalleryFactory#ImageGalleryFactory.json` + +Additionally, add a file called `contracts.ts`. In it, create a hook to provide the ABI and addresses of your contracts conveniently: + +```tsx + + + + + + + +export default function useContracts() { + return useMemo(() => { + return { + imageGalleryFactory: { + address: addresses[ + 'ImageGalleryFactory#ImageGalleryFactory' + ] as `0x${string}`, + abi: imageGalleryFactory.abi as Abi, + }, + imageGallery: { + abi: imageGallery.abi as Abi, + }, + }; + }, []); +} +``` + +:::info + +Note that we're **not** including an `address` for the `imageGallery` itself. We'll need to set this dynamically as users might have more than one gallery. + +::: + +### Add Content + +You can use a few strategies to organize the components that interact with the blockchain. One is to create a centralized component that stores all of the state related to smart contracts and uses a single instance of `useWriteContract`. Doing so makes it easier to convey the transaction lifecycle to your users, at the cost of re-fetching all the data from your RPC provider after every transaction. This becomes sub-optimal if your app interacts with many contracts, or even different read functions within the same contract. + +Add a folder in `app` called `components`, and create a file called `Content.tsx`. In it, add the following: + +- Imports for React, wagmi, your contracts, and Tanstack +- State variables for: + - When a reload is needed + - When you are waiting on a transaction response + - The list of gallery addresses for the connected wallet +- Hooks for: + - `useAccount()` + - `useQueryClient()` + - `useContracts()` + - `useWriteContract()` + - `useWaitForTransactionReceipt()` +- `useEffects` to: + - Listen for a receipt and set `reload` to true and `awaitingResponse` false + - Listen for needing a reload and invalidating the query for galleryAddresses + - Error handling + - Receipt of gallery addresses +- A `useReadContract` to fetch the list of gallery addresses for this user +- Frontend code to display the button to create a gallery if the user is signed in + +You'll end up with something similar to: + +```tsx +'use client'; + + +import { + useAccount, + useReadContract, + useWaitForTransactionReceipt, + useWriteContract, +} from 'wagmi'; + + + +export default function Content() { + const [reload, setReload] = useState(false); + const [awaitingResponse, setAwaitingResponse] = useState(false); + const [galleryAddresses, setGalleryAddresses] = useState([]); + + const account = useAccount(); + const queryClient = useQueryClient(); + const { imageGalleryFactory } = useContracts(); + + const { data, writeContract, error: writeError } = useWriteContract(); + + const { data: receipt, error: receiptError } = useWaitForTransactionReceipt({ + hash: data, + }); + + useEffect(() => { + if (receipt) { + setReload(true); + setAwaitingResponse(false); + } + }, [receipt]); + + useEffect(() => { + if (reload) { + setReload(false); + queryClient.invalidateQueries({ queryKey: galleryAddressesQueryKey }); + } + }, [reload]); + + useEffect(() => { + if (writeError) { + console.error(writeError); + setAwaitingResponse(false); + } + }, [writeError]); + + useEffect(() => { + if (receiptError) { + console.error(receiptError); + setAwaitingResponse(false); + } + }, [receiptError]); + + const { data: galleryAddressesData, queryKey: galleryAddressesQueryKey } = + useReadContract({ + abi: imageGalleryFactory.abi, + address: imageGalleryFactory.address, + functionName: 'getGalleries', + args: [account.address], + }); + + useEffect(() => { + if (galleryAddressesData) { + const newAddresses = galleryAddressesData as string[]; + newAddresses.reverse(); + setGalleryAddresses(newAddresses); + } + }, [galleryAddressesData]); + + function handleCreateGallery() { + setAwaitingResponse(true); + writeContract({ + abi: imageGalleryFactory.abi, + address: imageGalleryFactory.address, + functionName: 'createImageGallery', + args: [account.address], + }); + } + + return ( +
    + {account.isConnected && ( +
    +
    + +
    +
    + )} +
    + ); +} +``` + +**Don't forget** to add your `` component to `page.tsx`, below the `` component. + +Test the app and make sure you can complete the transaction to create a gallery. + +### Gallery List + +Next, you'll need to display the list of a user's galleries and enable them to select which one they want to interact with. A dropdown list will serve this function well. Add a component called `AddressList.tsx`, and in it add: + +```tsx + + +type AddressDropdownProps = { + addresses: string[]; // Array of EVM addresses + handleSetActiveAddress: Function; +}; + +const AddressDropdown: React.FC = ({ + addresses, + handleSetActiveAddress, +}) => { + const [selectedAddress, setSelectedAddress] = useState(''); + + useEffect(() => { + if (selectedAddress) { + console.log(selectedAddress); + handleSetActiveAddress(selectedAddress); + } + }, [selectedAddress]); + + return ( +
    +

    Select a Gallery

    +
    + +
    +
    + ); +}; + +export default AddressDropdown; +``` + +This component **doesn't** interact directly with the blockchain. It accepts the array of `addresses` and a function to handle setting the `activeAddress`. + +To use it in `Content.tsx`, you'll need to add a new state variable for the `activeAddress`: + +```tsx +const [activeAddress, setActiveAddress] = useState(null); +``` + +You'll also need a handler for when the `activeAddress` is set. You can't just use the `setActiveAddress()` function because you need to tell the app to reload if the user changes which gallery is active, so that the images in that gallery are loaded. + +```tsx +function handleSetActiveAddress(address: string) { + setReload(true); + setActiveAddress(address); +} +``` + +Finally, add the new component under the ` + +
    +
    + +
    + + )} + +); +``` + +Run the app, log in with your wallet **that has the gallery you created for testing** and select the gallery. + +You're now displaying an image that is stored onchain **forever**! + +## Image Uploader + +The last thing to do for this initial implementation is to add functionality so that users can upload their own images through the app and save them onchain without needing to do the base64 conversion on their own. + +For now, we'll just generate an error if the file is too big, but later on we can do that for the user as well. + +Add the `ImageUploader` component. This needs to handle uploading the image and displaying any errors. We'll keep the state for the image itself in `Content` so that it's accessible to other components: + +```tsx + + +type ImageUploaderProps = { + setUploadedBase64Image: (base64: string) => void; // Function to set the uploaded base64 image +}; + +const ImageUploader: React.FC = ({ + setUploadedBase64Image, +}) => { + const [error, setError] = useState(null); + + const handleImageUpload = (event: React.ChangeEvent) => { + const file = event.target.files?.[0]; + + if (!file) { + setError('No file selected'); + return; + } + + if (!file.type.startsWith('image/')) { + setError('Only image files are allowed'); + return; + } + + if (file.size > 30 * 1024) { + setError('Image size must be 30KB or smaller'); + return; + } + + const reader = new FileReader(); + reader.onload = () => { + const base64 = reader.result as string; + setUploadedBase64Image(base64); + setError(null); + }; + reader.onerror = () => { + setError('Failed to read file'); + }; + reader.readAsDataURL(file); + }; + + return ( +
    +
    + + + {error &&

    {error}

    } +
    +
    + ); +}; + +export default ImageUploader; +``` + +As before, we'll need to make some updates to `Content.tsx` to complete the implementation. + +First, add a state variable for the image: + +```tsx +const [uploadedBase64Image, setUploadedBase64Image] = useState(''); +``` + +Then add the `ImageUploader` to the `return`: + +```tsx + +``` + +Later on, you'll probably want to make a component for displaying the uploaded image, but for now just add it below the uploader button component: + +```tsx +{ + uploadedBase64Image && ( +
    + Uploaded +
    + ); +} +``` + +Finally, you need to add a button and a handler to call the smart contract function to save the image onchain. + +```tsx +function handleSaveOnchain() { + // console.log(uploadedBase64Image); + setAwaitingResponse(true); + writeContract({ + abi: imageGallery.abi, + address: activeAddress as `0x${string}`, + functionName: 'addImage', + args: ['', uploadedBase64Image], + }); +} +``` + +Add the button inside the check for an `uploadedBase64Image` so that it only displays when there is an image to upload: + +```tsx +{ + uploadedBase64Image && ( +
    + Uploaded + +
    + ); +} +``` + +Test the app to save your new image, and make sure the error displays if you try to upload an image that is too large. + +## Conclusion + +In this tutorial, you built a fully functional onchain image gallery using Flow EVM. You created smart contracts that can store images directly on the blockchain and a modern React frontend that allows users to interact with these contracts. The implementation demonstrates how Flow's efficient gas pricing makes operations that would be prohibitively expensive on other chains not just possible, but practical. + +Now that you have completed the tutorial, you should be able to: + +- Construct a composable onchain image gallery that can be used permissionlessly by onchain apps and other contracts to store and retrieve images +- Build an onchain app that can interact with this contract to save and display images +- Compare the price of spending 30 million gas on Flow with the price on other chains + +Now that you've completed this tutorial, you're ready to explore more complex onchain storage patterns and build applications that take advantage of Flow's unique capabilities for storing and processing larger amounts of data than traditionally possible on other chains. + + + +[FlowtoBooth]: https://flowtobooth.vercel.app/ +[Cadence]: https://cadence-lang.org/docs +[Next.js]: https://nextjs.org/docs/app/getting-started/installation +[Solidity]: https://soliditylang.org/ +[Hardhat]: ../../evm/guides/hardhat.md +[Foundry]: ../../evm/guides/foundry.md +[Remix]: ../../evm/guides/remix.md +[native VRF]: ../../evm/guides/vrf.md +[OpenZeppelin]: https://www.openzeppelin.com/ +[Ownable]: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol +[evm-testnet.flowscan.io]: https://evm-testnet.flowscan.io/ +[Hardhat]: ../../evm/guides/hardhat.md +[Foundry]: ../../evm/guides/foundry.md +[Remix]: ../../evm/guides/remix.md +[Flow Wallet]: https://wallet.flow.com/ +[Flow Faucet]: https://faucet.flow.com/fund-account +[add the Flow Wallet]: ../../evm/guides/rainbowkit.md +[rainbowkit]: https://www.rainbowkit.com/ +[wagmi]: https://wagmi.sh/ +[viem]: https://viem.sh/ \ No newline at end of file diff --git a/static/markdown/tutorials/flowtobooth/index.md b/static/markdown/tutorials/flowtobooth/index.md new file mode 100644 index 0000000000..abda423483 --- /dev/null +++ b/static/markdown/tutorials/flowtobooth/index.md @@ -0,0 +1,37 @@ +--- +sidebar_position: 3 +title: FlowtoBooth +description: Learn how to build apps that showcase Flow's unique capabilities through fun benchmark applications. +keywords: + - tutorials + - guides + - learning + - flow + - evm + - smart contracts + - development + - blockchain + - benchmarks + - gas efficiency +--- + +# FlowtoBooth Tutorials + +The FlowtoBooth tutorial series teaches you how to build a fun benchmark application that showcase Flow's unique capabilities, particularly its efficient gas pricing that makes traditionally expensive operations practical and affordable. + +These tutorials are designed to inspire developers by demonstrating what's possible on Flow, though they may not always represent production best practices. + +## Image Gallery + +Learn how to store and retrieve images directly onchain: + +- [Build a Fully-Onchain Image Gallery](image-gallery.md) + +## Coming Soon + +More FlowtoBooth tutorials are in development, including: + +- Composing on the Image Gallery to mint NFTs from the gallery +- Using [Cross-VM] to allow users to mint several NFTS with one approval + +[Cross-VM]: ../cross-vm-apps/index.md \ No newline at end of file diff --git a/static/markdown/tutorials/index.md b/static/markdown/tutorials/index.md new file mode 100644 index 0000000000..f19cdf7ef7 --- /dev/null +++ b/static/markdown/tutorials/index.md @@ -0,0 +1,99 @@ +--- +sidebar_position: 1 +title: Tutorials +description: Learn cutting edge techniques to take advantage of the power of Flow with EVM and Cadence. +keywords: + - tutorials + - guides + - learning + - flow + - cadence + - evm + - smart contracts + - development + - blockchain + - advanced + - gas efficiency + - onchain storage + - benchmarks + - performance + - web3 + - dapp + - onchain app + - cross-vm + - hybrid apps + - COAs + - batched transactions + - VM bridge + - token launch + - image gallery + - wagmi + - rainbowkit + - FCL + - VRF + - randomness + - Random Beacon + - commit-reveal + - AI + - ChatGPT + - Cursor + - AgentKit + - Flow documentation + - Flow AI assistance +--- + +Flow Cadence and Flow EVM are two VMs running on the Flow blockchain. A few months after the release of the Crescendo upgrade, we're seeing more apps that aren't Cadence apps -OR- EVM apps, they're both! Cadence unlocks superpowers such as vast computation and storage, native VRF, a much safer and more secure language for handling digital ownership, and more. Flow EVM unlocks the power of the Ethereum ecosystem, allowing you to bring in traditional tools, assets, and liquidity. + +For this grand future, we'll need a new suite of tutorials, guides, and resources to help you build with the best of both worlds. This section is dedicated to those tutorials. + +## AI Plus Flow + +Learn how to leverage AI tools to enhance your Flow development experience. These tutorials show you how to integrate various AI assistants with Flow development to boost productivity and code quality. + +- [Use Flow Knowledge Base in Cursor] - Learn how to set up Cursor with Flow knowledge bases to get intelligent assistance while developing Flow applications +- [Use Flow Knowledge Base in ChatGPT] - Create a custom GPT that understands Flow and Cadence to provide accurate answers to your development questions +- [Flow Data Sources] - Learn about this comprehensive resource and how to integrate it with various AI platforms +- [Build AI Agents with AgentKit] - Learn how to create AI agents that can interact with Flow using AgentKit + +## Token Launch + +Learn how to launch your own token on Flow using Cadence and EVM. This guide covers the process of registering and deploying tokens that can be used across both virtual machines. + +- [Register a Token] - Step-by-step guide to registering and deploying your token on Flow + +## Cross-VM Applications + +Learn how to build applications that interact with both Cadence and Flow EVM. These tutorials cover everything from basic integration to advanced features like transaction batching and token bridging. + +- [Introduction to Cross-VM Applications] - Learn how to use FCL with Wagmi and RainbowKit to create a cross-VM app +- [Add Flow Cadence to Your wagmi App] - Learn how to integrate Flow Cadence with your existing wagmi/RainbowKit application to enable batch transactions and other Cadence features. +- [Interacting with COAs] - Learn how to create and interact with Cadence Owned Accounts (COAs) to control EVM accounts from Cadence +- [Batched EVM Transactions] - Discover how to batch multiple EVM transactions into a single Cadence transaction +- [Cross-VM Bridge] - Explore how to bridge fungible and non-fungible tokens between Cadence and EVM environments + +## Native VRF + +Learn how to leverage Flow's native VRF capabilities in both Cadence and Solidity smart contracts. These tutorials demonstrate how to implement secure randomness without relying on external oracles. + +- [Secure Randomness with Commit-Reveal in Cadence] - Learn how to implement secure randomness in Cadence using Flow's commit-reveal scheme +- [Deploy a Solidity Contract Using Cadence] - Discover how to deploy and interact with Solidity contracts on Flow EVM using Cadence + +## FlowtoBooth + +Explore Flow's unique capabilities through fun benchmark applications that showcase what's possible with Flow's efficient gas pricing. These tutorials demonstrate practical applications of Flow's advanced features. + +- [Build a Fully-Onchain Image Gallery] - Create a fully onchain image gallery that demonstrates Flow's efficient storage capabilities + +[Use Flow Knowledge Base in Cursor]: ai-plus-flow/cursor/index.md +[Use Flow Knowledge Base in ChatGPT]: ai-plus-flow/chatgpt/index.md +[Flow Data Sources]: ai-plus-flow/flow-data-sources.md +[Build AI Agents with AgentKit]: ai-plus-flow/agentkit-flow-guide.md +[Register a Token]: token-launch/register-token.md +[Introduction to Cross-VM Applications]: cross-vm-apps/introduction.md +[Interacting with COAs]: cross-vm-apps/interacting-with-coa.md +[Batched EVM Transactions]: cross-vm-apps/batched-evm-transactions.md +[Cross-VM Bridge]: cross-vm-apps/vm-bridge.md +[Build a Fully-Onchain Image Gallery]: flowtobooth/image-gallery.md +[Secure Randomness with Commit-Reveal in Cadence]: native-vrf/commit-reveal-cadence.md +[Deploy a Solidity Contract Using Cadence]: native-vrf/deploy-solidity-contract.md +[Add Flow Cadence to Your wagmi App]: ./cross-vm-apps/add-to-wagmi.md \ No newline at end of file diff --git a/static/markdown/tutorials/native-vrf/commit-reveal-cadence.md b/static/markdown/tutorials/native-vrf/commit-reveal-cadence.md new file mode 100644 index 0000000000..b19a88e822 --- /dev/null +++ b/static/markdown/tutorials/native-vrf/commit-reveal-cadence.md @@ -0,0 +1,264 @@ +--- +sidebar_position: 1 +title: Secure Randomness with Commit-Reveal in Cadence +description: Guide on implementing secure randomness in Cadence using Flow's commit-reveal scheme +keywords: + - blockchain + - randomness + - Cadence + - Flow blockchain + - commit-reveal + - secure randomness + - Random Beacon + - smart contracts + - Coin Toss + - decentralization + - fairness + - cryptography +--- + +# Secure Randomness with Commit-Reveal in Cadence + +Randomness is a critical component in blockchain applications, enabling fair and unpredictable outcomes for use cases like gaming, lotteries, and cryptographic protocols. The most basic approach to generating a random number on EVM chains is to utilize block hashes, which combines the block hash with a user-provided seed and hashes them together. The resulting hash can be used as a pseudo-random number. However, this approach has limitations: + +1. Predictability: Miners can potentially manipulate the block hash to influence the generated random number. +2. Replay attacks: In case of block reorganizations, the revealed answers will not be re-used again. + +[Chainlink VRF][chainlink-vrf] is a popular tool that improves on this by providing another approach for generating provably random values on Ethereum and other blockchains by relying on a decentralized oracle network to deliver cryptographically secure randomness from off-chain sources. However, this dependence on external oracles introduces several weaknesses, such as cost, latency, and scalability concerns. + +In contrast, Flow offers a simpler and more integrated approach with its Random Beacon contract, which provides native on-chain randomness at the protocol level, eliminating reliance on external oracles and sidestepping their associated risks. Via a commit-and-reveal scheme, Flow's protocol-native secure randomness can be used within both Cadence and Solidity smart contracts. + +## Objectives + +By the end of this guide, you will be able to: + +- Deploy a Cadence smart contract on the Flow blockchain +- Implement commit-reveal randomness to ensure fairness +- Interact with Flow's on-chain randomness features +- Build and test the Coin Toss game using Flow's Testnet + +## Prerequisites + +You'll need the following: + +- Flow Testnet Account: An account on the Flow Testnet with test FLOW tokens for deploying contracts and executing transactions (e.g., via [Flow Faucet][flow-faucet]). +- Flow CLI or Playground: The Flow CLI or Flow Playground for deploying and testing contracts (install via [Flow Docs][flow-docs]). + +## Overview + +In this guide, we will explore how to use a commit-reveal scheme in conjunction with Flow's Random Beacon to achieve secure, non-revertible randomness. This mechanism mitigates post-selection attacks, where participants attempt to manipulate or reject unfavorable random outcomes after they are revealed. + +To illustrate this concept, we will build a Coin Toss game on Flow, demonstrating how smart contracts can leverage commit-reveal randomness for fair, tamper-resistant results. + +### What is the Coin Toss Game? + +The Coin Toss Game is a decentralized betting game that showcases Flow's commit-reveal randomness. Players place bets without knowing the random outcome, ensuring fairness and resistance to manipulation. + +The game consists of two distinct phases: + +1. Commit Phase – The player places a bet by sending Flow tokens to the contract. The contract records the commitment and requests a random value from Flow's Random Beacon. The player receives a Receipt, which they will use to reveal the result later. +2. Reveal Phase – Once the random value becomes available in `RandomBeaconHistory`, the player submits their Receipt to determine the outcome: + - If the result is 0, the player wins and receives double their bet. + - If the result is 1, the player loses, and their bet remains in the contract. + +### Why Use Commit-Reveal Randomness? + +- Prevents manipulation – Players cannot selectively reveal results after seeing the randomness. +- Ensures fairness – Flow's Random Beacon provides cryptographically secure, verifiable randomness. +- Reduces reliance on external oracles – The randomness is generated natively on-chain, avoiding additional complexity, third party risk and cost. + +## Building the Coin Toss Contract + +In this section, we'll walk through constructing the `CoinToss.cdc` contract, which contains the core logic for the Coin Toss game. To function properly, the contract relies on supporting contracts and a proper deployment setup. + +This tutorial will focus specifically on writing and understanding the `CoinToss.cdc` contract, while additional setup details can be found in the [original GitHub repo][github-repo]. + +### Step 1: Defining the `CoinToss.cdc` Contract + +Let's define our `CoinToss.cdc` and bring the other supporting contracts. + +```cadence +import "Burner" +import "FungibleToken" +import "FlowToken" + +import "RandomConsumer" + +access(all) contract CoinToss { + /// The multiplier used to calculate the winnings of a successful coin toss + access(all) let multiplier: UFix64 + /// The Vault used by the contract to store funds. + access(self) let reserve: @FlowToken.Vault + /// The RandomConsumer.Consumer resource used to request & fulfill randomness + access(self) let consumer: @RandomConsumer.Consumer + + /* --- Events --- */ + access(all) event CoinFlipped(betAmount: UFix64, commitBlock: UInt64, receiptID: UInt64) + access(all) event CoinRevealed(betAmount: UFix64, winningAmount: UFix64, commitBlock: UInt64, receiptID: UInt64) +} +``` + +### Step 2: Implementing the Commit Phase With `flipCoin` + +Let's define the first step in our scheme; the commit phase. We do this through a `flipCoin` public function. In this method, the caller commits a bet. The contract takes note of the block height and bet amount, returning a `Receipt` resource which is used by the former to reveal the coin toss result and determine their winnings. + +```cadence +access(all) fun flipCoin(bet: @{FungibleToken.Vault}): @Receipt { + let request <- self.consumer.requestRandomness() + let receipt <- create Receipt( + betAmount: bet.balance, + request: <-request + ) + self.reserve.deposit(from: <-bet) + + emit CoinFlipped(betAmount: receipt.betAmount, commitBlock: receipt.getRequestBlock()!, receiptID: receipt.uuid) + + return <- receipt + } +``` + +### Step 3: Implementing the Reveal Phase With `revealCoin` + +Now we implement the reveal phase with the `revealCoin` function. Here the caller provides the Receipt given to them at commitment. The contract then "flips a coin" with `_randomCoin()` providing the Receipt's contained Request. If result is 1, user loses, but if it's 0 the user doubles their bet. Note that the caller could condition the revealing transaction, but they've already provided their bet amount so there's no loss for the contract if they do. + +```cadence +access(all) fun revealCoin(receipt: @Receipt): @{FungibleToken.Vault} { + let betAmount = receipt.betAmount + let commitBlock = receipt.getRequestBlock()! + let receiptID = receipt.uuid + + let coin = self._randomCoin(request: <-receipt.popRequest()) + + Burner.burn(<-receipt) + + // Deposit the reward into a reward vault if the coin toss was won + let reward <- FlowToken.createEmptyVault(vaultType: Type<@FlowToken.Vault>()) + if coin == 0 { + let winningsAmount = betAmount * self.multiplier + let winnings <- self.reserve.withdraw(amount: winningsAmount) + reward.deposit( + from: <-winnings + ) + } + + emit CoinRevealed(betAmount: betAmount, winningAmount: reward.balance, commitBlock: commitBlock, receiptID: receiptID) + + return <- reward + } +``` + +The final version of `CoinToss.cdc` should look like [this contract code][coin-toss-contract-code]. + +## Testing CoinToss on Flow Testnet + +To make things easy, we've already deployed the `CoinToss.cdx` contract for you at this address: [0xb6c99d7ff216a684][coin-toss-contract]. We'll walk through placing a bet and revealing the result using [run.dnz][run-dnz], a Flow-friendly tool similar to Ethereum's Remix. + +### Placing a Bet with flipCoin + +First, you'll submit a bet to the CoinToss contract by withdrawing Flow tokens and storing a receipt. Here's how to get started: + +1. Open Your Dev Environment: Head to [run.dnz][run-dnz]. +2. Enter the Transaction Code: Paste the following Cadence code into the editor: + +```cadence +import FungibleToken from 0x9a0766d93b6608b7 +import FlowToken from 0x7e60df042a9c0868 +import CoinToss from 0xb6c99d7ff216a684 + +/// Commits the defined amount of Flow as a bet to the CoinToss contract, saving the returned Receipt to storage +/// +transaction(betAmount: UFix64) { + + prepare(signer: auth(BorrowValue, SaveValue) &Account) { + // Withdraw my bet amount from my FlowToken vault + let flowVault = signer.storage.borrow(from: /storage/flowTokenVault)! + let bet <- flowVault.withdraw(amount: betAmount) + + // Commit my bet and get a receipt + let receipt <- CoinToss.flipCoin(bet: <-bet) + + // Check that I don't already have a receipt stored + if signer.storage.type(at: CoinToss.ReceiptStoragePath) != nil { + panic("Storage collision at path=".concat(CoinToss.ReceiptStoragePath.toString()).concat(" a Receipt is already stored!")) + } + + // Save that receipt to my storage + // Note: production systems would consider handling path collisions + signer.storage.save(<-receipt, to: CoinToss.ReceiptStoragePath) + } +} +``` + +3. Set Your Bet: A modal will pop up asking for the betAmount. Enter a value (e.g., 1.0 for 1 Flow token) and submit +4. Execute the Transaction: Click "Run," and a WalletConnect window will appear. Choose Blocto, sign in with your email, and hit "Approve" to send the transaction to Testnet. + +![remix5-sc](./imgs/remix5.png) + +5. Track it: You can take the transaction id to [FlowDiver][flow-diver][.io](https://testnet.flowdiver.io/tx/9c4f5436535d36a82d4ae35467b37fea8971fa0ab2409dd0d5f861f61e463d98) to have a full view of everything that's going on with this `FlipCoin` transaction. + +### Revealing the Coin Toss Result + +Let's reveal the outcome of your coin toss to see if you've won. This step uses the receipt from your bet, so ensure you're using the same account that placed the bet. Here's how to do it: + +1. Return to your Dev Environment: Open [run.dnz][run-dnz] again. +2. Enter the Reveal Code: Paste the following Cadence transaction into the editor: + +```cadence +import FlowToken from 0x7e60df042a9c0868 +import CoinToss from 0xb6c99d7ff216a684 + +/// Retrieves the saved Receipt and redeems it to reveal the coin toss result, depositing winnings with any luck +/// +transaction { + + prepare(signer: auth(BorrowValue, LoadValue) &Account) { + // Load my receipt from storage + let receipt <- signer.storage.load<@CoinToss.Receipt>(from: CoinToss.ReceiptStoragePath) + ?? panic("No Receipt found in storage at path=".concat(CoinToss.ReceiptStoragePath.toString())) + + // Reveal by redeeming my receipt - fingers crossed! + let winnings <- CoinToss.revealCoin(receipt: <-receipt) + + if winnings.balance > 0.0 { + // Deposit winnings into my FlowToken Vault + let flowVault = signer.storage.borrow<&FlowToken.Vault>(from: /storage/flowTokenVault)! + flowVault.deposit(from: <-winnings) + } else { + destroy winnings + } + } +} +``` + +After running this transaction, we reveal the result of the coin flip and it's 1! Meaning we have won nothing this time, but keep trying! + +You can find the full transaction used for this example, with its result and events, at [FlowDiver.io/tx/][flow-diver-tx]. + +## Conclusion + +The commit-reveal scheme, implemented within the context of Flow's Random Beacon, provides a robust solution for generating secure and non-revertible randomness in decentralized applications. By leveraging this mechanism, developers can ensure that their applications are: + +- Fair: Outcomes remain unbiased and unpredictable. +- Resistant to manipulation: Protects against post-selection attacks. +- Immune to replay attacks: A common pitfall in traditional random number generation on other blockchains. + +The CoinToss game serves as a practical example of these principles in action. By walking through its implementation, you've seen firsthand how straightforward yet effective this approach can be—balancing simplicity for developers with robust security for users. As blockchain technology advances, embracing such best practices is essential to creating a decentralized ecosystem that upholds fairness and integrity, empowering developers to innovate with confidence. + +This tutorial has equipped you with hands-on experience and key skills: + +- You deployed a Cadence smart contract on the Flow blockchain. +- You implemented commit-reveal randomness to ensure fairness. +- You interacted with Flow's on-chain randomness features. +- You built and tested the Coin Toss game using Flow's Testnet. + +By harnessing Flow's built-in capabilities, you can now focus on crafting engaging, user-centric experiences without grappling with the complexities or limitations of external systems. This knowledge empowers you to create secure, scalable, and fair decentralized applications. + +[chainlink-vrf]: https://docs.chain.link/vrf +[flow-faucet]: https://testnet-faucet.onflow.org/ +[flow-docs]: https://docs.onflow.org/flow-cli/install/ +[flow-diver]: https://testnet.flowdiver.io/ +[github-repo]: https://github.com/onflow/random-coin-toss +[run-dnz]: https://run.dnz.dev/ +[coin-toss-contract]: https://contractbrowser.com/A.b6c99d7ff216a684.CoinToss +[coin-toss-contract-code]: https://github.com/onflow/random-coin-toss/blob/main/contracts/CoinToss.cdc +[flow-diver-tx]: https://testnet.flowdiver.io/tx/a79fb2f947e7803eefe54e48398f6983db4e0d4d5e217d2ba94f8ebdec132957 \ No newline at end of file diff --git a/static/markdown/tutorials/native-vrf/deploy-solidity-contract.md b/static/markdown/tutorials/native-vrf/deploy-solidity-contract.md new file mode 100644 index 0000000000..82a5b45afc --- /dev/null +++ b/static/markdown/tutorials/native-vrf/deploy-solidity-contract.md @@ -0,0 +1,247 @@ +--- +sidebar_position: 2 +title: Deploy a Solidity Contract Using Cadence +description: Guide on how to deploy a Solidity contract using Cadence +keywords: + - Solidity + - Cadence + - Flow EVM + - NFTs + - blockchain + - smart contracts + - Ethereum + - Flow + - deployment + - Remix + - Overflow +--- + +# Deploy a Solidity Contract using Cadence + +## Why Solidity And Cadence? + +Solidity powers Ethereum's vast ecosystem, with a deep library of contracts like ERC721s for NFTs and a huge developer base. Deploying Solidity contracts on Flow's EVM layer leverages Flow's consensus for lower fees, quicker transactions, and slick asset handling, while giving you access to additional tools, including native VRF. + +Imagine gaming NFTs minted cheaper, DeFi logic ported without rewrites, or Ethereum projects tapping Flow's scalable, user-first design. Flow EVM runs Solidity natively, and Cadence bridges the gap—letting you reuse trusted contracts while unlocking Flow's edge. + +## Objectives + +After completing this guide, you'll be able to: + +- Deploy a Solidity contract on Flow EVM using Cadence +- Call functions on this contract from the Cadence side + +## Prerequisites: + +- NodeJs and NPM (must be installed - follow [this guide][node-npm-install]) +- Go +- Flow Command Line Interface (Flow CLI) (must be installed - follow [this guide][flow-cli-install]) +- Remix (can be accessed online - available at [Remix][remix]) +- Overflow (must be installed - install via Go with `go get github.com/bjartek/overflow/v2`) +- Cadence Owned Account (COA) (must be created - follow [this guide][coa-guide] to set up) + +For this guide, we're using Remix for Solidity contract compilation and Overflow for running Cadence transactions on Flow EVM. To deploy a Solidity contract using Cadence, you'll need a Cadence Owned Account; the guide linked above explains how to create one. + +## High-Level Walkthrough + +At a high level, this guide walks you through deploying a Solidity contract on the Flow blockchain's EVM layer using Cadence in three main steps: + +1. Compile the Solidity Contract: You'll start by taking a Solidity contract (like an ERC721 for NFTs) and compiling it into bytecode using Remix, an online Ethereum development tool. This bytecode is the machine-readable version of your contract, ready to be deployed. + +2. Deploy to Flow EVM with Cadence: Next, you'll set up a local environment with tools like Overflow and the Flow CLI. Using a Cadence transaction, you'll deploy the bytecode to Flow's EVM layer via a Cadence Owned Account (COA), bridging the two ecosystems seamlessly. + +3. Interact from Cadence: Finally, you'll use a Cadence script to call a function on your deployed Solidity contract—like minting an NFT—demonstrating how Cadence can interact with Ethereum-style logic on Flow. + +This process leverages Ethereum's robust contract library and Flow's efficient, user-friendly blockchain, opening up a world of cross-platform possibilities—all in a few straightforward steps. + +## Step 1: Compile the Solidity Contract + +Start by compiling your Solidity contract to get its bytecode. For this example, use OpenZeppelin's ERC721 contract for tracking game items. Here's how to do it in Remix: + +1. Open Remix: Go to [Remix][remix] in your browser. +2. Create a New File: In the Remix file explorer, click the "+" button and name the file (e.g., `GameItem.sol`). +3. Paste the Contract Code: Copy the OpenZeppelin ERC721 contract code (e.g., from [this example][coa-guide]) and paste it into the new file. +4. Compile the Contract: + - Select the appropriate Solidity compiler version (e.g., 0.8.x) in the "Solidity Compiler" tab. + - Click "Compile GameItem.sol". +5. Copy the Bytecode: + - Go to the "Compilation Details" (or "Bytecode" section after compilation). + - Copy the "object" field under the bytecode section. + +![Remix Screenshot](imgs/remix1.png) + +6. Save the Bytecode: + - From your project's root directory, create a folder named `bytecode`. + - Inside it, create a file called `GameItem.js`. + - Paste the bytecode into `GameItem.js` as a string (e.g., `module.exports = "0x..."`). + +Here's the Cadence transaction we'll use later to deploy this bytecode on Flow EVM: + +```cadence +import "EVM" + +transaction(code: String, pathId: Int) { + let coa: auth(EVM.Deploy) &EVM.CadenceOwnedAccount + + prepare(signer: auth(Storage) &Account) { + let coaPath = StoragePath(identifier: signer.address.toString().concat("EVM_").concat(pathId.toString()))! + self.coa = signer.storage.borrow( + from: coaPath) ?? panic("Could not borrow reference to the COA!") + } + + execute { + self.coa.deploy(code: code.decodeHex(), gasLimit: 15000000, value: EVM.Balance(attoflow: 0)) + } +} +``` + +## Step 2: Set Up Your Environment and Deploy the Contract + +To run the transactions and tests, we'll use [Overflow][overflow]. Follow these steps to set up and deploy: + +1. Initialize a Go Project: + - Open your terminal and navigate to your project's root directory. + - Run: `go mod init flow/tutorials` to create a Go module. +2. Install Overflow: + - Run: `go get github.com/bjartek/overflow/v2` to install the Overflow package. +3. Create the Task File: + - In the root directory, create a folder called `tasks`. + - Inside `tasks`, create a file named `main.go`. + - Paste the following Go code into `main.go`: + +```go +package main + +import ( + "fmt" + "io/ioutil" + "log" + . "github.com/bjartek/overflow/v2" + "github.com/fatih/color" +) + +func readJSFile(filePath string) (string, error) { + content, err := ioutil.ReadFile(filePath) + if err != nil { + return "", err + } + return string(content), nil +} + +func main() { + filePath := "bytecode/GameItem.js" + jsContent, err := readJSFile(filePath) + if err != nil { + log.Fatalf("Error reading JavaScript file: %v", err) + } + o := Overflow( + WithGlobalPrintOptions(), + WithNetwork("testnet"), + ) + + color.Red("Should be able to create a COA") + o.Tx("create_COA", + WithSigner("gamer"), + ).Print() + + color.Cyan("Deploy a Solidity contract to Random's COA") + o.Tx("deploy_sol_contract", + WithSigner("gamer"), + WithArg("code", jsContent), + WithArg("pathId", 0), + ).Print() +} +``` + +4. Run the Deployment: + - From the terminal, navigate to the root directory. + - Run: `go run ./tasks/main.go`. + - This will: + - Create a Cadence Owned Account (COA) for the "gamer" account. + - Deploy the Solidity contract using the bytecode from `GameItem.js`. +5. Verify the Deployment: + - Check the terminal output for the deployed contract address (e.g., `0xb93cB988D0722E17B67A5E169a47FB6F3A4dea1b`). + - Visit the [Flow EVM Testnet Scanner][testnet-scanner] and search for the address to confirm the deployment. + +![Remix Screenshot](imgs/remix3.png) + +Note: The "gamer" account (e.g., `0xb995271139c0126f`) is a Testnet account. The `pathId` (set to `0`) corresponds to the COA slot. If you've created multiple COAs, increment `pathId` (e.g., `1`, `2`) accordingly. + +## Step 3: Call a Function on the Deployed Contract + +Now, let's call the `awardItem` function from the deployed ERC721 contract using this Cadence script: + +1. Cadence Script Preparation: + Use the following Cadence script to call the contract function: + +```cadence +import "EVM" + +access(all) +fun main(hexEncodedAddress: String, address: Address, pathId: UInt64): [AnyStruct] { + let account = getAuthAccount(address) + let coaPath = StoragePath(identifier: address.toString().concat("EVM_").concat(pathId.toString()))! + let coa = account.storage.borrow( + from: coaPath + ) ?? panic("Could not borrow reference to the COA!") + let addressBytes = hexEncodedAddress.decodeHex().toConstantSized<[UInt8; 20]>()! + + let callResult = coa.call( + to: EVM.EVMAddress(bytes: addressBytes), + data: EVM.encodeABIWithSignature( + "awardItem(address,string)", + [EVM.addressFromString("000000000000000000000002A16A68E971e4670B"), "{name: gamerz}"] + ), + gasLimit: 15000000, + value: EVM.Balance(attoflow: 0) + ) + + return EVM.decodeABI(types: [Type()], data: callResult.data) +} +``` + +2. Update the Go File: + Open `tasks/main.go` and add the following code at the end of the `main` function (replace the `hexEncodedAddress` with your deployed contract address): + +```go +color.Cyan("Mint a game item from the Solidity contract") +o.Script("call_sol_function", + WithArg("hexEncodedAddress", "b93cB988D0722E17B67A5E169a47FB6F3A4dea1b"), + WithArg("address", "gamer"), + WithArg("pathId", 0), +).Print() +``` + +3. Run the Script: + + - In the terminal, run: `go run ./tasks/main.go` again. + - This executes the Cadence script, calling `awardItem` to mint an NFT. + +4. Check the Result: + - The terminal will display the token ID of the newly minted NFT (e.g., a UInt256 value). + - See the screenshot below for an example output: + +![Result Screenshot](imgs/remix4.png) + +The terminal output shows the unique token ID that was generated when minting the game item through the Solidity contract using Cadence. + + +The `awardItem` function is called with a test address and a string parameter. In a real-world scenario, you would replace these with actual wallet addresses and more meaningful metadata. + + +## Conclusion + +Deploying a Solidity contract within a Cadence environment on the Flow blockchain is not only feasible but also presents an exciting opportunity for you to harness the strengths of both programming languages. Throughout this guide, you've navigated the critical steps involved in the deployment process, from compiling your Solidity contract using Remix to executing transactions with Overflow and Cadence scripts. By completing this guide, you've achieved the following: + +- Deployed a Solidity contract on Flow EVM using Cadence: You compiled and deployed your Solidity contract to Flow's EVM layer via a Cadence transaction. +- Called functions from Cadence: You used a Cadence script to mint an NFT by invoking the `awardItem` function on your deployed contract. + +As blockchain technology continues to evolve, adopting these best practices is crucial for fostering a secure and trustworthy ecosystem. This empowers you to innovate while staying true to the core principles of decentralization and fairness. + +[node-npm-install]: https://docs.npmjs.com/downloading-and-installing-node-js-and-npm +[flow-cli-install]: https://developers.flow.com/tools/flow-cli/install +[remix]: https://remix.ethereum.org/ +[coa-guide]: https://developers.flow.com/evm/cadence/interacting-with-coa + +[overflow]: https://github.com/bjartek/overflow] +[testnet-scanner]: https://evm-testnet.flowscan.io/ \ No newline at end of file diff --git a/static/markdown/tutorials/native-vrf/index.md b/static/markdown/tutorials/native-vrf/index.md new file mode 100644 index 0000000000..05493dfdf5 --- /dev/null +++ b/static/markdown/tutorials/native-vrf/index.md @@ -0,0 +1,35 @@ +--- +title: Native VRF +description: A series of tutorials on using Flow's native VRF capabilities in both Cadence and Solidity smart contracts. +sidebar_position: 4 +keywords: + - VRF + - randomness + - Cadence + - Solidity + - Flow EVM + - smart contracts + - commit-reveal + - secure randomness + - Random Beacon + - blockchain + - gaming + - NFTs + - DeFi +--- + +# Native VRF Tutorials + +This series covers how to leverage Flow's native VRF (Verifiable Random Function) capabilities in both Cadence and Solidity smart contracts. Flow's Random Beacon provides cryptographically secure randomness at the protocol level, eliminating the need for external oracles and their associated costs. + +## Tutorials + +- **[Secure Randomness with Commit-Reveal in Cadence]** - Learn how to implement secure randomness in Cadence using Flow's commit-reveal scheme. +- **[Deploy a Solidity Contract Using Cadence]** - Discover how to deploy and interact with Solidity contracts on Flow EVM using Cadence. + +## More Coming Soon + +Stay tuned—more tutorials and advanced guides are on the way! + +[Secure Randomness with Commit-Reveal in Cadence]: ./commit-reveal-cadence.md +[Deploy a Solidity Contract Using Cadence]: ./deploy-solidity-contract.md \ No newline at end of file diff --git a/static/markdown/tutorials/token-launch/index.md b/static/markdown/tutorials/token-launch/index.md new file mode 100644 index 0000000000..f616b344ac --- /dev/null +++ b/static/markdown/tutorials/token-launch/index.md @@ -0,0 +1,13 @@ +--- +sidebar_position: 2 +title: Token Launch +description: Learn how to register your tokens on Flow to ensure visibility in wallets and ecosystem projects. +--- + +# Token Launch + +This section covers the process of registering your tokens on Flow. + +### Guides: + +- **[Register Your Token](register-token.md)**: Steps to register your Fungible Token on Flow Cadence or ERC20 on Flow EVM so it appears in Flow Wallet, IncrementFi, and other ecosystem apps. \ No newline at end of file diff --git a/static/markdown/tutorials/token-launch/register-token.md b/static/markdown/tutorials/token-launch/register-token.md new file mode 100644 index 0000000000..7b08c21d18 --- /dev/null +++ b/static/markdown/tutorials/token-launch/register-token.md @@ -0,0 +1,48 @@ +--- +title: Register Your Token on Flow +description: 'Register tokens to get listed on Flow Wallet, IncrementFi, and other Flow Apps.' +sidebar_label: Register Token +sidebar_position: 2 +--- + +# Register Your Token on Flow + +To make your token visible in Flow ecosystem projects like **Flow Wallet** and **IncrementFi**, you need to register it on the Flow Token List. This process will generate JSON files based on Uniswap TokenList Standard and ensures that wallets, explorers, and onchain apps can recognize and display your token correctly. + +There are two ways to register your token: **manually** via a web interface or **programmatically** during token deployment. + +--- + +## Manual Registration (~1 min) + +The following works for both fungible tokens on Flow Cadence and ERC20 tokens on Flow EVM. + +1. **Go to** [Token List Registration](https://token-list.fixes.world/). +2. **Enter your contract address** in the **"Quick Register"** field and press **Enter**. +3. **Click "Register"** and sign the transaction. + - If your token is **already registered to VM Bridge**, you're done. + - Otherwise, the **first transaction** registers the token to **VM Bridge** (costs **1 $FLOW**). + - After that, click **"Register"** again and sign the **second transaction** to finalize the process. + +--- + +## Programmatic Registration (~1-2 hrs) + +For seamless automation, you can integrate token registration into your token deployment workflow. + +### Register ERC-20 Tokens automatically on Flow EVM + +- Use this **Cadence transaction**: [register-evm-asset.cdc](https://github.com/fixes-world/token-list/blob/main/cadence/transactions/register-evm-asset.cdc) +- This transaction should be executed **right after deploying your ERC-20 contract**. +- **Note:** Similar to manual registration: + - If the token **is not bridged** to **VM Bridge**, you will need to **send the transaction twice**. + - The **first transaction** deploys a **VM Bridged Cadence contract** for the ERC-20. + - The **second transaction** registers it on the Token List. + +--- + +### Next Steps + +- Verify your token listing in Flow Wallet. + +For any issues, refer to the [Token List GitHub Repository](https://github.com/fixes-world/token-list) or reach out to the [Flow developer community](https://discord.gg/flow). \ No newline at end of file