From b1c6e3b106e076f2505331aa0731911a4c63c6a6 Mon Sep 17 00:00:00 2001 From: Owen Date: Wed, 6 Nov 2024 15:07:00 -0500 Subject: [PATCH] Validator Manager Docs + Cleanup (#1929) * add OKX OS * 1922 okx integration page (#1925) * add code to okxos.mdx * Update okxos.mdx * Update okxos.mdx * nit formatting * add disclaimer, change import to require * update note on API Key storage * update descriptions and add code * update code example description * update code snippets * add transaction checking * add get tx * add bash script * nit spelling * update conclusion * Update okxos.mdx * nit:formatting * fix broken links * rm elastic subnets, rm wagmi subnet reference * add evm-l1 section + redirects * validator manager docs * fix FolderCode icon * rewardmanager info, nits, fix broken links --------- Signed-off-by: Owen Co-authored-by: Julian Martinez <73849597+Julian-dev28@users.noreply.github.com> --- .github/linkChecker.ts | 2 +- app/(home)/page.client.tsx | 12 +- app/layout.config.tsx | 12 +- components/mermaid.tsx | 19 + .../add-utility/cross-chain-bridge.mdx | 343 ------------------ .../make-avalanche-l1-permissionless.mdx | 2 + .../elastic-avalanche-l1s/parameters.mdx | 2 + content/docs/avalanche-l1s/meta.json | 8 - .../upgrade/customize-avalanche-l1.mdx | 253 ------------- .../docs/dapps/c-chain-or-avalanche-l1.mdx | 63 ++++ content/docs/dapps/meta.json | 1 + .../background-requirements.mdx | 0 .../defining-precompile.mdx | 0 .../deploying-precompile.mdx | 0 .../executing-test-cases.mdx | 0 .../generating-your-precompile.mdx | 0 .../custom-precompiles}/introduction.mdx | 0 .../writing-test-cases.mdx | 0 .../evm-l1s/default-precompiles/allowlist.mdx | 13 + .../default-precompiles/feemanager.mdx | 115 ++++++ .../default-precompiles/nativeminter.mdx | 21 ++ .../default-precompiles/overview.mdx} | 2 +- .../default-precompiles/rewardmanager.mdx | 131 +++++++ .../default-precompiles/warpmessenger.mdx | 21 ++ content/docs/evm-l1s/index.mdx | 9 + content/docs/evm-l1s/meta.json | 28 ++ .../validator-manager/add-validator.mdx | 19 + .../evm-l1s/validator-manager/contract.mdx | 109 ++++++ .../custom-validator-manager.mdx | 93 +++++ .../validator-manager/remove-validator.mdx | 42 +++ .../evm-l1s/validator-manager/upgrade.mdx | 8 + .../microsoft-azure.mdx | 3 +- .../avalanche-community-proposals.mdx | 0 .../avalanche-consensus.mdx | 0 .../{learn => protocol}/avalanche-l1s.mdx | 0 .../docs/{learn => protocol}/avax-token.mdx | 0 .../c-chain-or-avalanche-l1.mdx | 0 .../docs/{learn => protocol}/disclaimer.mdx | 0 content/docs/{learn => protocol}/index.mdx | 0 content/docs/{learn => protocol}/meta.json | 1 + .../networks/fuji-testnet.mdx | 0 .../{learn => protocol}/networks/mainnet.mdx | 0 .../{learn => protocol}/primary-network.mdx | 0 .../{learn => protocol}/rewards-formula.mdx | 0 .../{learn => protocol}/virtual-machines.mdx | 0 content/docs/virtual-machines/meta.json | 12 +- content/integrations/goldrush.mdx | 1 - mdx-components.tsx | 6 + next.config.mjs | 20 + package.json | 1 + 50 files changed, 746 insertions(+), 626 deletions(-) create mode 100644 components/mermaid.tsx delete mode 100644 content/docs/avalanche-l1s/add-utility/cross-chain-bridge.mdx create mode 100644 content/docs/dapps/c-chain-or-avalanche-l1.mdx rename content/docs/{virtual-machines/evm-customization => evm-l1s/custom-precompiles}/background-requirements.mdx (100%) rename content/docs/{virtual-machines/evm-customization => evm-l1s/custom-precompiles}/defining-precompile.mdx (100%) rename content/docs/{virtual-machines/evm-customization => evm-l1s/custom-precompiles}/deploying-precompile.mdx (100%) rename content/docs/{virtual-machines/evm-customization => evm-l1s/custom-precompiles}/executing-test-cases.mdx (100%) rename content/docs/{virtual-machines/evm-customization => evm-l1s/custom-precompiles}/generating-your-precompile.mdx (100%) rename content/docs/{virtual-machines/evm-customization => evm-l1s/custom-precompiles}/introduction.mdx (100%) rename content/docs/{virtual-machines/evm-customization => evm-l1s/custom-precompiles}/writing-test-cases.mdx (100%) create mode 100644 content/docs/evm-l1s/default-precompiles/allowlist.mdx create mode 100644 content/docs/evm-l1s/default-precompiles/feemanager.mdx create mode 100644 content/docs/evm-l1s/default-precompiles/nativeminter.mdx rename content/docs/{virtual-machines/evm-customization/precompile-overview.mdx => evm-l1s/default-precompiles/overview.mdx} (99%) create mode 100644 content/docs/evm-l1s/default-precompiles/rewardmanager.mdx create mode 100644 content/docs/evm-l1s/default-precompiles/warpmessenger.mdx create mode 100644 content/docs/evm-l1s/index.mdx create mode 100644 content/docs/evm-l1s/meta.json create mode 100644 content/docs/evm-l1s/validator-manager/add-validator.mdx create mode 100644 content/docs/evm-l1s/validator-manager/contract.mdx create mode 100644 content/docs/evm-l1s/validator-manager/custom-validator-manager.mdx create mode 100644 content/docs/evm-l1s/validator-manager/remove-validator.mdx create mode 100644 content/docs/evm-l1s/validator-manager/upgrade.mdx rename content/docs/{learn => protocol}/avalanche-community-proposals.mdx (100%) rename content/docs/{learn => protocol}/avalanche-consensus.mdx (100%) rename content/docs/{learn => protocol}/avalanche-l1s.mdx (100%) rename content/docs/{learn => protocol}/avax-token.mdx (100%) rename content/docs/{avalanche-l1s => protocol}/c-chain-or-avalanche-l1.mdx (100%) rename content/docs/{learn => protocol}/disclaimer.mdx (100%) rename content/docs/{learn => protocol}/index.mdx (100%) rename content/docs/{learn => protocol}/meta.json (92%) rename content/docs/{learn => protocol}/networks/fuji-testnet.mdx (100%) rename content/docs/{learn => protocol}/networks/mainnet.mdx (100%) rename content/docs/{learn => protocol}/primary-network.mdx (100%) rename content/docs/{learn => protocol}/rewards-formula.mdx (100%) rename content/docs/{learn => protocol}/virtual-machines.mdx (100%) diff --git a/.github/linkChecker.ts b/.github/linkChecker.ts index 723c60ae16a..dacc01b084a 100644 --- a/.github/linkChecker.ts +++ b/.github/linkChecker.ts @@ -5,7 +5,7 @@ import { sync as globSync } from 'glob'; const baseUrl = 'http://localhost:3000'; // base url of the website -const whitelist = ["crates.io", "softwaretestinghelp.com", "coinbase.com", "assets.website-files.com", "moralis.io"] // some websites return 404 for head requests, so we need to whitelist them, (fix: pass header -H 'Accept: text/html' and parse text/html) +const whitelist = ["crates.io", "softwaretestinghelp.com", "coinbase.com", "assets.website-files.com", "moralis.io", "1rpc.io"] // some websites return 404 for head requests, so we need to whitelist them, (fix: pass header -H 'Accept: text/html' and parse text/html) // see https://github.com/rust-lang/crates.io/issues/788 interface LinkCheckResult { diff --git a/app/(home)/page.client.tsx b/app/(home)/page.client.tsx index ec71e75ac34..11007d3d18d 100644 --- a/app/(home)/page.client.tsx +++ b/app/(home)/page.client.tsx @@ -5,7 +5,7 @@ import React, { Fragment, type ReactElement, } from 'react'; -import { IndentDecrease, Layers, MailIcon, MonitorCheck, Settings, SproutIcon, SquareGanttChart, TerminalIcon, Webhook, HomeIcon, BadgeDollarSign, CpuIcon, Files, Folder, Globe, Link, SquareIcon, ArrowLeftRight, Coins, SquareCode, SquareStackIcon, Triangle, ChevronDownIcon } from 'lucide-react'; +import { IndentDecrease, Layers, MailIcon, MonitorCheck, Settings, SproutIcon, SquareGanttChart, TerminalIcon, Webhook, HomeIcon, FolderCode, BadgeDollarSign, CpuIcon, Files, Folder, Globe, Link, SquareIcon, ArrowLeftRight, Coins, SquareCode, SquareStackIcon, Triangle, ChevronDownIcon } from 'lucide-react'; import { RootToggle } from 'fumadocs-ui/components/layout/root-toggle'; import { Menu, Transition } from '@headlessui/react' @@ -125,13 +125,19 @@ export function HamburgerMenu(): React.ReactElement { url: '/dapps', }, { - title: 'Avalanche L1s', + title: 'Avalanche CLI', description: 'Build Your L1 Blockchain', icon: , url: '/avalanche-l1s', }, { - title: 'Virtual Machines', + title: 'EVM L1s', + description: 'Customize the Ethereum VM', + icon: , + url: '/evm-l1s', + }, + { + title: 'Custom Virtual Machines', description: 'Customize Your Execution Layer', icon: , url: '/virtual-machines', diff --git a/app/layout.config.tsx b/app/layout.config.tsx index 911b25b22c2..735cf0e4312 100644 --- a/app/layout.config.tsx +++ b/app/layout.config.tsx @@ -2,7 +2,7 @@ import { type BaseLayoutProps, type DocsLayoutProps } from 'fumadocs-ui/layout'; import { Title, HomeTitle } from '@/app/layout.client'; import { docsPageTree } from '@/utils/docs-loader'; import { RootToggle } from 'fumadocs-ui/components/layout/root-toggle'; -import { MailIcon, SproutIcon, SquareGanttChart, IndentDecrease, Layers, MonitorCheck, Settings, Webhook } from 'lucide-react'; +import { MailIcon, SproutIcon, SquareGanttChart, IndentDecrease, Layers, MonitorCheck, Settings, Webhook, Server, FolderCode } from 'lucide-react'; // home page configuration (HomeTitle includes hamburger menu) export const homebaseOptions: BaseLayoutProps = { @@ -68,13 +68,19 @@ export const docsOptions: DocsLayoutProps = { url: '/dapps', }, { - title: 'Avalanche L1s', + title: 'Avalanche CLI', description: 'Build Your L1 Blockchain', icon: , url: '/avalanche-l1s', }, { - title: 'Virtual Machines', + title: 'EVM L1s', + description: 'Customize the Ethereum VM', + icon: , + url: '/evm-l1s', + }, + { + title: 'Custom Virtual Machines', description: 'Customize Your Execution Layer', icon: , url: '/virtual-machines', diff --git a/components/mermaid.tsx b/components/mermaid.tsx new file mode 100644 index 00000000000..b52498d9178 --- /dev/null +++ b/components/mermaid.tsx @@ -0,0 +1,19 @@ +"use client"; +import React, { useEffect } from "react"; +import mermaid from "mermaid"; + +mermaid.initialize({ + startOnLoad: true, +}); + +type MermaidProps = { + readonly chart: string; +}; + +const Mermaid = ({ chart }: MermaidProps): JSX.Element => { + useEffect(() => mermaid.contentLoaded(), []); + + return
{chart}
; +}; + +export default Mermaid; \ No newline at end of file diff --git a/content/docs/avalanche-l1s/add-utility/cross-chain-bridge.mdx b/content/docs/avalanche-l1s/add-utility/cross-chain-bridge.mdx deleted file mode 100644 index 892763eb020..00000000000 --- a/content/docs/avalanche-l1s/add-utility/cross-chain-bridge.mdx +++ /dev/null @@ -1,343 +0,0 @@ ---- -title: Deploy a Cross-Chain Bridge -description: Learn how to deploy a cross-chain bridge between WAGMI and Fuji Testnet. ---- - - -This tutorial is for demo purpose on how to build a cross-chain bridge. It is not for production use. You must take the full responsibility to ensure your bridge's security. - - -Introduction[​](#introduction "Direct link to heading") -------------------------------------------------------- - -In this tutorial, we will be building a bridge between **[WAGMI](/avalanche-l1s/wagmi-avalanche-l1)** and **[Fuji](/learn/networks/fuji-testnet)**. This bridge will help us to transfer native **WGM** coin wrapped into **wWGM** back and forth from the WAGMI chain to the Fuji chain. Using this guide, you can deploy a bridge between any EVM-based chains for any ERC20 tokens. - -The wrapped version of a native coin is its pegged ERC20 representation. Wrapping it with the ERC20 standard makes certain processes like delegated transactions much easier. You can easily get wrapped tokens by sending the native coin to the wrapped token contract address. - -> WAGMI is an independent EVM-based test chain deployed on a custom Avalanche L1 on the Avalanche network. - -We will be using **ChainSafe**\'s bridge repository, to easily set up a robust and secure bridge. - -Workflow of the Bridge[​](#workflow-of-the-bridge "Direct link to heading") ---------------------------------------------------------------------------- - -WAGMI and Fuji chains are not interconnected by default, however, we could make them communicate. Relayers watch for events (by polling blocks) on one chain and perform necessary action using those events on the other chain. This way we can also perform bridging of tokens from one chain to the other chain through the use of smart contracts. - -Here is the basic high-level workflow of the bridge - - -1. Users deposit token on the Bridge contract -2. Bridge contract asks Handler contract to perform deposit action -3. Handler contract **locks** the deposited token in the token safe -4. Bridge contract emits `Deposit` event -5. Relayer receives the `Deposit` event from the source chain -6. Relayer creates a voting proposal on the destination chain to mint a new token -7. After threshold relayer votes, the proposal is executed -8. Tokens are **minted** to the recipient's address - -Bridging tokens from source to destination chain involves the **lock and mint** approach. Whereas bridging tokens from destination to source chain involves **burn and release** approach. We cannot mint and burn tokens that we do not control. Therefore we lock them in the token safe on the source chain. And mint the corresponding token (which we will deploy and hence control) on the destination chain. - -![architecture](/images/cross-chain1.png) - -Requirements[​](#requirements "Direct link to heading") -------------------------------------------------------- - -These are the requirement to follow this tutorial: - -- Set up [WAGMI](/avalanche-l1s/wagmi-avalanche-l1) and [Fuji](/dapps/end-to-end/fuji-workflow#set-up-fuji-network-on-core-optional) on Core -- Import `wWGM` token (asset) on the WAGMI network (Core). Here is the address - `0x3Ee7094DADda15810F191DD6AcF7E4FFa37571e4` -- `WGM` coins on the WAGMI chain. Drip `1 WGM` from the [WAGMI Faucet](https://faucet.trywagmi.xyz/). -- `AVAX` coins on the Fuji chain. Drip `10 AVAX` from the [Fuji Faucet](https://core.app/tools/testnet-faucet//). If you already have an AVAX balance greater than zero on Mainnet, paste your C-Chain address there, and request test tokens. Otherwise, please request a faucet coupon on [Guild](https://guild.xyz/avalanche). Admins and mods on the official [Discord](https://discord.com/invite/RwXY7P6) can provide testnet AVAX if developers are unable to obtain it from the other two options. -- Wrapped `WGM` tokens on the WAGMI chain. Send a few `WGM` coins to the `wWGM` token address (see second point), to receive the same amount of `wWGM`. Always keep some `WGM` coins, to cover transaction fees. - -Setting Up Environment[​](#setting-up-environment "Direct link to heading") ---------------------------------------------------------------------------- - -Let's make a new directory `deploy-bridge`, where we will be keeping our bridge codes. We will be using the following repositories: - -- [`ChainSafe/chainbridge-deploy`](https://github.com/ChainSafe/chainbridge-deploy): This will help us in setting up of our bridge contracts -- [`ChainSafe/ChainBridge`](https://github.com/ChainSafe/ChainBridge): This will help us in setting up of our off-chain relayer. - -### Installing ChainBridge Command-Line Tool[​](#installing-chainbridge-command-line-tool "Direct link to heading") - -Using the following command, we can clone and install ChainBridge's command-line tool. This will help us in setting up bridge contracts and demonstrating bridge transfers. Once the bridge contracts are deployed, you can use its ABI and contract address to set up your UI. - -```bash -git clone -b v1.0.0 --depth 1 https://github.com/ChainSafe/chainbridge-deploy \ -&& cd chainbridge-deploy/cb-sol-cli \ -&& npm install \ -&& make install -``` - -This will build the contracts and installs the `cb-sol-cli` command. - -### Setting Up Environment Variables[​](#setting-up-environment-variables "Direct link to heading") - -Let's set up environment variables, so that, we do not need to write their values every time we issue a command. Move back to the `deploy-bridge` directory (main project directory) and make a new file `configVars`. Put the following contents inside it - - -```bash -SRC_GATEWAY=https://subnets.avax.network/wagmi/wagmi-chain-testnet/rpc -DST_GATEWAY=https://api.avax-test.network/ext/bc/C/rpc - -SRC_ADDR="" -SRC_PK="" -DST_ADDR="" -DST_PK="" - -SRC_TOKEN="0x3Ee7094DADda15810F191DD6AcF7E4FFa37571e4" -RESOURCE_ID="0x00" -``` - -- `SRC_ADDR` and `DST_ADDR` are the addresses that will deploy bridge contracts and will act as a relayer. -- `SRC_TOKEN` is the token that we want to bridge. Here is the address of the wrapped ERC20 version of the WGM coin aka wWGM. -- `RESOURCE_ID` could be anything. It identifies our bridged ERC20 tokens on both sides (WAGMI and Fuji). - -Every time we make changes to these config variables, we have to update our bash environment. Run the following command according to the relative location of the file. These variables are temporary and are only there in the current terminal session, and will be flushed, once the session is over. Make sure to load these environment variables anywhere you will using them in the bash commands (like `$SRC_GATEWAY` or `$SRC_ADDR`) - -Setting Up Source Chain[​](#setting-up-source-chain "Direct link to heading") ------------------------------------------------------------------------------ - -We need to set up our source chain as follows: - -- Deploy Bridge and Handler contract with `$SRC_ADDR` as default and only relayer -- Register the `wWGM` token as a resource on the bridge - -### Deploy Source Contracts[​](#deploy-source-contracts "Direct link to heading") - -The command-line tool `cb-sol-cli` will help us to deploy the contracts. Run the following command in the terminal session where the config vars are loaded. It will add `SRC_ADDR` as the default relayer for relaying events from the WAGMI chain (source) to the Fuji chain (destination). - -**One of the most important parameter to take care of while deploying bridge contract is the `expiry`** **value. It is the number of blocks after which a proposal is considered cancelled. By default it is** **set to `100`. On Avalanche Mainnet, with this value, the proposals could be expired within 3-4 minutes.** **You should choose a very large expiry value, according to the chain you are deploying bridge to.** **Otherwise your proposal will be cancelled if the threshold number of vote proposals are not received** **on time.** - -You should also keep this in mind that sometimes during high network activity, a transaction could stuck for a long time. Proposal transactions stuck in this scenario, could result in the cancellation of previous proposals. Therefore, expiry values should be large enough, and relayers should issue transactions with a competitive max gas price. - -```bash -cb-sol-cli --url $SRC_GATEWAY --privateKey $SRC_PK --gasPrice 25000000000 deploy \ - --bridge --erc20Handler \ - --relayers $SRC_ADDR \ - --relayerThreshold 1 \ - --expiry 500 \ - --chainId 0 -``` - -The output will return deployed contracts' (Bridge and Handler) address. Update the `configVars` file with these addresses by adding the following 2 variables and loading them to the environment. - -```bash -SRC_BRIDGE="" -SRC_HANDLER="" -``` - -Make sure to load these using the `source` command. - -### Configure Resource on Bridge[​](#configure-resource-on-bridge "Direct link to heading") - -Run the following command to register the `wWGM` token as a resource on the source bridge. - -```bash -cb-sol-cli --url $SRC_GATEWAY --privateKey $SRC_PK --gasPrice 25000000000 bridge register-resource \ - --bridge $SRC_BRIDGE \ - --handler $SRC_HANDLER \ - --resourceId $RESOURCE_ID \ - --targetContract $SRC_TOKEN -``` - -Setting Up Destination Chain[​](#setting-up-destination-chain "Direct link to heading") ---------------------------------------------------------------------------------------- - -We need to set up our destination chain as follows: - -- Deploy Bridge and Handler contract with `$DST_ADDR` as default and only relayer -- Deploy mintable and burnable ERC20 contract representing bridged `wWGM` token -- Register the `wWGM` token as a resource on the bridge -- Register the `wWGM` token as mintable/burnable on the bridge -- Giving permissions to Handler contract to mint new `wWGM` tokens - -### Deploy Destination Contracts[​](#deploy-destination-contracts "Direct link to heading") - -Run the following command to deploy Bridge, ERC20 Handler, and `wWGM` token contracts on the Fuji chain. Again it will set `DST_ADDR` as the default relayer for relaying events from Fuji chain (destination) to WAGMI chain (source). For this example, both `SRC_ADDR` and `DST_ADDR` represent the same thing. - -```bash -cb-sol-cli --url $DST_GATEWAY --privateKey $DST_PK --gasPrice 25000000000 deploy\ - --bridge --erc20 --erc20Handler \ - --relayers $DST_ADDR \ - --relayerThreshold 1 \ - --chainId 1 -``` - -Update the environment variables with the details which you will get by running the above command. Don't forget to load these variables. - -```bash -DST_BRIDGE="" -DST_HANDLER="" -DST_TOKEN="" -``` - -### Configuring Resource on Bridge[​](#configuring-resource-on-bridge "Direct link to heading") - -Run the following command to register deployed `wWGM` token as a resource on the bridge. - -```bash -cb-sol-cli --url $DST_GATEWAY --privateKey $DST_PK --gasPrice 25000000000 bridge register-resource \ - --bridge $DST_BRIDGE \ - --handler $DST_HANDLER \ - --resourceId $RESOURCE_ID \ - --targetContract $DST_TOKEN -``` - -### Setting Token as Mintable and Burnable on Bridge[​](#setting-token-as-mintable-and-burnable-on-bridge "Direct link to heading") - -The bridge has two options when it receives a deposit of a token: - -- Lock the received token on one chain and mint the corresponding token on the other chain -- Burn the received token on one chain and release the corresponding token on the other chain - -We cannot mint or burn any token which we do not control. Though we can lock and release such tokens by putting them in a token safe. The bridge has to know which token it can burn. With the following command, we can set the resource as burnable. The bridge will choose the action accordingly, by seeing the token as burnable or not. - -```bash -cb-sol-cli --url $DST_GATEWAY --privateKey $DST_PK --gasPrice 25000000000 bridge set-burn \ - --bridge $DST_BRIDGE \ - --handler $DST_HANDLER \ - --tokenContract $DST_TOKEN -``` - -Now let's permit the handler to mint the deployed ERC20 (wWGM) token on the destination chain. Run the following command. - -```bash -cb-sol-cli --url $DST_GATEWAY --privateKey $DST_PK --gasPrice 25000000000 erc20 add-minter \ - --minter $DST_HANDLER \ - --erc20Address $DST_TOKEN -``` - -> The deployer of the contracts (here `SRC_ADDR` or `DST_ADDR`) holds the admin rights. An admin can add or remove a new relayer, minter, admin etc. It can also mint new ERC20 tokens on the destination chain. You can issue these commands using `cb-sol-cli` with the options mentioned in these [files](https://github.com/ChainSafe/chainbridge-deploy/tree/main/cb-sol-cli/docs). The mint command should not be used manually, unless some intervention is required, when the relayers failed to mint the tokens on the destination chain on time. - -Deploy Relayer[​](#deploy-relayer "Direct link to heading") ------------------------------------------------------------ - -All the on-chain setups like deploying bridges, handlers, tokens, etc. are complete. But the two chains are not interconnected. We need some off-chain relayer to communicate messages between the chains. The relayer will poll for deposit events on one chain, and submit vote proposals to mint or release the corresponding token on another chain. - -Since we set the relayer threshold to 1, while deploying the bridge and handler, we require a voting proposal from only 1 relayer. But in production, we should use a large set of relayers with a high threshold to avoid power concentration. - -For this purpose, we will be using ChainSafe's relayer. Follow the steps described below to deploy the relayer. - -### Cloning and Building Relayer[​](#cloning-and-building-relayer "Direct link to heading") - -Open a new terminal session, while keeping the previous session loaded with environment variables. We have to load the environment variables in this session too. Load these variables in this session too using the `source` command. - -Now, move to the `deploy-bridge` directory and run the following command to clone the relayer repository (implemented in Go), and build its binary. - -```bash -git clone -b v1.1.1 --depth 1 https://github.com/ChainSafe/chainbridge \ -&& cd chainbridge \ -&& make build -``` - -This will create a binary inside the `chainbridge/build` directory as `chainbridge`. - -### Configuring Relayer[​](#configuring-relayer "Direct link to heading") - -The relayer requires some configurations like source chain, destination chain, bridge, handler address, etc. Run the following command. It will make a `config.json` file with the required details in it. You can update these details, as per your need. - -```bash -echo "{ - \"chains\": [ - { - \"name\": \"WAGMI\", - \"type\": \"ethereum\", - \"id\": \"0\", - \"endpoint\": \"$SRC_GATEWAY\", - \"from\": \"$SRC_ADDR\", - \"opts\": { - \"bridge\": \"$SRC_BRIDGE\", - \"erc20Handler\": \"$SRC_HANDLER\", - \"genericHandler\": \"$SRC_HANDLER\", - \"gasLimit\": \"1000000\", - \"maxGasPrice\": \"50000000000\", - \"http\": \"true\", - \"blockConfirmations\":\"0\" - } - }, - { - \"name\": \"Fuji\", - \"type\": \"ethereum\", - \"id\": \"1\", - \"endpoint\": \"$DST_GATEWAY\", - \"from\": \"$DST_ADDR\", - \"opts\": { - \"bridge\": \"$DST_BRIDGE\", - \"erc20Handler\": \"$DST_HANDLER\", - \"genericHandler\": \"$DST_HANDLER\", - \"gasLimit\": \"1000000\", - \"maxGasPrice\": \"50000000000\", - \"http\": \"true\", - \"blockConfirmations\":\"0\" - } - } - ] -}" >> config.json -``` - -Check and confirm the details in the `config.json` file. - -> In the above command, you can see that `blockConfirmations` is set to `0`. This will work well for networks like Avalanche because the block is confirmed once it's committed. Unlike other chains such as Ethereum, which requires 20-30 block confirmations. Therefore, use this configuration with caution, depending on the type of chain you are using. - -> It can cause serious problems if a corresponding token is minted or released based on an unconfirmed block. - -### Set Up Keys[​](#set-up-keys "Direct link to heading") - -Give relayer access to your keys. Using these keys, the relayer will propose deposit events and execute proposals. It will ask to set a password for encrypting these keys. Every time you start the relayer, it will ask for this password. - -```bash -./build/chainbridge accounts import --privateKey $SRC_PK -``` - -```bash -./build/chainbridge accounts import --privateKey $DST_PK -``` - -Let's Test the Bridge[​](#lets-test-the-bridge "Direct link to heading") ------------------------------------------------------------------------- - -The setup is now complete - both on-chain and off-chain. Now we just have to start the relayer and test the bridge. For testing purposes, we will be using `cb-sol-cli` to make deposit transactions on the bridge. But you can make your frontend and integrate it with the bridge using the ABIs. - -### Start Relayer[​](#start-relayer "Direct link to heading") - -Run the following command to start the relayer. It will print logs of all the events associated with our bridge, happening on both the chains. So keep the relayer running and follow the next commands in the other terminal session. - -```bash -./build/chainbridge --config config.json --verbosity trace --latest -``` - -### Approve Handler to Spend my Tokens[​](#approve-handler-to-spend-my-tokens "Direct link to heading") - -Now, let's deposit tokens on the WAGMI bridge. But before that, we need to approve the handler to spend (lock or burn) tokens on our (here `SRC_PK`) behalf. The amount here is in Wei (1 ether (WGM) = 10^18 Wei). We will be approving 0.1 wWGM. - -```bash -cb-sol-cli --url $SRC_GATEWAY --privateKey $SRC_PK --gasPrice 25000000000 erc20 approve \ - --amount 100000000000000000 \ - --erc20Address $SRC_TOKEN \ - --recipient $SRC_HANDLER -``` - -### Deposit Tokens to the Bridge[​](#deposit-tokens-to-the-bridge "Direct link to heading") - -Once approved, we can send a deposit transaction. Now let's deposit 0.1 wWGM on the bridge. The handler will lock (transfer to token safe) 0.1 wWGM from our address (here `SRC_PK`) and mint the new tokens on the destination chain to the recipient (here `DST_ADDR`). - -```bash -cb-sol-cli --url $SRC_GATEWAY --privateKey $SRC_PK --gasPrice 25000000000 erc20 deposit \ - --amount 100000000000000000 \ - --dest 1 \ - --bridge $SRC_BRIDGE \ - --recipient $DST_ADDR \ - --resourceId $RESOURCE_ID -``` - -This transaction will transfer 0.1 wWGM to token safe and emit a `Deposit` event, which will be captured by the relayer. Following this event, it will send a voting proposal to the destination chain. Since the threshold is 1, the bridge will execute the proposal, and new wWGM minted to the recipient's address. Here is the screenshot of the output from the relayer. - -![output](/images/cross-chain2.png) - -Similarly, we can transfer the tokens back to the WAGMI chain. - -Conclusion[​](#conclusion "Direct link to heading") ---------------------------------------------------- - -Similar to the above process, you can deploy a bridge between any 2 EVM-based chains. We have used the command-line tool to make approvals and deposits. This can be further extended to build a frontend integrated with the bridge. Currently, it depends on a single relayer, which is not secure. We need a large set of relayers and a high threshold to avoid any kind of centralization. - -You can learn more about these contracts and implementations by reading ChainSafe's [ChainBridge](https://chainbridge.chainsafe.io/) documentation. diff --git a/content/docs/avalanche-l1s/elastic-avalanche-l1s/make-avalanche-l1-permissionless.mdx b/content/docs/avalanche-l1s/elastic-avalanche-l1s/make-avalanche-l1-permissionless.mdx index ca134793fc9..9a216cc7fb1 100644 --- a/content/docs/avalanche-l1s/elastic-avalanche-l1s/make-avalanche-l1-permissionless.mdx +++ b/content/docs/avalanche-l1s/elastic-avalanche-l1s/make-avalanche-l1-permissionless.mdx @@ -3,6 +3,8 @@ title: Make Avalanche L1 Permissionless description: Learn how to transform a Permissioned Avalanche L1 into an Elastic Avalanche L1. --- +> Elastic L1s / Elastic Subnets have been deprecated. Please check out the PoS Validator Manager instead + Elastic Avalanche L1s are permissionless Avalanche L1s. More information can be found [here](/avalanche-l1s/elastic-avalanche-l1s/parameters). This how-to guide focuses on taking an already created permissioned Avalanche L1 and transforming it to an elastic (or permissionless) Avalanche L1. diff --git a/content/docs/avalanche-l1s/elastic-avalanche-l1s/parameters.mdx b/content/docs/avalanche-l1s/elastic-avalanche-l1s/parameters.mdx index 44e4df0b5a5..138a733f71f 100644 --- a/content/docs/avalanche-l1s/elastic-avalanche-l1s/parameters.mdx +++ b/content/docs/avalanche-l1s/elastic-avalanche-l1s/parameters.mdx @@ -3,6 +3,8 @@ title: Parameters description: Learn about the different parameters of Elastic Avalanche L1s. --- +> Elastic L1s / Elastic Subnets have been deprecated. Please check out the PoS Validator Manager instead + Avalanche Permissioned Avalanche L1s can be turned into Elastic Avalanche L1s via the `TransformSubnetTx` transaction. `TransformSubnetTx` specifies a set of structural parameters for the Elastic Avalanche L1. This reference document describes these structural parameters and illustrates the constraints they must satisfy. diff --git a/content/docs/avalanche-l1s/meta.json b/content/docs/avalanche-l1s/meta.json index 6d4497efa87..7f049290873 100644 --- a/content/docs/avalanche-l1s/meta.json +++ b/content/docs/avalanche-l1s/meta.json @@ -14,22 +14,14 @@ "deploy-a-avalanche-l1/production-infrastructure", "deploy-a-avalanche-l1/multisig-auth", "deploy-a-avalanche-l1/custom-virtual-machine", - "---Elastic Avalanche L1s---", - "elastic-avalanche-l1s/make-avalanche-l1-permissionless", - "elastic-avalanche-l1s/parameters", "---Maintain an Avalanche L1---", "maintain/view-avalanche-l1s", "maintain/pause-resume", "maintain/delete-avalanche-l1", "maintain/transfer-pchain-funds", - "---Add Utility on an Avalanche L1---", - "add-utility/deploy-smart-contract", - "add-utility/testnet-faucet", - "add-utility/cross-chain-bridge", "---Upgrade an Avalanche L1---", "...upgrade", "---Miscellaneous---", - "wagmi-avalanche-l1", "troubleshooting" ] } \ No newline at end of file diff --git a/content/docs/avalanche-l1s/upgrade/customize-avalanche-l1.mdx b/content/docs/avalanche-l1s/upgrade/customize-avalanche-l1.mdx index 12729021563..a7a056573a1 100644 --- a/content/docs/avalanche-l1s/upgrade/customize-avalanche-l1.mdx +++ b/content/docs/avalanche-l1s/upgrade/customize-avalanche-l1.mdx @@ -427,262 +427,9 @@ In the amount field you can specify either decimal or hex string. This will mint ### Configuring Dynamic Fees[​](#configuring-dynamic-fees "Direct link to heading") -You can configure the parameters of the dynamic fee algorithm on chain using the `FeeConfigManager`. In order to activate this feature, you will need to provide the `FeeConfigManager` in the genesis: - -```json -{ - "config": { - "feeManagerConfig": { - "blockTimestamp": 0, - "adminAddresses": ["0x8db97C7cEcE249c2b98bDC0226Cc4C2A57BF52FC"] - } - } -} -``` - -The precompile implements the `FeeManager` interface which includes the same `AllowList` interface used by ContractNativeMinter, TxAllowList, etc. For an example of the `AllowList` interface, see the [TxAllowList](#allowlist-interface) above. - -The `Stateful Precompile` contract powering the `FeeConfigManager` adheres to the following Solidity interface at `0x0200000000000000000000000000000000000003` (you can load this interface and interact directly in Remix). It can be also found in [IFeeManager.sol](https://github.com/ava-labs/subnet-evm/blob/5faabfeaa021a64c2616380ed2d6ec0a96c8f96d/contract-examples/contracts/IFeeManager.sol): - -```solidity -//SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; -import "./IAllowList.sol"; - -interface IFeeManager is IAllowList { - struct FeeConfig { - uint256 gasLimit; - uint256 targetBlockRate; - uint256 minBaseFee; - uint256 targetGas; - uint256 baseFeeChangeDenominator; - uint256 minBlockGasCost; - uint256 maxBlockGasCost; - uint256 blockGasCostStep; - } - event FeeConfigChanged( - address indexed sender, - FeeConfig oldFeeConfig, - FeeConfig newFeeConfig - ); - - // Set fee config fields to contract storage - function setFeeConfig( - uint256 gasLimit, - uint256 targetBlockRate, - uint256 minBaseFee, - uint256 targetGas, - uint256 baseFeeChangeDenominator, - uint256 minBlockGasCost, - uint256 maxBlockGasCost, - uint256 blockGasCostStep - ) external; - - // Get fee config from the contract storage - function getFeeConfig() - external - view - returns ( - uint256 gasLimit, - uint256 targetBlockRate, - uint256 minBaseFee, - uint256 targetGas, - uint256 baseFeeChangeDenominator, - uint256 minBlockGasCost, - uint256 maxBlockGasCost, - uint256 blockGasCostStep - ); - - // Get the last block number changed the fee config from the contract storage - function getFeeConfigLastChangedAt() - external - view - returns (uint256 blockNumber); -} -``` - -FeeConfigManager precompile uses `IAllowList` interface directly, meaning that it uses the same `AllowList` interface functions like `readAllowList` and `setAdmin`, `setManager`, `setEnabled`, `setNone`. For more information see [AllowList Solidity interface](#allowlist-interface). - -In addition to the `AllowList` interface, the FeeConfigManager adds the following capabilities: - -- `getFeeConfig`: retrieves the current dynamic fee config -- `getFeeConfigLastChangedAt`: retrieves the timestamp of the last block where the fee config was updated -- `setFeeConfig`: sets the dynamic fee config on chain (see [here](#fee-config) for details on the fee config parameters). This function can only be called by an `Admin`, `Manager` or `Enabled` address. -- `FeeConfigChanged`: an event that is emitted when the fee config is updated. Topics include the sender, the old fee config, and the new fee config. - -You can also get the fee configuration at a block with the `eth_feeConfig` RPC method. For more information see [here](/api-reference/subnet-evm-api#eth_feeconfig). - -#### Initial Fee Config Configuration[​](#initial-fee-config-configuration "Direct link to heading") - -It's possible to enable this precompile with an initial configuration to activate its effect on activation timestamp. This provides a way to define your fee structure to take effect at the activation. - -To use the initial configuration, you need to specify the fee config in `initialFeeConfig` field in your genesis or upgrade file: - -```json -{ - "feeManagerConfig": { - "blockTimestamp": 0, - "initialFeeConfig": { - "gasLimit": 20000000, - "targetBlockRate": 2, - "minBaseFee": 1000000000, - "targetGas": 100000000, - "baseFeeChangeDenominator": 48, - "minBlockGasCost": 0, - "maxBlockGasCost": 10000000, - "blockGasCostStep": 500000 - } - } -} -``` - -This will set the fee config to the values specified in the `initialFeeConfig` field. For further information about precompile initial configurations see [Initial Precompile Configurations](#initial-precompile-configurations). - -### Changing Fee Reward Mechanisms[​](#changing-fee-reward-mechanisms "Direct link to heading") - -Fee reward mechanism can be configured with this stateful precompile contract called as `RewardManager`. Configuration can include burning fees, sending fees to a predefined address, or enabling fees to be collected by block producers. This precompile can be configured as follows in the genesis file: - -```json -{ - "config": { - "rewardManagerConfig": { - "blockTimestamp": 0, - "adminAddresses": ["0x8db97C7cEcE249c2b98bDC0226Cc4C2A57BF52FC"] - } - } -} -``` - -`adminAddresses` denotes admin accounts who can add other `Admin` or `Enabled` accounts. `Admin`, `Manager` and `Enabled` are both eligible to change the current fee mechanism. - -The precompile implements the `RewardManager` interface which includes the `AllowList` interface. For an example of the `AllowList` interface, see the [TxAllowList](#allowlist-interface) above. - -The `Stateful Precompile` contract powering the `RewardManager` adheres to the following Solidity interface at `0x0200000000000000000000000000000000000004` (you can load this interface and interact directly in Remix). It can be also found in [IRewardManager.sol](https://github.com/ava-labs/subnet-evm/blob/5faabfeaa021a64c2616380ed2d6ec0a96c8f96d/contract-examples/contracts/IRewardManager.sol): - -```solidity -//SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; -import "./IAllowList.sol"; - -interface IRewardManager is IAllowList { - // RewardAddressChanged is the event logged whenever reward address is modified - event RewardAddressChanged( - address indexed sender, - address indexed oldRewardAddress, - address indexed newRewardAddress - ); - - // FeeRecipientsAllowed is the event logged whenever fee recipient is modified - event FeeRecipientsAllowed(address indexed sender); - - // RewardsDisabled is the event logged whenever rewards are disabled - event RewardsDisabled(address indexed sender); - - // setRewardAddress sets the reward address to the given address - function setRewardAddress(address addr) external; - - // allowFeeRecipients allows block builders to claim fees - function allowFeeRecipients() external; - - // disableRewards disables block rewards and starts burning fees - function disableRewards() external; - - // currentRewardAddress returns the current reward address - function currentRewardAddress() external view returns (address rewardAddress); - - // areFeeRecipientsAllowed returns true if fee recipients are allowed - function areFeeRecipientsAllowed() external view returns (bool isAllowed); -} -``` - -`RewardManager` precompile uses `IAllowList` interface directly, meaning that it uses the same `AllowList` interface functions like `readAllowList` and `setAdmin`, `setEnabled`, `setNone`. For more information see [AllowList Solidity interface](#allowlist-interface). - -In addition to the `AllowList` interface, the `RewardManager` adds the following capabilities: - -- `setRewardAddress`: sets the address to which fees are sent. This address can be a contract or a user address. The address becomes the required coinbase address for the blocks that this mechanism is enabled on. Meaning that it will receive the fees collected from the transactions in the block. Receiving fees will not call any contract functions or fallback functions. It will simply increase the balance of the address by the amount of fees. -- `allowFeeRecipients`: enables block producers to claim fees. This will allow block producers to claim fees by specifying their own addresses in their chain configs. See [here](#fee-recipient) for more information on how to specify the fee recipient address in the chain config. -- `disableRewards`: disables block rewards and starts burning fees. -- `currentRewardAddress`: returns the current reward address. This is the address to which fees are sent. It can include black hole address (`0x010...0`) which means that fees are burned. It can also include a predefined hash (`0x0000000000000000000000000000000000000000`) denoting custom fee recipients are allowed. It's advised to use the `areFeeRecipientsAllowed` function to check if custom fee recipients are allowed first. -- `areFeeRecipientsAllowed`: returns true if custom fee recipients are allowed. -- `RewardAddressChanged`: an event that is emitted when the reward address is updated. Topics include the sender, the old reward address, and the new reward address. -- `FeeRecipientsAllowed`: an event that is emitted when fee recipients are allowed. Topics include the sender. -- `RewardsDisabled`: an event that is emitted when rewards are disabled. Topics include the sender. - -These 3 mechanisms (burning, sending to a predefined address, and enabling fees to be collected by block producers) cannot be enabled at the same time. Enabling one mechanism will take over the previous mechanism. For example, if you enable `allowFeeRecipients` and then enable `disableRewards`, the `disableRewards` will take over and fees will be burned. - -Note that reward addresses or fee recipient addresses are not required to be an admin or enabled account. - -#### Initial Configuration[​](#initial-configuration "Direct link to heading") - -It's possible to enable this precompile with an initial configuration to activate its effect on activation timestamp. This provides a way to enable the precompile without an admin address to change the fee reward mechanism. This can be useful for networks that require a one-time reward mechanism change without specifying any admin addresses. Without this initial configuration, the precompile will inherit the `feeRecipients` mechanism activated at genesis. Meaning that if `allowFeeRecipients` is set to true in the genesis file, the precompile will be enabled with the `allowFeeRecipients` mechanism. Otherwise it will keep burning fees. To use the initial configuration, you need to specify the initial reward mechanism in `initialRewardConfig` field in your genesis or upgrade file. - -In order to allow custom fee recipients, you need to specify the `allowFeeRecipients` field in the `initialRewardConfig`: - -```json -{ - "rewardManagerConfig": { - "blockTimestamp": 0, - "initialRewardConfig": { - "allowFeeRecipients": true - } - } -} -``` - -In order to set an address to receive all transaction rewards, you need to specify the `rewardAddress` field in the `initialRewardConfig`: - -```json -{ - "rewardManagerConfig": { - "blockTimestamp": 0, - "initialRewardConfig": { - "rewardAddress": "0x8db97C7cEcE249c2b98bDC0226Cc4C2A57BF52FC" - } - } -} -``` - -In order to disable rewards and start burning fees, you need to leave all fields in the `initialRewardConfig` empty: - -```json -{ - "rewardManagerConfig": { - "blockTimestamp": 0, - "initialRewardConfig": {} - } -} -``` - -However this is different than the default behavior of the precompile. If you don't specify the `initialRewardConfig` field, the precompile will inherit the `feeRecipients` mechanism activated at genesis. Meaning that if `allowFeeRecipients` is set to true in the genesis file, the precompile will be enabled with the `allowFeeRecipients` mechanism. Otherwise it will keep burning fees. Example configuration for this case: - -```json -{ - "rewardManagerConfig": { - "blockTimestamp": 0, - "adminAddresses": ["0x8db97C7cEcE249c2b98bDC0226Cc4C2A57BF52FC"] - } -} -``` - -If `allowFeeRecipients` and `rewardAddress` are both specified in the `initialRewardConfig` field then an error will be returned and precompile won't be activated. For further information about precompile initial configurations see [Initial Precompile Configurations](#initial-precompile-configurations). ### Avalanche Warp Messaging[​](#avalanche-warp-messaging "Direct link to heading") -Warp Precompile enabled cross-blockchain communication between other Layer 1s and primary-network (C-Chain). In order to use Warp messaging, Subnet-EVM chains must activate their Warp precompiles. Warp can be activated with the following lines in upgrade.json: - -```json -{ - "warpConfig": { - "blockTimestamp": (uint), - "quorumNumerator": (uint) - } -} -``` - -`blockTimestamp` must be set to a timestamp after Durango date. `quorumNumerator` is the stake percentage of validators that must sign a Warp message for it to be considered valid. It must be set to a value between 33 and 100. The default value is 67. The `warpConfig` precompile can be later disabled by setting `disable` to `true` in the upgrade.json file. - -If you want to use Warp messaging in an existing Subnet-EVM chain, you should coordinate an upgrade with `upgrade.json`. See [Network Upgrades: Enable/Disable Precompiles](#network-upgrades-enabledisable-precompiles) for more information. - Currently Warp Precompile can only be activated in Mainnet after Durango occurs. Durango in Mainnet is set at 11 AM ET (4 PM UTC) on Wednesday, March 6th, 2024. If you plan to use Warp messaging in your own Subnet-EVM chain in Mainnet you should upgrade to AvalancheGo 1.11.11 or later and coordinate your precompile upgrade. Warp Config's "blockTimestamp" must be set after `1709740800`, Durango date (11 AM ET (4 PM UTC) on Wednesday, March 6th, 2024). diff --git a/content/docs/dapps/c-chain-or-avalanche-l1.mdx b/content/docs/dapps/c-chain-or-avalanche-l1.mdx new file mode 100644 index 00000000000..13117e6b554 --- /dev/null +++ b/content/docs/dapps/c-chain-or-avalanche-l1.mdx @@ -0,0 +1,63 @@ +--- +title: C-Chain or Avalanche L1? +description: Learn key concepts to decide when to build on an Avalanche L1 vs. C-Chain. +--- + +In this article, we discuss often-overlooked differentiating characteristics of Avalanche L1s, with a primary focus on EVM-based applications. The goal is to identify the pros and cons of building an app on [C-Chain](/learn/primary-network#c-chain) versus [Subnet-EVM](https://github.com/ava-labs/subnet-evm), and help developers make more informed decisions. + +When to Use an Avalanche L1[​](#when-to-use-a-avalanche-l1 "Direct link to heading") +----------------------------------------------------------------------- + +There are many advantages to running your own Avalanche L1. If you find one or more of these a good match for your project then an Avalanche L1 might be a good solution for you. But make sure to check the reasons to use the C-Chain instead, as some trade-offs involved might make that a preferred solution. + +### We Want Our Own Gas Token[​](#we-want-our-own-gas-token "Direct link to heading") + +C-Chain is an Ethereum Virtual Machine (EVM) chain; it requires the gas fees to be paid in its native token. That is, the application may create its own utility tokens (ERC-20) on the C-Chain, but the gas must be paid in AVAX. In the meantime, [Subnet-EVM](https://github.com/ava-labs/subnet-evm) effectively creates an application-specific EVM-chain with full control over native(gas) coins. The operator can pre-allocate the native tokens in the chain genesis, and mint more using the [Subnet-EVM](https://github.com/ava-labs/subnet-evm) precompile contract. And these fees can be either burned (as AVAX burns in C-Chain) or configured to be sent to an address which can be a smart contract. + +Note that the Avalanche L1 gas token is specific to the application in the chain, thus unknown to the external parties. Moving assets to other chains requires trusted bridge contracts (or upcoming cross Avalanche L1 communication feature). + +### We Want Higher Throughput[​](#we-want-higher-throughput "Direct link to heading") + +The primary goal of the gas limit on C-Chain is to restrict the block size and therefore prevent network saturation. If a block can be arbitrarily large, it takes longer to propagate, potentially degrading the network performance. The C-Chain gas limit acts as a deterrent against any system abuse but can be quite limiting for high throughput applications. Unlike C-Chain, Avalanche L1 can be single-tenant, dedicated to the specific application, and thus host its own set of validators with higher bandwidth requirements, which allows for a higher gas limit thus higher transaction throughput. Plus, [Subnet-EVM](https://github.com/ava-labs/subnet-evm) supports fee configuration upgrades that can be adaptive to the surge in application traffic. + +Avalanche L1 workloads are isolated from the Primary Network; which means, the noisy neighbor effect of one workload (for example NFT mint on C-Chain) cannot destabilize the Avalanche L1 or surge its gas price. This failure isolation model in the Avalanche L1 can provide higher application reliability. + +### We Want Strict Access Control[​](#we-want-strict-access-control "Direct link to heading") + +The C-Chain is open and permissionless where anyone can deploy and interact with contracts. However, for regulatory reasons, some applications may need a consistent access control mechanism for all on-chain transactions. With [Subnet-EVM](https://github.com/ava-labs/subnet-evm), an application can require that “only authorized users may deploy contracts or make transactions.” Allow-lists are only updated by the administrators, and the allow list itself is implemented within the precompile contract, thus more transparent and auditable for compliance matters. + +### We Need EVM Customization[​](#we-need-evm-customization "Direct link to heading") + +If your project is deployed on the C-Chain then your execution environment is dictated by the setup of the C-Chain. Changing any of the execution parameters means that the configuration of the C-Chain would need to change, and that is expensive, complex and difficult to change. So if your project needs some other capabilities, different execution parameters or precompiles that C-Chain does not provide, then Avalanche L1s are a solution you need. You can configure the EVM in an Avalanche L1 to run however you want, adding precompiles, and setting runtime parameters to whatever your project needs. + +When to Use the C-Chain[​](#when-to-use-the-c-chain "Direct link to heading") +----------------------------------------------------------------------------- + +All the reasons for using an Avalanche L1 outlined above are very attractive to developers and might make it seem that every new project should look into launching an Avalanche L1 instead of using the C-Chain. Of course, things are rarely that simple and without trade-offs. Here are some advantages of the C-Chain that you should take into account. + +### We Want High Composability with C-Chain Assets[​](#we-want-high-composability-with-c-chain-assets "Direct link to heading") + +C-Chain is a better option for seamless integration with existing C-Chain assets and contracts. It is easier to build a DeFi application on C-Chain, as it provides larger liquidity pools and thus allows for efficient exchange between popular assets. A DeFi Avalanche L1 can still support composability of contracts on C-Chain assets but requires some sort of off-chain system via the bridge contract. In other words, an Avalanche L1 can be a better choice if the application does not need high composability with the existing C-Chain assets. Plus, the upcoming support for cross Avalanche L1 communication will greatly simplify the bridging process. + +### We Want High Security[​](#we-want-high-security "Direct link to heading") + +The security of Avalanche Primary Network is a function of the security of the underlying validators and stake delegators. Some choose C-Chain in order to achieve maximum security by utilizing thousands of Avalanche Primary Network validators. Some may choose to not rely on the entire security of the base chain. + +The better approach is to scale up the security as the application accrues more values and adoption from its users. And Avalanche L1 can provide elastic, on-demand security to take such organic growth into account. + +### We Want Low Initial Cost[​](#we-want-low-initial-cost "Direct link to heading") + +C-Chain has economic advantages of low-cost deployment, whereas each Avalanche L1 validator is required to validate the Primary Network by staking AVAX (minimum 2,000 AVAX for Mainnet). For fault tolerance, we recommend at least five validators for an Avalanche L1, even though there is no requirement that the Avalanche L1 owner should own all these 5 validators, it still further increases the upfront costs. + +### We Want Low Operational Costs[​](#we-want-low-operational-costs "Direct link to heading") + +C-Chain is run and operated by thousands of nodes, it is highly decentralized and reliable, and all the infrastructure (explorers, indexers, exchanges, bridges) has already been built out by dedicated teams that maintain them for you at no extra charge. Project deployed on the C-Chain can leverage all of that basically for free. On the other hand, if you run your own Avalanche L1 you are basically in charge of running your own L1 network. You (or someone who you partner with or pay to) will need to do all those things and you will ultimately be responsible for them. If you don't have a desire, resources or partnerships to operate a high-availability 24/7 platform, you're probably better off deploying on the C-Chain. + +Conclusion[​](#conclusion "Direct link to heading") +--------------------------------------------------- + +Here we presented some considerations both in favor of running your own Avalanche L1 and in favor of deploying on the C-Chain. You should carefully weigh and consider what makes the most sense for your and your project: deploying on an Avalanche L1 or deploying on the C-Chain. + +But, there is also a third way: deploy on C-Chain now, then move to your own Avalanche L1 later. If an application has relatively low transaction rate and no special circumstances that would make the C-Chain a non-starter, you can begin with C-Chain deployment to leverage existing technical infrastructure, and later expand to an Avalanche L1. That way you can focus on working on the core of your project and once you have a solid product/market fit and have gained enough traction that the C-Chain is constricting you, plan a move to your own Avalanche L1. + +Of course, we're happy to talk to you about your architecture and help you choose the best path forward. Feel free to reach out to us on [Discord](https://chat.avalabs.org/) or other [community channels](https://www.avax.network/community) we run. \ No newline at end of file diff --git a/content/docs/dapps/meta.json b/content/docs/dapps/meta.json index 39f1b02ccc9..ec70d7b1112 100644 --- a/content/docs/dapps/meta.json +++ b/content/docs/dapps/meta.json @@ -4,6 +4,7 @@ "pages": [ "---dApps on Avalanche---", "index", + "c-chain-or-avalanche-l1", "chain-settings", "block-explorers", "---Smart Contract Development---", diff --git a/content/docs/virtual-machines/evm-customization/background-requirements.mdx b/content/docs/evm-l1s/custom-precompiles/background-requirements.mdx similarity index 100% rename from content/docs/virtual-machines/evm-customization/background-requirements.mdx rename to content/docs/evm-l1s/custom-precompiles/background-requirements.mdx diff --git a/content/docs/virtual-machines/evm-customization/defining-precompile.mdx b/content/docs/evm-l1s/custom-precompiles/defining-precompile.mdx similarity index 100% rename from content/docs/virtual-machines/evm-customization/defining-precompile.mdx rename to content/docs/evm-l1s/custom-precompiles/defining-precompile.mdx diff --git a/content/docs/virtual-machines/evm-customization/deploying-precompile.mdx b/content/docs/evm-l1s/custom-precompiles/deploying-precompile.mdx similarity index 100% rename from content/docs/virtual-machines/evm-customization/deploying-precompile.mdx rename to content/docs/evm-l1s/custom-precompiles/deploying-precompile.mdx diff --git a/content/docs/virtual-machines/evm-customization/executing-test-cases.mdx b/content/docs/evm-l1s/custom-precompiles/executing-test-cases.mdx similarity index 100% rename from content/docs/virtual-machines/evm-customization/executing-test-cases.mdx rename to content/docs/evm-l1s/custom-precompiles/executing-test-cases.mdx diff --git a/content/docs/virtual-machines/evm-customization/generating-your-precompile.mdx b/content/docs/evm-l1s/custom-precompiles/generating-your-precompile.mdx similarity index 100% rename from content/docs/virtual-machines/evm-customization/generating-your-precompile.mdx rename to content/docs/evm-l1s/custom-precompiles/generating-your-precompile.mdx diff --git a/content/docs/virtual-machines/evm-customization/introduction.mdx b/content/docs/evm-l1s/custom-precompiles/introduction.mdx similarity index 100% rename from content/docs/virtual-machines/evm-customization/introduction.mdx rename to content/docs/evm-l1s/custom-precompiles/introduction.mdx diff --git a/content/docs/virtual-machines/evm-customization/writing-test-cases.mdx b/content/docs/evm-l1s/custom-precompiles/writing-test-cases.mdx similarity index 100% rename from content/docs/virtual-machines/evm-customization/writing-test-cases.mdx rename to content/docs/evm-l1s/custom-precompiles/writing-test-cases.mdx diff --git a/content/docs/evm-l1s/default-precompiles/allowlist.mdx b/content/docs/evm-l1s/default-precompiles/allowlist.mdx new file mode 100644 index 00000000000..d1e918a0915 --- /dev/null +++ b/content/docs/evm-l1s/default-precompiles/allowlist.mdx @@ -0,0 +1,13 @@ +--- +title: AllowList Interface +description: The AllowList interface is used by many default precompiles to permission access to the features they provide. +--- + +The AllowList is a security feature used by precompiles to manage which addresses have permission to interact with certain contract functionalities. In the case of the Native Minter Precompile, the allow list is used to control who can mint new native tokens. + +The AllowList consists of three roles: +- **Admin**: Full control over the allow list, including the ability to add or remove Admins, Managers, and Enabled addresses. +- **Manager**: Can add or remove **Enabled** addresses but cannot modify Admins or Managers. +- **Enabled**: These addresses can use the precompiled contract (e.g., mint native tokens) but cannot modify the allow list. + +The allow list provides a granular way to assign permissions, ensuring that only authorized addresses can mint native tokens or manage the minting process. \ No newline at end of file diff --git a/content/docs/evm-l1s/default-precompiles/feemanager.mdx b/content/docs/evm-l1s/default-precompiles/feemanager.mdx new file mode 100644 index 00000000000..a0254c49f4a --- /dev/null +++ b/content/docs/evm-l1s/default-precompiles/feemanager.mdx @@ -0,0 +1,115 @@ +--- +title: FeeManager Precompile +description: Learn how to use the FeeManager Precompile on your Avalanche L1 blockchain. +--- + +You can configure the parameters of the dynamic fee algorithm on chain using the `FeeConfigManager`. In order to activate this feature, you will need to provide the `FeeConfigManager` in the genesis: + +```json +{ + "config": { + "feeManagerConfig": { + "blockTimestamp": 0, + "adminAddresses": ["0x8db97C7cEcE249c2b98bDC0226Cc4C2A57BF52FC"] + } + } +} +``` + +The precompile implements the `FeeManager` interface which includes the same `AllowList` interface used by ContractNativeMinter, TxAllowList, etc. For an example of the `AllowList` interface, see the [TxAllowList](#allowlist-interface) above. + +The `Stateful Precompile` contract powering the `FeeConfigManager` adheres to the following Solidity interface at `0x0200000000000000000000000000000000000003` (you can load this interface and interact directly in Remix). It can be also found in [IFeeManager.sol](https://github.com/ava-labs/subnet-evm/blob/5faabfeaa021a64c2616380ed2d6ec0a96c8f96d/contract-examples/contracts/IFeeManager.sol): + +```solidity +//SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; +import "./IAllowList.sol"; + +interface IFeeManager is IAllowList { + struct FeeConfig { + uint256 gasLimit; + uint256 targetBlockRate; + uint256 minBaseFee; + uint256 targetGas; + uint256 baseFeeChangeDenominator; + uint256 minBlockGasCost; + uint256 maxBlockGasCost; + uint256 blockGasCostStep; + } + event FeeConfigChanged( + address indexed sender, + FeeConfig oldFeeConfig, + FeeConfig newFeeConfig + ); + + // Set fee config fields to contract storage + function setFeeConfig( + uint256 gasLimit, + uint256 targetBlockRate, + uint256 minBaseFee, + uint256 targetGas, + uint256 baseFeeChangeDenominator, + uint256 minBlockGasCost, + uint256 maxBlockGasCost, + uint256 blockGasCostStep + ) external; + + // Get fee config from the contract storage + function getFeeConfig() + external + view + returns ( + uint256 gasLimit, + uint256 targetBlockRate, + uint256 minBaseFee, + uint256 targetGas, + uint256 baseFeeChangeDenominator, + uint256 minBlockGasCost, + uint256 maxBlockGasCost, + uint256 blockGasCostStep + ); + + // Get the last block number changed the fee config from the contract storage + function getFeeConfigLastChangedAt() + external + view + returns (uint256 blockNumber); +} +``` + +FeeConfigManager precompile uses `IAllowList` interface directly, meaning that it uses the same `AllowList` interface functions like `readAllowList` and `setAdmin`, `setManager`, `setEnabled`, `setNone`. For more information see [AllowList Solidity interface](#allowlist-interface). + +In addition to the `AllowList` interface, the FeeConfigManager adds the following capabilities: + +- `getFeeConfig`: retrieves the current dynamic fee config +- `getFeeConfigLastChangedAt`: retrieves the timestamp of the last block where the fee config was updated +- `setFeeConfig`: sets the dynamic fee config on chain (see [here](#fee-config) for details on the fee config parameters). This function can only be called by an `Admin`, `Manager` or `Enabled` address. +- `FeeConfigChanged`: an event that is emitted when the fee config is updated. Topics include the sender, the old fee config, and the new fee config. + +You can also get the fee configuration at a block with the `eth_feeConfig` RPC method. For more information see [here](/api-reference/subnet-evm-api#eth_feeconfig). + +#### Initial Fee Config Configuration[​](#initial-fee-config-configuration "Direct link to heading") + +It's possible to enable this precompile with an initial configuration to activate its effect on activation timestamp. This provides a way to define your fee structure to take effect at the activation. + +To use the initial configuration, you need to specify the fee config in `initialFeeConfig` field in your genesis or upgrade file: + +```json +{ + "feeManagerConfig": { + "blockTimestamp": 0, + "initialFeeConfig": { + "gasLimit": 20000000, + "targetBlockRate": 2, + "minBaseFee": 1000000000, + "targetGas": 100000000, + "baseFeeChangeDenominator": 48, + "minBlockGasCost": 0, + "maxBlockGasCost": 10000000, + "blockGasCostStep": 500000 + } + } +} +``` + +This will set the fee config to the values specified in the `initialFeeConfig` field. For further information about precompile initial configurations see [Initial Precompile Configurations](#initial-precompile-configurations). diff --git a/content/docs/evm-l1s/default-precompiles/nativeminter.mdx b/content/docs/evm-l1s/default-precompiles/nativeminter.mdx new file mode 100644 index 00000000000..cbd7df1f941 --- /dev/null +++ b/content/docs/evm-l1s/default-precompiles/nativeminter.mdx @@ -0,0 +1,21 @@ +--- +title: NativeMinter Precompile +description: Learn how to use the AllowList Precompile on your Avalanche L1 blockchain. +--- + +The Native Minter Precompile allows you to mint additional native tokens beyond the initial supply on your Avalanche L1 blockchain. + +In order to activate this feature, you will need to provide the `FeeConfigManager` in the genesis: + +```json +{ + "config": { + "nativeMinterConfig": { + "blockTimestamp": 0, + "adminAddresses": ["0x8db97C7cEcE249c2b98bDC0226Cc4C2A57BF52FC"] + } + } +} +``` + +By enabling this feature, you can define who has permission to mint new tokens and how minting is managed over time. \ No newline at end of file diff --git a/content/docs/virtual-machines/evm-customization/precompile-overview.mdx b/content/docs/evm-l1s/default-precompiles/overview.mdx similarity index 99% rename from content/docs/virtual-machines/evm-customization/precompile-overview.mdx rename to content/docs/evm-l1s/default-precompiles/overview.mdx index 7df8a02f04a..0dc8ebd1e95 100644 --- a/content/docs/virtual-machines/evm-customization/precompile-overview.mdx +++ b/content/docs/evm-l1s/default-precompiles/overview.mdx @@ -1,5 +1,5 @@ --- -title: Interacting with Precompiles +title: Precompile Overview description: Interact with native Subnet-EVM precompiles --- diff --git a/content/docs/evm-l1s/default-precompiles/rewardmanager.mdx b/content/docs/evm-l1s/default-precompiles/rewardmanager.mdx new file mode 100644 index 00000000000..40a55a32138 --- /dev/null +++ b/content/docs/evm-l1s/default-precompiles/rewardmanager.mdx @@ -0,0 +1,131 @@ +--- +title: RewardManager Precompile +description: Learn how to use the RewardManager Precompile on your Avalanche L1 blockchain. +--- + + +Fee reward mechanism can be configured with this stateful precompile contract called as `RewardManager`. Configuration can include burning fees, sending fees to a predefined address, or enabling fees to be collected by block producers. This precompile can be configured as follows in the genesis file: + +```json +{ + "config": { + "rewardManagerConfig": { + "blockTimestamp": 0, + "adminAddresses": ["0x8db97C7cEcE249c2b98bDC0226Cc4C2A57BF52FC"] + } + } +} +``` + +`adminAddresses` denotes admin accounts who can add other `Admin` or `Enabled` accounts. `Admin`, `Manager` and `Enabled` are both eligible to change the current fee mechanism. + +The precompile implements the `RewardManager` interface which includes the `AllowList` interface. For an example of the `AllowList` interface, see the [TxAllowList](#allowlist-interface) above. + +The `Stateful Precompile` contract powering the `RewardManager` adheres to the following Solidity interface at `0x0200000000000000000000000000000000000004` (you can load this interface and interact directly in Remix). It can be also found in [IRewardManager.sol](https://github.com/ava-labs/subnet-evm/blob/5faabfeaa021a64c2616380ed2d6ec0a96c8f96d/contract-examples/contracts/IRewardManager.sol): + +```solidity +//SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; +import "./IAllowList.sol"; + +interface IRewardManager is IAllowList { + // RewardAddressChanged is the event logged whenever reward address is modified + event RewardAddressChanged( + address indexed sender, + address indexed oldRewardAddress, + address indexed newRewardAddress + ); + + // FeeRecipientsAllowed is the event logged whenever fee recipient is modified + event FeeRecipientsAllowed(address indexed sender); + + // RewardsDisabled is the event logged whenever rewards are disabled + event RewardsDisabled(address indexed sender); + + // setRewardAddress sets the reward address to the given address + function setRewardAddress(address addr) external; + + // allowFeeRecipients allows block builders to claim fees + function allowFeeRecipients() external; + + // disableRewards disables block rewards and starts burning fees + function disableRewards() external; + + // currentRewardAddress returns the current reward address + function currentRewardAddress() external view returns (address rewardAddress); + + // areFeeRecipientsAllowed returns true if fee recipients are allowed + function areFeeRecipientsAllowed() external view returns (bool isAllowed); +} +``` + +`RewardManager` precompile uses `IAllowList` interface directly, meaning that it uses the same `AllowList` interface functions like `readAllowList` and `setAdmin`, `setEnabled`, `setNone`. For more information see [AllowList Solidity interface](#allowlist-interface). + +In addition to the `AllowList` interface, the `RewardManager` adds the following capabilities: + +- `setRewardAddress`: sets the address to which fees are sent. This address can be a contract or a user address. The address becomes the required coinbase address for the blocks that this mechanism is enabled on. Meaning that it will receive the fees collected from the transactions in the block. Receiving fees will not call any contract functions or fallback functions. It will simply increase the balance of the address by the amount of fees. +- `allowFeeRecipients`: enables block producers to claim fees. This will allow block producers to claim fees by specifying their own addresses in their chain configs. See [here](#fee-recipient) for more information on how to specify the fee recipient address in the chain config. +- `disableRewards`: disables block rewards and starts burning fees. +- `currentRewardAddress`: returns the current reward address. This is the address to which fees are sent. It can include black hole address (`0x010...0`) which means that fees are burned. It can also include a predefined hash (`0x0000000000000000000000000000000000000000`) denoting custom fee recipients are allowed. It's advised to use the `areFeeRecipientsAllowed` function to check if custom fee recipients are allowed first. +- `areFeeRecipientsAllowed`: returns true if custom fee recipients are allowed. +- `RewardAddressChanged`: an event that is emitted when the reward address is updated. Topics include the sender, the old reward address, and the new reward address. +- `FeeRecipientsAllowed`: an event that is emitted when fee recipients are allowed. Topics include the sender. +- `RewardsDisabled`: an event that is emitted when rewards are disabled. Topics include the sender. + +These 3 mechanisms (burning, sending to a predefined address, and enabling fees to be collected by block producers) cannot be enabled at the same time. Enabling one mechanism will take over the previous mechanism. For example, if you enable `allowFeeRecipients` and then enable `disableRewards`, the `disableRewards` will take over and fees will be burned. + +Note that reward addresses or fee recipient addresses are not required to be an admin or enabled account. + +#### Initial Configuration[​](#initial-configuration "Direct link to heading") + +It's possible to enable this precompile with an initial configuration to activate its effect on activation timestamp. This provides a way to enable the precompile without an admin address to change the fee reward mechanism. This can be useful for networks that require a one-time reward mechanism change without specifying any admin addresses. Without this initial configuration, the precompile will inherit the `feeRecipients` mechanism activated at genesis. Meaning that if `allowFeeRecipients` is set to true in the genesis file, the precompile will be enabled with the `allowFeeRecipients` mechanism. Otherwise it will keep burning fees. To use the initial configuration, you need to specify the initial reward mechanism in `initialRewardConfig` field in your genesis or upgrade file. + +In order to allow custom fee recipients, you need to specify the `allowFeeRecipients` field in the `initialRewardConfig`: + +```json +{ + "rewardManagerConfig": { + "blockTimestamp": 0, + "initialRewardConfig": { + "allowFeeRecipients": true + } + } +} +``` + +In order to set an address to receive all transaction rewards, you need to specify the `rewardAddress` field in the `initialRewardConfig`: + +```json +{ + "rewardManagerConfig": { + "blockTimestamp": 0, + "initialRewardConfig": { + "rewardAddress": "0x8db97C7cEcE249c2b98bDC0226Cc4C2A57BF52FC" + } + } +} +``` + +In order to disable rewards and start burning fees, you need to leave all fields in the `initialRewardConfig` empty: + +```json +{ + "rewardManagerConfig": { + "blockTimestamp": 0, + "initialRewardConfig": {} + } +} +``` + +However this is different than the default behavior of the precompile. If you don't specify the `initialRewardConfig` field, the precompile will inherit the `feeRecipients` mechanism activated at genesis. Meaning that if `allowFeeRecipients` is set to true in the genesis file, the precompile will be enabled with the `allowFeeRecipients` mechanism. Otherwise it will keep burning fees. Example configuration for this case: + +```json +{ + "rewardManagerConfig": { + "blockTimestamp": 0, + "adminAddresses": ["0x8db97C7cEcE249c2b98bDC0226Cc4C2A57BF52FC"] + } +} +``` + +If `allowFeeRecipients` and `rewardAddress` are both specified in the `initialRewardConfig` field then an error will be returned and precompile won't be activated. For further information about precompile initial configurations see [Initial Precompile Configurations](#initial-precompile-configurations). diff --git a/content/docs/evm-l1s/default-precompiles/warpmessenger.mdx b/content/docs/evm-l1s/default-precompiles/warpmessenger.mdx new file mode 100644 index 00000000000..3a3a299035f --- /dev/null +++ b/content/docs/evm-l1s/default-precompiles/warpmessenger.mdx @@ -0,0 +1,21 @@ +--- +title: WarpMessenger Precompile +description: Learn how to use the WarpMessenger Precompile on your Avalanche L1 blockchain. +--- + +The `WarpMessenger` Precompile is used to perform cross chain operations among Avalanche L1s. + +Warp Precompile enabled cross-blockchain communication between other Layer 1s and primary-network (C-Chain) by leveraging the Avalanche P-Chain. In order to use Warp messaging, Subnet-EVM chains must activate their Warp precompiles. Warp can be activated with the following lines in upgrade.json: + +```json +{ + "warpConfig": { + "blockTimestamp": (uint), + "quorumNumerator": (uint) + } +} +``` + +`blockTimestamp` must be set to a timestamp after Durango date. `quorumNumerator` is the stake percentage of validators that must sign a Warp message for it to be considered valid. It must be set to a value between 33 and 100. The default value is 67. The `warpConfig` precompile can be later disabled by setting `disable` to `true` in the upgrade.json file. + +If you want to use Warp messaging in an existing Subnet-EVM chain, you should coordinate an upgrade with `upgrade.json`. See [Network Upgrades: Enable/Disable Precompiles](#network-upgrades-enabledisable-precompiles) for more information. diff --git a/content/docs/evm-l1s/index.mdx b/content/docs/evm-l1s/index.mdx new file mode 100644 index 00000000000..adf09e30171 --- /dev/null +++ b/content/docs/evm-l1s/index.mdx @@ -0,0 +1,9 @@ +--- +title: Introduction +description: Learn how to customize the Ethereum Virtual Machine. +--- + +Precompiles can be used to execute low level Go code through Solidity. + +Subnet-EVM comes with a set of default precompiles that can be used to extend the functionality of the EVM. Such as the Warp Messenger, AllowList, and Reward Manager. +Furthermore, you can create custom precompiles that can be used to extend the functionality of the EVM. \ No newline at end of file diff --git a/content/docs/evm-l1s/meta.json b/content/docs/evm-l1s/meta.json new file mode 100644 index 00000000000..d8a33df6f54 --- /dev/null +++ b/content/docs/evm-l1s/meta.json @@ -0,0 +1,28 @@ +{ + "title": "evm-l1s", + "root": true, + "pages": [ + "index", + "---Validator Manager---", + "validator-manager/contract", + "validator-manager/add-validator", + "validator-manager/remove-validator", + "validator-manager/upgrade", + "validator-manager/custom-validator-manager", + "---Default Precompiles---", + "default-precompiles/overview", + "default-precompiles/allowlist", + "default-precompiles/rewardmanager", + "default-precompiles/feemanager", + "default-precompiles/nativeminter", + "default-precompiles/warpmessenger", + "---Custom Precompiles---", + "custom-precompiles/introduction", + "custom-precompiles/background-requirements", + "custom-precompiles/generating-your-precompile", + "custom-precompiles/defining-your-precompile", + "custom-precompiles/writing-test-cases", + "custom-precompiles/executing-test-cases", + "custom-precompiles/deploying-precompile" + ] + } \ No newline at end of file diff --git a/content/docs/evm-l1s/validator-manager/add-validator.mdx b/content/docs/evm-l1s/validator-manager/add-validator.mdx new file mode 100644 index 00000000000..5465163b566 --- /dev/null +++ b/content/docs/evm-l1s/validator-manager/add-validator.mdx @@ -0,0 +1,19 @@ +--- +title: Add Validator +description: Learn how to add validators to your Avalanche L1 blockchain. +--- + + +### Register a Validator + +Validator registration is initiated with a call to `initializeValidatorRegistration`. The sender of this transaction is registered as the validator owner. Churn limitations are checked - only a certain (configurable) percentage of the total weight is allowed to be added or removed in a (configurable) period of time. The `ValidatorManager` then constructs a `RegisterL1ValidatorMessage` Warp message to be sent to the P-Chain. Each validator registration request includes all of the information needed to identify the validator and its stake weight, as well as an `expiry` timestamp before which the `RegisterL1ValidatorMessage` must be delivered to the P-Chain. If the validator is not registered on the P-Chain before the `expiry`, then the validator may be removed from the contract state by calling `completeEndValidation`. + +The `RegisterL1ValidatorMessage` is delivered to the P-Chain as the Warp message payload of a `RegisterL1ValidatorTx`. Please see the transaction specification for validity requirements. The P-Chain then signs a `L1ValidatorRegistrationMessage` Warp message indicating that the specified validator was successfully registered on the P-Chain. + +The `L1ValidatorRegistrationMessage` is delivered to the `ValidatorManager` via a call to `completeValidatorRegistration`. For PoS Validator Managers, staking rewards begin accruing at this time. + +### (PoS only) Register a Delegator + +`PoSValidatorManager` supports delegation to an actively staked validator as a way for users to earn staking rewards without having to validate the chain. Delegators pay a configurable percentage fee on any earned staking rewards to the host validator. A delegator may be registered by calling `initializeDelegatorRegistration` and providing an amount to stake. The delegator will be registered as long as churn restrictions are not violated. The delegator is reflected on the P-Chain by adjusting the validator's registered weight via a `SetL1ValidatorWeightTx`. The weight change acknowledgement is delivered to the `PoSValidatorManager` via an `L1ValidatorWeightMessage`, which is provided by calling `completeDelegatorRegistration`. + +The P-Chain is only willing to sign an `L1ValidatorWeightMessage` for an active validator. Once a validator exit has been initiated (via a call to `initializeEndValidation`), the `PoSValidatorManager` must assume that the validator has been deactivated on the P-Chain, and will therefore not sign any further weight updates. Therefore, it is invalid to initiate adding or removing a delegator when the validator is in this state, though it may be valid to complete an already initiated delegator action, depending on the order of delivery to the P-Chain. If the delegator weight change was submitted (and a Warp signature on the acknowledgement retrieved) before the validator was removed, then the delegator action may be completed. Otherwise, the acknowledgement of the validation end must first be delivered before completing the delegator action. diff --git a/content/docs/evm-l1s/validator-manager/contract.mdx b/content/docs/evm-l1s/validator-manager/contract.mdx new file mode 100644 index 00000000000..384388c4ba1 --- /dev/null +++ b/content/docs/evm-l1s/validator-manager/contract.mdx @@ -0,0 +1,109 @@ +--- +title: Validator Manager Contract +description: Documentation for the Validator Manager used to manage Avalanche L1 validators, as defined in ACP-77. +--- +import { Steps, Step } from 'fumadocs-ui/components/steps'; + +> ValidatorManager +class PoSValidatorManager { + initializeEndValidation() + completeDelegatorRegistration() + initializeEndDelegation() + completeEndDelegation() +} +<> PoSValidatorManager +class ERC20TokenStakingManager { + initializeValidatorRegistration() + initializeDelegatorRegistration() +} +class NativeTokenStakingManager { + initializeValidatorRegistration() payable + initializeDelegatorRegistration() payable +} +class PoAValidatorManager { + initializeValidatorRegistration() + initializeEndValidation() +} + +ValidatorManager <|-- PoSValidatorManager +ValidatorManager <|-- PoAValidatorManager +PoSValidatorManager <|-- ERC20TokenStakingManager +PoSValidatorManager <|-- NativeTokenStakingManager +`} /> + +## Deploying + +Three concrete `ValidatorManager` contracts are provided - `PoAValidatorManager`, `NativeTokenStakingManager`, and `ERC20TokenStakingManager`. `NativeTokenStakingManager` and `ERC20TokenStakingManager` implement `PoSValidatorManager`, which itself implements `ValidatorManager`. These are implemented as [upgradeable](https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/master/contracts/proxy/utils/Initializable.sol) contracts. There are numerous [guides](https://blog.chain.link/upgradable-smart-contracts/) for deploying upgradeable smart contracts, but the general steps are as follows: + + + +Deploy the implementation contract + + +Deploy the proxy contract + + +Call the implementation contract's `initialize` function + +- Each flavor of `ValidatorManager` requires different settings. For example, `ValidatorManagerSettings` specifies the churn parameters, while `PoSValidatorManagerSettings` specifies the staking and rewards parameters. + + + +Initialize the validator set by calling `initializeValidatorSet` + +- When a Subnet is first created on the P-Chain, it must be explicitly converted to an L1 via [`ConvertSubnetToL1Tx`](https://github.com/avalanche-foundation/ACPs/tree/main/ACPs/77-reinventing-subnets#convertsubnettol1tx). The resulting `SubnetToL1ConversionMessage` Warp [message](https://github.com/avalanche-foundation/ACPs/tree/main/ACPs/77-reinventing-subnets#subnettol1conversionmessage) is provided in the call to `initializeValidatorSet` to specify the starting validator set in the `ValidatorManager`. Regardless of the implementation, these initial validators are treated as PoA and are not eligible for staking rewards. + + + + +### PoAValidatorManager + +Proof-of-Authority validator management is provided via `PoAValidatorManager`, which restricts modification of the validator set to a specified owner address. After deploying `PoAValidatorManager.sol` and a proxy, the `initialize` function takes the owner address, in addition to standard `ValidatorManagerSettings`. + +### PoSValidatorManager + +Proof-of-Stake validator management is provided by the abstract contract `PoSValidatorManager`, which has two concrete implementations: `NativeTokenStakingManager` and `ERC20TokenStakingManager`. In addition to basic validator management provided in `ValidatorManager`, `PoSValidatorManager` supports uptime-based validation rewards, as well as delegation to a chosen validator. This [state transition diagram](https://github.com/ava-labs/teleporter/blob/main/contracts/validator-manager/StateTransition.md) illustrates the relationship between validators and delegators. + +The `weightToValueFactor` fields of the `PoSValidatorManagerSettings` passed to `PoSValidatorManager`'s `initialize` function sets the factor used to convert between the weight that the validator is registered with on the P-Chain, and the value transferred to the contract as stake. This involves integer division, which may result in loss of precision. When selecting `weightToValueFactor`, it's important to make the following considerations: + +1. If `weightToValueFactor` is near the denomination of the asset, then staking amounts on the order of 1 unit of the asset may cause the converted weight to round down to 0. This may impose a larger-than-expected minimum stake amount. + - Ex: If USDC (denomination of 6) is used as the staking token and `weightToValueFactor` is 1e9, then any amount less than 1,000 USDC will round down to 0 and therefore be invalid. +2. Staked amounts up to `weightToValueFactor - 1` may be lost in the contract as dust, as the validator's registered weight is used to calculate the original staked amount. + - Ex: `value=1001` and `weightToValueFactor=1e3`. The resulting weight will be `1`. Converting the weight back to a value results in `value=1000`. +3. The validator's weight is represented on the P-Chain as a `uint64`. `PoSValidatorManager` restricts values such that the calculated weight does not exceed the maximum value for that type. + +### NativeTokenStakingManager + +`NativeTokenStakingManager` allows permissionless addition and removal of validators that post the L1's native token as stake. Staking rewards are minted via the Native Minter Precompile, which is configured with a set of addresses with minting privileges. As such, the address that `NativeTokenStakingManager` is deployed to must be added as an admin to the precompile. This can be done by either calling the precompile's `setAdmin` method from an admin address, or setting the address in the Native Minter precompile settings in the chain's genesis (`config.contractNativeMinterConfig.adminAddresses`). There are a couple of methods to get this address: one is to calculate the resulting deployed address based on the deployer's address and account nonce: `keccak256(rlp.encode(address, nonce))`. The second method involves manually placing the `NativeTokenStakingManager` bytecode at a particular address in the genesis, then setting that address as an admin. + +```json +{ + "config" : { + ... + "contractNativeMinterConfig": { + "blockTimestamp": 0, + "adminAddresses": [ + "0xffffffffffffffffffffffffffffffffffffffff" + ] + } + }, + "alloc": { + "0xffffffffffffffffffffffffffffffffffffffff": { + "balance": "0x0", + "code": "", + "nonce": 1 + } + } +} +``` + +## ERC20TokenStakingManager + +`ERC20TokenStakingManager` allows permissionless addition and removal of validators that post an ERC20 token as stake. The ERC20 is specified in the call to `initialize`, and must implement `IERC20Mintable`. Care should be taken to enforce that only authorized users are able to mint the ERC20 staking token. diff --git a/content/docs/evm-l1s/validator-manager/custom-validator-manager.mdx b/content/docs/evm-l1s/validator-manager/custom-validator-manager.mdx new file mode 100644 index 00000000000..1744ab60108 --- /dev/null +++ b/content/docs/evm-l1s/validator-manager/custom-validator-manager.mdx @@ -0,0 +1,93 @@ +--- +title: Customize Validator Manager +description: Learn how to implement a custom Validator Manager on your Avalanche L1 blockchain. +--- + +The Validator Manager contracts provide a framework for managing validators on an Avalanche L1 blockchain, as defined in [ACP-77](https://github.com/avalanche-foundation/ACPs/tree/main/ACPs/77-reinventing-subnets). `ValidatorManager.sol` is the top-level abstract contract that provides basic functionality. Developers can build upon it to implement custom logic for validator management tailored to their specific requirements. + +## Building a Custom Validator Manager + +To implement custom validator management logic, you can create a new contract that inherits from `ValidatorManager` or one of its derived contracts (`PoSValidatorManager`, `PoAValidatorManager`, etc.). By extending these contracts, you can override existing functions or add new ones to introduce your custom logic. + +**Inherit from the Base Contract** + + Decide which base contract suits your needs. If you require Proof-of-Stake functionality, consider inheriting from `PoSValidatorManager`. For Proof-of-Authority, `PoAValidatorManager` might be appropriate. If you need basic functionality, you can inherit directly from `ValidatorManager`. + + ```solidity + pragma solidity ^0.8.0; + + import "./ValidatorManager.sol"; + + contract CustomValidatorManager is ValidatorManager { + // Your custom logic here + } + ``` + +### Override Functions + +Override existing functions to modify their behavior. Ensure that you adhere to the function signatures and access modifiers. + +```solidity +function initializeValidatorRegistration() public override { + // Custom implementation +} +``` +### Add Custom Functions + +Introduce new functions that implement the custom logic required for your blockchain. + +```solidity +function customValidatorLogic(address validator) public { + // Implement custom logic +} +``` +### Modify Access Control + +Adjust access control as needed using modifiers like onlyOwner or by implementing your own access control mechanisms. + +```solidity +modifier onlyValidator() { + require(isValidator(msg.sender), "Not a validator"); + _; +} +``` + +### Integrate with the P-Chain + +Ensure that your custom contract correctly constructs and handles Warp messages for interaction with the P-Chain, following the specifications in ACP-77. + +### Testing + +Thoroughly test your custom Validator Manager contract to ensure it behaves as expected and adheres to the required protocols. + +Example: Custom Reward Logic +Suppose you want to implement a custom reward distribution mechanism. You can create a new contract that inherits from PoSValidatorManager and override the reward calculation functions. + +```solidity + +pragma solidity ^0.8.0; + +import "./PoSValidatorManager.sol"; + +contract CustomRewardValidatorManager is PoSValidatorManager { + function calculateValidatorReward(address validator) internal view override returns (uint256) { + // Implement custom reward calculation logic + return super.calculateValidatorReward(validator) * 2; // Example: double the reward + } + + function calculateDelegatorReward(address delegator) internal view override returns (uint256) { + // Implement custom delegator reward calculation logic + return super.calculateDelegatorReward(delegator) / 2; // Example: halve the reward + } +} +``` + +### Considerations +**Security Audits**: Custom contracts should be audited to ensure security and correctness. + +**Compliance with ACP-77**: Ensure your custom logic complies with the specifications of ACP-77 to maintain compatibility with Avalanche's protocols. + +**Upgradeable Contracts**: If you plan to upgrade your contract in the future, follow best practices for upgradeable contracts. + +### Conclusion +Building on top of `ValidatorManager.sol` allows you to customize validator management to fit the specific needs of your Avalanche L1 blockchain. By extending and modifying the base contracts, you can implement custom staking mechanisms, reward distribution, and access control tailored to your application. \ No newline at end of file diff --git a/content/docs/evm-l1s/validator-manager/remove-validator.mdx b/content/docs/evm-l1s/validator-manager/remove-validator.mdx new file mode 100644 index 00000000000..792460759ca --- /dev/null +++ b/content/docs/evm-l1s/validator-manager/remove-validator.mdx @@ -0,0 +1,42 @@ +--- +title: Remove Validator +description: Learn how to remove validators from your Avalanche L1 blockchain. +--- + +### Remove a Validator + +Validator exit is initiated with a call to `initializeEndValidation` on the `ValidatorManager`. Only the validator owner may initiate exit. For `PoSValidatorManagers` a `ValidationUptimeMessage` Warp message may optionally be provided in order to calculate the staking rewards; otherwise the latest received uptime will be used (see [(PoS only) Submit an Uptime Proof](#pos-only-submit-an-uptime-proof)). This proof may be requested directly from the L1 validators, which will provide it in a `ValidationUptimeMessage` Warp message. If the uptime is not sufficient to earn validation rewards, the call to `initializeEndValidation` will fail. `forceInitializeEndValidation` acts the same as `initializeEndValidation`, but bypasses the uptime-based rewards check. Once `initializeEndValidation` or `forceInitializeEndValidation` is called, staking rewards cease accruing for `PoSValidatorManagers`. + +The `ValidatorManager` constructs an `L1ValidatorWeightMessage` Warp message with the weight set to `0`. This is delivered to the P-Chain as the payload of a `SetL1ValidatorWeightTx`. The P-Chain acknowledges the validator exit by signing an `L1ValidatorRegistrationMessage` with `valid=0`, which is delivered to the `ValidatorManager` by calling `completeEndValidation`. The validation is removed from the contract's state, and for `PoSValidatorManagers`, staking rewards are disbursed and stake is returned. + +#### Disable a Validator Directly on the P-Chain + +ACP-77 also provides a method to disable a validator without interacting with the L1 directly. The P-Chain transaction `DisableL1ValidatorTx` disables the validator on the P-Chain. The disabled validator's weight will still count towards the L1's total weight. + +Disabled L1 validators can re-activate at any time by increasing their balance with an `IncreaseBalanceTx`. Anyone can call `IncreaseBalanceTx` for any validator on the P-Chain. A disabled validator can only be completely and permanently removed from the validator set by a call to `initializeEndValidation`. + + +### (PoS only) Remove a Delegator + +Delegators removal may be initiated by calling `initializeEndDelegation`, as long as churn restrictions are not violated. Similar to `initializeEndValidation`, an uptime proof may be provided to be used to determine delegator rewards eligibility. If no proof is provided, the latest known uptime will be used (see [(PoS only) Submit an Uptime Proof](#pos-only-submit-an-uptime-proof)). The validator's weight is updated on the P-Chain by the same mechanism used to register a delegator. The `L1ValidatorWeightMessage` from the P-Chain is delivered to the `PoSValidatorManager` in the call to `completeEndDelegation`. + +Either the delegator owner or the validator owner may initiate removing a delegator. This is to prevent the validator from being unable to remove itself due to churn limitations if it has too high a proportion of the Subnet's total weight due to delegator additions. The validator owner may only remove Delegators after the minimum stake duration has elapsed. + + +### (PoS only) Collect Staking Rewards + +#### Submit an Uptime Proof + +The rewards calculator is a function of uptime seconds since the validator's start time. In addition to doing so in the calls to `initializeEndValidation` and `initializeEndDelegation` as described above, uptime proofs may also be supplied by calling `submitUptimeProof`. Unlike `initializeEndValidation` and `initializeEndDelegation`, `submitUptimeProof` may be called by anyone, decreasing the likelihood of a validation or delegation not being able to claim rewards that it deserved based on its actual uptime. + +#### Validation Rewards + +Validation rewards are distributed in the call to `completeEndValidation`. + +#### Delegation Rewards + +Delegation rewards are distributed in the call to `completeEndDelegation`. + +#### Delegation Fees + +Delegation fees owed to validators are _not_ distributed when the validation ends as to bound the amount of gas consumed in the call to `completeEndValidation`. Instead, `claimDelegationFees` may be called after the validation is completed. diff --git a/content/docs/evm-l1s/validator-manager/upgrade.mdx b/content/docs/evm-l1s/validator-manager/upgrade.mdx new file mode 100644 index 00000000000..95f948d6648 --- /dev/null +++ b/content/docs/evm-l1s/validator-manager/upgrade.mdx @@ -0,0 +1,8 @@ +--- +title: Upgrade Validator Manager +description: Learn how to upgrade the Validator Manager on your Avalanche L1 blockchain from PoA to PoS. +--- + +## Convert PoA to PoS + +A `PoAValidatorManager` can later be converted to a `PoSValidatorManager` by upgrading the implementation contract pointed to by the proxy. After performing the upgrade, the `PoSValidatorManager` contract should be initialized by calling `initialize` as described above. The validator set contained in the `PoAValidatorManager` will be tracked by the `PoSValidatorManager` after the upgrade, but these validators will neither be eligible to stake and earn staking rewards, nor support delegation. diff --git a/content/docs/nodes/on-third-party-services/microsoft-azure.mdx b/content/docs/nodes/on-third-party-services/microsoft-azure.mdx index cbdad85643f..a1f7c2b5f2b 100644 --- a/content/docs/nodes/on-third-party-services/microsoft-azure.mdx +++ b/content/docs/nodes/on-third-party-services/microsoft-azure.mdx @@ -13,8 +13,7 @@ Not only does running a validator node enable you to receive rewards in AVAX, bu Hardware requirements to run a validator are relatively modest: 8 CPU cores, 16 GB of RAM and 1 TB SSD. It also doesn't use enormous amounts of energy. Avalanche's [revolutionary consensus mechanism](/learn/avalanche-consensus) is able to scale to millions of validators participating in consensus at once, offering unparalleled decentralisation. -Currently the minimum amount required to stake to become a validator is 2,000 AVAX. Alternatively, validators can also charge a small fee to enable users to delegate their stake with them to help towards running costs. You can use a calculator [here](https://vscout.io/) to see how much rewards you would earn when running a node, compared to delegating. - +Currently the minimum amount required to stake to become a validator is 2,000 AVAX. Alternatively, validators can also charge a small fee to enable users to delegate their stake with them to help towards running costs. In this article we will step through the process of configuring a node on Microsoft Azure. This tutorial assumes no prior experience with Microsoft Azure and will go through each step with as few assumptions possible. At the time of this article, spot pricing for a virtual machine with 2 Cores and 8 GB memory costs as little as 0.01060perhourwhichworksoutatabout0.01060 per hour which works out at about 113.44 a year, **a saving of 83.76%! compared to normal pay as you go prices.** In comparison a virtual machine in AWS with 2 Cores and 4 GB Memory with spot pricing is around $462 a year. diff --git a/content/docs/learn/avalanche-community-proposals.mdx b/content/docs/protocol/avalanche-community-proposals.mdx similarity index 100% rename from content/docs/learn/avalanche-community-proposals.mdx rename to content/docs/protocol/avalanche-community-proposals.mdx diff --git a/content/docs/learn/avalanche-consensus.mdx b/content/docs/protocol/avalanche-consensus.mdx similarity index 100% rename from content/docs/learn/avalanche-consensus.mdx rename to content/docs/protocol/avalanche-consensus.mdx diff --git a/content/docs/learn/avalanche-l1s.mdx b/content/docs/protocol/avalanche-l1s.mdx similarity index 100% rename from content/docs/learn/avalanche-l1s.mdx rename to content/docs/protocol/avalanche-l1s.mdx diff --git a/content/docs/learn/avax-token.mdx b/content/docs/protocol/avax-token.mdx similarity index 100% rename from content/docs/learn/avax-token.mdx rename to content/docs/protocol/avax-token.mdx diff --git a/content/docs/avalanche-l1s/c-chain-or-avalanche-l1.mdx b/content/docs/protocol/c-chain-or-avalanche-l1.mdx similarity index 100% rename from content/docs/avalanche-l1s/c-chain-or-avalanche-l1.mdx rename to content/docs/protocol/c-chain-or-avalanche-l1.mdx diff --git a/content/docs/learn/disclaimer.mdx b/content/docs/protocol/disclaimer.mdx similarity index 100% rename from content/docs/learn/disclaimer.mdx rename to content/docs/protocol/disclaimer.mdx diff --git a/content/docs/learn/index.mdx b/content/docs/protocol/index.mdx similarity index 100% rename from content/docs/learn/index.mdx rename to content/docs/protocol/index.mdx diff --git a/content/docs/learn/meta.json b/content/docs/protocol/meta.json similarity index 92% rename from content/docs/learn/meta.json rename to content/docs/protocol/meta.json index 97adadb30ff..580ab1f0f1c 100644 --- a/content/docs/learn/meta.json +++ b/content/docs/protocol/meta.json @@ -10,6 +10,7 @@ "primary-network", "rewards-formula", "virtual-machines", + "c-chain-or-avalanche-l1", "---Networks---", "networks/mainnet", "networks/fuji-testnet", diff --git a/content/docs/learn/networks/fuji-testnet.mdx b/content/docs/protocol/networks/fuji-testnet.mdx similarity index 100% rename from content/docs/learn/networks/fuji-testnet.mdx rename to content/docs/protocol/networks/fuji-testnet.mdx diff --git a/content/docs/learn/networks/mainnet.mdx b/content/docs/protocol/networks/mainnet.mdx similarity index 100% rename from content/docs/learn/networks/mainnet.mdx rename to content/docs/protocol/networks/mainnet.mdx diff --git a/content/docs/learn/primary-network.mdx b/content/docs/protocol/primary-network.mdx similarity index 100% rename from content/docs/learn/primary-network.mdx rename to content/docs/protocol/primary-network.mdx diff --git a/content/docs/learn/rewards-formula.mdx b/content/docs/protocol/rewards-formula.mdx similarity index 100% rename from content/docs/learn/rewards-formula.mdx rename to content/docs/protocol/rewards-formula.mdx diff --git a/content/docs/learn/virtual-machines.mdx b/content/docs/protocol/virtual-machines.mdx similarity index 100% rename from content/docs/learn/virtual-machines.mdx rename to content/docs/protocol/virtual-machines.mdx diff --git a/content/docs/virtual-machines/meta.json b/content/docs/virtual-machines/meta.json index 04967e5a454..ee5fe76b4f4 100644 --- a/content/docs/virtual-machines/meta.json +++ b/content/docs/virtual-machines/meta.json @@ -14,16 +14,6 @@ "rust-vms/intro-avalanche-rs", "rust-vms/setting-up-environment", "rust-vms/installing-vm", - "timestamp-vm", - "---EVM Customization---", - "evm-customization/introduction", - "evm-customization/background-requirements", - "evm-customization/generating-your-precompile", - "evm-customization/defining-your-precompile", - "evm-customization/writing-test-cases", - "evm-customization/executing-test-cases", - "evm-customization/deploying-precompile", - "evm-customization/precompile-overview" - + "timestamp-vm" ] } \ No newline at end of file diff --git a/content/integrations/goldrush.mdx b/content/integrations/goldrush.mdx index 92e370d03bf..00bce081f71 100644 --- a/content/integrations/goldrush.mdx +++ b/content/integrations/goldrush.mdx @@ -37,7 +37,6 @@ For detailed guides and API references, visit the [GoldRush Docs](https://goldru - [Accounting and tax tools](https://bit.ly/crypto-tax-tool) - [NFT rendering](https://goldrush-nft-gallery-ui.vercel.app/) - [App onboarding](https://goldrush-wallet-portfolio-ui.vercel.app/activity/0xfc43f5f9dd45258b3aff31bdbe6561d97e8b71de/) -- [Custom block explorers](https://goldrush-block-explorer.vercel.app/) ## Conclusion Use GoldRush to build faster. GoldRush helps scale hundreds of projects from crypto native teams to Fortune 500 companies. diff --git a/mdx-components.tsx b/mdx-components.tsx index 4d9f7357116..86e04e21996 100644 --- a/mdx-components.tsx +++ b/mdx-components.tsx @@ -17,6 +17,11 @@ import YouTube from "@/components/youtube"; import Gallery from "@/components/gallery"; import { cn } from "./utils/cn"; import { BadgeCheck } from "lucide-react"; +import dynamic from "next/dynamic"; + +const Mermaid = dynamic(() => import("@/components/mermaid"), { + ssr: false, +}); export function useMDXComponents(components: MDXComponents): MDXComponents { return { @@ -42,6 +47,7 @@ export function useMDXComponents(components: MDXComponents): MDXComponents { Accordions, YouTube, Gallery, + Mermaid, InstallTabs: ({ items, children, diff --git a/next.config.mjs b/next.config.mjs index 624fcd87028..2e140136001 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -994,6 +994,26 @@ const config = { source: '/subnets/wagmi-subnet', destination: '/avalanche-l1s/wagmi-avalanche-l1', permanent: true, + }, + { + source: '/learn/:path*', + destination: '/protocol/:path*', + permanent: true, + }, + { + source: '/avalanche-l1s/upgrade/customize-avalanche-l1', + destination: '/evm-l1s/custom-precompiles/introduction', + permanent: true, + }, + { + source: '/virtual-machines/evm-customization/:path*', + destination: '/evm-l1s/custom-precompiles/:path*', + permanent: true, + }, + { + source: '/avalanche-l1s/c-chain-or-avalanche-l1', + destination: '/dapps/c-chain-or-avalanche-l1', + permanent: true, } ] }, diff --git a/package.json b/package.json index cb3f263e638..8df7966124a 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "geist": "^1.3.1", "katex": "^0.16.11", "lucide-react": "^0.435.0", + "mermaid": "^11.4.0", "next": "^14.2.4", "posthog-js": "^1.166.1", "react": "^18.3.1",