# BNB Chain Documentation — Full Content > Complete developer documentation for BNB Chain (https://docs.bnbchain.org). > Covers BNB Smart Chain (EVM-compatible L1, 0.45s blocks), opBNB (OP-Stack L2, > up to 5,000 TPS), and BNB Greenfield (decentralized storage). Each page is > delimited by an H2 header with its title and source URL. > > Source repo: https://github.com/bnb-chain/bnb-chain.github.io > Generated by: generate_llms_txt.py --- ## Home > Source: https://docs.bnbchain.org/ # BNB Chain: Empowering the Future of Decentralized Applications BNB Chain is a leading blockchain ecosystem designed to support the growing demands of the decentralized web (Web3). Offering a unique combination of speed, scalability, and affordability, BNB Chain has become a popular choice for developers building decentralized applications (DApps) and for users seeking to participate in the world of decentralized finance (DeFi). ## **Key Features and Benefits** * **Compatibility with the Ethereum Ecosystem** Developers can easily port their existing Ethereum-based projects to BNB Chain, benefiting from its enhanced performance. * **Massive User Base** BNB Chain Handle the largest daily active users and the highest peak EVM transactions with economical fees. * **Strongest Ecosystem** It is Supported by a robust ecosystem of top-tier RPC plants, wallets, blockchain explorers, data indices, and substantial grants. * **Thriving DeFi Ecosystem** BNB Chain boasts a vast array of DeFi applications, including decentralized exchanges (DEXs), lending protocols, yield farming platforms, and more. * **Community-Driven Growth** BNB Chain is supported by a vibrant community of developers, validators, and users who contribute to its ongoing development and expansion. * **Most Diversified Assets APIs** Full support on all popular tokens. The greatest opportunity for composability. ## **Chains** BNB Chain is composed of three blockchains - BNB Smart Chain (BSC), opBNB and BNB Greenfield. Powering and coordinating the ecosystem is the BNB token. Along with fueling transactions on BNB Chain, the BNB token also acts as a governance token. Within this ecosystem, the ownership, usage, and monetization of data are possible for all users and participants in the BNB Chain ecosystem. ## **Use Cases** * **Decentralized Finance (DeFi)** BNB Chain is a hub for DeFi activities, providing users with access to a wide range of financial products and services, all powered by blockchain technology. * **LSD and Restaking** BNB Chain is secured by more than 20M BNB staking and 20K delegators. The development for LSD and Restaking has been bolstered by a substantial amount of assets and a solid user base. * **Gaming and Non-Fungible Tokens (NFTs)** The platform's fast transaction speeds and low fees make it ideal for gaming and NFT applications. opBNB further enhances this capability. * **Decentralized Applications (DApps)** Developers can build and deploy a variety of DApps on BNB Chain, leveraging its robust infrastructure and growing user base. * **Data Storage and Management** BNB Greenfield opens up new possibilities for decentralized data storage and management, catering to a wide range of use cases. * **AI with blockchain technology** With the growing demand for Artificial Intelligence or AI, there is now more than ever a need to integrate AI with blockchain technology to reap its benefits. BNB Chain is making this integration a reality by providing a robust platform that easily integrates blockchain and AI. ## **Quick Start** Getting Started with high performance Layer1 particularly for decentralized finance (DeFi) Getting Started with Layer2 scaling solution on BNB Chain ecosystem Getting Started with cutting-edge decentralized storage --- ## Announcements > Source: https://docs.bnbchain.org/announce/ # Announcement 2026 Feb 6th --- ## NA > Source: https://docs.bnbchain.org/announce/na/ # No Upcoming Upgrade Plan Yet --- ## Fjord Hardfork(opBNB) > Source: https://docs.bnbchain.org/announce/fjord-opbnb/ # Fjord Upgrade of opBNB ## Upgrade Timeline The Fjord upgrade will happen at: - Testnet: Sep-10-2024 06:00 AM +UTC - Mainnet: Sep-24-2024 06:00 AM +UTC ## Upgrade opBNB op-node and op-geth to v0.5.0 Before Hardfork Releases: - https://github.com/bnb-chain/opbnb/releases/tag/v0.5.0 - https://github.com/bnb-chain/op-geth/releases/tag/v0.5.0 Docker Images - ghcr.io/bnb-chain/op-node:v0.5.0 - ghcr.io/bnb-chain/op-geth:v0.5.0 - ghcr.io/bnb-chain/op-batcher:v0.5.0 - ghcr.io/bnb-chain/op-proposer:v0.5.0 ## Key Highlight: L1 fee calculation changed Fjord updates the L1 cost calculation function to use a FastLZ-based compression estimator. The L1 cost is computed as: ``` l1FeeScaled = l1BaseFeeScalar*l1BaseFee*16 + l1BlobFeeScalar*l1BlobBaseFee estimatedSizeScaled = max(minTransactionSize * 1e6, intercept + fastlzCoef*fastlzSize) l1Fee = estimatedSizeScaled * l1FeeScaled / 1e12 ``` You can find the detailed explanation in the [spec](https://specs.optimism.io/protocol/fjord/exec-engine.html). ## User Facing Changes * New flag `--wait-node-sync` added to op-batcher (default false), indicates if during startup, the batcher should wait for a recent batcher tx on L1 to finalize (via more block confirmations). This should help avoid duplicate batcher txs * New flag `--wait-node-sync` added to op-proposer (default false), indicates if during startup, the proposer should wait for the rollup node to sync to the current L1 tip before proceeding with its driver loop * New flag `--compression-algo` added to op-batcher (default zlib), user can choose brotli algo after Fjord fork * New flag `--l1.rpc-max-cache-size` added to op-node (default 1000), so user can config the the maximum cache size of the L1 client ## Pull Requests * Merge upstream v1.7.7 by @bnoieh in https://github.com/bnb-chain/opbnb/pull/216 * feat(op-node): Keep consistent status when meet an unexpected el sync by @krish-nr in https://github.com/bnb-chain/opbnb/pull/222 * feat(op-node): add l1 cache size config by @welkin22 in https://github.com/bnb-chain/opbnb/pull/225 * feat(op-chain-ops): add Wright fork config into genesis file generation code by @welkin22 in https://github.com/bnb-chain/opbnb/pull/226 --- ## Wright Hardfork(opBNB) > Source: https://docs.bnbchain.org/announce/wright-opbnb/ # Wright Upgrade of opBNB ## Upgrade Timeline The Wright upgrade will happen at: - Testnet: August 15 2024, 06:00:00 AM UTC - Mainnet: August 27 2024 06:00:00 AM UTC ## Upgrade opBNB op-geth to v0.4.5 Before Hardfork op-geth need to be upgraded before the hardfork time. - https://github.com/bnb-chain/op-geth/releases/tag/v0.4.5 op-node upgrade is optional but recommended. - https://github.com/bnb-chain/opbnb/releases/tag/v0.4.4 ## Key Highlight: [gasless feature support](https://github.com/bnb-chain/op-geth/pull/130) To support gasless transactions on opBNB, the following features have been introduced: - The base fee is set to 0. - The bundle feature is supported. - When the gas price is set to 0, the L1 fee will also be set to 0. Combined with these features and a sponsor (paymaster), users can send transactions without holding BNB to pay gas fees. --- ## Mongolian Hardfork(Greenfield) > Source: https://docs.bnbchain.org/announce/mongolian-greenfield/ # Mongolian Upgrade of Greenfield ## Upgrade Timeline - Testnet: July 31th 2024 07:00:00 AM UTC Blockheight: 10,780,238 - Mainnet: August 8th 2024 07:00:00 AM UTC Blockheight: 10,314,605 ## Validators and SPs should complete upgrading to the latest version before hardfork: For Validators: greenfield [v1.9.0](https://github.com/bnb-chain/greenfield/releases/tag/v1.9.0?ref=bnbchain.ghost.io) For SPs: greenfield-storage-provider [v1.9.0](https://github.com/bnb-chain/greenfield-storage-provider/releases/tag/v1.9.0?ref=bnbchain.ghost.io) ## New features introduced: * [#639] https://github.com/bnb-chain/greenfield/pull/639 feat: Support msg to create policy by cross chain ## Bug fixing * [#638] https://github.com/bnb-chain/greenfield/pull/638 fix: initial val for min value comparison should be large enough * [#640] https://github.com/bnb-chain/greenfield/pull/640 fix: broken links reroute from local repo to bnbchain docs ## Docs * [#633] https://github.com/bnb-chain/greenfield/pull/633 docs: replace docs link [//]: # (Reference: https://www.bnbchain.org/en/blog/bnb-greenfield-mongolian-hardfork) --- ## Veld Hardfork(Greenfield) > Source: https://docs.bnbchain.org/announce/veld-greenfield/ # Veld Upgrade of Greenfield ## Upgrade Timeline - Testnet: June 25 2024 07:00:00 AM UTC Blockheight: 9,581,218 - Mainnet: July 8 2024 07:00:00 AM UTC Blockheight: 9,269,910 ## Validators and SPs should complete upgrading to the latest version before hardfork: For Validators: greenfield [v1.8.0](https://github.com/bnb-chain/greenfield/releases/tag/v1.8.0?ref=bnbchain.ghost.io) For SPs: greenfield-storage-provider [v1.8.0](https://github.com/bnb-chain/greenfield-storage-provider/releases/tag/v1.8.0?ref=bnbchain.ghost.io) ## New features introduced: No new feature is introduced. ## Bug fixing * [#621](https://github.com/bnb-chain/greenfield/pull/621) fix: add bucket status to bucket migration related events * [#625](https://github.com/bnb-chain/greenfield/pull/625) fix: discontinued bucket can't be migrated * [#626](https://github.com/bnb-chain/greenfield/pull/626) fix: principal value supports group name * [#632](https://github.com/bnb-chain/greenfield/pull/632) fix: ignore register channel error [//]: # (Reference: https://www.bnbchain.org/en/blog/bnb-greenfield-veld-hardfork) --- ## Second Sunset Hardfork(BC) > Source: https://docs.bnbchain.org/announce/second-sunset-bc/ # Second Sunset Hardfork of BC ## Upgrade Timeline The Second Sunset Hardfork will happen at: - Mainnet: July 14 2024 6:00:00 AM UTC ## Upgrade to BC Node v0.10.22 Before Hardfork BC node need to be upgraded before the hardfork time. - https://github.com/bnb-chain/node/releases/tag/v0.10.22 ### Upgrade Instructions As a fullnode runner, you need to take the following steps before the hardfork block height. 1) Download the new v0.10.22 binary and replace the previous version. 2) Download the new config file [app.toml](https://github.com/bnb-chain/node/releases/download/v0.10.22/mainnet_config.zip) to replace the previous version or add the following under the [upgrade] module of `app.toml`. ```toml SecondSunsetHeight = 378062790 ``` 3) Stop the bnbchaind process and restart it with v0.10.22. ```shell service bnbchaind restart ``` ## Key Highlight All TimeLocks and AtomicSwaps on BC tesnet will automatically be refunded to user accounts. All the BSC delegations will be automatically undelegated and refunded to user accounts after the unbonding period. For more information about BNB Chain Fusion, please refer to [this](https://www.bnbchain.org/en/bnb-chain-fusion). --- ## Feynman Hardfork(BSC) > Source: https://docs.bnbchain.org/announce/feynman-bsc/ # Feynman Upgrade of BSC ## Upgrade Timeline The Haber upgrade will happen at: - Testnet: March 11 2024 06:00:00 AM UTC - Mainnet: April 18 2024 05:49:00 AM UTC ## Upgrade to BSC Node v1.3.13 Before Hardfork Feyman upgrade is the most important milestone of [BNB Chain Fusion](https://github.com/bnb-chain/BEPs/blob/master/BEPs/BEP333.md). The BNB Chain Fusion is a strategic shift to migrate the Beacon Chain’s functionalities to BNB Smart Chain (BSC) and retire Beacon Chain. This move aims to streamline the network, improve efficiency, reduce security risks, and align BNB Chain's architecture with the current technological demands and future growth. [BEP333](https://github.com/bnb-chain/BEPs/blob/master/BEPs/BEP333.md) propose to securely and smoothly transit the BNB Beacon Chain and BNB Smart Chain (BSC) from a dual-chain structure into a single chain structure and thus decommission the Beacon Chain. Due to Feyman's upgrade, it will have a significant impact on the BNB ecosystem. We welcome the community to submit issues on GitHub or Discord. Kindly remind that BNB Chain has a [bug bounty program](https://bugbounty.bnbchain.org/user.php/login/index.html) if anyone find any security issues. ## Key Highlight BEP-294, BEP-297 and BEP-299 will be deployed in the BSC Feynman hard fork. - BEP-294 will take effect immediately. Validators created on BSC will receive triple voting power when staking an equal amount of BNB. This encourages the transfer of voting power from the Beacon Chain to BSC. - The BEP-297 governance functionality will not be activated immediately after the hardfork. It will only be automatically enabled once more than 10 million BNB are migrated to BSC. - The smart contract of BEP-299 is not available as the merkel root in the smart contract is still empty at this time. Only after the Beacon Chain comes to a complete halt, the Token Migration feature will be initiated by setting the Merkle root for balance dump through governance. - Cross-chain re-delegation, which allows users to un-delegate their stakes from Beacon Chain and then delegate them on BSC in one Beacon Chain transaction, will be enabled after governance opening the related cross-chain channel. --- ## Haber Hardfork(BSC) > Source: https://docs.bnbchain.org/announce/haber-bsc/ # Haber Upgrade of BSC ## Upgrade Timeline The Haber upgrade will happen at: - Testnet: May 29 2024 06:07:00 AM UTC - Mainnet: June 20 2024 06:05:00 AM UTC ## Upgrade to BSC Node v1.4.8 Before Hardfork Release [v1.4.8](https://github.com/bnb-chain/bsc/releases/tag/v1.4.8) is a cut-in **hard fork release for BSC Testnet and Mainnet**, the HF name is: [Haber](https://forum.bnbchain.org/t/bnb-chain-roadmap-mainnet/936#h-4haber-wip-25), it only supports one BEP: [BEP-381: Precompile for secp256r1 Curve Support](https://github.com/bnb-chain/BEPs/blob/master/BEPs/BEP-381.md) ## Key Highlight: EIP 7212 - secp256r1 Curve Precompile BSC would use address 0x100 as secp256r1 pre-compile contract, which is same as other major chains to make it easier for developers. Developers may refer this code on how to use this pre-compile contract: https://github.com/getclave/clave-contracts/blob/master/contracts/helpers/VerifierCaller.sol , which is same as other major chains to make it easier for developers. ## Key Highlight: [BEP 336](https://github.com/bnb-chain/BEPs/blob/master/BEPs/BEP-336.md) - Enable Blob Carrying Transaction for BSC Introduce a new transaction format for “blob-carrying transactions” which contain a large amount of data that cannot be accessed by EVM execution, but whose commitment can be accessed. The format is intended to be fully compatible with the format that will be used in full sharding. --- ## Haber Hardfork(opBNB) > Source: https://docs.bnbchain.org/announce/haber-opbnb/ # Haber Upgrade of opBNB ## Upgrade Timeline The Haber upgrade will happen at: - Testnet: May 30 2024, 06:00:00 AM UTC - Mainnet: June 20 2024 08:00:00 AM UTC ## Upgrade to opBNB Node v0.4.2 Before Hardfork op-node and op-geth need to be upgraded before the hardfork time. - https://github.com/bnb-chain/opbnb/releases/tag/v0.4.2 - https://github.com/bnb-chain/op-geth/releases/tag/v0.4.2 ## Key Highlight: EIP 7212 - secp256r1 Curve Precompile One of the significant enhancements in this release is the introduction of a precompile for the secp256r1 curve, as specified in [EIP 7212](https://github.com/ethereum/EIPs/pull/7212). This precompile allows for efficient elliptic curve operations, which is crucial for improving the performance and security of cryptographic applications on the blockchain. ## Key Highlight: [BEP 336](https://github.com/bnb-chain/BEPs/blob/master/BEPs/BEP-336.md) - Switch DA from calldata to blob of BSC DA data will be submitted to the BSC network in blob format. Regular BSC nodes only retain blob data from the past 18 days. If you are syncing data from the genesis block or are more than 18 days behind the latest block, you will need to ensure that your configured L1 endpoint supports persisting blob data for a longer period of time. We will ensure that the Testnet snapshot provided by this snapshot repository is within the 18-day range, so you can also choose to use the snapshot to avoid relying on older blob data to start your new node. --- ## Second Sunset Hardfork(BC testnet) > Source: https://docs.bnbchain.org/announce/second-sunset-bc-testnet/ # Second Sunset Hardfork of BC Testnet ## Upgrade Timeline The Second Sunset Hardfork will happen at: - Testnet: June 21 2024 6:00:00 AM UTC ## Upgrade to BC Node v0.10.21 Before Hardfork BC node need to be upgraded before the hardfork time. - https://github.com/bnb-chain/node/releases/tag/v0.10.21 ### Upgrade Instructions As a fullnode runner, you need to take the following steps before the hardfork block height. 1) Download the new v0.10.21 binary and replace the previous version. 2) Download the new config file [app.toml](https://github.com/bnb-chain/node/releases/download/v0.10.21/testnet_config.zip) to replace the previous version or add the following under the [upgrade] module of `app.toml`. ```toml SecondSunsetHeight = 54554742 ``` 3) Stop the bnbchaind process and restart it with v0.10.21. ```shell service bnbchaind restart ``` ## Key Highlight All TimeLocks and AtomicSwaps on BC tesnet will automatically be refunded to user accounts. All the BSC delegations will be automatically undelegated and refunded to user accounts after the unbonding period. For more information about BNB Chain Fusion, please refer to [this](https://www.bnbchain.org/en/bnb-chain-fusion). --- ## Final Sunset Hardfork(BC testnet) > Source: https://docs.bnbchain.org/announce/final-sunset-bc-testnet/ # Final Sunset Hardfork of BC Testnet ## Upgrade Timeline The Final Sunset Hardfork will happen at: - Testnet: August 1 2024 6:00:00 AM UTC ## Upgrade to BC Node v0.10.23 Before Hardfork BC node need to be upgraded before the hardfork time. - https://github.com/bnb-chain/node/releases/tag/v0.10.23 ### Upgrade Instructions As a fullnode runner, you need to take the following steps before the hardfork block height. 1) Download the new v0.10.23 binary and replace the previous version. 2) Download the new config file [app.toml](https://github.com/bnb-chain/node/releases/download/v0.10.23/testnet_config.zip) to replace the previous version or add the following under the [upgrade] module of `app.toml`. ```toml FinalSunsetHeight = 56218686 ``` 3) Stop the bnbchaind process and restart it with v0.10.23. ```shell service bnbchaind restart ``` ## Key Highlight After Final Sunset, the cross-chain communication between the Beacon Chain and BSC will be completely stopped. The validators in the Beacon Chain community will gradually shut down, and the entire chain will no longer accept new transactions or propose new blocks. For more information about BNB Chain Fusion, please refer to [this](https://www.bnbchain.org/en/bnb-chain-fusion). --- ## Bohr Hardfork(BSC) > Source: https://docs.bnbchain.org/announce/bohr-bsc/ # Bohr Upgrade of BSC ## Upgrade Timeline The Bohr upgrade will happen at: - Testnet: 2024-08-20 01:23:16 AM UTC(passed) - Mainnet: 2024-09-26 02:20:00 AM UTC ## Upgrade BSC Mainnet Nodes to v1.4.14 Before Hardfork Release [v1.4.14](https://github.com/bnb-chain/bsc/releases/tag/v1.4.14) is a hard fork release for BSC Mainnet, the HF name is: [Bohr](https://forum.bnbchain.org/t/bnb-chain-roadmap-mainnet/936) There are 4 BEPs in Bohr: - BEP-341: Validators can produce consecutive blocks - BEP-402: Complete missing fields in Block Header to generate Signature - BEP-404: Clear Miner History when Switching Validators Set - BEP-410: Add Agent for Validators ## Key Highlight: [BEP-341: Validators can produce consecutive blocks](https://github.com/bnb-chain/BEPs/blob/master/BEPs/BEP-341.md) Among these BEPs, BEP-341 holds the most significance as it proposes a change to the block production protocol. However, BEP-341 will only come into effect after the affirmative outcome of a governance vote. ## Key Highlight: [BEP-402: Complete missing fields in Block Header to generate Signature](https://github.com/bnb-chain/BEPs/blob/master/BEPs/BEP-402.md) BEP-402 updates the block header signature logic, please pay special attention if your product involves the logic of block header verification. --- ## Altai Hardfork(Gnfd) > Source: https://docs.bnbchain.org/announce/altai-gnfd/ # Altai Upgrade of Greenfield ## Upgrade Timeline - Testnet: Sep 21th 2024 06:00:00 AM UTC Blockheight: 12,513,708 - Mainnet: Sep 23th 2024 06:00:00 AM UTC Blockheight: 11,917,971 For Validators: greenfield [v1.9.1](https://github.com/bnb-chain/greenfield/releases/tag/v1.9.1?ref=bnbchain.ghost.io) For SP: no action needed. ## Hot Fix Release Greenfield and the Metamask extension are facing compatibility issues, affecting some functionalities such as bucket creation on Dcellar. This issue is occurring because the MetaMask Extension recently upgraded its middleware library to the latest version, implementing stricter EIP712 signature verification rules. This release contains the hotfix to resolve this issue, all dapps that using the go-sdk and js-sdk is suggested to upgrade to the latest version. - [Go-SDK v1.7.3](https://github.com/bnb-chain/greenfield-go-sdk/releases/tag/v1.7.3) - [Js-SDK v2.2.0-alpha](https://github.com/bnb-chain/greenfield-js-sdk/releases/tag/%40bnb-chain%2Fgreenfield-js-sdk%402.2.0-alpha.0) --- ## Final Sunset of BC (Mainnet) > Source: https://docs.bnbchain.org/announce/final-sunset-bc-mainnet/ # Final Sunset Hardfork of BC Mainnet ## Upgrade Timeline The Final Sunset Hardfork will happen at: - Mainnet: November 19 2024 6:00:00 AM UTC ## Upgrade to BC Node v0.10.24 Before Hardfork BC node need to be upgraded before the hardfork time. - https://github.com/bnb-chain/node/releases/tag/v0.10.24 ### Upgrade Instructions As a fullnode runner, you need to take the following steps before the hardfork block height. 1) Download the new v0.10.24 binary and replace the previous version. 2) Download the new config file [app.toml](https://github.com/bnb-chain/node/releases/download/v0.10.24/mainnet_config.zip) to replace the previous version or add the following under the [upgrade] module of `app.toml`. ```toml FinalSunsetHeight = 384544850 ``` 3) Stop the bnbchaind process and restart it with v0.10.24. ```shell service bnbchaind restart ``` ## Key Highlight After Final Sunset, the cross-chain communication between the Beacon Chain and BSC will be completely stopped. The validators in the Beacon Chain community will gradually shut down, and the entire chain will no longer accept new transactions or propose new blocks. For more information about BNB Chain Fusion, please refer to [this](https://www.bnbchain.org/en/bnb-chain-fusion). --- ## Greenfield Savanna Hardfork > Source: https://docs.bnbchain.org/announce/savanna-greenfield/ # Savanna Upgrade of Greenfield ## Upgrade Timeline - Testnet: December 2nd 2024 07:00:00 AM UTC Blockheight: 14691233 - Mainnet: December 12th 2024 07:00:00 AM UTC Blockheight: 14667574 ## Validators and SPs should complete upgrading to the latest version before hardfork: For Validators: greenfield [v1.10.0](https://github.com/bnb-chain/greenfield/releases/tag/v1.10.0?ref=bnbchain.ghost.io) For SPs: greenfield-storage-provider [v1.10.0](https://github.com/bnb-chain/greenfield-storage-provider/releases/tag/v1.10.0?ref=bnbchain.ghost.io) ## Bug fixing * [#647] https://github.com/bnb-chain/greenfield/pull/647 fix: fail to resume frozen payment account when netflow is zero * [#1435] https://github.com/bnb-chain/greenfield-storage-provider/pull/1435 feat: fix gc objects [//]: # (Reference: https://www.bnbchain.org/en/blog/bnb-greenfield-savanna-hardfork) --- ## Pascal Hardfork(BSC) > Source: https://docs.bnbchain.org/announce/pascal-bsc/ # Pascal Upgrade of BSC ## Upgrade Timeline The Pascal upgrade will happen at: - Testnet: 2025-02-25 03:18:00 AM UTC - Mainnet: 2025-03-20 02:10:00 AM UTC There are 5 BEPs in Pascal: - BEP-439: Implement EIP-2537: Precompile for BLS12-381 curve operations - BEP-440: Implement EIP-2935: Serve historical block hashes from state - BEP-441: Implement EIP-7702: Set EOA account code - BEP-466: Make the block format compatible with EIP-7685 - BEP-496: Implement EIP-7623: Increase calldata cost --- ## Lorentz Hardfork(BSC) > Source: https://docs.bnbchain.org/announce/lorentz-bsc/ # Lorentz Upgrade of BSC ## Upgrade Timeline The Lorentz upgrade will happen at: - Testnet: 2025-04-08 07:33:00 AM UTC - Mainnet: 2025-04-29 05:05:00 AM UTC ## Upgrade BSC Mainnet Nodes to v1.5.10 Before Hardfork [v1.5.10](https://github.com/bnb-chain/bsc/releases/tag/v1.5.10) is a hard fork release for BSC Mainnet, the HF name is: [Lorentz](https://forum.bnbchain.org/t/bnb-chain-roadmap-mainnet/936#p-1418-h-2lorentz-wip-9) There is only one BEP in Lorentz: - BEP-520: shorter block interval phase one: 1.5 seconds --- ## Maxwell Hardfork(BSC) > Source: https://docs.bnbchain.org/announce/maxwell-bsc/ # Maxwell Upgrade of BSC ## Upgrade Timeline The Maxwell upgrade will happen at: - Testnet: 2025-05-26 07:05:00 AM UTC - Mainnet: 2025-06-30 02:30:00 AM UTC There are three BEP in Maxwell: - [BEP-524: shorter block interval phase two: 0.75 seconds](https://github.com/bnb-chain/BEPs/blob/master/BEPs/BEP-524.md) - [BEP-563: add Enhanced Validator Network proposal](https://github.com/bnb-chain/BEPs/blob/master/BEPs/BEP-563.md) - [BEP-564: add New Block Fetching Messages proposal](https://github.com/bnb-chain/BEPs/blob/master/BEPs/BEP-564.md) ## Upgrade BSC Testnet Nodes to v1.5.13 Before Hardfork [v1.5.13](https://github.com/bnb-chain/bsc/releases/tag/v1.5.13) is a hard fork release for BSC Testnet, the HF name is: [Maxwell](https://forum.bnbchain.org/t/bnb-chain-roadmap-mainnet/936#p-1418-h-3-maxwell-wip-10) --- ## Volta Upgrade of opBNB > Source: https://docs.bnbchain.org/announce/volta-opbnb/ # Volta Upgrade of opBNB ## Upgrade Timeline The Volta upgrade will happen at: - Testnet: Apr-02-2025 03:00 AM +UTC - Mainnet: Apr-21-2025 03:00 AM +UTC ## Upgrade opBNB op-node to v0.5.3-hotfix and op-geth to v0.5.7 Before Hardfork Releases: - https://github.com/bnb-chain/opbnb/releases/tag/v0.5.3-hotfix - https://github.com/bnb-chain/op-geth/releases/tag/v0.5.7 Docker Images - ghcr.io/bnb-chain/op-node:v0.5.3-hotfix - ghcr.io/bnb-chain/op-geth:v0.5.7 - ghcr.io/bnb-chain/op-batcher:v0.5.3-hotfix - ghcr.io/bnb-chain/op-proposer:v0.5.3-hotfix ## Key Highlight: Shorten Block Interval - [BEP-543](https://github.com/bnb-chain/BEPs/blob/master/BEPs/BEP-543.md): effectively reducing the block time from 1 second to an impressive 500 milliseconds. This enhancement significantly improves transaction efficiency and overall network performance, allowing for faster processing and a more seamless experience for users. --- ## Fermi Hardfork(BSC) > Source: https://docs.bnbchain.org/announce/fermi-bsc/ # Fermi Upgrade of BSC ## Upgrade Timeline The Fermi upgrade will happen at: - Testnet: 2025-11-10 02:25:00 AM UTC - Mainnet: 2026-01-14 02:30:00 AM UTC There are five BEPs in Fermi: - [BEP-590: Extended Voting Rules for Fast Finality Stability](https://github.com/bnb-chain/BEPs/blob/master/BEPs/BEP-590.md) - [BEP-619: Short Block Interval Phase Three: 0.45 Seconds](https://github.com/bnb-chain/BEPs/blob/master/BEPs/BEP-619.md) - [BEP-592: Non-Consensus Based Block-Level Access List](https://github.com/bnb-chain/BEPs/blob/master/BEPs/BEP-592.md) - [BEP-593: Incremental Snapshot](https://github.com/bnb-chain/BEPs/blob/master/BEPs/BEP-593.md) - [BEP-610: Implement EVM Super Instruction](https://github.com/bnb-chain/BEPs/blob/master/BEPs/BEP-610.md) ## Upgrade BSC Testnet Nodes to v1.6.2+ Before Hardfork [v1.6.2](https://github.com/bnb-chain/bsc/releases/tag/v1.6.2) is a hard fork release for BSC Testnet, the HF name is: [Fermi](https://forum.bnbchain.org/t/bnb-chain-upgrades-testnet/934#p-1416-h-4-fermi-wip-5) ## Upgrade BSC Mainnet Nodes to v1.6.4+ Before Hardfork [v1.6.4](https://github.com/bnb-chain/bsc/releases/tag/v1.6.4) is a hard fork release for BSC Testnet, the HF name is: [Fermi](https://forum.bnbchain.org/t/bnb-chain-roadmap-mainnet/936#p-1418-h-1-fermi-passed-8) --- ## Fourier Upgrade of opBNB > Source: https://docs.bnbchain.org/announce/fourier-opbnb/ # Fourier Upgrade of opBNB ## Upgrade Timeline The Fourier upgrade will happen at: - Testnet: Nov-06-2025 03:00:00 AM +UTC - Mainnet: Jan-07-2026 03:00:00 AM +UTC ## Upgrade opBNB op-node to v0.5.5 and op-geth to v0.5.9 Before Hardfork Releases: - [https://github.com/bnb-chain/opbnb/releases/tag/v0.5.4](https://github.com/bnb-chain/opbnb/releases/tag/v0.5.5) - [https://github.com/bnb-chain/op-geth/releases/tag/v0.5.8](https://github.com/bnb-chain/op-geth/releases/tag/v0.5.9) Docker Images - ghcr.io/bnb-chain/op-node:v0.5.5 - ghcr.io/bnb-chain/op-geth:v0.5.9 - ghcr.io/bnb-chain/op-batcher:v0.5.5 - ghcr.io/bnb-chain/op-proposer:v0.5.5 ## Key Highlight: Shorten Block Interval - [PR#305](https://github.com/bnb-chain/opbnb/pull/305): effectively reducing the block time from 500 milliseconds to an impressive 250 milliseconds. --- ## BNB Smart Chain > Source: https://docs.bnbchain.org/bnb-smart-chain/ User guide to get started on BNB Smart Chain BSC operates on a Proof-of-Staked-Authority (PoSA) blockchain BSC is a community-oriented ecosystem, meticulously built upon the foundation of decentralized governance. Validators secure the network based on the POSA consensus algorithm. Slashing is a component of on-chain governance that penalizes malicious or negative actions. BSC ecosystem and developer tools Run a BSC node Become a builder and create blocks and offering them to the validator Interacting with BSC requires sending requests to specific JSON-RPC API methods. --- ## Overview > Source: https://docs.bnbchain.org/bnb-smart-chain/overview/ # BNB Smart Chain - High Performance DeFi Hub BNB Smart Chain (BSC) is a high-performance blockchain network. Officially launched on September 1, 2020, BSC is designed to enhance the functionality of the BNB Chain and facilitate the development and interaction of decentralized applications (DApps), decentralized finance (DeFi) platforms, and other blockchain-based innovations. ### Key Features and Advantages 1. **Ethereum Virtual Machine (EVM) Compatibility:** BSC is fully compatible with the Ethereum Virtual Machine (EVM), enabling developers to port their Ethereum-based DApps and DeFi projects to BSC with minimal modifications. This compatibility extends to the use of popular Ethereum tools and applications, such as TrustWallet, MetaMask, Truffle, and Remix. 2. **Low Transaction Fees and Fast Block Times:** One of BSC's primary advantages is its low transaction fees. With the network-wide adoption of a **0.05 Gwei** standard gas price, typical transaction fees on BSC are around **$0.005** or less, significantly lower compared to Ethereum. BSC's block time is approximately **0.45 seconds** (reduced from 3s through the Lorentz, Maxwell, and Fermi hardforks), ensuring near-instant transaction confirmations and an overall smoother user experience. 3. **Robust Ecosystem and Growing Adoption:** Since its inception, BSC has seen rapid growth in its ecosystem. By May 2024, BSC supports over 1,500 DApps, with popular platforms such as PancakeSwap, Venus, and BakerySwap leading the charge. The total value locked (TVL) in BSC-based DeFi protocols exceeds $20 billion, reflecting its substantial market adoption and user trust. ### Role of BNB BNB is the native utility token of both BNB Chain and BNB Smart Chain. Within the BSC ecosystem, BNB is used for various purposes: - **Transaction Fees:** BNB is used to pay for transaction fees on BSC, offering users a cost-effective way to interact with the network. - **Staking:** Users can stake BNB to become validators or delegate their BNB to validators to earn rewards, contributing to the network's security and decentralization. As of May 2024, BNB staking rewards range from 5% to 15% annually, depending on the amount staked and the validator's performance. - **Governance:** BNB holders can participate in on-chain governance, voting on proposals that influence the future development and upgrades of the network. ### Future Prospects BNB Smart Chain is positioned as a significant player in the blockchain space, particularly in the realm of DeFi and DApps. With its emphasis on high performance, affordability, and interoperability, BSC aims to address some of the most pressing challenges facing blockchain technology today. As the blockchain landscape continues to evolve, BSC's strategic innovations and growing community are likely to drive further advancements and widespread adoption. --- ## Introduction > Source: https://docs.bnbchain.org/bnb-smart-chain/introduction/ # Introduction BNB Smart Chain is an innovative solution to bring programmability and interoperability to BNB Beacon Chain. BNB Smart Chain relies on a system of 45 validators with Proof of Staked Authority (PoSA) consensus that can support short block time and lower fees. The most bonded validator candidates of staking will become validators and produce blocks. The double-sign detection, malicious vote detection and other slashing logic guarantee security, stability, and chain finality. The active validator set consists of 45 validators: 21 Cabinet and 24 Candidates. BSC may also introduce additional validators into the validator set as backups. Candidates will produce blocks and charge gas fees in BSC mainnet, but in a much less chance than the official validator set of 45 (21 Cabinet + 24 Candidates). The unavailable candidates will be slashed as well though in a smaller size. A decent motivation is expected to be maintained so that the candidate validators are willing to ensure the quality and help secure BSC. In an extreme case, if a majority of the active 45 validators get attacked and offline, Candidate Validators can report to BNB Beacon Chain about the stale blocking, resume it and eventually propose a re-election of the active validator set. The BNB Smart Chain also supports EVM-compatible smart contracts and protocols. Cross-chain transfer and other communication are possible due to native support of interoperability. The BNB Smart Chain will be: * **A self-sovereign blockchain**: Provides security and safety with elected validators. * **EVM-compatible**: Supports all the existing Ethereum tooling along with faster finality and cheaper transaction fees. * **Fast Finality**: Finalizes the chain within two blocks in most cases. * **Interoperable**: Comes with efficient native dual chain communication; Optimized for scaling high-performance dApps that require a fast and smooth user experience. * **Distributed with on-chain governance**: Proof of Staked Authority (PoSA) brings in decentralization and community participants. As the native token, BNB will serve as both the gas of smart contract execution and tokens for staking. ## Proof of Staked Authority Although Proof-of-Work (PoW) has been recognized as a practical mechanism to implement a decentralized network, it is not friendly to the environment and also requires a large size of participants to maintain the security. Ethereum and some other blockchain networks, such as [MATIC Bor](https://github.com/maticnetwork/bor), [TOMOChain](https://tomochain.com/), [GoChain](https://gochain.io/), [xDAI](https://xdai.io/), do use [Proof-of-Authority(PoA)](https://en.wikipedia.org/wiki/Proof_of_authority) or its variants in different scenarios, including both testnet and mainnet. PoA provides some defense to 51% attack, with improved efficiency and tolerance to certain levels of Byzantine players (malicious or hacked). It serves as an easy choice to pick as the fundamentals. Meanwhile, the PoA protocol is most criticized for being not as decentralized as PoW, as the validators, i.e. the nodes that take turns to produce blocks, have all the authorities and are prone to corruption and security attacks. Other blockchains, such as EOS and Lisk both, introduce different types of [Delegated Proof of Stake (DPoS)](https://en.bitcoinwiki.org/wiki/DPoS) to allow the token holders to vote and elect the validator set. It increases the decentralization and favors community governance. BSC here proposes to combine DPoS and PoA for consensus, so that: 1. Blocks are produced by a limited set of validators 2. Validators take turns to produce blocks in a PoA manner, similar to [Ethereum's Clique](https://eips.ethereum.org/EIPS/eip-225) consensus design 3. Validator set are elected in and out based on a staking based governance Fast finalization can greatly improve user experience. The `Fast Finality` feature will be enabled upon the coming Plato upgrade. This will be a major advantage of BSC, and many dapps will benefit from it. The consensus protocol of BSC fulfills the following goals: 1. Short block time, **0.45 seconds** on mainnet (reduced from 3s through the Lorentz, Maxwell, and Fermi hardforks). 2. It requires very short time to confirm the finality of transactions, approximately **1 second** on mainnet with Fast Finality enabled. 3. There is no inflation of native token: BNB, the block reward is collected from transaction fees, and it will be paid in BNB. 4. It is 100% compatible with Ethereum system. 5. It allows modern proof-of-stake blockchain network governance. ## Security Given there are more than ½\*N+1 validators are honest, PoA based networks usually work securely and properly. However, there are still cases where certain amount Byzantine validators may still manage to attack the network, e.g. through the [Clone Attack](https://arxiv.org/pdf/1902.10244.pdf). BSC does introduce Slashing logic to penalize Byzantine validators for double signing or inavailability. This Slashing logic will expose the malicious validators in a very short time and make the "Clone Attack" very hard or extremely non-beneficial to execute. ## Fast Finality Finality is critical for blockchain security, once the block is finalized, it wouldn’t be reverted anymore. The fast finality feature is very useful, the users can make sure they get the accurate information from the latest finalized block, then they can decide what to do next instantly. More details of design, please refer to [BEP-126](https://github.com/bnb-chain/BEPs/blob/master/BEPs/BEP126.md) With Fast Finality enabled (since the Plato upgrade), the chain is finalized within two blocks if ⅔*N or more validators vote normally. At the current block time of **0.45 seconds**, this means finality is achieved in approximately **1.125 seconds**. If Fast Finality votes are insufficient, the chain falls back to probabilistic finality where more confirmations increase safety. For applications that need guaranteed finality, the `finalized` block tag in JSON-RPC calls (e.g., `eth_getBlockByNumber`) can be used to query only finalized blocks. ## Reward All the BSC validators in the current validator set will be rewarded with transaction fees in BNB. As BNB is not an inflationary token, there will be no mining rewards as what Bitcoin and Ethereum network generate, and the gas fee is the major reward for validators. Part of the fees collected is used as reward for finality voting. As BNB is also utility tokens with other use cases, delegators and validators will still enjoy other benefits of holding BNB. The reward for validators is the fees collected from transactions in each block. Validators can decide how much to give back to the delegators who stake their BNB to them, in order to attract more staking. Every validator will take turns to produce the blocks in the same probability (if they stick to 100% liveness), thus, in the long run, all the stable validators may get a similar size of the reward. Meanwhile, the stakes on each validator may be different, so this brings a counter-intuitive situation that more users trust and delegate to one validator, they potentially get less reward. So rational delegators will tend to delegate to the one with fewer stakes as long as the validator is still trustful (insecure validator may bring slashable risk). In the end, the stakes on all the validators will have less variation. This will actually prevent the stake concentration and "winner wins forever" problem seen on some other networks. ## Token Economy BC and BSC share the same token universe for BNB and BEP2 tokens. This defines: 1. The same token can circulate on both networks, and flow between them bi-directionally via a cross-chain communication mechanism. 2. The total circulation of the same token should be managed across the two networks, i.e. the total effective supply of a token should be the sum of the token’s total effective supply on both BSC and BC. 3. The tokens can be initially created on BSC in a similar format as ERC20 token standard, or on BC as a BEP2, then created on the other. There are native ways on both networks to link the two and secure the total supply of the token. ## Staking and Governance Proof of Staked Authority brings in decentralization and community involvement. Its core logic can be summarized as the below. You may see similar ideas from other networks, especially Cosmos and EOS. 1. Token holders, including the validators, can put their tokens "bonded" into the stake. Token holders can delegate their tokens onto any validator or validator candidate, to expect it can become an actual validator, and later they can choose a different validator or candidate to re-delegate their tokens. 2. All validator candidates will be ranked by the number of bonded tokens on them, and the top ones will become the real validators. 3. Validators can share (part of) their blocking reward with their delegators. 4. Validators can suffer from "Slashing", a punishment for their bad behaviors, such as double sign and/or instability. 5. There is an "unbonding period" for validators and delegators so that the system makes sure the tokens remain bonded when bad behaviors are caught, the responsible will get slashed during this period. --- ## Quick Guide > Source: https://docs.bnbchain.org/bnb-smart-chain/developers/quick-guide/ If you are a developer looking to build applications on the BNB Smart Chain (BSC), this document provides all the essential information you need. ## Getting Started BNB Smart Chain (BSC) is a high-performance blockchain network. Since BSC is EVM-compatible, your existing Ethereum smart contract skills will seamlessly transfer to BSC. ## Connecting Here are some resources to help you get connected to the BSC network: - [Network Information and RPC Providers](json_rpc/json-rpc-endpoint.md) - [Wallet Configuration](./wallet-configuration.md) ## Get Tokens BNB is the native utility token of BNB Smart Chain and is used to pay transaction fees. For the testnet, you can use the faucet to obtain test tokens on BSC. - [BSC Testnet Faucet](./faucet.md) For the mainnet, you can withdraw tokens directly from a centralized exchange (CEX) which supports BSC network(e.g. Binance). ## JSON-RPC API Interacting with BSC requires sending requests to specific JSON-RPC API methods. BSC's APIs are compatible with Geth. - [JSON-RPC API](json_rpc/json-rpc-endpoint.md) ## Developer Tools - Explorer - [NodeReal BSC Scan](https://bsctrace.com/) - [BSCScan](https://bscscan.com/) - SDK. If you are only using the SDK for Ethereum-compatible functions, then all Ethereum SDKs should work with BSC. - [ethers.js](https://docs.ethers.io) - [web3.js](https://web3js.readthedocs.io) - Tools - [Remix](https://remix.ethereum.org) - [Hardhat](https://hardhat.org) - [Foundry](https://book.getfoundry.sh/) - Indexing - [TheGraph](https://thegraph.com/) - [Covalent](https://www.covalenthq.com) - [Others](https://www.alchemy.com/dapps/list-of/indexing-tools-on-ethereum) - Wallets - [Binance Web3 Wallet](https://www.binance.com/en/web3wallet) - [Metamask](https://metamask.io/) - [TrustWallet](https://trustwallet.com/) - [Particle Network](https://wallet.particle.network/) - [Gem Wallet](https://gemwallet.com/) - [OKX Wallet](https://www.okx.com/nl/web3) - [MathWallet](https://mathwallet.org/en-us/) - [Sequence.build](https://sequence.build/landing) - [Avatar](https://avatarwallet.io/) - Oracle - [Binance Oracle](https://oracle.binance.com/docs/) - Account Abstraction - [Particle Network](https://wallet.particle.network/) - [Biconomy](https://docs.biconomy.io/supportedchains/) - [CyberConnect](https://cyberconnect.me/) - Storage - [BNB Greenfield](https://greenfield.bnbchain.org/en) - Data Analytics - [DefiLlama](https://defillama.com/chain/BSC) - [CoinGecko](https://www.coingecko.com/en/chains/binance-smart-chain) - [DappBay](https://dappbay.bnbchain.org/ranking/chain/bnb-smart-chain) For more tools and details, you can refer to [BSC Dev Tools](https://www.bnbchain.org/en/dev-tools). --- ## Json Rpc Endpoint > Source: https://docs.bnbchain.org/bnb-smart-chain/developers/json_rpc/json-rpc-endpoint/ # JSON-RPC-Endpoint JSON-RPC endpoints refers to the network location where a program could transfer its RPC requests to access server data. Once you connect a decentralized application to an RPC endpoint, you can access the functionalities of different operations, which could enable real-time usage of blockchain data. BNB Chain provides several RPC endpoints for connectinto both its Minent and Testnet. In this section, we list the JSON-RPC endpoints that can be used for connecting to BNB Smart Chain. ## One-click adding BSC network Visit the [ChainList](https://chainlist.org/chain/56) and connect to your wallet, it will add alive RPC endpoints. ## RPC Endpoints for BNB Smart Chain *The rate limit of BSC endpoint on Testnet and Mainnet is **10K/5min**.* `eth_getLogs` is disabled on below Mainnet endpoints, please use 3rd party endpoints from **[here](https://chainlist.org/chain/56)**. If you need to pull logs frequently, we recommend using WebSockets to push new logs to you when they are available. ### BSC Mainnet (ChainID 0x38, 56 in decimal) * https://bsc-dataseed.bnbchain.org * https://bsc-dataseed.nariox.org * https://bsc-dataseed.defibit.io * https://bsc-dataseed.ninicoin.io * https://bsc.nodereal.io * https://bsc-dataseed-public.bnbchain.org * https://bnb.rpc.subquery.network/public You could find more endpoints from **[here](https://chainlist.org/chain/56)**. ### BSC Testnet (ChainID 0x61, 97 in decimal) * https://bsc-testnet-dataseed.bnbchain.org * https://bsc-testnet.bnbchain.org * https://bsc-prebsc-dataseed.bnbchain.org ### RPC Providers * **Moralis:** * **NodeReal:** * **Ankr:** * **Chainstack:** * **GetBlock:** * **QuickNode:** * **BlockVision:** * **4EVERLAND:** * **NOWNodes:** * **dRPC:** * **SubQuery:** * **All That Node:** * **Alchemy:** ### Starting HTTP JSON-RPC You can start the HTTP JSON-RPC with the --http flag ```bash ## mainnet geth attach https://bsc-dataseed.bnbchain.org ## testnet geth attach https://bsc-testnet-dataseed.bnbchain.org ``` ## JSON-RPC API List BSC (BNB Smart Chain) is EVM-compatible and strives to be as compatible as possible with the Go-Ethereum API. However, BSC also has unique features, such as faster finality and the storage of blob data on the execution layer, which require their own specialized APIs. ### Geth(Go-Ethereum) API BSC is nearly fully compatible with the Geth APIs. Any exceptions or incompatibilities are explicitly listed. If you're looking for detailed usage of a specific API, you will most likely find the answer in the following link: [Geth JSON-RPC API documentation](https://geth.ethereum.org/docs/interacting-with-geth/rpc). ### Finality Ethereum's PoS consensus protocol, known as "Gasper," is built on LMD-GHOST (a fork choice rule) and Casper FFG (a finality gadget). Similarly, BSC's consensus protocol, called "Parlia," is constructed on top of a difficulty-based fork choice mechanism with FFG, as described in [BEP-126](https://github.com/bnb-chain/BEPs/blob/master/BEPs/BEP126.md). To further enhance BSC's throughput, validators are allowed to produce multiple consecutive blocks, as explained in [BEP-341](https://github.com/bnb-chain/BEPs/blob/master/BEPs/BEP-341.md). These differences result in BSC having a unique finality process compared to Ethereum. For more details, please refer to the the following doc: [BSC Finality API](bsc-api-list.md#finality-api). ### Blob Bsc implement EIP-4844, which support Shard Blob Transactions, as described in [BEP-336](https://github.com/bnb-chain/BEPs/blob/master/BEPs/BEP-336.md). For more details, please refer to the the following doc: [BSC Blob API](bsc-api-list.md#blob-api). ### Other BSC API Bsc implement some others apis, as described in: [BSC API](bsc-api-list.md#others). --- ## Bsc Api list > Source: https://docs.bnbchain.org/bnb-smart-chain/developers/json_rpc/bsc-api-list/ ## Finality API Finality is a crucial aspect of blockchain security, ensuring that once a block is confirmed, it cannot be reversed or altered. This provides users with the confidence to act on the information in the block without delay. ### Probabilistic Finality and Economic Finality BNB Smart Chain (BSC) implements a dual-layer finality mechanism combining Economic Finality and Probabilistic Finality to ensure transaction security and network efficiency. #### Economic Finality (Fast Finality) The Fast Finality feature, introduced through **[BEP-126](https://github.com/bnb-chain/BEPs/blob/master/BEPs/BEP126.md)**, enables Economic Finality using a slashing mechanism similar to Casper FFG and Tendermint. Key characteristics: - Block n achieves economic finality by block n+2 - Transaction finality time: **~3.75 seconds** (with 1.5 seconds block time) - Economic penalties make block reversal extremely expensive - Validators violating voting rules forfeit part of their staked assets This significantly improves user experience through faster and more reliable transaction confirmations. #### Probabilistic Finality (Fallback Mechanism) When Fast Finality is unavailable, BSC falls back to Probabilistic Finality. Security increases as more blocks are added - the deeper a block is buried, the lower the probability of reversal. Network Parameters: - TurnLength: 8 (consecutive blocks per validator) - ValidatorSize: 21 (total active validators) - Block Time: ~1.5 seconds Finality Requirements: - Majority (>1/2) validator confirmations: 88 blocks (11 × 8) ≈ 132 seconds - Supermajority (>2/3) validator confirmations: 120 blocks (15 × 8) ≈ 180 seconds This dual-layer approach ensures network security and finality guarantees even when Fast Finality encounters issues. ### Economic Finality API ### [eth_getHeaderByNumber]() as in the Ethereum client. **Parameters** **BlockNumber** QUANTITY|TAG * HEX String - an integer block number * String "earliest" for the earliest/genesis block * String "latest" - for the latest mined block * String "safe" - for the latest justified head block * String "**finalized**" - for the latest finalized block ### [eth_getBlockByNumber]() as in the Ethereum client. **Parameters** **BlockNumber** QUANTITY|TAG * HEX String - an integer block number * String "earliest" for the earliest/genesis block * String "latest" - for the latest mined block * String "safe" - for the latest justified head block * String "**finalized**" - for the latest finalized block **Full_transaction_flag** Boolean - If true it returns the full transaction objects, if false only the hashes of the transactions. ### eth_newFinalizedHeaderFilter Here are two APIs that can help you trace the latest finalized blocks: 1. Create a finalized header filter: ``` curl -X POST "http://localhost:8545" -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"eth_newFinalizedHeaderFilter","params":[],"id":1}' ``` This will return an rpc.ID which will expire in 5 minutes, then you can get another: ``` {"jsonrpc":"2.0","id":1,"result":"0xcbdc7c21459e2cfbf72e2028f15a98c"} ``` 2. Get latest finalized blocks using above rpc.ID. You can call it many times until rpc.ID expires: ``` curl -X POST "http://localhost:8545" -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"eth_getFilterChanges","params":["0xcbdc7c21459e2cfbf72e2028f15a98c"],"id":1}' ``` This will return block hashes: ``` {"jsonrpc":"2.0","id":1,"result":["0x4b52061726b9f15905217699fd5dab8ff9bb704b3b16d27c34541cb15752a91f","0x2b984b80b25f0dddc92ba11290a3d250fc8a3ec6a09bd485c21dbbb8155d2f90"]} ``` ### Combined Probabilistic Finality and Economic Finality API These methods allow you to handle block finality using a straightforward API. ### eth_getFinalizedHeader * `verifiedValidatorNum` must be within the range `[1, len(currentValidators)]`,with the exception that: - `-1` represents at least `len(currentValidators) * 1/2` - `-2` represents at least `len(currentValidators) * 2/3` - `-3` represents at least `len(currentValidators)` * Using `-1`, `-2`, or `-3` provides a convenient way to select the desired security level according to your application and the corresponding waiting time. When one of these values is used as the parameter, the returned block is increasingly less likely to be reverted. **Historically, blocks returned by `eth_getFinalizedHeader` with `-1`, `-2`, or `-3` on BSC have never been reverted.** * If the highest security level is required, you can choose `-3`. * This function calculates `probabilisticFinalizedHeight` as the highest height of the block verified by `verifiedValidatorNum` validators and then returns the block header with a height equal to `max(fastFinalizedHeight, probabilisticFinalizedHeight)`. * The height of the returned block header is guaranteed to increase monotonically. For example: ``` curl -X POST "http://localhost:8545/" -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"eth_getFinalizedHeader","params":[15],"id":1}' ``` ### eth_getFinalizedBlock * `verifiedValidatorNum` must be within the range `[1, len(currentValidators)]`,with the exception that: - `-1` represents at least `len(currentValidators) * 1/2` - `-2` represents at least `len(currentValidators) * 2/3` - `-3` represents at least `len(currentValidators)` * Using `-1`, `-2`, or `-3` provides a convenient way to select the desired security level according to your application and the corresponding waiting time. When one of these values is used as the parameter, the returned block is increasingly less likely to be reverted. **Historically, blocks returned by `eth_getFinalizedHeader` with `-1`, `-2`, or `-3` on BSC have never been reverted.** * If the highest security level is required, you can choose `-3`. * This function calculates `probabilisticFinalizedHeight` as the highest height of the block verified by `verifiedValidatorNum` validators and then returns the block header with a height equal to `max(fastFinalizedHeight, probabilisticFinalizedHeight)`. * If `fullTx` is true, the block includes all transactions; otherwise, only transaction hashes are included. * The height of the returned block is guaranteed to be monotonically increasing. For example: ``` curl -X POST "http://localhost:8545/" -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"eth_getFinalizedBlock","params":[11, false],"id":1}' curl -X POST "http://localhost:8545/" -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"eth_getFinalizedBlock","params":[15, true],"id":1}' ``` ## Blob API ### eth_getBlobSidecarByTxHash **Parameters** **Hash** String (REQUIRED) * HEX String - the hash of the transaction **full_blob_flag** Boolean (OPTIONAL) * Default is true. If ture it returns the full blob info, if false only return first 32 bytes of blobs. ``` curl -X POST "http://localhost:8545/" -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"eth_getBlobSidecarByTxHash","params":["0x377d3615d2e76f4dcc0c9a1674d2f5487cba7644192e7a4a5af9fe5f08b60a63"],"id":1}' curl -X POST "http://localhost:8545/" -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"eth_getBlobSidecarByTxHash","params":["0x377d3615d2e76f4dcc0c9a1674d2f5487cba7644192e7a4a5af9fe5f08b60a63", false],"id":1}' ``` ### eth_getBlobSidecars **Parameters** **BlockNumber** QUANTITY|TAG * HEX String - an integer block number * HEX String - the hash of the block * String "earliest" for the earliest/genesis block * String "latest" - for the latest mined block * String "safe" - for the latest justified head block * String "finalized" - for the latest finalized block **full_blob_flag** Boolean (OPTIONAL) * Default is true. If ture it returns the full blob info, if false only return first 32 bytes of blobs. ``` curl -X POST "http://localhost:8545/" -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"eth_getBlobSidecars","params":["latest"],"id":1}' curl -X POST "http://localhost:8545/" -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"eth_getBlobSidecarByTxHash","params":["0xc5043f", false],"id":1}' ``` ## Others ### eth_health * a health check endpoint to detect whether the RPC func of a node is ok. Return true is ok, false is no health. ``` curl -X POST "http://localhost:8545/" -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"eth_health","params":[],"id":1}' ``` ### eth_getTransactionsByBlockNumber * get all the transactions for the given block number. **Parameters** **BlockNumber** QUANTITY|TAG * HEX String - an integer block number * String "earliest" for the earliest/genesis block * String "latest" - for the latest mined block * String "safe" - for the latest justified head block * String "finalized" - for the latest finalized block ``` curl -X POST "http://localhost:8545/" -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"eth_getTransactionsByBlockNumber","params":["0x539492"],"id":1}' ``` ### eth_getTransactionDataAndReceipt * get the original transaction data and transaction receipt for the given transaction hash. **Parameters** **Hash** String (REQUIRED) * HEX String - the hash of the transaction ``` curl -X POST "http://localhost:8545/" -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"eth_getTransactionDataAndReceipt","params":["0x516a2ab1506b020e7f49d0d0ddbc471065624d1a603087262cebf4ca114ff588"],"id":1}' ``` --- ## Faucet > Source: https://docs.bnbchain.org/bnb-smart-chain/developers/faucet/ # Claim test tBNB Tokens ## Claim tBNB from Online Faucet To get some tBNB of BSC testnet for testing purposes, you can use the [online faucet](https://www.bnbchain.org/en/testnet-faucet) to claim your tokens. 1. Copy your wallet address and paste the address into the textbox 2. Select the tokens you need to claim. Major pegged tokens like BUSD, USDT, and others are supported. * Please note if your wallet balance is larger than **1 tBNB**, you can not get new tBNB from the Discord bot faucet.* ## Discord Faucet is no longer available Discord Faucet is no longer available as of September 2025. ## Claim tBNB from Third-party Faucets You can also claim tBNB from the following third-party faucets 1. https://faucet.quicknode.com/binance-smart-chain/bnb-testnet 2. https://faucet.chainstack.com/bnb-testnet-faucet 3. https://thirdweb.com/opbnb-testnet --- ## Node Best Practices > Source: https://docs.bnbchain.org/bnb-smart-chain/developers/node_operators/node_best_practices/ # BNB Smart Chain (BSC) Node Configuration: Best Practices ## Hardware Specifications To ensure optimal performance and reliability, it is crucial to select the appropriate node type based on your specific requirements for transaction processing and state querying on the BNB Smart Chain. ### Fast Node (Recommended Configuration) For users requiring access to the latest world state in a lightweight mode, the fast node is the ideal choice. It demands less from your system’s CPU and disk space. - **Processor**: Minimum 16-core CPU. - **Memory**: At least 32 GB RAM. - **Storage**: Solid State Drive (SSD) with a minimum capacity of 2TB. - **Network**: Stable and high-speed internet connection, minimum 5 MBps. ### Archive Node For comprehensive access to the entire historical world state of the BSC mainnet, consider deploying an Archive Node. Detailed instructions are available at [BSC Erigon GitHub repository](https://github.com/node-real/bsc-erigon). - **Processor**: Minimum 16-core CPU. - **Memory**: At least 128 GB RAM. - **Storage**: SSD with a minimum capacity of 10TB (NVME SSDs are recommended for optimal performance). - **Network**: Stable and high-speed internet connection, minimum 5 MBps. ### Full Node To obtain the latest world state and verify the validity of the state or to generate data proofs, a standard Full Node is suitable. - **Processor**: Minimum 16-core CPU. - **Memory**: At least 64 GB RAM. - **Storage**: Solid State Drive (SSD) with a minimum capacity of 3TB. - **Network**: Stable and high-speed internet connection, minimum 5 MBps. ## Peers Configuration ### Mainnet - There is no need to specify static nodes, only Bootnodes are required for mainnet which are already configured in the code. Also, Make sure to use the config.toml file from the latest release. For more details, Please refer this [blog](https://forum.bnbchain.org/t/try-bootnodes-after-bsc-release-v1-2-12/1998#h-32to-join-the-network-with-bootnodes-5). ### Testnet - Testnet still need to configure the StaticNodes manually and hence, the StaticNodes list is contained in the latest release's config.toml. For eg: For geth v1.3.7, the updated config.toml with static nodes can be looked over here: [geth v1.3.7 testnet config](https://github.com/bnb-chain/bsc/releases/download/v1.3.7/testnet.zip) ## Clarification of the snapshots As BSC will mainly support [PBSS & PebbleDB](https://forum.bnbchain.org/t/faq-pbss-pebbledb/2260), we will only cover snapshots of PBSS&PebbleDB and ignore snapshot of HashBased&LevelDB here. Please refer to this [reference](https://github.com/bnb-chain/bsc-snapshots/issues/349). ## Troubleshooting for no peers in testnet - Check for configuration issues like wrong chain id, wrong config file/dir. - Make sure to update the config.toml file as per the latest release - Don't use bootnodes on testnet, it's not required. - Deleting the `geth/nodes` and `geth/nodekey` file/dir might help - Re-download the snapshot and try again. Reference over [here](https://github.com/bnb-chain/bsc/issues/2164#issuecomment-1897980997) ## Monitoring Metrics and Alerts To maintain node health and performance, monitor the following key metrics: - **Transaction Pool Alert**: Triggered when the transaction pool exceeds 5000 transactions. - **Block Import Time Alert**: Activated if block import time exceeds 3 seconds. - **RPC Latency Alert**: Initiated when RPC latency surpasses 100ms. ## Performance Optimization BSC nodes offer configurable cache settings to enhance performance. It is advisable to allocate approximately one-third of the physical memory to the cache. For example, with 64GB of physical memory, the cache setting can be configured as: ``` --cache 20000 ``` ## Keep Track of Syncing Speed ``` t=2021-05-13T17:17:17+0800 lvl=info msg="Imported new chain segment" blocks=11 txs=3701 mgas=482.461 elapsed=8.075s mgasps=59.744 number=7,355,800 hash=0x84e085b1cd5b1ad4f9a954e2f660704c8375a80f04326395536eedf83363942f age=12h38m32s dirty="583.73 MiB" t=2021-05-13T17:17:20+0800 lvl=info msg="Deep froze chain segment" blocks=117 elapsed=263.497ms number=7,265,806 hash=0x7602f6b960b4092d39ff49781c64404a047e2c78bc166f071ee8714020c39b2e t=2021-05-13T17:17:25+0800 lvl=info msg="Imported new chain segment" blocks=17 txs=5025 mgas=740.885 elapsed=8.125s mgasps=91.177 number=7,355,817 hash=0xde7a2a76ff7b38414acf3b360bb427d2d0b7dd1f8fe2afe2ffd59d64b237a81b age=12h37m49s dirty="594.65 MiB" t=2021-05-13T17:17:33+0800 lvl=info msg="Imported new chain segment" blocks=18 txs=5108 mgas=748.016 elapsed=8.354s mgasps=89.535 number=7,355,835 hash=0x757c476f9fe30fc6ef001fb4a03fa991843cf3ed271f21cfc01a9bba5e5eff98 age=12h37m3s dirty="604.39 MiB" t=2021-05-13T17:17:42+0800 lvl=info msg="Imported new chain segment" blocks=18 txs=5612 mgas=799.778 elapsed=8.260s mgasps=96.815 number=7,355,853 hash=0x73e87742ef4405ffefec987fc4b8b19e69c54b8f914c27ea69a502fae4d735e0 age=12h36m18s dirty="613.03 MiB" ``` Your syncing speed is **mgasps**. The value should be around 100. If you are syncing slowly, please check the speed of your disk. ## Use Chaindata Snapshot Please download the chain data [snapshot](https://github.com/bnb-chain/bsc-snapshots) and extract to your home folder to speed up ## Store Your BNB with a Hardware Wallet The most valuable assets of a validator are two keys: one for signing transactions and another for signing blocks ## Securing Your Full Node RPC from Hackers Please do not expose your RPC endpoints to public network. ## Account Private keys To protect your BNB, do not share your 24 words with anyone. The only person who should ever need to know them is you. In short, HSMs are affordable, performant and portable pieces of hardware that help to securely generate, store and manage your private keys. Malware attacks and remote extraction of private keys are much more difficult when an HSM is configured properly. ## Software Vulnerabilities To protect your BNB, you should only download software directly from official sources, and make sure that you're always using the latest, most secure version ## Running Server as a Daemon It is important to keep **geth** running at all times. There are several ways to achieve this, and the simplest solution we recommend is to register **geth** as a systemd service so that it will automatically get started upon system reboots and other events. ## Set up a Backup Node * Run validator node in archive mode * Shut down nodes gracefully * Active monitoring with tools ## Steps to Run a Backup Node 1. Install the latest version of geth 2. Sync to the latest height using fast sync mode. You can either download the latest snapshot or start fast sync once your node is fully synced 3. Shut down your node gracefully kill -HUP $(pgrep geth) 4. Restart your node. ### Why Node will be Offline for a While After Restart? or What will Happen If the Client is Force Killed? After running (synchronized) for a long period of time and being abruptly terminated, only archived nodes are expected to quickly re-synchronize upon restart. Steps to reproduce: * Run the node synchronized for a period of time. * Abruptly kill the node (kill -9 or system crash). * Restart the node, observe where it resynchronizes from block height 1 hour ago. **Reasons** If Geth crashes (or is not shut down gracefully), the recent state held in memory is lost and needs to be regenerated. It takes Geth a long time to restore the states. The root reason is that **geth** does flush the state trie periodically. The period is defined as **trieTimeout** in **config.toml**. ## How to Upgrade a Backup Node to Become a Validator Node? You can stop mining new blocks by sending commands in **geth console** Connect to your validator node with **geth attach ipc:path/to/geth.ipc** ```bash miner.stop() ``` Then, let backup node resume validating , ```bash miner.start() ``` ## Securing the Validators Each validator candidate is encouraged to run its operations independently, as diverse setups increase the resilience of the network. Due to the high amount invested by validators it is highly essential to protect them against different DoS and DDoS attacks. In this section, we disscuss the security mechanism adopted by BSC for its validators. ### Sentry Nodes (DDOS Protection) Validators are responsible for ensuring that the network can sustain denial of service attacks. One recommended way to mitigate these risks is for validators to carefully structure their network topology in a so-called sentry node architecture. Sentry nodes can be quickly spun up or change their IP addresses. Because the links to the sentry nodes are in private IP space, an internet based attacked cannot disturb them directly. This will ensure validator block proposals and votes always make it to the rest of the network. To setup your sentry node architecture you can follow the instructions below: 1. Build a private network and setup trusted private connections between the validator node and its sentry Please do not expose your validator fullnode RPC endpoints to the public network. Install your [fullnode](full_node.md) 2. Set sentry as peers for the validator node In the console of the sentry node, run **admin.nodeInfo.enode** You should get something similar to this. ``` enode://f2da64f49c30a0038bba3391f40805d531510c473ec2bcc7c201631ba003c6f16fa09e03308e48f87d21c0fed1e4e0bc53428047f6dcf34da344d3f5bb69373b@[::]:30306?discport=0 ``` !!! Note: [::] will be parsed as localhost (127.0.0.1). If your nodes are on a local network check each individual host machine and find your IP with ifconfig If your peers are not on the local network, you need to know your external IP address (use a service) to construct the enode URL. Copy this value and in the console of the first node run, Update **config.toml** file of validator node ``` # make node invisible NoDiscovery = true # connect only to sentry StaticNodes = ["enode://f2da64f49c30a0038bba3391f40805d531510c473ec2bcc7c201631ba003c6f16fa09e03308e48f87d21c0fed1e4e0bc53428047f6dcf34da344d3f5bb69373b@[10.1.1.1]:30306"] ``` This will return true if successful, but that doesn’t mean the node was added successfully. To confirm run **admin.peers** and you should see the details of the node you just added. That way your validator node will try to peer with your provided sentry nodes only. 3. Confirm the connection To confirm run **admin.peers** and you should see the details of the node you just added. ### Firewall Configuration **geth** uses several TCP ports for different purposes. **geth** use a listener (TCP) port and a discovery (UDP) port, both on 30303 by default. If you need to run JSON-RPC, you'll also need TCP port 8545. Note that JSON-RPC port should not be opened to the outside world, because from there you can do admin operations. --- ## Full Node > Source: https://docs.bnbchain.org/bnb-smart-chain/developers/node_operators/full_node/ ## 1.About Full node stores the full world state on disk and is capable of: * handle new transactions and produce new blocks, can be used as a validator node. * execute and validate newly received blocks. * verify the states of every account, as it has the full world state. Currently, there are 3 different clients to run a BSC full: * Geth: https://github.com/bnb-chain/bsc * Erigon: https://github.com/node-real/bsc-erigon Only Geth will be covered in this page, as Erigon is mainly to support archive mode, pls refer [archive_node.md](./archive_node.md) for its usage. !!! tip If you want high performance and care little about state consistency, you can run a fast node, which is a full node with the flag `--tries-verify-mode none` set. Check [here](fast_node.md) for full details on running a fast node. ``` ./geth --config ./config.toml --datadir --cache 10000 --tries-verify-mode none --history.logs 576000 ``` ## 2.Run BSC Full Node: Geth ### 2.1.Supported Platforms We support running a full node on **Mac OS X**, **Linux**, and **Windows**. ### 2.2.Steps There are 2 approaches to setup a BSC full node from scratch: - By Snapshot(Recommend): download the latest snapshot and sync based on it. - From Genesis(Not Recommend): sync the whole BSC chain from genesis block. !!! tip As of Nov-2024, the latest block height of BSC mainnet is over 40M, it would need a more powerful hardware and take a great of time to sync from genesis, so it is suggested to setup a BSC full node based the snapshot. #### a.By Snapshot 1. Download the pre-build binaries from the [release page](https://github.com/bnb-chain/bsc/releases/latest) or follow the instructions below ```bash # Linux wget $(curl -s https://api.github.com/repos/bnb-chain/bsc/releases/latest |grep browser_ |grep geth_linux |cut -d\" -f4) mv geth_linux geth chmod -v u+x geth # MacOS wget $(curl -s https://api.github.com/repos/bnb-chain/bsc/releases/latest |grep browser_ |grep geth_mac |cut -d\" -f4) mv geth_mac geth chmod -v u+x geth ``` 2. Download the config files Download **genesis.json** and **config.toml** by: ```bash # mainnet wget $(curl -s https://api.github.com/repos/bnb-chain/bsc/releases/latest |grep browser_ |grep mainnet |cut -d\" -f4) unzip mainnet.zip # testnet wget $(curl -s https://api.github.com/repos/bnb-chain/bsc/releases/latest |grep browser_ |grep testnet |cut -d\" -f4) unzip testnet.zip ``` 3. Download snapshot Download latest chaindata snapshot from [here](https://github.com/bnb-chain/bsc-snapshots). Follow the guide to structure your files. 4. Start a full node ``` ## pls replace with your local path to datadir. ./geth --config ./config.toml --datadir --cache 10000 --rpc.allow-unprotected-txs --history.transactions 0 --history.logs 576000 ``` > **Note**: Consider adding `--history.logs.disable` for better performance, but `eth_getLogs` will be slower. 5. Monitor node status You can monitor the log from **.//bsc.log** by default. When your node has started syncing, you should be able to see the following output: ``` t=2022-09-08T13:00:27+0000 lvl=info msg="Imported new chain segment" blocks=1 txs=177 mgas=17.317 elapsed=31.131ms mgasps=556.259 number=21,153,429 hash=0x42e6b54ba7106387f0650defc62c9ace3160b427702dab7bd1c5abb83a32d8db dirty="0.00 B" t=2022-09-08T13:00:29+0000 lvl=info msg="Imported new chain segment" blocks=1 txs=251 mgas=39.638 elapsed=68.827ms mgasps=575.900 number=21,153,430 hash=0xa3397b273b31b013e43487689782f20c03f47525b4cd4107c1715af45a88796e dirty="0.00 B" t=2022-09-08T13:00:33+0000 lvl=info msg="Imported new chain segment" blocks=1 txs=197 mgas=19.364 elapsed=34.663ms mgasps=558.632 number=21,153,431 hash=0x0c7872b698f28cb5c36a8a3e1e315b1d31bda6109b15467a9735a12380e2ad14 dirty="0.00 B" ``` #### b.From Genesis ```bash ## start a full node from genesis with by one command ## pls replace with your local path to datadir. ./geth --config ./config.toml --datadir --cache 10000 --rpc.allow-unprotected-txs --history.transactions 0 --history.logs 576000 ``` > **Note**: Consider adding `--history.logs.disable` for better performance, but `eth_getLogs` will be slower. ### 2.3.Sync Mode There are two sync modes for running a full node: **snap** and **full** which can be specified by flag **--syncmode**. The **snap** sync mode is used for initial sync, which will download the latest states rather than execute the blocks from the genesis. When the initial sync is done, it will switch to full sync automatically. The **full** sync mode can also be used to do initial sync, which will execute all the blocks since genesis. But it is **not recommended**, since the amount of historical data is too large. Instead, you can download a snapshot from the [official repo](https://github.com/bnb-chain/bsc-snapshots) and start full sync from the snapshot. If the flag **--syncmode** is not provided, the default sync mode will depend on the state of the data folder. It will be **snap** mode if you sync from genesis or **full** mode if you start from a snapshot. ### 2.4.Others #### a.Greenfield Peers Opting for **full** sync mode means your node will only need block headers and bodies from other network peers. To expedite this process, consider utilizing the `Greenfield Peer`. This data seed, offered by Greenfield, allows for a more efficient synchronization. Configure your BSC node to connect with the Greenfield Light Peer by modifying your configuration file settings. For comprehensive instructions, see [Light Peer](../../../bnb-greenfield/for-developers/data-archive/light-peer.md). #### b.Local Private Network Please refer to [BSC-Deploy Tools](https://github.com/bnb-chain/node-deploy) to setup a local private network. #### c.Node Maintenance Please read [this guide](node_maintenance.md) #### d.Upgrade Geth Please read [this guide](upgrade_geth.md) --- ## Archive Node > Source: https://docs.bnbchain.org/bnb-smart-chain/developers/node_operators/archive_node/ # How to Run an Archive Node on BNB Smart Chain ## What is an archive node? Simply speaking, an archive node is a full node running with an additional special option, `--gcmode archive`. It stores all the historical data of the blockchain starting from the genesis block. As compared to a typical full node that just holds all the state change data for some latest blocks, an archive node always stores them for each block. ## Why is an archive node important? Developers are limited to querying the limited recent blocks to check the balance of an address and the state of a smart contract with a full node. It is hard to get all what they want as the blockchain is moving forward at the same time, while they can query any block at a specific point in time with an archive node. Archive nodes are used by various applications on the blockchain for challenging use cases, including but not limited to the followings: - Automatic trading system needs historical data to optimize trading model - Verification modules need state data to verify transactions in time - Analytical tools need full historical data to do data analysis - Exchange in some wallets depends on archive node for fast and efficient transfers ## Suggested Requirements Running an archive node will take a high cost as it includes all the block and state change data. First of all it needs the disk with sufficient capacity; besides this, the CPU and disk performance should be good enough to catch up with the latest block height. You can refer to the [suggested hardware requirements](https://github.com/node-real/bsc-erigon?tab=readme-ov-file#system-requirements). ## How to run an archive node for BSC mainnet? ### Run with an Erigon client [Erigon](https://github.com/node-real/bsc-erigon) now supports the BSC mainnet. The latest version allows you to sync an archive node from scratch in just 3 days, using 4.3 TB of disk space. You can use Erigon to operate an archive node as shown below. --- title: BSC Erigon Node Deployment Guide --- ### BSC Erigon Node Deployment BSC Erigon, maintained by the Node Real team, is a fork of Erigon aimed at becoming the premier archive node implementation for the BSC network. ## Hardware Requirements To ensure optimal performance of your BSC Erigon node, we recommend the following hardware specifications: * RAM: 64GB or more (higher RAM correlates with better performance) * Storage: SSD or NVMe - Archive Node: Minimum 5TB - Fast Node: Minimum 700GB ## BSC Erigon Node Deployment Steps ### 1. Obtain the Erigon Binary Option 1: Build from source ```shell git clone https://github.com/node-real/bsc-erigon.git cd bsc-erigon make erigon ``` Option 2: Use Docker image ```shell docker pull ghcr.io/node-real/bsc-erigon:${latest_version} ``` ### 2. Launch the Erigon Node By default, the node will run in archive mode. Syncing from scratch typically takes about 3 days. ```shell ./build/bin/erigon \ --datadir="" \ --chain=bsc \ --port=30303 \ --http.port=8545 \ --authrpc.port=8551 \ --torrent.port=42069 \ --private.api.addr=127.0.0.1:9090 \ --http --ws \ --http.api=eth,debug,net,trace,web3,erigon,bsc ``` **Note**: To avoid port conflicts, specify different ports for each chain if running multiple instances. ### 3. Running a Fast Node (Non-Archive Mode) Add the --prune.mode=minimal flag to start a fast node. This mode retains only the last 3 days of state and block data, supporting debug_trace* operations for the past 3 days. If you prefer not to spend days syncing, you can obtain fast node snapshots from [community-maintained repositories](https://github.com/48Club/bsc-snapshots). By following these steps, you can flexibly deploy either a full BSC Erigon node or a fast node based on your requirements. Whichever option you choose, BSC Erigon will provide you with an efficient and reliable node service. --- ## Fast Node > Source: https://docs.bnbchain.org/bnb-smart-chain/developers/node_operators/fast_node/ # Fast Node on BNB Smart Chain ## Note **Fast Node does not generate Trie Data when syncing. Once the Fast Node is running, there is no way to switch back to Full Node. Need to re-download snapshot data to restore it to Full Node.** ## Fast Node Functions * Stores the full blockchain history on disk and can answer the data request from the network. * Receives and validates the new blocks and transactions. * Verifies the states of every account. ## Steps to Run a Fast Node ### Download the pre-build binaries from [release page](https://github.com/bnb-chain/bsc/releases/latest) or follow the instructions below: ```bash # Linux wget $(curl -s https://api.github.com/repos/bnb-chain/bsc/releases/latest |grep browser_ |grep geth_linux |cut -d\" -f4) mv geth_linux geth chmod -v u+x geth # MacOS wget $(curl -s https://api.github.com/repos/bnb-chain/bsc/releases/latest |grep browser_ |grep geth_mac |cut -d\" -f4) mv geth_mac geth chmod -v u+x geth ``` ### Download the config files Download **genesis.json** and **config.toml** by: ```bash wget $(curl -s https://api.github.com/repos/bnb-chain/bsc/releases/latest |grep browser_ |grep mainnet |cut -d\" -f4) unzip mainnet.zip ``` ### Download snapshot Download latest chaindata snapshot from [here](https://github.com/bnb-chain/bsc-snapshots). Follow the guide to structure your files. :::note Your --datadir flag should point to the extracted chaindata folder path ::: ### Prune all trie data Fast node does not need trie data anymore. Delete the trie state by the following command. ``` ./geth db delete-trie-state --datadir ./node ``` ### Start Fast Node Without Snapshot Verification ```bash ## start a fast node ./geth --tries-verify-mode none --rpc.allow-unprotected-txs --cache 10000 --history.transactions 360000 --datadir --http.corsdomain * --config ./config.toml --history.logs 576000 ``` > **Note**: Consider adding `--history.logs.disable` for better performance, but `eth_getLogs` will be slower. --- ## Boot Node > Source: https://docs.bnbchain.org/bnb-smart-chain/developers/node_operators/boot_node/ Through the maintenance release [v1.2.12 4](https://github.com/bnb-chain/bsc/releases/tag/v1.2.12), Boot Nodes were introduced on the BSC mainnet. BSC Boot Nodes are similar to Ethereum Boot Nodes, refer [here](https://ethereum.org/en/developers/docs/nodes-and-clients/bootnodes/) for more details. The main benefit of Boot Nodes is that it would be easier for user to connect to the BSC network. Users would no longer need to setup the `StaticNodes` in `config.toml`, just leave it empty and make sure delete the `BootstrapNodes` field in `config.toml`. ## Impact To Users ### Static Nodes Could Be Stopped Previously, BSC provides a list of `StaticNodes` for users to connect to the network, they are working as a full node and also serving the P2P discovery protocol. New BSC nodes connect to the BSC network through these `StaticNodes`. It works, but is not quite stable, since they could have very heavy workload. These static nodes could be stopped and replaced by Boot Nodes in the future. And the `StaticNodes` list provided before could no longer be available. Like the list provided in [v1.2.11 5](https://github.com/bnb-chain/bsc/releases/tag/v1.2.11): ``` StaticNodes = [ "enode://bac6a548c7884270d53c3694c93ea43fa87ac1c7219f9f25c9d57f6a2fec9d75441bc4bad1e81d78c049a1c4daf3b1404e2bbb5cd9bf60c0f3a723bbaea110bc@3.255.117.110:30311", "enode://94e56c84a5a32e2ef744af500d0ddd769c317d3c3dd42d50f5ea95f5f3718a5f81bc5ce32a7a3ea127bc0f10d3f88f4526a67f5b06c1d85f9cdfc6eb46b2b375@3.255.231.219:30311", "enode://5d54b9a5af87c3963cc619fe4ddd2ed7687e98363bfd1854f243b71a2225d33b9c9290e047d738e0c7795b4bc78073f0eb4d9f80f572764e970e23d02b3c2b1f@34.245.16.210:30311", "enode://41d57b0f00d83016e1bb4eccff0f3034aa49345301b7be96c6bb23a0a852b9b87b9ed11827c188ad409019fb0e578917d722f318665f198340b8a15ae8beff36@34.245.72.231:30311", "enode://1bb269476f62e99d17da561b1a6b0d0269b10afee029e1e9fdee9ac6a0e342ae562dfa8578d783109b80c0f100a19e03b057f37b2aff22d8a0aceb62020018fe@3.254.51.234:30311", "enode://16c7e98f78017dafeaa4129647d1ec66b32ee9be5ec753708820b7363091ceb310f575e7abd9603005e0e34d7b3316c1a4b6c8c42d7f074ed2eb4d073f800a03@54.89.153.195:30311", "enode://ba88d1a8a5e849bec0eb7df9eabf059f8edeae9a9eb1dcf51b7768276d78b10d4ceecf0cde2ef191ced02f66346d96a36ca9da7d73542757d9677af8da3bad3f@35.153.161.166:30311", "enode://accbc0a5af0af03e1ec3b5e80544bdceea48011a6928cd82d2c1a9c38b65fd48ec970ba17bd8c0b0ec21a28faec9efe1d1ce55134784b9207146e2f62d8932ba@35.173.132.72:30311" ] ``` ### To Join The Network With BootNodes * If you are using BSC release before `v1.2.12`, you can also try BootNodes without upgrading to `v1.2.12`, you can just set up the `BootstrapNodes` field in your `config.toml` and restart. The six `BootstrapNodes` items listed below can be used directly, they are the current default `BootstrapNodes` in `v1.2.12`: ``` ... [Node.P2P] MaxPeers = 200 NoDiscovery = false BootstrapNodes = [ "enode://433c8bfdf53a3e2268ccb1b829e47f629793291cbddf0c76ae626da802f90532251fc558e2e0d10d6725e759088439bf1cd4714716b03a259a35d4b2e4acfa7f@52.69.102.73:30311", "enode://571bee8fb902a625942f10a770ccf727ae2ba1bab2a2b64e121594a99c9437317f6166a395670a00b7d93647eacafe598b6bbcef15b40b6d1a10243865a3e80f@35.73.84.120:30311", "enode://fac42fb0ba082b7d1eebded216db42161163d42e4f52c9e47716946d64468a62da4ba0b1cac0df5e8bf1e5284861d757339751c33d51dfef318be5168803d0b5@18.203.152.54:30311", "enode://3063d1c9e1b824cfbb7c7b6abafa34faec6bb4e7e06941d218d760acdd7963b274278c5c3e63914bd6d1b58504c59ec5522c56f883baceb8538674b92da48a96@34.250.32.100:30311", "enode://ad78c64a4ade83692488aa42e4c94084516e555d3f340d9802c2bf106a3df8868bc46eae083d2de4018f40e8d9a9952c32a0943cd68855a9bc9fd07aac982a6d@34.204.214.24:30311", "enode://5db798deb67df75d073f8e2953dad283148133acb520625ea804c9c4ad09a35f13592a762d8f89056248f3889f6dcc33490c145774ea4ff2966982294909b37a@107.20.191.97:30311" ] StaticNodes = [] ListenAddr = ":30311" ... ``` * If you are using BSC release `v1.2.12` or later, you no longer need to setup the `BootstrapNodes ` field, but you can not just leave it empty, make sure you delete it from `config.toml`. It would be preferred to delete it and use the default value in case there could be any update to the boot node list in the future. The `config.toml` would look like as follow: ``` ... [Node.P2P] MaxPeers = 200 NoDiscovery = false StaticNodes = [] ListenAddr = ":30311" .. ``` ### To Run A Boot Node Boot nodes are super-lightweight nodes, they can be ran by a very cheap device, like: `2 cores, 2GB memory, 20GB disk`. \ If you want to support the BSC ecosystem by providing new boot nodes, you can follow [this](https://github.com/bnb-chain/bsc#running-a-bootnode) guide to do it. ## Help Since boot nodes have been introduced recently, if you get any problem in using it, please let us know. You may just create new issue in [BSC GitHub repo](https://github.com/bnb-chain/bsc/issues). --- ## Docker Image > Source: https://docs.bnbchain.org/bnb-smart-chain/developers/node_operators/docker/ # How to Run A Fullnode Using BSC Docker Image ## Resources * Docker image: https://github.com/bnb-chain/bsc/pkgs/container/bsc * Dockerfile: https://github.com/bnb-chain/bsc/blob/master/Dockerfile ## Supported Platforms We support running a BSC docker image on **Mac OS X**, **Linux**, and **Windows**. ## Steps to Run a Fullnode in Docker ### Install Docker * Desktop Users: https://docs.docker.com/get-docker/ * Ubuntu Linux: https://docs.docker.com/engine/install/ubuntu/ #### Post install: Start docker during boot up: ``` systemctl enable docker.service systemctl enable containerd.service ``` Add user "ubuntu" to group docker so the user has privileges to run docker commands: ``` usermod -aG docker ubuntu ``` ### Pull BSC Node Image * Get latest version: https://github.com/bnb-chain/bsc/pkgs/container/bsc ``` docker pull ghcr.io/bnb-chain/bsc:latest ``` ### Download BSC Node Config Files Download **genesis.json** and **config.toml** by: Mainnet ```bash wget $(curl -s https://api.github.com/repos/bnb-chain/bsc/releases/latest |grep browser_ |grep mainnet |cut -d\" -f4) unzip mainnet.zip ``` Testnet ```bash wget $(curl -s https://api.github.com/repos/bnb-chain/bsc/releases/latest |grep browser_ |grep testnet |cut -d\" -f4) unzip testnet.zip ``` ### Running Docker Container 1. Dockers Variables and Config file Location Important **Environment Variables** to note: ``` $BSC_HOME = /bsc $DATA_DIR = /data ``` File location: * BSC_CONFIG=${BSC_HOME}/config/config.toml * BSC_GENESIS=${BSC_HOME}/config/genesis.json 2. Docker Volumes to Mount Essentially we need to bind mount two directories: | Mount | Local | Docker | | ----------------- | ------------- | -------------------------------------- | | Blockchain data | data/node | /bsc/node | | Config files | config | /bsc/config | 3. Download data on local host Download latest chaindata snapshot from [here](https://github.com/bnb-chain/bsc-snapshots). Follow the guide to structure your files. 4. Start container You can also use *ETHEREUM OPTIONS* to overwrite settings in the configuration file: ``` docker run -v $(pwd)/config:/bsc/config -v $(pwd)/data/node:/bsc/node -p 8575:8575 --rm --name bsc -it ghcr.io/bnb-chain/bsc:1.1.18_hr --http.addr 0.0.0.0 --http.port 8575 --http.vhosts '*' --verbosity 5 --history.logs 576000 ``` > **Note**: Consider adding `--history.logs.disable` for better performance, but `eth_getLogs` will be slower. * *-p 8575:8575*: This will map port 8575 from host to container, so it exposes 8575 on host node. * *--http --http.addr 0.0.0.0*: Extra Geth flags to enable RPC and listen on all network interfaces of the container. **NOTE**: port **8575** is the default port for the RPC service on TESTNET. If you are using mainnet the default port is **8545**. 5. Start Geth console ``` geth attach http://localhost:8575 ``` ### How to access the container Execute bash (shell/terminal) on the container named bsc: ``` docker exec -it bsc bash ``` Once logged in you can perform regular tasks you would do on a node without docker. ### How to Check Node Running Status #### Check Synchronization Start Geth Console: ``` geth attach ipc:node/geth.ipc ``` Once started, run: ``` >eth.syncing ``` #### Check Geth Logs ``` tail -f node/bsc.log ``` --- ## Upgrade Geth > Source: https://docs.bnbchain.org/bnb-smart-chain/developers/node_operators/upgrade_geth/ # How to Upgrade Geth Updating `geth` is as easy as it gets. You just need to download and install the newer version of `geth`, shutdown your node and restart with the new software. Geth will automatically use the data of your old node and sync the latest blocks that were mined since you shut down the old software. ### Step 1: Compile the New Version or download new pre-build binaries from release ```bash git clone https://github.com/bnb-chain/bsc # Enter the folder bsc was cloned into cd bsc # Compile and install bsc make geth ``` ```bash # Download pre-build binaries # Linux wget $(curl -s https://api.github.com/repos/bnb-chain/bsc/releases/latest |grep browser_ |grep geth_linux |cut -d\" -f4) mv geth_linux geth chmod -v u+x geth # MacOS wget $(curl -s https://api.github.com/repos/bnb-chain/bsc/releases/latest |grep browser_ |grep geth_mac |cut -d\" -f4) mv geth_mac geth chmod -v u+x geth make geth ``` ### Step 2: Stop Geth ``` $ pid=`ps -ef | grep geth | grep -v grep | awk '{print $2}'` $ kill $pid ``` ### Step 3: Restart !!! note Make sure to use the same start-up command you used before the upgrade. So in this case we use the same command as in our [tutorial](full_node.md) ```bash ./geth --config ./config.toml --datadir ./node --cache 10000 --rpc.allow-unprotected-txs --history.transactions 0 --history.logs 576000 ``` > **Note**: Consider adding `--history.logs.disable` for better performance, but `eth_getLogs` will be slower. --- ## Node Maintenance > Source: https://docs.bnbchain.org/bnb-smart-chain/developers/node_operators/node_maintenance/ # Node Maintenance ### Binary All the clients are suggested to upgrade to the latest release. The [latest version](https://github.com/bnb-chain/bsc/releases/latest) is supposed to be more stable and has better performance. ### Storage #### Prune State According to the test, the performance of a full node will degrade when the storage size reaches a high volume(previously it was 1.5TB, which is an experimental value, the latest number needs to be updated). We suggest that the fullnode always keep light storage by pruning the storage. #### How to Prune 1. Stop the BSC node. 2. Run `nohup geth snapshot prune-state --datadir {the data dir of your bsc node} &`. It will take 3-5 hours to finish. 3. Start the node once it is done. The maintainers should always have a few backup nodes in case one of the nodes is getting pruned. The hardware is also important, **make sure the SSD meets: 3 TB of free disk space, solid-state drive(SSD), gp3, 8k IOPS, 500 MB/S throughput, read latency <1ms (if node is started with snap sync, it will need NVMe SSD)**. #### Prune Ancient Data in Real Time Ancient data is block data that is already considered immutable. This is determined by a threshold which is currently set at 90000. This means that blocks older than 90000 are considered ancient data. We recommend the `--prunceancient` flag to users who don't care about the ancient data. This is also advised for users who want to save disk space since this will only keep data for the latest 90000 blocks. Note that once this flag is turned on, the ancient data will not be recovered again and you cannot go back running your node without this flag in the start-up command. #### How to use the flag ``` ./geth --tries-verify-mode none --config /server/config.toml --datadir /server/node --cache 8000 --rpc.allow-unprotected-txs --history.transactions 0 --pruneancient=true --syncmode=full --history.logs 576000 ``` > **Note**: Consider adding `--history.logs.disable` for better performance, but `eth_getLogs` will be slower. #### Prune Block Tools A new offline feature introduced in [v1.1.8](https://github.com/bnb-chain/bsc/releases/tag/v1.1.8) to prune undesired ancient block data. It will discard block, receipt, and header in the ancient database to save space. ##### How to prune 1. Stop the BSC Node. 2. Run ``` ./geth snapshot prune-block --datadir /server/node --datadir.ancient ./chaindata/ancient --block-amount-reserved 1024 ``` `block-amount-reserved` is the number of ancient data blocks that you want to keep after pruning. ### Light Storage When the node crashes or been force killed, the node will sync from a block that was a few minutes or a few hours ago. This is because the state in memory is not persisted into the database in real time, and the node needs to replay blocks from the last checkpoint once it start. The replaying time depends on the configuration `TrieTimeout` in the config.toml. We suggest you raise it if you can tolerate with long replaying time, so the node can keep light storage. ## Upgrade Geth Please read [this guide](upgrade_geth.md) --- ## Overview > Source: https://docs.bnbchain.org/bnb-smart-chain/developers/paymaster/overview/ # EOA Based Paymaster This document introduces a paymaster solution specifically designed for Externally Owned Account (EOA) wallets, differing from the paymaster defined in EIP-4337. With minimal modifications, wallets can integrate this solution to support gas fee sponsorship, significantly enhancing user experience. ## What is EOA based Paymaster The paymaster in [EIP-4337](https://github.com/ethereum/ercs/blob/master/ERCS/erc-4337.md) (Account Abstraction via Entry Point Contract Specification) is a crucial component designed to enhance the flexibility and user experience of Ethereum transactions. It allows a third party to pay for a user's transaction fees, removing the need for users to hold ETH to pay for gas. While EIP-4337 introduced the revolutionary concept of paymasters for smart contract wallets, a significant portion of the Ethereum ecosystem still relies on EOAs. Recognizing this, this present a groundbreaking paymaster solution specifically designed for EOA wallets. This innovation brings the benefits of transaction sponsorship and enhanced user experience to the broader BNB Chain user base, without requiring a shift to smart contract wallets. The EOA paymaster solution aims to democratize access to sponsored transactions, making blockchain interactions more user-friendly and cost-effective for millions of existing EOA wallet users. ## How does it Work Under [BEP322](https://github.com/bnb-chain/BEPs/blob/master/BEPs/BEP322.md)'s Proposer-Builder Separation (PBS) architecture, a significant shift occurs in transaction processing: 1. Validator Role: Validators no longer verify individual transaction gas prices within a block. 2. Transaction Bundling: Private transactions are grouped into bundles and submitted to builders. 3. Prioritization: Builders prioritize based on the aggregate gas price of each bundle. 4. Intra-Bundle Flexibility: Within a single bundle, gas prices can vary, allowing for zero-fee and higher-fee transactions to coexist. This flexibility enables innovative features such as sponsored gas fees and gasless transactions. ### Definitions **Bundle**: An ordered array of transactions that execute atomically, ensuring all transactions in the bundle are processed together or not at all. **Builder**: A new stakeholder in the MEV supply chain responsible for constructing blocks. Builders package transaction bundles, individual transactions from the public txpool, and private transaction order flow into proposed blocks. **Proposer**: A validator who selects the most profitable block from multiple builders' proposals for inclusion in the blockchain. **Paymaster**: An infrastructure component that enables transaction sponsorship, allowing self or third parties to cover gas fees. **Sponsor Policy**: A set of rules defined by the gas sponsor to determine which transactions qualify for sponsorship. This may include criteria such as whitelisted transaction senders or specific transaction types. ### Overall Workflow The gas sponsorship process involves several key components and steps: 1. User Initiation: - A user prepares a transaction using any compatible wallet. - The wallet sets the gas price to zero for potentially sponsored transactions. 2. Paymaster Submission: - The wallet submits the zero-gas-price transaction to the Paymaster. 3. Sponsor Policy Verification: - The Paymaster checks the transaction against existing sponsor policies. - Policies may include criteria such as sender/recipient addresses, token types, or transaction limits. 4. Sponsorship Processing: - If the transaction is eligible for sponsorship: a. The Paymaster creates a sponsor transaction with a higher gas price. b. The original user transaction and the sponsor transaction are combined into a bundle. - If not eligible, the transaction is rejected or returned to the user for normal processing. 5. Bundle Creation and Submission: - This bundle is submitted to multiple MEV builders. 6. Builder Selection and Block Proposal: - MEV builders incorporate the bundle into their block proposals. 7. Blockchain Inclusion: - Proposers (validators) select the most profitable block from the builders' proposals. - The selected block, containing both the user's original transaction and the sponsor's transaction, is added to the blockchain. - This ensures atomic execution of both transactions. 8. Post-Transaction Processing: - The Paymaster Manager updates the sponsor's account, deducting the appropriate amount for the sponsored gas. This solution leverages the BEP322 Proposer-Builder Separation architecture to enable seamless gas sponsorship without requiring significant changes to existing wallet infrastructures. It provides a flexible system that can accommodate various sponsorship models while maintaining the security and integrity of the blockchain network. ## Paymaster Infra Ready to enable gasless experiences in your app or wallet? Here's some helpful information on paymaster infrastructure that are available on BNB Chain: - [Nodereal](https://docs.nodereal.io/docs/megafuel-overview). The MegaFuel powered by Nodereal is a paymaster implementation based on BNB Chain Paymaster for EOA Wallet. With minimal modifications, wallets can integrate MegaFuel to support gas fee sponsorship, significantly enhancing user experience. At the same time, sponsors can customize their sponsorship on MegaFuel, allowing sponsored users to send gasless transactions. - [Bitget Wallet](https://web3.bitget.com/en/). Bitget Wallet has integrated the paymaster on BSC, providing gasless functionality for sponsored user transactions. --- ## Paymaster API Spec > Source: https://docs.bnbchain.org/bnb-smart-chain/developers/paymaster/paymaster-api/ # Paymaster API Spec To facilitate widespread adoption and ensure interoperability across diverse wallet implementations, it is crucial to establish a standardized set of interface specifications for paymasters. This standardization will enable wallet developers to integrate gas sponsorship features efficiently and consistently, regardless of the specific paymaster service they choose to utilize. ## API Spec Paymaster needs to implement a JSON-RPC API called `pm_isSponsorable`, so that it can return sponsor and policy information to wallets. Paymaster also needs to implement `eth_sendRawTransaction` JSON-RPC API. The detailed API Specs are defined as below: ### pm\_isSponsorable **Request Parameters** * `jsonrpc`: The JSON-RPC protocol version ("2.0"). * `id`: A unique identifier for the request (1 in this example). * `method`: The method name to be invoked ("pm\_isSponsorable"). * `params`: An array containing a single object with the following fields: * `to`: The recipient address of the transaction. * `from`: The sender address of the transaction. * `value`: The value of the transaction in hexadecimal. * `data`: Additional data for the transaction in hexadecimal. * `gas`: The gas limit of the transaction in hexadecimal. **Example:** ```plain { "jsonrpc": "2.0", "id": 1, "method": "pm_isSponsorable", "params": [ { "to": "0x...", // an address "from": "0x...", // an address"value": "0xa1", "data": "0x", "value": "0x1b4", "gas" : "0x101b4" } ] } ``` **Response Fields** * `jsonrpc`: The JSON-RPC protocol version ("2.0"). * `id`: The unique identifier for the request (1 in this example). * `result`: An object containing the sponsorship policy details: * (Required) `Sponsorable`: A boolean indicating whether the transaction is sponsorable (true or false). * (Required) `SponsorPolicy`:. The name of the sponsor policy. **Example:** ```json { "jsonrpc": "2.0", "id": 1, "result": { "Sponsorable": true, "SponsorPolicy": "a sample policy name" } } ``` ### ### eth\_sendrawtransaction The `eth_sendrawtransaction` API implemented by the Paymaster should follow this [Ethereum API Spec](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_sendrawtransaction). The client can create a new message call transaction or a contract creation for signed transactions via `eth_sendrawtransaction` API. **Request Parameters** The `params` should contain the signed transaction data. **Example:** ```plain { "jsonrpc": "2.0", "id": 1, "method": "eth_sendRawTransaction", "params": [ "0x02f86a6102850df8475800850df84758000a94cd9c02358c223a3e788c0b9d94b98d434c7aa0f18080c080a0bcb0e8ffa344e4b855c6e13ee9e4e5d22cff6ad8bd1145a93b93c5d332100c2ca03765236eba5fbb357e35014fd19ba4b3c6b87f3793bd14dddf7913fc8dcc88bf" ] } ``` **Response Fields** DATA, 32 Bytes - the transaction hash. **Example:** ```json { "id":1, "jsonrpc": "2.0", "result": "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331" } ``` --- ## Wallet Integration > Source: https://docs.bnbchain.org/bnb-smart-chain/developers/paymaster/wallet-integration/ # Wallet Integration This guide outlines the steps for wallet developers to integrate paymaster services, enabling gas fee sponsorship for their users. By following these standards, wallets can offer seamless, gasless transactions across multiple paymaster providers. ## Interaction Workflow Integration involves modifying the transaction creation and sending process to interact with paymaster services. For detailed information about the paymaster API interface, please refer to this [document](./paymaster-api.md). The main steps are: 1. **Transaction Preparation**: * When a user initiates a transaction, first call `gm_sponsorable` to check if it's eligible for sponsorship. * If sponsorable, set the transaction's gas price to zero. 2. **User Notification**: * Inform the user that the transaction will be gas-free and sponsored by the "policy name" returned by the API. 3. **Transaction Signing**: * Have the user sign the zero-gas-price transaction. 4. **Submission to Paymaster**: * Send the signed transaction to the paymaster using `eth_sendRawTransaction`. 5. **Response Handling**: * Process the paymaster's response: * If successful, inform the user that the transaction is submitted. * If failed, consider falling back to normal transaction processing or inform the user of the failure. 6. **Transaction Monitoring**: * Monitor the transaction status as usual. ## Best Practice 1. Always check sponsorability before modifying gas price. 2. Provide clear user feedback about sponsorship status. 3. Implement proper error handling for cases where sponsorship fails. 4. Consider fallback mechanisms for non-sponsored transactions. --- ## Try Gasless Transaction > Source: https://docs.bnbchain.org/bnb-smart-chain/developers/paymaster/wallet-demo/ # Experience Paymaster in mainstream Wallets Several mainstream cryptocurrency wallets have already implemented Paymaster integration. This tutorial will guide you through the experience of sending gasless transactions in paymaster integrated wallets. ## Paymaster Integrated Wallets Wallets with integrated Paymaster functionality offer a seamless experience for users. These wallets automatically detect whether a transaction is eligible for sponsorship. When a transaction qualifies, the wallet sets the gas price to zero without any user intervention. To illustrate this, we'll walk through the process by transferring stable coin on BSC. --- ## Overview > Source: https://docs.bnbchain.org/bnb-smart-chain/staking/overview/ # BSC Staking Overview BNB Smart Chain (BSC) operates on a Proof-of-Staked-Authority (PoSA) blockchain, with the staking mechanism proposed in [BEP-294](https://github.com/bnb-chain/BEPs/pull/294). This enables BNB holders to stake their tokens with specified validators to secure the network and earn staking rewards. Here's an overview covering the core staking concepts and operations on BSC. ## Basic Concepts ### Consensus Engine BSC uses a consensus mechanism which combines DPoS and PoA for consensus, in this system: * Blocks are produced by a limited set of validators. * Validators take turns to produce blocks in a PoA manner. * Validator set are elected in and out based on a staking based governance. The staking mechanism is essential for determining the eligibility of validators to produce blocks. ### Validator Set The validator set is the group of nodes that are responsible for validating transactions and producing blocks on the BSC. The validator set is determined by the amount of staking each validator has, which reflects the amount of BNB staked by the validator and its delegators. The top validators with the most staking are selected as the active validator set, and they take turns to propose and vote on blocks. The rest of the validators are in the standby validator set, and they can join the active validator set if their staking increases or if some active validators drop out. Any organization or individual can become part of the validator set by creating their validator on-chain and securing sufficient delegations. Similarly, they can opt-out by simply withdrawing all their BNB delegations. Validators can also be removed from the validator set by slashing, which is a penalty for misbehaving or being offline. ### Validator Election There are different roles for validators: * Cabinet: the top K (which is 21 currently) validators who get the most chance of producing blocks. * Candidate: the top (K, K+NumOfCandidates] (which is (21,45] currently) validators who get a small chance of producing blocks. * Inactive: the reset validators who get no chance of producing blocks. The validator set roles are determined every 24 hours based on the latest staking information. After UTC 00:00, the consensus engine sorts validators and updates the BSC validator set with the ranking information. ### System Contracts There are several built-in contracts (i.e., system contracts) to facilitate the BSC staking. * Validator Set Contract. The contract periodically elects a validator set. The contract also serves as a vault for temporarily storing validator rewards. * System Reward Contract. This contract acts as a vault to collect part of transaction fees. The funds are used for various public purposes, like distributing fast finality rewards. * Slash Contract. This contract is used to keep track of the number of times a validator becomes unavailable and triggers penalties once a certain threshold is reached. Additionally, this contract also handles other types of slash events, such as double signing and malicious voting in fast finality. * Stake Hub Contract. This contract serves as the entrypoint for managing validators and delegations, while also implementing the logic for slashing specific validators. For delegation/undelegation/redelegation operations, it will call different validators' implementation contracts to manage a user's stake. ### Credit Contract Each validator has its own validator contract that manages staking credit and facilitates the exchange between credit and BNB. The token name of a staking credit is "stake {{validator moniker}} credit", and the symbol is "st{{validator moniker}}". The contract will be created by the Stake Hub Contract when a validator is created. Whenever a user delegates BNB, an equivalent quantity of credit tokens are created. On the other hand, when a user withdraws their delegation, a corresponding amount of credit tokens are destroyed, thereby releasing the BNB. ### Reward Distribution The staking reward comes from transaction fee - when a block is produced, the majority of the block fee will be collected as reward for the validator who proposed the block. Every day, a portion of the rewards collected will be directly sent to the operator account of the validator as commission, while the remaining portion will be sent to the corresponding validator credit contract. And when a user undelegates and claims his/her stakes, the accumulated reward and the original stake will be sent back to him/her. ## Validator Operations Validators are nodes running BNB Smart Chain software, participating in the consensus process. They require a minimum BNB stake at their validator address and can receive delegations from other BNB holders. Validators earn rewards from transaction fees and share most of these rewards with their delegators. ### Create Validator To ensure the security of the network, becoming a validator on the BSC requires a minimum self-delegation of 2000 BNB. BNB holders can initiate a `CreateValidator` transaction with the `StakeHub` contract to become a validator. For more information, refer to [Create BSC Validator](../validator/create-val.md). ### Edit Validator Validators can update their information using transactions like `EditConsensusAddress`, `EditCommissionRate`, `EditDescription`, and `EditVoteAddress`. ## Delegator Operations Delegators are BNB holders who stake their BNB with a validator, sharing rewards. They can select any active or standby validator, switch between them, undelegate their BNB, and claim rewards anytime. Users can refer to the [user guide](./user-guide.md) for instructions on these actions. --- ## User Guide > Source: https://docs.bnbchain.org/bnb-smart-chain/staking/user-guide/ # Manage Stakes with BNB Staking dApp Leverage the BNB staking dApp for streamlined management of your stakes. This guide provides a step-by-step walkthrough for using the dApp on both BSC testnet and mainnet. - **Testnet**: [https://testnet-staking.bnbchain.org/en/bnb-staking](https://testnet-staking.bnbchain.org/en/bnb-staking) - **Mainnet**: [https://www.bnbchain.org/en/bnb-staking](https://www.bnbchain.org/en/bnb-staking) ## Connect Wallet To interact with the dApp, first connect your web3 wallet. Currently, `TrustWallet` (mainnet only) and `MetaMask` are supported, along with any wallets compatible with `WalletConnect`. ## Delegate Stakes 1. Select a validator to delegate your stakes to. Detailed information about each validator is available on their respective pages. 2. Click the `Delegate` button to initiate a new delegation. 3. Enter the amount of BNB you wish to delegate. 4. After confirming the delegation, your connected wallet will prompt you to sign the transaction. Successful transactions will be visible in the `My Staking` page, complete with transaction hash. ## Redelegate Stakes On the `My Staking` page, you can manage your existing delegations. >Note: A redelegation fee of 0.002% applies to discourage frequent switching between validators. 1. Click `Redelegate` to shift your stake to a different validator. 2. In the ensuing popup, select your new validator and specify the amount to redelegate. You can opt to move the entire amount or just a portion. ## Undelegate Stakes To claim your stakes and rewards, you need to undelegate. 1. Click the `Undelegate` button next to the relevant delegation. 2. You can choose to undelegate the entire amount or a portion. Note that undelegated stakes are subject to a 7-day unbonding period before they are returned to your account. ## Claim Stakes After the unbonding period, you can claim your stakes by clicking the `Claim` button. ## FAQs ### Q1: Which wallet can be used to delegate to validators? Currently, `MetaMask` and `TrustWallet` are supported, along with any wallets compatible with `WalletConnect`. ### Q2: Can I delegate/undelegate/redelegate/claim stakes on explorers? If you want to do the aforementioned delegate/undelegate/redelegate/claim operations on BscScan or BscTrace, you should call the staking hub contract in the following URLs: * [BscScan Stake Hub](https://bscscan.com/address/0x0000000000000000000000000000000000002002#writeContract) * [BscTrace Stake Hub](https://bsctrace.com/address/0x0000000000000000000000000000000000002002?tab=Contract&p=1&view=contract_write) ### Q3: What is staking credit (stBNB)? When you delegate BNB to a validator, you receive **staking credit tokens** as proof of your stake. Each validator issues its own unique credit token: **Token Naming:** - Name: `Stake{{validator moniker}}Credit` - Symbol: `st{{validator moniker}}` - Example: Staking with "BNB48Club" → receive "stBNB48Club" **Key Properties:** - ✅ Represents your staked BNB + accumulated rewards - ✅ Auto-compounding: value increases as validators earn rewards - ✅ Rewards automatically distributed when you undelegate - ❌ Non-transferable between addresses and each validator's credit is unique ### Q4: How to calculate my staking balance? Your staking credit value in BNB can be calculated using: ``` Your BNB Value = (stCreditAmount × totalPooledBNB) ÷ totalSupply() ``` **Where:** - `stCreditAmount`: Your staking credit balance - `totalPooledBNB`: Total BNB in validator's pool (stakes + rewards) - `totalSupply()`: Total supply of the validator's staking credit **Example:** | Time | totalPooledBNB | totalSupply | Your stCredit | Your Value | Profit | |------|----------------|-------------|---------------|------------|--------| | Day 1 | 10,000 BNB | 10,000 | 100 | 100 BNB | - | | Day 30 | 11,000 BNB | 10,000 | 100 | **110 BNB** | +10 BNB (10%) | Your staking credit automatically appreciates as the validator earns block rewards! ### Q5: How to query total pooled BNB programmatically? Use this JavaScript example to query a validator's total pooled BNB: ```javascript import { ethers } from 'ethers'; const provider = new ethers.JsonRpcProvider('https://bsc-dataseed.bnbchain.org'); const OPERATOR = '0x...'; // validator operator address const hub = new ethers.Contract('0x0000000000000000000000000000000000002002', ['function getValidatorCreditContract(address) view returns (address)'], provider); const creditAddr = await hub.getValidatorCreditContract(OPERATOR); const credit = new ethers.Contract(creditAddr, ['function getPooledBNB(address) view returns (uint256)'], provider); const bnb = await credit.getPooledBNB(OPERATOR); console.log('Pooled BNB:', ethers.formatEther(bnb)); ``` --- ## Build Staking dApps > Source: https://docs.bnbchain.org/bnb-smart-chain/staking/developer-guide/ # Build BSC Staking dApps Guide This guide covers essential staking operations like creating validators, editing their information, and delegating. Developers can use these interfaces to build stake-related dApps. ## StakeHub Contract The BSC staking mainly uses the smart contracts `StakeHub` for validator and delegation management. - `StakeHub`: Manages validator creations, user delegations, and executes penalty for validator slash. For the full interfaces of `StakeHub`, please refer to [the ABI file](https://github.com/bnb-chain/bsc-genesis-contract/blob/bc-fusion/abi/stakehub.abi). (Address `0x0000000000000000000000000000000000002002`) ## Creating Validator To create a validator, use the `createValidator` function with the following parameters: ```solidity function createValidator( address consensusAddress, bytes calldata voteAddress, bytes calldata blsProof, Commission calldata commission, Description calldata description ) external payable ``` - `consensusAddress`: The consensus address of the validator. - `voteAddress`: The vote address of the validator. - `blsProof`: The BLS signature as proof of the vote address. - `commission`: The commission structure, including rate, maxRate, and maxChangeRate. - `description`: The description of the validator, including moniker, identity, website, and details. > **Note**: Creating a validator requires locking 1 BNB, and the transaction must be sent with a sufficient BNB amount to cover this lock amount plus any self-delegation, in total 2001BNB. ## Edit Validator ### Edit Consensus Address To change the consensus address of a validator, use the `editConsensusAddress` function with the following parameters: ```solidity function editConsensusAddress(address newConsensusAddress) external ``` - `newConsensusAddress`: The new consensus address of the validator. ### Edit Commission Rate To update the commission rate of a validator, use the `editCommissionRate` function with the following parameters: ```solidity function editCommissionRate(uint64 newCommissionRate) external ``` - `newCommissionRate`: The new commission structure, including rate, maxRate, and maxChangeRate. ### Edit Description To update the description of a validator, use the `editDescription` function with the following parameters: ```solidity function editDescription(Description memory newDescription) external ``` - `newDescription`: The new description of the validator, including moniker, identity, website, and details. ### Edit Vote Address To change the vote address of a validator, use the `editVoteAddress` function with the following parameters: ```solidity function editVoteAddress(bytes calldata newVoteAddress, bytes calldata blsProof) external ``` - `newVoteAddress`: The new vote address of the validator. - `blsProof`: The BLS signature as proof of the vote address. ## Delegation Operations ### Delegate To delegate BNB to a validator, call the `delegate` function with the following parameters: ```solidity function delegate(address operatorAddress, bool delegateVotePower) external payable ``` - `operatorAddress`: The operator address of the validator. - `delegateVotePower`: The flag to indicate whether the delegator would like to delegate his/her voting power to the validator for governance. ### Undelegate To undelegate BNB from a validator, use the `undelegate` function with the following parameters: ```solidity function undelegate(address operatorAddress, uint256 shares) external ``` - `operatorAddress`: The operator address of the validator. - `shares`: The amount of shares to undelegate from the validator. ### Redelegate To redelegate BNB from one validator to another, use the `redelegate` function with the following parameters: ```solidity function redelegate(address srcValidator, address dstValidator, uint256 shares, bool delegateVotePower) external ``` - `srcValidator`: The operator address of the source validator to redelegate from. - `dstValidator`: The operator address of the destination validator to redelegate to. - `delegateVotePower`: The flag to indicate whether the delegator would like to delegate his/her voting power to the destination validator for governance. ## Claim To claim undelegated BNB after the unbonding period, use the `claim` function for a single request or `claimBatch` for multiple requests: ```solidity function claim(address operatorAddress, uint256 requestNumber) external ``` - `operatorAddress`: The operator address of the validator. - `requestNumber`: The number of unbonding requests to claim from. `0` means claiming from all unbonding requests. ```solidity function claimBatch(address[] calldata operatorAddresses, uint256[] calldata requestNumbers) external ``` - `operatorAddress`: The operator addresses of the validators. - `requestNumber`: The numbers of unbonding requests to claim from the validators. ## Precision Loss During the conversion process between credit tokens and BNB, it is inevitably encounter the usage of integer division, which may results in a precision loss. It can lead to tangible issues. For example, a user who delegates 1 BNB and then decides to undelegate immediately. Due to the aforementioned precision loss, they will only be able to claim back 0.99..99 BNB, which is essentially 1 minus a tiny fraction (1e-18) of BNB. In staking pools like Lido and Rocket Pool, users might encounter similar issues. However, these issues can be effectively addressed through thoughtful product design. For instance, when displaying information to users, rounding up to only preserve eight decimal places could be one solution. Or instead of undelegating, users can exchange their credit tokens for BNB, with the exact conversion results prominently displayed. ## FAQs ### What is validator's credit contract? For each validator, there is a credit contract which will be automatically deployed when it is created. Meanwhile, the contract cannot be upgraded or changed by any validator operator. The credit contract is a BEP20 contract, and the ABI is the same as [Stake Credit contract](https://github.com/bnb-chain/bsc-genesis-contract/blob/master/abi/stakecredit.abi). It provides functions for querying delegations, including: * `balanceOf(address)`: Get the credit balance of a delegator. * `getPooledBNB(address)`: Get the pooled BNB amount of a delegator. * `getPooledBNBByShares(uint256)`: Get the pooled BNB amount for a specific amount of shares. * `getSharesByPooledBNB(uint256)`: Get the shares for a specific amount of pooled BNB. * `pendingUnbondingRequests(address)`: Get the count of unbonding requests for a delegator. * `unbondRequest(address, uint256)`: Get the details of a unbond request for a delegator. * `claimableUnbondRequest(address)`: Get the count of claimable unbonding requests for a delegator. * `lockedBNBs(address, uint256)`: Get the locked BNBs for a delegator's unbond queue. ### How to get the shares/BNB for a delegator? For any specific validator, please call the `balanceOf` function of the validator's creat contract to get the delegator's shares. To get the BNB amount instead of shares, the function `getPooledBNB` can be used. To get the shares of all validators, please call the `balanceOf` function for each validator and sum up the results. Please refer to the following to see how to get the information of all validators, and use a muticall contract to improve the efficiency. ### How to calculate the BNB amount for a specific amount of shares? The credit contract provides the `getPooledBNBByShares` function to calculate the BNB amount for some specific amount of shares. To do the vice visa, please use the `getSharesByPooledBNB` function to calculate the shares for some specific BNB amount. ### How to calculate the APR/APY of a validator? Please be noted that each validator will have its own APR/APY, and the staking system will auto compound the rewards. The reward is distributed to each validator's BNB pool at 00:00:00 UTC time every day. To calculate the APR/APY of a validator, the total pooled BNB amount and the propagandising reward amount for the same day are needed. The `StakeHub` contract provides the `getValidatorTotalPooledBNBRecord(address,uint256)(uint256)` and `getValidatorRewardRecord(address,uint256)(uint256)` for the purpose. The following code shows how to calculate the APY at a given day: ```go // example code, do not use it in production // stakehub is the instance of StakeHub contract stakeHub, _ := contracts.NewStakeHub(ethcommon.HexToAddress("0x0000000000000000000000000000000000002002"), client.GetEthClient()) // get how many blocks are in a day interval, _ := stakeHub.BREATHEBLOCKINTERVAL(nil) // get the block time of a given block header, _ := p.client.GetBlockHeader(blockHeight) // calculate the index paramter to call the following functions index := int64(header.Time) / interval.Int64() // get the total pooled BNB amount and the crrospanding reward amount for the given validator and index totalPooledBNB, _ := stakeHub.GetValidatorTotalPooledBNBRecord(nil, validatorOperatorAddress, index) reward, _ := stakeHub.GetValidatorRewardRecord(nil, validatorOperatorAddress, index) // calculate the APY rate, _ := big.NewFloat(0).Quo(big.NewFloat(0).SetInt(reward), big.NewFloat(0).SetInt(totalPooledBNB)).Float64() apy := math.Pow(1+rate, 365) - 1.0 ``` ### How to get the unbonding delegations of a delegator, and the unbonded requests which can be claimed? The credit contract provides the `pendingUnbondRequest` function to get the unbonding delegation count for a delegator. To review the details of an unbond request, please call the `unbondRequest` function with a `index` parameter to define which unbond request will be returned. To get the claimable unbonded requests, please call the `claimableUnbondRequest` function to get the count of claimable ones. To get the locked BNBs for unbonding requests, please use the `lockedBNBs` function. It has the parameter `number` to define the sum of first `number` unbonding requests' BNB locked in the delegator's unbond queue. Set the `number` to `0` to get all the locked BNBs. ### How to get the reward of a delegator? The contracts do not save the initial delegation amount of a delegator. To get the accumulated reward, the following steps can be taken: 1) track the initial delegation amount in your system, 2) call the `getPooledBNB` of the credit contract of a validator, 3) do the math. You can refer to [this code repository](https://github.com/bnb-chain/staking-reward-example) for example. ### How to get the total staking address of a validator? The contract does not provide a function to get the total staking address of a validator. It needs an offchain service to index `Delegated`, `Redelegated`, `Undelegated` events for the purpose. ### How to get all validators' information? The `StakeHub` contract provides the `getValidators` function to get all validators' information, including the `operator` addresses and `credit contract` addresses. To get more information of a specific validator, please refer to the following functions: * `getValidatorConsensusAddress` * `getValidatorCreditContract` * `getValidatorVoteAddress` * `getValidatorBasicInfo` * `getValidatorDescription` * `getValidatorCommission` --- ## Overview > Source: https://docs.bnbchain.org/bnb-smart-chain/governance/overview/ # BSC Governance Overview [BEP-297](https://github.com/bnb-chain/BEPs/pull/297) introduces the native governance module for BSC, drawing inspiration from the [OpenZeppelin Governor](https://docs.openzeppelin.com/contracts/4.x/governance). Here are the key features of BSC Governance: - **Proposal and Voting Rights**: Staking credit holders can propose and vote on governance matters. - **Continuous Rewards**: Voters can keep earning staking rewards during the voting period. - **Flexible Delegation**: Users can delegate their voting rights, enabling others to participate in governance. - **Secure Execution**: Proposals undergo a time lock period before execution once passed. ## Workflow Overview ### Submit Proposal - **Initiation**: Any staking credit holder can submit a proposal following the [user guide](./user-guide.md). - **Details Required**: Proposer address, target addresses, values, function signatures, calldatas, and a comprehensive description. - **Requirements**: A minimum stake of 200 BNB and no pending proposals from the same delegator. ### Cast Vote - **Engagement**: Voters cast their votes through the `castVote` transaction on the `Governor` contract. - **Information Needed**: Voter address, proposal ID, and support value (True or False). - **Flexibility**: Voters can adjust their support value throughout the voting period, current set at **7 days**. - **Voting Power**: Voting power is the staking credit amount a voter holds when a proposal is submitted. ### Execute Proposal - **Execution Quorum**: The percentage of voted staking credit to total staking credit should be no less than the governance quorum, currently set at **10%**. - **Tally Threshold**: The voting power percentage for `Yes` should be no less than that for `No` and should meet the tally threshold, currently set at **50%**. - **Execution Timelock**: When a proposal meets the execution conditions, there is still a necessary delay before it can be triggered, currently set at **1 day**. ## Delegation of Voting Power Staking credit holders can delegate their voting power to participate in governance if they lack time or expertise. Delegating to a trusted party like a validator or a professional service allows them to benefit from expertise and avoid losing rewards by not voting. --- ## User Guide > Source: https://docs.bnbchain.org/bnb-smart-chain/governance/user-guide/ # Manage Governance with Tally dApp This document provides a guide on how to participate in governance on the BNB Smart Chain (BSC) using Tally. It covers the process of delegating voting power, creating proposals, voting on proposals, and executing proposals. BNB Chain DAOs are created on Tally both for the mainnet and testnet. * Testnet: [https://www.tally.xyz/gov/bnb-chain-testnet](https://www.tally.xyz/gov/bnb-chain-testnet) * Mainnet: [https://www.tally.xyz/gov/bnb-chain](https://www.tally.xyz/gov/bnb-chain) ## Parameters There are several parameters which will affect the governance process on the BSC. | Parameter | Description | Mainnet Value | Testnet Value | |-------------------------|----------------------------------------------------------------------------------|---------------|---------------| | votingDelay | a fixed duration after which users can vote to a proposal | 0 hour | 0 hour | | votingPeriod | the voting period before tally | 7 days | 1 day | | proposalThreshold | a fixed amount of gov BNB needed for a proposal | 200 govBNB | 100 govBNB | | quorumNumberRator | the percentage of the total voting power required to produce a final vote result | 10% | 10% | | startGovThreshold | the total supply of gov token to enable the gov function | 10M BNB | 10M BNB | | minPeriodAfterTheQuorum | the time to add for voting when a proposal reaches quorum | 1 day | 1 hour | | timerlockDelay | the timer locker duration to execute a proposal | 1 day | 6 hours | ## Governance Process Guide You need to connect to your Web3 wallet (e.g., TrustWallet, BEW, Metamask) for the following operations. ### Delegate Voting Power After you have delegated your BNB to a BSC validator, you can start participating in the BSC governance. To participate in BSC governance, you first need to delegate your voting power to a validator or yourself if you wish to vote directly. You can click the `My voting power` button in the top right corner of the screen to delegate your voting power. You can delegate your voting power to yourself if you want to vote/create proposals directly, or to others if you want him/her to vote/create proposals on your behalf. If you delegate the voting power to yourself, you will see the current number of your voting power to participate in the governance. ### Create Proposals If you have sufficient voting power (i.e., greater than the `proposalThreshold`), you can create proposals on the BSC network. Be noted that a user can only has one proposal in active/pending state at a time to prevent spamming. To create a proposal, click on the "Create new proposal" button on the top right corner of the screen. After you have created a proposal, you can add a title, description, and a list of actions for the proposal. A text proposal only requires a title and a description, and it will not be executed by the network for there is no action. To add an action, click on the "Add action" button, and fill in the details of the action. - `Target Contract Address`: The contract address to be called by the proposal. - `ABI File`: The ABI file of the contract. You can upload the ABI file manually if the ABI file is not correctly detected. - `Conctract Method`: The method of the contract to be called. - `Calldata`: The input data for the contract method. Which is optional. After you input all the details, click on the "Publish" will publish your proposal. You can also cancel a proposal by clicking on the "Cancel proposal" button. ### Vote on Proposals Once a proposal is live (i.e., after the `votingDelay` and before the `votingPeriod`), you can cast your vote to support or oppose the proposal. To vote on a proposal, click on the "Vote on chain" button. You can cast `For`, or `Against`, or `Abstain` votes to the proposal. ### Execute Proposals If a proposal reaches the quorum (i.e., reaches the `quorumNumberRator` of the total voting power) and it passes (i.e., more than 50% of the voted voting power supports the proposal), it can be executed by the network. To execute a proposal, firstly the proposal needs to be queued by clicking the `Queue` button. After the proposal is queued and exceeds the timelock duration (i.e, the `timerlockDelay` duration), it can be executed by anyone by clicking the `Execute` button. ### More References - [Delegations on Tally](https://docs.tally.xyz/knowledge-base/delegations-on-tally) - [Proposals on Tally](https://docs.tally.xyz/knowledge-base/proposals) --- ## BNB Advocate`s Guide > Source: https://docs.bnbchain.org/bnb-smart-chain/governance/bnb-kol/ # BNB On-Chain Governance Voting: A BNB Advocate`s Guide # Introduction Key Opinion Leaders (BNB Advocates) hold significant influence within the BNB Chain community. Your participation in on-chain governance is vital to ensure the network evolves in a truly decentralized manner. By maximizing your voting power, you can amplify your community's voice and drive positive change. # How to Increase Voting Power **As a tech leader, there are two primary ways to enhance your governance power:** 1. Increase your BNB holdings: The more BNB you hold in your wallet, the more voting power you possess. Consider acquiring additional BNB to boost your influence in governance decisions. 2. Receive delegated BNB: Encourage your community members to delegate their voting power to you. This empowers you to vote on their behalf, increasing your overall influence in the governance process. **Steps to Gain More Voting Power from Your Community** 1. Educate and Advocate: Explain the importance of on-chain governance and how it empowers the community to shape the future of BNB Chain. Clearly articulate the benefits of delegating voting power to you as a trusted tech leader. 2. Share Proposals and Insights: Regularly share your thoughts on upcoming proposals and explain how they might impact the community. Provide insightful analysis and encourage your followers to engage in the discussion. 3. Simplify Delegation: Make the delegation process as easy as possible for your community. Provide clear instructions and guidance on how to delegate their voting power to you. 4. Transparent Communication: Maintain open and transparent communication with your community. Keep them informed about how you plan to utilize their delegated voting power and the rationale behind your voting decisions. 5. Build Trust: Continuously build trust with your community by demonstrating your commitment to their interests and the overall well-being of the BNB Chain ecosystem. ## Steps of governance power delegation(To be shared to your followers) 1. Access the BNB Chain Governance page: 1. Go to the Tally website (https://www.tally.xyz/gov/bnb-chain). 1. Connect Your Wallet: 1. Click on "Connect Wallet" and select your preferred wallet provider. 2. Follow the prompts to connect and authorize access to your wallet. 2. Navigate to Delegation: 1. Locate and click on the "Delegate" button or tab. 1. Choose Your Delegate: 1. You have two main options: 1. Delegate to Self: This means you will directly control your voting power and vote on proposals yourself. 2. Delegate to Another Address: Enter the wallet address of the person or entity you want to delegate your voting power to. 1. Confirm and Sign 1. Once you've made your selection, review the details and click on the "Delegate" or "Delegate Votes" button. 2. Your wallet will prompt you to confirm and sign the transaction. 2. Verify Delegation: 1. After the transaction is confirmed on the blockchain, you can go to the "Votes" or "My Delegates" section on Tally to verify that your delegation was successful. # Important Considerations: - Factors Affecting Voting Power: - BNB Staking: The more BNB you staked on validators, the greater your voting power. - Delegated BNB: The more people delegate their voting power to you, your voting power increases. # Disclaimer: - The specific process and rules for BNB on-chain governance voting might evolve. Always refer to official BNB Chain documentation and announcements for the latest information. - Remember: On-chain governance is a powerful tool that enables the BNB Chain community to make collective decisions about the network's future. By participating, you contribute to the growth and development of the BNB Chain ecosystem. --- ## Temperature Check > Source: https://docs.bnbchain.org/bnb-smart-chain/governance/temp-check/ # BSC Governance Temperature Check ## Overview BNB Chain governance involves a two-step process: temperature check and final decision voting. The temperature check, typically conducted through the Snapshot platform, allows any BNB holder to gauge community sentiment on a proposal. If the proposal receives enough support, it proceeds to the final decision voting phase. This phase often involves on-chain voting by validators or those with staked BNB, and the outcome determines whether the proposal is implemented or rejected. ## Submit a Proposal !!! info Anyone who staked more than 1BNB can create proposals. Step 1: Head to the space which you wish to create your proposal for. Connect with the wallet provider - make sure the connected wallet is where you delegate BNB Step 2: Click New proposal in space sidebar Fill in the following fields: - Title - Description - Discussion link Step 3: Select the desired voting system, specify the possible vote options, and define the duration of your proposal. Make sure you allow enough time for users to vote. Step 4: Click `Publish` - and you can see your proposal in the proposals list on the space page. ## Voting ### Vote on a Proposal !!! info All BNBChain delegators can vote for proposals. Step 1: Log in to voting space URL: https://snapshot.org/#/bnbchain-dao.eth Step 2: Go to the snapshot link of the proposal. For example, in this case, a community member created a voting proposal for BEP-341. https://snapshot.org/#/bnbchain-dao.eth/proposal/0xd2ad975fbe1abd4bf71a5032239650741a64af0133feec83f43b98bc42fa7efe Step 3: Connect your wallet and vote After you connect your wallet, make sure to use the same address of your BNB Staking. And choose the voting option. ### Delegate Voting Power Step 1: Go to https://snapshot.org/#/delegate/bnbchain-dao.eth Step 2: Enter the address you want to delegate to. Step 3: Click Confirm to save your delegation. ### Undelegate Voting Power Step 1: Go to https://snapshot.org/#/delegate/bnbchain-dao.eth Step 2: Find the current delegatees in Top delegates. Step 3: Click the 'x' button along a delegatee to undelegate, the wallet will ask user to sign and send transaction to bsc ### Factors Affecting Temperature Governance Power: - BNB Holding Balance: The more BNB you hold, the greater your voting power. - Staked BNB: Delegating your BNB to a validator also contributes to your governance power. This ensures those actively participating in the network's security have a say. https://www.bnbchain.org/en/bnb-staking - ListDAO Staked BNB: Your staked listDAO BNB(slisBNB) https://docs.bsc.lista.org/user-guide/liquid-staking-slisbnb --- ## Governance APIs > Source: https://docs.bnbchain.org/bnb-smart-chain/governance/apis/ # BSC Governance APIs This guide gives an overview of governance operations for BSC, such as creating proposals, casting votes, and executing them. ## Governance Contracts The BSC governance facilitates decentralized decision-making within the BSC ecosystem, utilizing two primary smart contracts: `GovToken` for governance token management and `Governor` for proposal management and voting. - `GovToken`: Manages governance tokens, enabling holders to participate in governance decisions. It supports syncing token balances with staked assets and delegating voting rights. (Address: `0x0000000000000000000000000000000000002005`) - `Governor`: Manages the creation, voting, and execution of governance proposals. It also ensures only eligible participants can propose changes and vote. (Address: `0x0000000000000000000000000000000000002004`) ## Create Proposal To create a proposal, you need to call the `propose` function of `Governor` with the following parameters: ```solidity function propose(address[] memory targets, uint256[] memory values, bytes[] memory calldatas, string memory description) public returns (uint256 proposalId) ``` - `targets`: Contract addresses the proposal will interact with. - `values`: BNB values (in wei) for each call. - `calldatas`: Encoded function calls. - `description`: Description of the proposal. ## Cast Vote To cast a vote, you need to call the `castVote` function of `Governor` with the following parameters: ```solidity function castVote(uint256 proposalId, uint8 support, string memory reason) public returns (uint256) ``` - `proposalId`: ID of the proposal. - `support`: Vote choice (e.g., for, against, abstain). - `reason`: (Optional) Reason for your vote. ## Check Proposal State To get the state of a proposal, you need to call the `state` function of `Governor` with the following parameters: ```solidity function state(uint256 proposalId) public view returns (ProposalState) ``` - `proposalId`: ID of the proposal. ## Queue Proposal To schedules the proposal for execution, you need to call the `queue` function of `Governor` with the following parameters: ```solidity function queue(address[] memory targets, uint256[] memory values, bytes[] memory calldatas, bytes32 descriptionHash) public returns (uint256 proposalId) ``` - `targets`: Contract addresses the proposal will interact with. - `values`: Ether values (in wei) for each call. - `calldatas`: Encoded function calls. - `descriptionHash`: Hash of the description of the proposal. ## Execute Proposal To apply the changes after the timelock delay, you need to call the `execute` function of `Governor` with the following parameters: ```solidity function execute(address[] memory targets, uint256[] memory values, bytes[] memory calldatas, bytes32 descriptionHash) public payable returns (uint256) ``` - `targets`: Contract addresses the proposal will interact with. - `values`: Ether values (in wei) for each call. - `calldatas`: Encoded function calls. - `descriptionHash`: Hash of the description of the proposal. ## Delegate Vote To delegate voting power to someoneles, you need to call the `delegateVote` function of `GovToken` with the following parameters: - **Delegator address**: The address of the delegator, who delegates their voting power to another address. - **Delegatee address**: The address of the delegatee, who receives the voting power from the delegator and participates in governance on their behalf. ```solidity function delegateVote(address delegator, address delegatee) external ``` - `delegator`: The address of the delegator, who delegates their voting power to another address. - `delegatee`: The address of the delegatee, who receives the voting power from the delegator. ## Contract ABI For the full interfaces of `Governor`, please refer to [the ABI file](https://github.com/bnb-chain/bsc-genesis-contract/blob/bc-fusion/abi/Governor.abi). For the full interfaces of `GovToken`, please refer to [the ABI file](https://github.com/bnb-chain/bsc-genesis-contract/blob/bc-fusion/abi/govtoken.abi). --- ## Overview > Source: https://docs.bnbchain.org/bnb-smart-chain/validator/overview/ # BSC Validator Overview BNB Smart Chain(BSC) relies on a system of multiple validators with [Proof of Staked Authority (PoSA) consensus](https://github.com/bnb-chain/whitepaper/blob/master/WHITEPAPER.md#consensus-and-validator-quorum) that can support short block time and lower fees. The most bonded validators in staking will have the opportunity to produce blocks. The double-sign detection and other slashing logics ensure security, stability, and chain finality. BSC conducts a daily election process post **00:00 UTC** to select the top **45** active validators based on their staking rankings for block production. Among these, the **21** validators with the highest staked amounts are referred to as **Cabinets**, while the remaining **24** validators are known as **Candidates**. The remaining inactive validators must wait for the next round of elections to become active validators before they can participate in block production. In the set of **45** active validators, each epoch selects **18** validators from the **Cabinets** and **3** validators from the **Candidates**, forming a group of **21** validators as the consensus validators set for the current epoch to produce blocks. If a validator is elected as the consensus validator but fails to participate in produce blocks, it will face slashing consequences. **Cabinets** are more likely to be elected as consensus validators for block generation than **Candidates**, who have a slightly lower probability of being chosen for the same role. However, whether it's **Cabinets** or **Candidates**, if they are not online when it's their turn to produce a block, they will be slashed. This measure aims to encourage more validators to participate in the consensus, enhancing the decentralization and security of BSC. ## What is Validator? Validators on the BSC are nodes responsible for producing blocks and securing the network through the [POSA consensus mechanism](https://github.com/bnb-chain/whitepaper/blob/master/WHITEPAPER.md#consensus-and-validator-quorum). They participate in packaging transactions, creating and validating blocks to secure the BSC network, earning BNB tokens as rewards in exchange. ## The Network Topology Validators on the BSC network are interconnected through a peer-to-peer (P2P) network, allowing for both direct and indirect connections. As a validator node operator, you have two operational modes to choose from: - **Mode A(Ease of Use)**: You can expose your validator's public IP address directly to the P2P network, which facilitates a direct connection. This mode is the most straightforward and offers high efficiency due to fewer network hops. To mitigate potential security risks, it is highly recommended to deactivate the HTTP module whenever possible and avoid exposing HTTP access to the public. Additionally, it's crucial to safeguard your validator node's information to prevent Distributed Denial of Service (DDoS) attacks that could target the P2P port. - **Mode B(Enhanced Security)**: This mode conceals your validator node behind one or more SentryNodes, which are essentially regular BSC full nodes. The SentryNode acts as a protective intermediary between your hidden validator node and the public P2P network. It primarily shields the validator from threats such as DDoS attacks and other security vulnerabilities. ## Economics Validator's rewards come from transaction fees and commission fees from delegators. Let us also assume that the reward for a block is 100 BNB and that a certain validator has **20%** of self-bonded BNB and sets its commission rate to **20%**. These tokens do not go directly to the proposer. Instead, they are shared among validators and delegators. These **100 BNB** will be distributed according to each participant's stake: ``` Commission: 100 BNB × 20% = 20 BNB (goes directly to validator) Remaining for All Delegators: 100 BNB - 20 BNB = 80 BNB (distributed proportionally) Validator's Share of Remaining: 80 BNB × 20% = 16 BNB Other Delegators' Share: 80 BNB × 80% = 64 BNB Total Validator Reward: 20 BNB (commission) + 16 BNB (self-delegation share) = 36 BNB ``` The rewards for motivating validators to vote for Fast Finality also comes from transaction fees. The specific rules can refer to [BEP126](https://github.com/bnb-chain/BEPs/blob/master/BEPs/BEP126.md#43-reward) If validators double sign, malicious vote or frequently offline, their staked BNB (not including BNB of users that delegated to them) can be slashed. The penalty depends on the severity of the violation. You can learn to see the revenue history from BitQuery's [chart](https://explorer.bitquery.io/bsc/miners) or a table of [BscScan](https://bscscan.com/validatorset) ## Risks for Validators If validators attempt to cheat the system or violate the specifications, they may incur a penalty known as **[slashing](../slashing/overview.md)**. ### Double Sign Slash Running your validator keys simultaneously on two or more machines will result in Double-Sign slashing. The penalty for double-sign slash: 1. **200 staked BNB** will be slashed for the validator. 2. The double sign jail time is **30 days**, preventing the malicious validator from participating in consensus until manual intervention is taken. > Note: > **Rewards for submitting double-sign evidence:** **5BNB**. > Anyone can submit a slashing request with the evidence of double sign, which should contain the **2 block headers** with the same height and parent block, sealed by the offending validator. ### Malicious Fast Finality Vote Slash Running your validators with the same consensus keys and bls voting keys concurrently on two or more machines will result in malicious vote slash. The penalty for malicious vote slash: 1. **200 staked BNB** will be slashed for the validator. 2. The malicious vote jail time is **30 days**, you can send an `unjail` transaction after the jail time to reactivate your validator. > Note: **Rewards for submitting Malicious Vote evidence:** **5BNB**. Anyone can submit a slash request with the evidence of malicious vote on BSC, which should contain the **2 votes**, signed by the offending validator. ### Downtime Slash If your validator misses over **50 blocks** in **24 hours**, the blocking reward won't be given to you but will be shared among other validators. If your validator continues to miss more than **150 blocks** within **24 hours**, it will trigger the following penalty for being offline. 1. **10 staked BNB** will be slashed for the validator. 2. The offline jail time is **2 days**. This allows the validator to send an `unjail` transaction and resume as an active validator after 2 days. ### Low Self-Delegation Slash Validators must stake a minimum of 2000 BNB for self-delegation. If the self-delegated amount is less, the penalty is 2 days of jail time. --- ## Run Validator > Source: https://docs.bnbchain.org/bnb-smart-chain/validator/run-val/ # Run BSC Validator ## Validator Hardware Requirements ### Mainnet - Instance Spec: - Suggest i7i.8xlarge or i7ie.6xlarge instance type on AWS (better to disable HyperThread, which could have 10%+ performance gain). - or other instance spec to meet >=400 mgasps - Memory: 128 GB - Disk: **IMPORTANT** 7TB, NVMe SSD, 40k IOPS, 500 MB/S throughput, read latency <1ms. - Network Bandwidth: >= 512 Mbps ### Testnet - CPU: "AMD Gen 3 or newer" or "Intel Ice Lake or newer" - Memory: 16 GB - Disk: 1.5 TB, solid-state drive(SSD), gp3, 8k IOPS, 250 MB/S throughput. - Network Bandwidth: >= 128 Mbps ## Setup Validator Node ### 1. Install BSC Fullnode Follow the instructions [here to set up a full node](../developers/node_operators/full_node.md). ### 2. Prepare Accounts Two accounts require preparation before running a validator: the Consensus account and the BLS Vote account. Ensure these accounts match the corresponding ones when creating a new validator. #### Generate Consensus Address To create a new mining consensus account, run this command and set a password for the account: ```shell geth account new --datadir ${DATA_DIR} ``` - `DATA_DIR`: Where your key store files are saved. If you already have a consensus account, skip this step. Save the password in a file named password.txt: ```shell echo {your-password for the consensus account} > password.txt ``` #### Generate BLS Vote Address To set up a new BLS account, use this command: ```shell geth bls account new --datadir ${DATA_DIR} ``` - `DATA_DIR`: The directory to store your key store files. If you already have a BLS vote key, you can create a BLS wallet and recover it with the keyfile using: ```shell geth bls account import ${KEY_FILE} --datadir ${DATA_DIR} ``` To retrieve your bls address, run: ```shell geth bls account list --datadir ${DATA_DIR} ``` Save the password in a file named blspassword.txt: ```shell echo {your-password for the BLS wallet} > blspassword.txt ``` ### 3. Start Validator Node > Warning: Please do not expose your RPC endpoints to public network! Start your validator using the command line below: ```bash geth --config ./config.toml --datadir ./node -unlock {accounts to sign txs, including your mining account at least} --miner.etherbase {the address of your mining account} --password password.txt --blspassword blspassword.txt --mine --vote --allow-insecure-unlock --cache 18000 --history.transactions 0 --history.logs.disable ``` ## Post Running ### 1. Monitor node status To get started quickly, run GethExporter in a Docker container. ``` docker run -it -d -p 9090:9090 \ -e "GETH=http://mygethserverhere.com:8545" \ hunterlong/gethexporter ``` ### 2. Update validator profile You can submit a PullRequest to this repository to update your information: Reference: ### 3. Publish Validator Information Please submit a Pull Request to this repo This repository is a place for validator candidates to give potential delegators a brief introduction about your team and infrastructure, and present your ecosystem contributions. ### 4. Stop Validating You can stop mining new blocks by sending commands in **geth console** Connect to your validator node with **geth attach ipc:path/to/geth.ipc** ```bash miner.stop() ``` To resume validating, ```bash miner.start() ``` ## Some Tips & Tools ### 1.Run backup node Backup node could help when your primary validator node encounters issues due to a variety of potential reasons, ensuring the continuity and reliability of your participation in the network. ### 2.Check your node’s stability There is a javascript in BSC repo to dump the slash status of each validator. ``` cd /cmd/jsutils # 1.To dump the slashes of the lates block: node getslashcount.js --Rpc https://bsc-dataseed.bnbchain.org # 2.You may also specify the block number: node getslashcount.js --Rpc https://bsc-dataseed.bnbchain.org --Num 39938351 ``` If your validator operates smoothly, you should expect minimal or even no penalties, known as "slashes," on a daily basis. Generally speaking, if your validator incurs more than three slashes within a single day, it would be prudent to investigate the cause for this anomaly. ### 3.About maintenance mode Should your validator incur 50 slashes, it will automatically transition into maintenance mode. It is imperative to promptly diagnose and rectify any issues with your node to prevent further penalties. Failure to do so may result in your node being placed in a more restrictive state, often referred to as "jail." Upon successfully restoring your node's functionality, it is crucial to promptly [exit maintenance mode](https://github.com/bnb-chain/bsc/blob/master/docs/parlia/README-BEP-127.md#exit-maintenance) to resume normal operations and avoid any unnecessary downtime or penalties. ``` // note: replace "0x75B851a27D7101438F45fce31816501193239A83" with your validator's consensus address. geth attach geth.ipc web3.eth.sendTransaction({ from: "0x75B851a27D7101438F45fce31816501193239A83", to: "0x0000000000000000000000000000000000001000", data: "0x04c4fec6"}) ``` ### 4.Filter out peers by regex pattern This functionality was introduced with version [1.4.6](https://github.com/bnb-chain/bsc/releases/tag/v1.4.6), primarily designed to identify and exclude peers that may present operational challenges, thereby preventing connections with them. For further details, please refer to this Pull Request: [PR#2404](https://github.com/bnb-chain/bsc/pull/2404). Generally, this feature is not necessary for regular operation. However, in the event that a release contains critical bugs and an immediate upgrade of all nodes to a stable version is not feasible, this feature can be employed to disconnect from peers running the problematic versions. This serves as a temporary solution to mitigate the impact of the bugs until a comprehensive upgrade can be performed. For example, if v1.4.9 has known issues, we wanna disconnect nodes of this version, you may update your `config.toml` and restart: ``` [Node.P2P] PeerFilterPatterns = ["Geth/v1.4.9.*"] ``` --- ## Create Validator > Source: https://docs.bnbchain.org/bnb-smart-chain/validator/create-val/ # Create BSC Validator This guide outlines the process for creating a new validator on the BNB Smart Chain (BSC). The BNB staking dApp is the official tool for creating and managing validators on the BSC. - **Testnet**: [https://testnet-staking.bnbchain.org/en/bnb-staking](https://testnet-staking.bnbchain.org/en/bnb-staking) - **Mainnet**: [https://www.bnbchain.org/en/bnb-staking](https://www.bnbchain.org/en/bnb-staking) ## Terminology - **Operator Address**: The address for creating and modifying validator information on the BSC. You should use this address when connecting to the staking dApp. The corresponding account should have more than 2001 BNB for creating validtors and paying transaction fees. - **Consensus Address**: A unique address for your validator's node. It is used for consensus engine when mining new blocks. It should be different from the operator address. - **BLS Vote Address**: A BLS address used for fast finality voting. - **BLS Proof**: A BLS signature verifying ownership of the vote address. - **Identity**: For associating a new validator with an existing one. This is optional unless you're migrating an old validator. ## Steps ### 1. Connecting to the dApp Please connect to the staking dApp using your **Operator Address**. `Trust Wallet`, `MetaMask`, and `WalletConnect` options are available for the step. Make sure that the account has more than 2001 BNB before moving on to the next step. ### 2. Filling out the form Navigate to the dApp and select the `Become a Validator` button in the right middle of the page to initiate the creation process. The following information is required to create a validator. #### 2.1 Basic Information You'll need to provide the following details on the `Create Validator` page: - **Validator Name**: Choose a name consisting of 3-9 alphanumeric characters, excluding special characters. - **Website**: Provide a URL to a website with additional information about your validator. - **Description**: A brief description of your validator. To enhance your validator's visibility, consider uploading additional information to the [BSC validator directory](https://github.com/bnb-chain/bsc-validator-directory). Your avatar, once uploaded, will be displayed in the staking dApp. #### 2.2 Addresses The following addresses are required: - **Consensus Address**: A unique address for your validator's node. - **Vote Address**: An address used for fast finality voting. - **BLS Proof**: A BLS signature verifying ownership of the vote address. - **Identity**: For associating a new validator with an existing one. This is optional unless you're migrating an old validator. ##### Generate Consensus Address Download the BSC geth binary from [the official release page](https://github.com/bnb-chain/bsc/releases/). Note: Make sure you are downloading the correct binary based on your machine's platform, e.g., if you are using MacOS, you should download the `geth_mac` file. In the following, we will refer the binary as `geth` for simplicity. To create a new account for mining, please use the following command and set a password for the account. ```shell geth account new --datadir ${DATA_DIR} ``` - `DATA_DIR`: The directory where you want to store your key store files. This command will provide the public address (consensus address) and the path to your private key. Remember to back up the key file safely! A sample consensus address is `0x4b3FFeDb3470D441448BF18310cAd868Cf0F44B5`. If you already have an account for mining, you can use the seed phrase to recover the account. ```shell geth account import --datadir ${DATA_DIR} ``` ##### Generate BLS Vote Address and Proof To create a new bls account please use the following command. ```shell geth bls account new --datadir ${DATA_DIR} ``` - `DATA_DIR`: The directory where you want to store your key store files. If you already have a voting key, create a bls wallet and use the keyfile to recover it, using the following command. ```shell geth bls account import ${KEY_FILE} --datadir ${DATA_DIR} ``` - `DATA_DIR`: The backup file for restoring the BLS account. Then you can get your vote address by running the following command. ```shell geth bls account list --datadir ${DATA_DIR} ``` A sample bls address is `b5fe571aa1b39e33c2735a184885f737a59ba689177f297cba67da94bea5c23dc71fd4deefe2c0d2d21851eb11081f69`. Then you can get your bls proof by running the following command. ```shell geth bls account generate-proof --datadir ${DATA_DIR} --chain-id ${BSC_CHAIN_ID} ${OPEATOR_ADDRESS} ${VOTE_ADDRESS} ``` - `BSC_CHAIN_ID`: `56` for BSC mainnet, and `97` for BSC testnet. - `OPEATOR_ADDRESS`: The address of your account, which will be recognized as the operator of the new validator. - `VOTE_ADDRESS`: The vote address created in the last step. A sample bls proof is `0xaf762123d031984f5a7ae5d46b98208ca31293919570f51ae2f0a03069c5e8d6d47b775faba94d88dbbe591c51c537d718a743b9069e63b698ba1ae15d9f6bf7018684b0a860a46c812716117a59c364e841596c3f0a484ae40a1178130b76a5`. ##### Create Identity Identity is used to associate the new validator with the old validator created on the BNB Beacon Chain. It should be left empty after the Beacon Chain fusion. #### 2.3 Commissions - **Rate**: The commission rate of the validator. - **Max Rate**: The maximum commission rate that the validator can set. - **Max Change Rate**: The maximum rate change the validator can set to every epoch (1 day). #### 2.4 Self-delegation - **Self Delegate Amount**: The amnout to delegate when creating the validator. The minimal number to input is `2001` - for the minimal self delegation amount is 2000 BNB and extra 1 BNB for locking to a dead address. ### 3. Submitting the form Once you have filled out all the required information, click the `Submit` button to submit the transaction. Note: Upon completing these steps, your node is not guaranteed to become an active validator. Selection is based on a ranking that reflects the total BNB staked, with only the top N nodes being chosen as active validators. The number N is determined by the "maxElectedValidators" parameter within the StakeHubContract (0x0000000000000000000000000000000000002002). As of November 4th, 2024, this number stands at 8 for the testnet and 45 for the mainnet. --- ## Secure Validator > Source: https://docs.bnbchain.org/bnb-smart-chain/validator/security/ # Secure BSC Validator Each BSC validator is encouraged to run its operations independently, as diverse setups increase the resilience of the network. Due to the high amount invested by validators it is highly essential to protect them against different DoS and DDoS attacks. In this section, we discuss the security mechanism adopted by BSC for its validators. ## Sentry Nodes (DDOS Protection) Validators should ensure network resilience against denial of service attacks. One effective approach to reduce these risks is by organizing their network in a sentry node architecture. Sentry nodes, easily deployed and capable of IP address changes, operate in private IP space, shielding them from direct internet attacks. This setup guarantees that validator block proposals and votes reliably reach the network. To setup your sentry node architecture you can follow the instructions below: ### 1. Setup Nodes Construct a private network and establish trusted connections between the validator node and its sentry nodes. Refer to the [fullnode guide](../developers/node_operators/full_node.md) for setting up your validator and sentry nodes. Avoid exposing your validator's RPC endpoints to the public network. ### 2. Add Peers Connect individual sentry nodes' console, execute `admin.nodeInfo.enode` command. This will provide you with the enode information for each node, as illustrated below. ``` enode://f2da64f49c30a0038bba3391f40805d531510c473ec2bcc7c201631ba003c6f16fa09e03308e48f87d21c0fed1e4e0bc53428047f6dcf34da344d3f5bb69373b@[::]:30306?discport=0 ``` >!!! Note: **[::]** will be interpreted as the localhost (127.0.0.1) address. If your nodes are within a local network, ensure to inspect each host machine to determine its IP using the ifconfig command. However, if your peers are outside the local network, you must be aware of your external IP address to form the enode URL correctly. Replace **[::]** with the correct node URL, copy the enode details, and add them to the `config.toml` file of the validator node like this: ``` # make node hidden NoDiscovery = true # connect exclusively to sentry StaticNodes = ["enode://f2da64f49c30a0038bba3391f40805d531510c473ec2bcc7c201631ba003c6f16fa09e03308e48f87d21c0fed1e4e0bc53428047f6dcf34da344d3f5bb69373b@[10.1.1.1]:30306"] ``` ### 3. Confirm Connections Connect to the validator's console, run `admin.peers`, and you will see the details of the sentry nodes you added. ## Firewall Configuration `Geth` utilizes different ports for various functions. It utilizes a listener (TCP) port and a discovery (UDP) port for P2P connections, typically configured to 30303. Ensure this port is open. The default JSON-RPC service port is TCP port 8545. To prevent unauthorized admin operations, refrain from exposing the JSON-RPC port externally. --- ## Key Management > Source: https://docs.bnbchain.org/bnb-smart-chain/validator/manage-keys/ # Key Management for BSC Validator [BEP-294](https://github.com/bnb-chain/BEPs/pull/294) and [BEP-297](https://github.com/bnb-chain/BEPs/pull/297) introduce the native staking and governance features for BNB Smart Chain (BSC). For a validator, when participating in staking (e.g., creating a validator, self-delegating) and governance, there are several wallet keys that will be involved. To help validators manage their keys and funds effectively and safely, the following practices are recommended. ## Operator Key The operator key is used for operating a validator, including creating a validator, editing the information of a validator, and undelegating. When creating a validator, the operator key is also used for self-delegating with more than 2001 BNB. When interacting with the new BSC staking dApp, the operator key is mostly involved. Be noted that the operator address can not be changed for a validator. **Recommendation: Use a hardware wallet, a Safe wallet or an MPC wallet. There should be more than 2001 BNB in the operator account when creating a new validator.** ## Staking Key For a validator, it can also use another key, different from the operator key, to manage his/her delegation if needed. Then, such a staking key will be used to delegate/undelegate/redelegate to different validators and claim rewards. This key could be used frequently, depending on how a validator manages its delegations and rewards. Be noted that this key is optional, depending on the needs of a validator. **Recommendation: Use a hardware wallet, a Safe wallet or an MPC wallet.** ## Consensus Key The consensus key is used for signing proposed blocks when mining blocks. No fund is needed for this account. **Recommendation: Use a hot wallet so that it can be easily accessed by a validator node.** ## Fast Finality Vote Key The fast finality vote key (BLS vote key) is used in the [fast finality feature](https://github.com/bnb-chain/BEPs/blob/master/BEPs/BEP126.md) for signing votes of recently mined blocks. No fund is needed for this account. **Recommendation: Use a hot wallet so that it can be easily accessed by a validator node.** ## Governance Vote Key The [BEP-297](https://github.com/bnb-chain/BEPs/pull/297) introduces the native BSC staking feature. A delegator (including validators for self-delegation) can delegate someone else to participate in governance on his/her behalf. When there is governance delegation, the governance vote key will be used for casting votes to BSC proposals. The related wallet should store some BNB for gas fees of the voting transaction. Be noted that this key is optional, depending on the needs of a validator. **Recommendation: Use a hardware wallet, a Safe wallet or an MPC wallet.** --- ## Overview > Source: https://docs.bnbchain.org/bnb-smart-chain/validator/mev/overview/ # BSC MEV Overview The BSC network has introduced the [Builder API Specification](https://github.com/bnb-chain/BEPs/blob/master/BEPs/BEP322.md) to establish a fair and unified MEV market. Previously, BSC clients lacked native support for validators to integrate with multiple MEV providers at once. The network became unstable because of the many different versions of the client software being used. The latest BSC client adopts the [Proposer-Builder Separation](https://ethereum.org/en/roadmap/pbs/) model. Within this unified framework, several aspects of the BSC network have been improved: - **Stability**: Validators only need to use the official client to seamlessly integrate with various Builders. - **Economy**: Builders that can enter without permission promote healthy market competition. Validators can extract more value by integrating with more builders, which benefits delegators as well. - **Transparency**: This specification aims to bring transparency to the BSC MEV market, exposing profit distribution among stakeholders to the public. ## What is MEV and PBS MEV, also known as Maximum (or Miner) Extractable Value, can be described as the measure of total value that may be extracted from transaction ordering. Common examples include arbitraging swaps on decentralized exchanges or identifying opportunities to liquidate DeFi positions. Maximizing MEV requires advanced technical expertise and custom software integrated into regular validators. The returns are likely higher with centralized operators. Proposer-builder separation(PBS) solves this problem by reconfiguring the economics of MEV. Block builders create blocks and submit them to the block proposer, and the block proposer simply chooses the most profitable one, paying a fee to the block builder. This means even if a small group of specialized block builders dominate MEV extraction, the reward still goes to any validator on the network. ## How it Works on BSC The figure above illustrates the basic workflow of PBS operating on the BSC network. - MEV Searchers are independent network participants who detect profitable MEV opportunities and submit their transactions to builders. Transactions from searchers are usually bundled together and included in a block, or none of them will be included. - The builder collects transactions from various sources to create an unsealed block and offer it to the block proposer. The builder will specify in the request the amount of fees the proposer needs to pay to the builder if this block is adopted. The unsealed block from the builder is also called a **block bid** as it may request tips. - The proposer chooses the most profitable block from multiple builders, and pays the fee to the builder by appending a payment transaction at the end of the block. A new component called **Sentry** has been introduced to enhance network security and account isolation. It assists proposers in communicating with builders and enables payment processing. ## What is More The PBS model on BSC differs in several aspects from its implementation on Ethereum. This is primarily due to: 1. **Different Trust Model**. Validators in the BNB Smart Chain are considered more trustworthy, as it requires substantial BNB delegation and must maintain a high reputation. This stands in contrast to Ethereum, where becoming an Ethereum validator is much easier, the barrier to becoming a validator is very low (i.e., 32 ETH). 2. **Different Consensus Algorithms.** In Ethereum, a block header is transferred from a builder to a validator for signing, allowing the block to be broadcasted to the network without disclosing the transactions to the validator. In contrast, in BSC, creating a valid block header requires executing transactions and system contract calls (such as transferring reward and depositing to the validator set contract), making it impossible for builders to propose the whole block. 3. **Different Blocking Time.** With a shorter block time of 3 seconds in BSC compared to Ethereum's 12 seconds, designing for time efficiency becomes crucial. These differences have led to different designs on BSC's PBS regarding payment, interaction, and APIs. For more design philosophy, please refer to [BEP322:Builder API Specification for BNB Smart Chain](https://github.com/bnb-chain/BEPs/blob/master/BEPs/BEP322.md). --- ## Validator Guide > Source: https://docs.bnbchain.org/bnb-smart-chain/validator/mev/validator-integration/ # Integration Guide for Validator ## Decision Make When activating MEV functionality, validators encounter a mix of opportunities and challenges. Before enabling this feature, validators need to carefully evaluate these risk accordingly: 1. More maintenance work. Apart from the validator, additional maintenance of the Sentry service and its related network components is required. 2. Network risk. Due to Sentry service being exposed to the public network, it is inevitably susceptible to possible network attacks. 3. Financial risk. Validators need to pay fees to builders, securely managing accounts is a crucial topic. After identifying these risks, let's begin the journey. ## Validator Topology It is suggested that to split the internal network into two part: 1. Private network. The private network is isolated from the public network. All access to components within this network is strictly restricted. The Validator and Payment wallet are expected to be deployed within a private network environment. 2. Nat network. The components in this network can communicate with the public internet under certain constraints, and the communication can be established through load balancers provided by various cloud platforms. Sentry service should be deployed within a NAT network environment. It is essential to configure appropriate safeguards on the network gateway to prevent DoS attacks and other potential threats. The validator should open its RPC access to the mev-sentry. The mev-sentry should open its RPC to the public network with a domain host. The information of validator should be registered in [bsc-mev-info](https://github.com/bnb-chain/bsc-mev-info). ### Hardware Spec Mev-Sentry: The recommended specifications for the mev-sentry machine are 2 CPUs and 4 GB of RAM. ## Preparation The BNB Chain community has maintained an open-source version of the Sentry service. You can clone the code repository from [here](https://github.com/bnb-chain/bsc-mev-sentry). Before actually deploying the Sentry service, it is crucial to carefully consider and determine several key parameters: 1. **BidFeeCeil.** This represents the maximum fee that a validator is willing to pay for a block proposed by a builder. When this value is 0, it signifies that the validator does not accept any charges from the builder. 2. **BidSimulationLeftOver.** This parameter indicates how long before the block time the validator should cease simulating the blocks from the builder. It is generally advisable to set it to a few tens of milliseconds. Setting it too small may result in blocks being broadcast too late and subsequently discarded during network congestion. It is suggested to purchase a domain that is related to the moniker name of the validator. The builders will send requests through this domain. A BSC account should be created in advance as the payment account. No BNB is required in that account if **BidFeeCeil** is zero, otherwise, it needs to be ensured that there is enough balance in the account. Go to the [bsc-mev-info](https://github.com/bnb-chain/bsc-mev-info) repo to find more information about running builders which will be used during setup. ## Quick Setup **Step 1**: **Setup Sentry.** Deploy the sentry service according to the readme of [sentry repo](https://github.com/bnb-chain/bsc-mev-sentry). Here are a few key points to highlight. - ❗❗❗This is an important security notice: Please do not configure any validator's private key in the config file of the sentry. Please create entirely new accounts as pay bid accounts. - One sentry service can manage multiple validators. - The **PrivateURL** of validator is used by the sentry to access the validator, it can be IP:Port or internal domain URL. - The **PublicHostName** of validator is used by the builder to access the validator, the sentry will forward to different validators according to different hostname of the request. - For each Builder, define its Address and public URL. The address will be used to authorize the identity of builders. **Step 2: Change the Config of Validator.** Upgrade the validators to version v1.4.x or later, add a few new sections in the config.toml. Example: ```toml [Eth.Miner.Mev] Enabled = true # open bid receiving GreedyMergeTx = true # merge local tx to the MEV bid block ValidatorCommission = 100 # validator claim 1% from block reward BidSimulationLeftOver = 50000000 # 50ms, the time left for bid simulation SentryURL = "http://bsc-mev-sentry.io" # it is used for the validator to access the sentry, it should be a private URL or IP:Port. # Find builders in [bsc-mev-info](https://github.com/bnb-chain/bsc-mev-info) [[Eth.Miner.Mev.Builders]] Address = "0x45EbEBe8...664D59c12" # builder address which validator is willing to receive bid from [[Eth.Miner.Mev.Builders]] Address = "0x980A75eC...fc9b863D5" # builder address which validator is willing to receive bid from ``` **Step 3: Publish information** It is highly recommended to publish information in [bsc-mev-info](https://github.com/bnb-chain/bsc-mev-info) so other builders can find it. --- ## Builder Guide > Source: https://docs.bnbchain.org/bnb-smart-chain/validator/mev/builder-integration/ # Integration Guide for Builder The [Builder API Specification](https://github.com/bnb-chain/BEPs/blob/master/BEPs/BEP322.md) defines the standard interface that builders should implement, while the specific implementation is left open to MEV API providers. The BNB Chain community offers a simple [implementation example](https://github.com/bnb-chain/bsc-builder) for reference. ## Customize Builder Although the builder offers great flexibility, there are still some essential standards that must be followed: 1. The builder needs to set up a **builder account**, which is used to sign the block bid and receive fees. The builder can ask for a tip (builder fee) on the block that it sends to the sentry. If the block is finally selected, the **builder account** will receive the tip. 2. The builder needs to implement the **mev_reportIssue** API to receive the errors report from validators. 3. In order to prevent transaction leakage, the builder can only send block bids to the in-turn validator. 4. At most 3 block bids are allowed to be sent at the same height from the same builder. Here are some sentry APIs that may interest a builder: 1. **mev_bestBidGasFee**. It will return the current most profitable reward that the validator received among all the blocks received from all builders. The reward is calculated as: **gasFee\*(1 - commissionRate) - tipToBuilder**. A builder may compare the **bestBidGasFee** with a local one and then decide to send the block bid or not. 2. **mev_params.** It will return the **BidSimulationLeftOver**,**ValidatorCommission**, **GasCeil** and **BidFeeCeil** settings on the validator. If the current time is after **(except block time - BidSimulationLeftOver)**, then there is no need to send block bids any more; **ValidatorCommission** and **BidFeeCeil** helps the builder to build its fee charge strategy. The **GasCeil** helps a builder know when to stop adding more transactions. Builders have the freedom to define various aspects like pricing models for users, creating intuitive APIs, and define the bundle verification rules. ## Setup with Example Builder **Step 1: Find Validator Information** For validators that open MEV integration, the public information is shown at [bsc-mev-info](https://github.com/bnb-chain/bsc-mev-info). Builders can also provide information here to the validator. **Step 2: Set up Builder.** The builder must sign the bid using an account, such as the etherbase account specified in the config.toml file. ```toml [Eth.Miner.Mev] BuilderEnabled = true # open bid sending BuilderAccount = "0x..." # builder address which signs bid, usually it is the same as etherbase address ``` Configure the validator node list, including the address of the validator and the public URL. The public URL refers to the sentry service. ```toml [[Eth.Miner.Mev.Validators]] Address = "0x23707D3D...6455B52B3" URL = "https://bsc-fuji.io" [[Eth.Miner.Mev.Validators]] Address = "0x52825922...3A1A7A422" URL = "http://bsc-mathwallet.io" ``` **Step 3: Publish information** It is highly recommended to publish information in [bsc-mev-info](https://github.com/bnb-chain/bsc-mev-info). --- ## User Guide > Source: https://docs.bnbchain.org/bnb-smart-chain/validator/mev/user-guide/ # User Guide PBS(Proposer-Builder Separation) framework offers several advantages for BNB Chain users: - Users are less likely to have their transactions front-run or sandwiched. - Increased competition among block builders can lead to more efficient markets and potentially lower gas prices. - Enhanced transaction privacy: Users' transactions are exposed to fewer parties before being included in a block. - Faster transaction processing: More efficient block construction can lead to quicker transaction confirmations. ## For Retail Traders When you trade on a decentralized exchange (DEX), you risk being targeted by bots that can front-run your trades, meaning they see your transaction in the public mempool and execute a similar trade first, profiting from the price change you were going to cause. This can result in you getting a worse price or even losing money. Private RPCs offer a solution to this problem. They route your transactions through a private mempool(Provided by builders), hiding them from bots. This means your trades are less likely to be front-run, and you're more likely to get the price you expect. Some DEX protocols or builder providers are keen to provide free protection features, and the average transaction confirmation time is around 4-5 seconds, and it may fluctuate according to the network conditions. | Role | Status and Comments | | ---------------------------- | ------------------------------------------------------------ | | Free Privacy Protecting RPCs | [Pancake Swap Private RPC](https://docs.pancakeswap.finance/products/pancakeswap-private-rpc) [48 Club Private RPC](https://docs.48.club/privacy-rpc)[Merkle Free BSC Private RPC](https://merkle.io/free-bsc-rpc)[BlockRazor Private RPC with Refund](https://rpc.blockrazor.io/) | ### Builder Proxies The builder proxies act as a transaction broadcaster for builders. Instead of users' transactions being limited to a smaller set of pre-registered validators or specific builders, the proxies take each submitted transaction and broadcasts it to all registered builders across the network. This broader dissemination benefits users by significantly increasing the chances of their transaction being picked up by a builder and included in the next block, leading to faster transaction confirmation times. Furthermore, the increased competition among builders, who now have access to a larger pool of transactions, can potentially result in more efficient block construction and, indirectly, potentially lower transaction fees and improved censorship resistance for users. A transaction proxy sample code is built by NodeReal, You can find it in the open-source git repo here https://github.com/node-real/private-tx-sender | Builder Proxy | Associated Builders | Link | |---|---|---| | Blockrazor | 48Club, BloXroute, NodeReal | https://blockrazor.gitbook.io/blockrazor/builder/bsc | Merkle | 48Club, BlockRazor | https://www.merkle.io/bsc-rpc **Wallets with Manual MEV Protection:** Several wallets now offer built-in protection against malicious MEV (Miner Extractable Value) attacks, enhancing the security and fairness of users' transactions. This protection is often available as a feature that users can manually enable during their swap or trading activities. - **Private Transaction Relays:** These relays hide transaction details from malicious actors, preventing them from front-running or sandwich attacking the user's trade. - **Specialized Builders:** Some wallets utilize builders that prioritize user protection and fair ordering of transactions, minimizing the potential for MEV exploitation. | Type | Name | Status | How to enable | | ------ | -------------- | --------- | ------------------------------------------------------------ | | Wallet | Trust Wallet | Supported | [TrustWallet Swap MEV Protection](https://trustwallet.com/blog/introducing-mev-protection-secure-your-swaps-with-trust-wallet) | | Wallet | Binance Web3 Wallet | Supported | [Binance Alpha tokens MEV Protection](https://www.binance.com/en/support/announcement/introducing-binance-alpha-discover-emerging-crypto-projects-c6499e95c15e408ca44ca5f6db975d4d) | | Wallet | OKX Wallet | Supported | [OKX Wallet Enable Swap MEV Protection](https://www.okx.com/help/okx-wallet-supports-flashbot-to-prevent-mev-attack) | | Wallet | TokenPocket Wallet | Supported | [TokenPocket Swap MEV Protection](https://help.tokenpocket.pro/en/security-knowledge/security-measure/mev-protection-tutorial) | | Wallet | Safepal Wallet | Supported | [Safepal Swap MEV Protection](https://safepalsupport.zendesk.com/hc/en-us/articles/33892098077851-Use-SafePal-to-Protect-Your-Swaps-from-MEV-Attacks) | | Wallet | Math Wallet | Supported | [Mathwallet Swap MEV Protection](https://blog.mathwallet.org/?p=4799) | ## For Professional Traders and Service Providers While free private RPCs offer a good level of protection, you can opt for even stronger safeguards with premium private RPC services. These services often provide advanced features and dedicated infrastructure for enhanced security and performance. | Role | Status and Comments | | ------------------------------------------------------------ | ------------------------------------------------------------ | | 5 Builders (Private privacy protecting RPC service providers) | [BloxRoute](https://bloxroute.com/products/protected-transactions/)[Blocksmith](https://docs.blocksmith.org/bsc-builder/private-rpc)[Nodereal](https://docs.nodereal.io/reference/bsc-bundle-service-api#overview)[Blockrazor](https://blockrazor.gitbook.io/blockrazor/mev-service/bsc)[Puissant](https://docs.48.club/) | There are two aspects that may impact the transaction inclusion speed. 1. Validator Network: Providers with a larger network of integrated validators can often offer faster inclusion speeds. More validators mean more opportunities for your transaction to be picked up and added to a block. 2. Builder Usage: Higher usage of a builder's service generally leads to faster inclusion. Increased usage makes the builder's block proposals more valuable to validators, incentivizing them to prioritize those blocks. You can view the latest MEV builder data (MEV_Blocks_by_Builders) from the [Dune dashboard](https://dune.com/bnbchain/bnb-smart-chain-mev-stats), and select the appropriate builders to broadcast transactions. The contacts of each builder are listed above in Table 1. You can check the number of validators integrated and the number of blocks of each builder, as mentioned above. 1. The more validators are integrated, the faster the builder can be. 2. The more blocks that are produced, the faster the builder can be. --- ## FAQs > Source: https://docs.bnbchain.org/bnb-smart-chain/validator/mev/faqs/ # FAQs ### 1. Why is the MEV solution important for the BNB Chain ecosystem? BNB Chain's MEV solution leverages Proposer Builder Separation (PBS) architecture to foster a more transparent and fair block space market. Through PBS, users gain the power to select their preferred builder for transaction submission, while MEV rewards are equitably distributed among searchers, validators, builders, and BNB stakers. This approach promotes transparency, fairness, user choice, and network security. By distributing rewards across various roles, BNB Chain encourages wider participation and reduces the risk of centralization, to build a decentralized and inclusive blockchain ecosystem. ### 2. Do builders fetch the in-turn proposer's GasCeil to build block? Yes, you could using RPC mev_params to query validator's MEV information before building block, it can help to 1) calculate a valid header with gas no more than GasCeil; 2) calculate the left bidding time by BidSimulationLeftOver; 3) calculate suitable builderFee by validatorCommission. ### 3. How does the validator choose the best bid? The block reward is calculated as **gasFee**, the validator reward is calculated as **gasFee*commissionRate - builderFee**. Every time the validator receives a new bid, it will compare its reward with the existing best bid. If it has better block reward and validator reward, the new bid will go into simulation. If simulation succeeds before block sealing, it will be compared with local mined block reward. If the bid's block reward and validator reward are both superior to the local block, it will be sealed by the validator. ### 4. Who can become the builder? BNB Chain is a permission-less ecosystem, anyone who implements the standard builder API could be the BNB Chain builder. ### 5. Where can I find the BNB Chain builders information? You can find the BNB Chain builders through a public [builder info repo](https://github.com/bnb-chain/bsc-mev-info/tree/main/mainnet/builders) ### 6. How many validators have been integrated with the builders? You can find the validators that has implemented the PBS solution from [validator info repo](https://github.com/bnb-chain/bsc-mev-info/tree/main/mainnet/validators) ### 7. Where can I find the BNB Chain MEV statistic dashboard? You can view the MEV statistics from [MEV Stats Dashboard](https://dune.com/bnbchain/bnb-smart-chain-mev-stats) --- ## Overview > Source: https://docs.bnbchain.org/bnb-smart-chain/validator/evn/overview/ ## Background After [Maxwell Hardfork](https://www.bnbchain.org/en/blog/bnb-chain-announces-maxwell-hardfork-bsc-moves-to-0-75-second-block-times), the block interval has be reduced to 0.75s, which is a huge improvement in user experience for BSC, and at the same time has greater performance requirements for the client's network, execution and other components. BSC introduced a new network layer optimization, Enhanced Validator Network, aka EVN. It is not a new P2P network, but based on the current P2P network to optimize the validator network and reduce the latency of core consensus messages as much as possible. You can also check [BEP-563](https://github.com/bnb-chain/BEPs/blob/master/BEPs/BEP-563.md) and [BEP-564](https://github.com/bnb-chain/BEPs/blob/master/BEPs/BEP-564.md) for more details. ## How EVN Works ### NodeID Registration Node operator could add the validator’s EVN NodeIDs through the configuration file(config.toml), then the node will automatically sign a registration tx to register the node id on chain. It establishes the identity mapping from the consensus layer to the network layer. ### EVN Peer Identification All validators/sentry will pull the on-chain registration information, identify whether the connected P2P Peer belongs to the NodeID of a validator, and mark it as an EVN Peer. ### Broadcast Optimization Transaction broadcast is disabled between all EVN Peers, and mined blocks are broadcast to all connected EVN Peers. Non-mined blocks still use the old gossip broadcast mechanism. ### EVN Whitelist This is an EVN whitelist that takes effect on this node. It will consider the whitelisted Peers to be EVN Peers as well and apply the EVN broadcast algorithm. ### EVN Peer Connection Currently, EVN Peers are mainly connected directly through static nodes, allowing most EVN Peers to connect directly to each other. --- ## Best Practice > Source: https://docs.bnbchain.org/bnb-smart-chain/validator/evn/best-practice/ ## Network Requirements At the network layer, BSC requires minimal latency to maximize time available for critical operations like block packaging and verification. The BSC network maintains decentralization through validators distributed across diverse geographic locations worldwide. Taking AWS's network service as an example, the measured latency of some regions are: - AP<->EU, latency ~100ms - AP<->US, latency ~80ms - US<->EU, latency ~35ms This data will be the theoretical best value of network message latency, and it is also the reference value for network environment testing between validators. ## Configuration There are two different modes to configure your node, depends on how your validator is connected to the network. ### Mode-1: Sentry Mode In this mode, the operator could create multiple nodes, including multiple validator nodes, multiple sentry nodes, and fullnode nodes. The validator always remains in a secure intranet environment. Sentry is responsible for quickly exchanging messages with EVN Peer and forwarding them to the validator. Fullnode is a redundant path for additional transactions and other messages. Mainly introduces the configuration changes of validator and sentry, and the fullnode configuration remains unchanged. #### Validator Configuration The example of `Config.toml`. ```toml [Eth] EVNNodeIDsToAdd = ["sentryNodeID1", "sentryNodeID2"] [Node] EnableEVNFeatures = true EnableQuickBlockFetching = true [Node.P2P] StaticNodes = [ "", "", "", "..." ] ``` `EVNNodeIDsToAdd` fills in the sentry nodeID here. Because the validator is protected in the external network, sentry will act as an EVN Peer to help forward public EVN Peer messages. `EnableEVNFeatures` enables the EVN network. `EnableQuickBlockFetching` enables BEP-564, which will speed up block retrieval. #### Sentry Configuration The example of `Config.toml`. ```toml [Node] EnableEVNFeatures = true EnableQuickBlockFetching = true [Node.P2P] EVNNodeIdsWhitelist = [""] ProxyedValidatorAddresses = [""] StaticNodes = [ "enode://3dd9e7e22180cda7c2a7015d3582811327abb3bc5f330879be7bc3217be4ed7c4ec0d5117ab0fae6542d3e5d199f3d935b7bca108b565f07806ed7687af8d1b5@52.198.165.142:30311", "enode://70aeb4f0cc52df44f4ef0c72ca0eca8a210b9916ad02bcd147cc58bbfee9259ee46dfa23e13512f98bdb3937d62d2d0a521a90c76161ccffd24bb10829d8d542@13.112.162.162:30311", "enode://4af65e07b676e3634e4e2e6df01b23e32eb73fdc200b7f98a4807b16e8faefae4d3875bea4d88e203e319f6a61859b66c0b8254191a2058629a00fe6e42e7b18@54.155.24.228:30311", "enode://2a6cfdbfc8f401d09a766efa53411bb5457fd5903331afee5363017f65623f0c0c43873c14bfb4001cf02811b1196f710bb3911a36e683cb557b11244cffe212@54.77.55.214:30311", "enode://cc6d828a735db591cb2a0454a94b9602be6c0aca6c73f771efaabc7f68c46085b953c97f880efb17597578320444acc9e207042297689515c18e659d138bb393@23.23.111.240:30311", "enode://5035ae74e04b4290885c3cea546ca179cb80c1461141b8c3124bb6707993c1e68dafd2f5fd9b13a8d076225412bf5bbefe81c16aa812a35e7c19bb1020b8c124@34.205.243.82:30311", "" ] ``` `EVNNodeIdsWhitelist`: it is optional and is an EVN Peer whitelist that is only valid for the current node. In the transition period before enabling maxwell, the whitelist can be used to apply EVN in advance. At the same time, the operator can put the cooperating builder into the local whitelist. `ProxyedValidatorAddresses`: it is optional and is only for sentry to identify which blocks should be broadcast to all EVN Peers, it is configured as the protected validator address. `StaticNodes`: it includes a list of well maintained EVN nodes for validators to connect to, the list could be changed in the future. ### Mode-2: Simple Mode With simple mode, the operator could run a validator node by exposing it directly to the public network environment, so that they can directly connect to other nodes. #### Validator Configuration The example of `Config.toml`. ```toml [Eth] EVNNodeIDsToAdd = ["validator NodeID", "other nodeids"] [Node] EnableEVNFeatures = true EnableQuickBlockFetching = true [Node.P2P] EVNNodeIdsWhitelist = [""] StaticNodes = [ "enode://3dd9e7e22180cda7c2a7015d3582811327abb3bc5f330879be7bc3217be4ed7c4ec0d5117ab0fae6542d3e5d199f3d935b7bca108b565f07806ed7687af8d1b5@52.198.165.142:30311", "enode://70aeb4f0cc52df44f4ef0c72ca0eca8a210b9916ad02bcd147cc58bbfee9259ee46dfa23e13512f98bdb3937d62d2d0a521a90c76161ccffd24bb10829d8d542@13.112.162.162:30311", "enode://4af65e07b676e3634e4e2e6df01b23e32eb73fdc200b7f98a4807b16e8faefae4d3875bea4d88e203e319f6a61859b66c0b8254191a2058629a00fe6e42e7b18@54.155.24.228:30311", "enode://2a6cfdbfc8f401d09a766efa53411bb5457fd5903331afee5363017f65623f0c0c43873c14bfb4001cf02811b1196f710bb3911a36e683cb557b11244cffe212@54.77.55.214:30311", "enode://cc6d828a735db591cb2a0454a94b9602be6c0aca6c73f771efaabc7f68c46085b953c97f880efb17597578320444acc9e207042297689515c18e659d138bb393@23.23.111.240:30311", "enode://5035ae74e04b4290885c3cea546ca179cb80c1461141b8c3124bb6707993c1e68dafd2f5fd9b13a8d076225412bf5bbefe81c16aa812a35e7c19bb1020b8c124@34.205.243.82:30311", "" ] ``` --- ## Network Monitor > Source: https://docs.bnbchain.org/bnb-smart-chain/validator/evn/network-monitor/ # Network Monitoring In EVN, special metrics are provided to observe the message delay indicators of the EVN network and help analyze the causes of delay. ## Peer Latency Peer Latency, it observes the message latency with remote peers, calculated by `RoundTripTime/2`. ```bash # Grafana query statement p2p_peers_latency{quantile="$quantile", job=~"$jobs"} ``` Suggesting to monitor message delay under quantile=0.95. If the latency is too high under quantile=0.95, you need to optimize the network provider or connect to better static nodes to improve it. ### The latency of each peer You can also query Peer Latency with this command: ```bash ./bsc attach --exec "admin.peers" ./geth.ipc | grep -E "enode|latency" ``` The command will output the transient latency value, you can observe the latency of each node and analyze the slow nodes. ## Core Message Latency These metrics represent the delay of the consensus core process, suggesting to monitor message delay under quantile=0.95. ```bash # Grafana query statement # Delay relative to Header.MilliTimestamp when sending blocks chain_delay_block_send{quantile="$quantile", job=~"$jobs"} # Delay relative to Header.MilliTimestamp when starting to import blocks chain_delay_block_insert{quantile="$quantile", job=~"$jobs"} # Delay relative to Header.MilliTimestamp when receiving majority votes chain_delay_vote_majority{quantile="$quantile", job=~"$jobs"} # Time relative to Header.MilliTimestamp when starting mining chain_delay_block_mining{quantile="$quantile", job=~"$jobs"} ``` `chain_delay_block_insert` and `chain_delay_vote_majority` can help you troubleshoot the latency of receiving blocks or voting, and optimize in combination with Peer Latency. `chain_delay_block_send` and `chain_delay_block_mining` are related to validator mining and determine whether blocks are generated normally. ## Recent Blocks Query the core process timestamp of the recent blocks. These are millisecond timestamps. ```bash # Grafana query statement report_blocks{job=~"$jobs"} ``` This list can be used to troubleshoot problems and conduct detailed analysis of the performance of a certain validator. --- ## FAQs > Source: https://docs.bnbchain.org/bnb-smart-chain/validator/evn/faqs/ # FAQs ### Q1: How to get node’s NodeID? you can use the following command to query your enode information. ```bash ./bsc --exec "admin.nodeInfo.id" attach ./geth.ipc ``` ### Q2: Can multiple validators share sentry nodes? Yes, for service providers who act as agents for multiple validators, they can use fewer sentries to achieve the same function. It is worth noting that the combination of validators and sentry is best to be in the same region machine. ### Q3: Can a validator use multiple sentry nodes? Of course, multiple sentries improve redundancy and reduce message delays caused by single sentry failures. It is also recommended that validators connect to multiple fullnodes and other P2P nodes to receive more transactions and improve message redundancy. ### Q4: How to register other key ecosystem player into EVN network As only validator can register evn nodeid, so they can ask validator's help to register for them. It could be useful for some key users like mev-builders, infra providers... But there is a limitation on the number of evn nodeids that each validator can register, by default it is 5, but it can be changed by governance. --- ## Overview > Source: https://docs.bnbchain.org/bnb-smart-chain/slashing/overview/ # BSC Slashing Overview Slashing is a component of on-chain governance that penalizes malicious or negative actions. Anyone can submit a slash transaction on BSC, which involves providing evidence and paying fees. Successful submissions yield significant rewards. Currently, there are three types of slashable cases. ## Double Sign It is quite a serious error and very likely a deliberate offense when a validator signs more than one block with the same height and parent block. The reference protocol implementation should already have logic to prevent this, so only the malicious code can trigger this. When Double Sign happens, the validator should be removed from the Validator Set right away. Anyone can submit a slash transaction with the evidence of Double Sign to the BSC Slash Contract, which should contain the 2 block headers with the same height and parent block, sealed by the offending validator. Upon receiving the evidence, the contract will verify its validity. The validator will be removed from validator set, a predefined amount of BNB would be slashed from the self-delegated BNB of the validator. Both validator and its delegators will not receive the staking rewards. Part of the slashed BNB will be allocated to the submitter’s address, which is a reward and larger than the cost of submitting slash request transaction. The rest of the slashed BNB will be allocated to the other validators’ credit addresses, and distributed to all delegators in the same way as blocking reward. ## Malicious Fast Finality Vote It is quite a serious error and very likely a deliberate offense when a validator signs two fast finality votes with the same target height or the span of one vote including the span of another vote. The reference protocol implementation should already have logic to prevent this, so only the malicious code can trigger this. When Malicious Vote happens, the validator should be removed from the Validator Set right away. Anyone can submit slash transaction with the evidence of Malicious Vote to the BSC Slash Contract. Evidence of malicious voting needs to be provided, which includes two conflicting votes and the voting key used for the signature. Upon receiving the evidence, the contract will verify its validity. The validator will be removed from the current set of validators, and the submitter will receive the reward from the system contract. A predefined amount of BNB would be slashed from the self-delegated BNB of the validator. Both validator and its delegators will not receive the staking rewards. The slashed BNB will be allocated to the other validators’ credit addresses, and distributed to all delegators in the same way as blocking reward. ## Unavailability The liveness of BSC relies on everyone in the Proof of Staked Authority validator set can produce blocks timely when it is their turn. Validators can miss their turn due to any reason, especially problems in their hardware, software, configuration or network. This instability of the operation will hurt the performance and introduce more indeterministic into the system. There is an internal smart contract that records the missed blocking metrics of each validator. If the metrics exceed the set threshold, the blocking reward for the validator will not be given to them but shared with other validators performing better. This process aims to gradually remove poorly-operating validators from the set, reducing rewards for their delegators. If the metrics stay above a higher threshold, the validator will be removed from rotation, and a set amount of BNB will be deducted from their self-delegated BNB. This action results in both validators and delegators not receiving their staking rewards. --- ## Slash Rules > Source: https://docs.bnbchain.org/bnb-smart-chain/slashing/slash-rules/ # BSC Slash Rules Three types of malicious behaviors can lead to slashing on the BSC network. ## Double Sign Anyone can submit a slash request with evidence of Double Sign. The evidence must adhere to the following rules: * Two block headers have the same height and the same parent block hash * Two block headers are sealed by the same validator * Two signatures of these two blocks must not be the same * The time of these two blocks must be within the validity of the evidence, which is 24 hours If the evidence is valid: 1. **200BNB** would be slashed from the **self-delegated** BNB of the validator 2. The remaining slashed BNB will be allocated to the credit addresses of validators participating in the next distribution 3. Set the validator `jailed` with a duration of **30 days**, and remove it from the active validator set ## Malicious Vote Anyone can submit a slash request on BSC with the evidence of Malicious Vote. The evidence must adhere to the following rules: * The target number voted by two votes lags behind the block header of the canonical chain by no more than 256 * The source numbers of the two votes are both smaller than their respective target numbers * The source hash and target hash of the two votes are both not equal * The target number of the two votes is the same or the span of one vote includes the span of the other vote * The two votes are signed by the same voting key, and the verification of signatures are both passed * The voting key used for signing is in the list sent by the last two breathe blocks If the evidence is valid: 1. **200BNB** would be slashed from the **self-delegated** BNB of the validator 2. **5BNB** would allocate to the submitter from the system reward contract as a reward if the validator is active when the evidence submitted 3. The remaining slashed BNB will be allocated to the credit addresses of validators participating in the next distribution 4. Set the validator `jailed` with a duration of **30 days**, and remove it from the active validator set ## Unavailability There is an internal smart contract that records the missed blocking metrics of each validator. If a validator misses over 333 blocks(governable) in 24 hours, they will not receive the block reward; instead, it will be shared among other validators. If a validator misses more than 1000 blocks(governable) in 24 hours: 1. **10BNB**(governable) would be slashed from the **self-delegated** BNB of the validator 2. The slashed BNB will be allocated to the credit addresses of validators participating in the next distribution 3. Set the validator `jailed` with a duration of **2 days**, and remove it from the active validator set --- ## Slash Monitor > Source: https://docs.bnbchain.org/bnb-smart-chain/slashing/monitor/ # BSC Slash Monitor ## Monitor Slash Generally, without maliciously altering BSC node code or mistakenly running the validator, validators would not typically incur double sign slashes or malicious vote slashes. Validators should consistently monitor for potential slashes due to node unavailability, as it can lead to slash events. As best practice, it is advisable to keep monitoring the event log of the slash contract on the BSC scanner at . You can check your validator's slash indicator in the above contract. Pay attention to values above 50. If it goes over 200, the validator will be slashed. If it goes over 600, the validator will be jailed. Pls refer https://docs.bnbchain.org/bnb-smart-chain/slashing/slash-rules/ for more details. ## Unjail Validator Once a Validator is slashed into a jailed state, the Validator must wait for a specific period before being able to unjail. Once the waiting period elapses, the Validator can access the BNB Staking dApp and proceed to click on the `unjail` button to initiate the unjail transaction. **BNB Staking dApp:** - **Testnet**: [https://testnet-staking.bnbchain.org/en/bnb-staking](https://testnet-staking.bnbchain.org/en/bnb-staking) - **Mainnet**: [https://www.bnbchain.org/en/bnb-staking](https://www.bnbchain.org/en/bnb-staking) --- ## Cross Chain Bridge > Source: https://docs.bnbchain.org/bnb-smart-chain/cross-chain-bridge/ # BNB Chain Cross-Chain Bridge Guide > **Status:** Draft · Last updated: 4 Jun 2025 --- ## 1 Who Is This Guide For? * 🧑‍💻 **Users** who want to transfer tokens in and out of BNB Chain from other chains like **Ethereum** or **Solana**. * 🛠️ **Developers** who want to integrate a cross-chain bridge widget on their website using BNB Chain's **Canonical Bridge**. ## 2 Why This Guide Matters Many users don’t realize that cross-chain transfers are possible or easy. BNB Chain offers a bridge aggregator that shows the **best route** for moving assets between chains using one of our **six route providers**: **Supported Route Providers**: * Stargate * Celer * deBridge * Meson * LayerZero * Mayan > ✅ We help users **see available routes** for transferring assets **into or out of BNB Chain**, but we **do not operate the routes or control token availability**. ## 3 How to Use the BNB Chain Bridge (User Guide) ### Step-by-Step 1. Visit [bnbchain.org/en/bnb-chain-bridge](https://www.bnbchain.org/en/bnb-chain-bridge). 2. Choose your **source chain** (e.g. Ethereum) and **destination chain** (e.g. BNB Chain). 3. Connect your wallet to source chain. 4. Choose a token to bridge and enter the amount. 5. The bridge tool will display **available routes** based on your token and chains. 6. Click **Send** (or **Approve** if required). 7. Wait for the transaction to complete. You’ll receive your tokens on the destination chain. ## 4 Understanding Bridge Aggregation BNB Chain’s bridge tool is an **aggregator**. It finds available routes from partner bridge providers but: * ❌ We do not custody tokens. * ❌ We cannot add tokens ourselves. * ✅ We simplify access and offer visibility into supported routes. You can use the bridge for **all directions** – not just from BNB Chain to others, but also from Ethereum, Solana, and other supported chains **to BNB Chain**. ## 5 Developer Guide: Integrate the Canonical Bridge Widget To integrate the same aggregator bridge experience in your own dApp or website: ### 📦 Canonical Bridge Repository GitHub: [github.com/bnb-chain/canonical-bridge](https://github.com/bnb-chain/canonical-bridge) ### Features * Embed cross-chain bridging into any website. * Supports the same 6 route providers. * React component + config options. * Supports custom networks, tokens, style. * Supports other chain to other chain transfer (e.g. Ethereum to Base) ### Use Cases * DeFi dApps * Wallet UIs * NFT platforms offering cross-chain support ## 6 FAQs | Question | Answer | | --------------------------------------- | --------------------------------------------------------------------------------------- | | I don’t see my token listed? | Route providers decide which tokens they support. You can contact them directly. | | Is this a bridge just for BNB Chain? | No — it supports **all chains** connected via our 6 providers. | | Can I use this from Solana to Ethereum? | Yes, as long as a route provider supports it. (Only available in Canonical Bridge Widget) | | Can I embed this bridge in my dApp? | Yes — use the [Canonical Bridge widget](https://github.com/bnb-chain/canonical-bridge). | ## 7 Final Notes * Users should always verify token addresses and routes. * For token support, contact the respective bridge provider. * BNB Chain simplifies access to existing infrastructure — we aggregate, not operate. ## 8 Changelog * **2025-05-28** – Initial draft of user + developer combined guide. --- ## Benchmark > Source: https://docs.bnbchain.org/bnb-smart-chain/benchmark/design-reference/ # Benchmark - Design The purpose of this document is to share the design adopted by BSC for characterizing its performance using close-to-real test scenarios. **Nodes Design** * A: Client(s) → Validator(s) * B: Client(s) → FullNode(s) → Validator(s) Both are acceptable; but ***B is recommended***. **Scenarios Design** The ***default*** design mimics typical transactions in a DeFi application, and the weight parameters enhance the flexibility of adding/removing scenarios with minimal implementation effort. | Scenarios | Weight | | ---| --- | | Native token (BNB) transfer | 10 | | Contract token (BEP20) transfer | 10 | | Wrapped Native token (WBNB) deposit | 5 | | Wrapped Native token (WBNB) withdraw | 5 | | UniswapV2 - AddLiquidity | 5 | | UniswapV2 - RemoveLiquidity | 5 | | UniswapV2 - SwapExactTokensForTokens | 30 | | UniswapV2 - SwapBNBForExactTokens | 30 | | \[***Optional***\] ERC721 mint/transfer | 5 | | \[***Optional***\] ERC1155 mint/Transfer | 5 | | \[***Optional***\] Blob transaction | 1 | | \[***Optional***\] EIP7702 transaction | 1 | | \[***Optional***\] user-defined contract for the evaluation of _CPU intensive operations_ | 100 | **Data Design** * 16 BEP20 tokens are created. * 24 trading pairs are created: * 8 of them are among BEP20 tokens, e.g. T0←→T8, T1←→T9, etc; * 16 of them are among native token and ERC20 tokens, e.g. BNB←→T0, BNB←→T1, etc; * Each active user is allocated native tokens, wrapped native tokens, and two BEP20 tokens forming a trading pair. All tokens are distributed equally across active users based on modulo operation results. * After token allocation, each active user can run any scenario listed above using their allocated tokens. * A group of distinct test users is pre-selected from active users to serve as load generators. * ***For transfer scenarios, we use either distinct "to" addresses to maximize the transaction parallelism or a limited set of "to" addresses to minimize it***. **Data Volume** * A: Generate 1M active users and set up the test scenarios with 100k+ blocks * B: Generate 25M active users and set up the test scenarios with 1.0M-2.5M blocks Both are acceptable, but ***B is recommended as it includes more blocks, accounts and states changes, which provides insights into how storage growth impacts performance over time***. **Evaluation Criteria** * No node failures should occur during execution. * The number of transactions per block should be consistent with the transaction propagation rate to validators' mempools and the sending rate from the test client. And there should be no backlog in validators' mempools after the test client stops. * The empty block rate must be below 0.1%. * The failed transaction rate, including send-errors and zero-receipt-status transactions, must be less than 0.1%; * A block finality metric must be defined. For example, in BSC, the p90 block finality time must be less than 2 seconds; **Contract Code Reference** * BEP20: [https://bscscan.com/token/0x55d398326f99059ff775485246999027b3197955#code](https://bscscan.com/token/0x55d398326f99059ff775485246999027b3197955#code) * WBNB: [https://bscscan.com/address/0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c#code](https://bscscan.com/address/0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c#code) * UniswapV2: [https://github.com/Uniswap/v2-core](https://github.com/Uniswap/v2-core) --- ## FAQ > Source: https://docs.bnbchain.org/bnb-smart-chain/faq/ # Frequently Asked Questions (FAQ) Welcome to the FAQ section for BNB Smart Chain. Below are some common questions and helpful articles to guide you: - [Recovering Tokens Sent to Wrong Chain or Address](./recovering-tokens-sent-to-wrong-chain-or-address.md) - [Tokens Not Showing in Wallet](./tokens-not-showing-in-wallet.md) - [Transfer NEXO from Tangem into BSC](./transfer-nexo-from-tangem-into-bsc.md) - [Lorentz Hard Fork Upgrade](./plorentz-hard-fork-upgrade.md) If your issue is not listed here, please explore our other documentation or open an issue. --- ## opBNB > Source: https://docs.bnbchain.org/bnb-opbnb/ Deposit BNB to opBNB to start your journey Run a fullnode on opBNB network Deploy a simple HelloWorld smart contract on opBNB and build a Web3 frontend Use multi-sig wallet service based on the Gnosis Safe protocol to secure assets and projects --- ## Overview > Source: https://docs.bnbchain.org/bnb-opbnb/overview/ # opBNB - High-performance layer 2 solution The opBNB network is the Layer 2 scaling solution for the BNB Smart Chain powered by [bedrock version](https://community.optimism.io/docs/developers/bedrock/) of Optimism OP Stack. It works by offloading transaction processing and resource usage from the BNB Smart Chain, while still posting data to the underlying mainnet. Users interact with the opBNB network by depositing funds from BSC and using applications and contracts on opBNB. Sequencers then aggregate transactions, compute state transitions and submit them to the rollup contract on BSC. Provers generate cryptographic proofs that prove the validity of these state transitions, and Verifiers check the proofs to verify the opBNB state is correct. At its core, opBNB allows users to deposit and withdraw funds, use smart contracts, and view network data with high throughput and low fees. By leveraging Layer 2, opBNB is able to scale beyond the constraints of the BNB Smart Chain and provide an improved experience for users. ### Key Features and Advantages 1. **Optimistic Rollup Technology:** opBNB employs Optimistic Rollup, a Layer-2 scaling solution that processes transactions off-chain while maintaining the security of the main BSC chain. By bundling multiple transactions into a single batch and then submitting them to the main chain, Optimistic Rollup reduces the computational load on BSC, resulting in faster and cheaper transactions. 2. **Increased Transaction Throughput:** The adoption of Optimistic Rollup allows opBNB to achieve significantly higher transaction throughput compared to the BSC main chain. As of early 2024, opBNB supports up to 5,000 transactions per second (TPS), addressing one of the critical bottlenecks in blockchain scalability. 3. **Lower Transaction Fees:** One of the primary benefits of opBNB is the reduction in transaction fees. By processing transactions off-chain and only settling the final state on the BSC main chain, opBNB dramatically lowers the costs associated with executing transactions. This makes it an attractive option for developers and users alike, particularly for micro-transactions and DeFi applications. 4. **Enhanced User Experience:** With faster transaction confirmations and lower fees, opBNB significantly enhances the overall user experience. This improvement is crucial for the mass adoption of blockchain technology, as it makes interactions with DApps and DeFi platforms more seamless and affordable. 5. **Robust Security:** Despite processing transactions off-chain, opBNB maintains a high level of security by relying on the security model of the underlying BSC main chain. Optimistic Rollup's fraud-proof mechanism ensures that any invalid transactions can be challenged and corrected, safeguarding the integrity of the network. --- ## Network Information > Source: https://docs.bnbchain.org/bnb-opbnb/get-started/network-info/ ## Network Information | Name | Value | | --------------- |----------------------------------------------------------------------------------| | Network Name | opBNB | | Description | The Layer 2 network of BNB Smart Chain. | | RPC Endpoint | [See here](#rpc-endpoints) | | Chain ID | 5611(Testnet), 204(Mainnet) | | Currency Symbol | tBNB(Testnet) BNB(Mainnet) | | Block Explorer | https://testnet.opbnbscan.com, https://opbnbscan.com, https://opbnb.bscscan.com/ | | Bridge | https://opbnb-testnet-bridge.bnbchain.org, https://opbnb-bridge.bnbchain.org | ## RPC Endpoints You can use either public and private RPC endpoints to access opBNB. ### Public Testnet RPC Endpoints(WSS is supported) - https://opbnb-testnet-rpc.bnbchain.org/ - https://opbnb-testnet.publicnode.com ### Public Mainnet RPC Endpoints(WSS is supported) - https://opbnb-mainnet-rpc.bnbchain.org - https://opbnb.publicnode.com ### Private opBNB RPC Endpoints NodeReal supports the opBNB network, you can create your free opBNB RPC endpoints with your github or discord. - https://nodereal.io/api-marketplace/opbnb-rpc *To use the above private RPC endpoint, make sure to login to [MegaNode service](https://nodereal.io/meganode) and create your private endpoints.* --- ## Wallet Configuration > Source: https://docs.bnbchain.org/bnb-opbnb/get-started/wallet-configuration/ # Wallet configuration You can use any Ethereum or BSC wallet with opBNB. For instance, I will show you how to set up Metamask and Trustwallet for opBNB. To configure your wallet to work with opBNB, you will need to add both the BNB smart chain(Layer 1) and the opBNB network(Layer 2). Follow these steps: 1. Add the BNB smart chain to your wallet. This is the Layer 1 blockchain that opBNB is built on top of. *Testnet* - Network Name: BSC Testnet - RPC URL: [https://data-seed-prebsc-1-s1.bnbchain.org:8545](https://data-seed-prebsc-1-s3.bnbchain.org:8545/) - ChainID: 97 - Symbol: tBNB - Explorer: [https://testnet.bscscan.com/](https://testnet.bscscan.com/) *Mainnet* - Network Name: BSC Mainnet - RPC URL: [https://bsc-dataseed.bnbchain.org](https://bsc-dataseed.bnbchain.org) - ChainID: 56 - Symbol: BNB - Explorer: [https://bscscan.com/](https://bscscan.com/) 2. Add the opBNB network to your wallet. *Testnet* - Network Name: opBNB Testnet - RPC URL: [https://opbnb-testnet-rpc.bnbchain.org](https://opbnb-testnet-rpc.bnbchain.org) - ChainID: 5611 - Symbol: tBNB - Explorer: [http://testnet.opbnbscan.com/](http://testnet.opbnbscan.com/) *Mainnet* - Network Name: opBNB Mainnet - RPC URL: [https://opbnb-mainnet-rpc.bnbchain.org ](https://opbnb-mainnet-rpc.bnbchain.org) - ChainID: 204 - Symbol: BNB - Explorer: [http://opbnbscan.com/](http://opbnbscan.com/) ## References - How to configure Trustwallet or Metamask [Trustwallet](https://chrome.google.com/webstore/detail/trust-wallet/egjidjbpglichdcondbcbdnbeeppgdph) After you install the Trustwallet in your browser, you can go to settings->network. Select add custom network and enter the network information I mentioned above. _[Metamask](https://chrome.google.com/webstore/detail/metamask/nkbihfbeogaeaoehlefnkodbefgpgknn)_ After you install the metamask in your browser, you can go to settings -> networks -> add network page. Select add manual network and enter the network information. *Depending on your location and preference, you can choose from a variety of RPC endpoints for BSC and opBNB. For more information about the endpoints and their features, please refer to the network information document that we have prepared for you. To ensure the best performance and user experience, you can test the latency of each endpoint before you configure it with your wallet.* --- ## Deposit to opBNB > Source: https://docs.bnbchain.org/bnb-opbnb/get-started/deposit-to-opbnb/ # Deposit BNB(tBNB) to opBNB Before building or deploying any applications on the opBNB network, you must first deposit BNB(tBNB) as your gas token from BNB Smart Chain to opBNB. You can do this using the [opBNB bridge dApp(Testnet)](https://opbnb-testnet-bridge.bnbchain.org/) or [opBNB bridge dApp(Mainnet)](https://opbnb-bridge.bnbchain.org). Follow these steps to deposit tokens from BNB Smart Chain to opBNB: 1. Make sure you have BNB(tBNB) tokens in your wallet on the BNB Smart Chain. 2. In your wallet, switch your network to BNB Smart Chain. This is the Layer 1 network where your tokens currently are. 3. Enter the amount of BNB(tBNB) you want to deposit to the opBNB network. 4. Click "Deposit" to begin the transfer. 5. Your wallet will prompt you to confirm the transaction. Click "Confirm" to sign it and pay the required gas fee. 6. Once the transaction is processed, switch your network in your wallet to opBNB. The BNB amount you have deposited will appear in your wallet. 7. You can now build, deploy, and interact with dApps on the opBNB network using the BNB(tBNB) you deposited. To withdraw tokens from opBNB back to BNB Smart Chain, simply go to the bridge, enter the amount to withdraw, and confirm the transaction. The bridge will transfer your tokens from the opBNB network back to the BNB Smart Chain testnet. ## opBNB Bridge Supported Tokens The opBNB bridge supports you to transfer your assets from BSC to opBNB. The bridge supports most of the popular tokens, including BEP-20 tokens and wrapped bitcoin. If you want to test your applications that require these tokens, you can use the opBNB bridge to deposit and withdraw them in a simple and convenient way. *The bridge page also provides a faucet link that allows you to claim these tokens from the faucet directly. To begin, simply click on the faucet link on the bridge page.* --- ## Withdraw from opBNB > Source: https://docs.bnbchain.org/bnb-opbnb/get-started/withdraw-from-opbnb/ To transfer your tokens from opBNB to BSC, you can use the [opBNB bridge dApp(Testnet)](https://opbnb-testnet-bridge.bnbchain.org/) or [opBNB bridge dApp(Mainnet)](https://opbnb-bridge.bnbchain.org). Users who do not want to wait 7 days to claim their tokens can use a community bridge, but please note that community bridges may not be as secure as the official opBNB bridge. *Note that the default option is the community bridge. To use the opBNB bridge, switch to the "official bridge" tab.* ## Steps of withdrawal through official bridge For users who choose the official opBNB bridge, you will need to wait for a challenge period of 7 days before you can claim your tokens on BSC. This challenge period is a security measure to prevent fraud and theft. The challenge period is necessary to ensure the security of the opBNB network and users. However, it can be inconvenient for users who need their tokens quickly. If you need your tokens immediately, you may want to consider using a community bridge instead. However, please be aware that community bridges may not be as secure as the official opBNB bridge. Do your research first. There are 2 steps after you submit your withdrawal request. 1. *Submit Proof:* When you withdraw your tokens, they will be transferred from the opBNB network to the BSC network. After you submit the withdrawal request, your withdrawal status will change to *Waiting for Proof*, which indicates that the transaction is pending for the proof submission. You need to submit the proof manually. 2. *Claim Token:* After you submit your proof, you need to wait until the transaction is ready to be collected after the challenge window, which is 7 days. The challenge window is a period of time during which anyone can challenge the validity of the transaction. If no one challenges the transaction, it will be finalized and you can collect your tokens on the BSC network. ## Third-party Bridges There are also third-party bridges with shorter withdrawal time. - [zkbridge](https://www.zkbridge.com/gallery/opbnb) --- ## Why BSC Requires opBNB > Source: https://docs.bnbchain.org/bnb-opbnb/core-concepts/why-bsc-requires-opbnb/ # Why BSC Requires opBNB Layer 1 networks are the base networks that provide the infrastructure for data transmission and validation, such as BSC and Ethereum. These networks face the challenge of network congestion during peak periods, which usually happens when any popular application runs a promotion campaign or experiences a spike in traffic. Network congestion can lead to high transaction fees, slow transactions, and poor user experience. To overcome these challenges, layer 1 networks need to improve their scalability, which is the ability to handle more transactions per second without compromising security. For example, BSC had a web3 game on BNB Smart Chain (BSC) in 2021 which generated over [8 million transactions per day](https://bscscan.com/address/0x39bea96e13453ed52a734b6aceed4c41f57b2271?ref=binance.ghost.io#analytics). 1. BSC's throughput capacity would presumably be vastly exceeded, resulting in slowed transaction speeds, delayed transaction finality, and a poor user experience both for game players and users of other dApps. 2. Daily gas fees could potentially rise to over [6,800 BNB](https://bscscan.com/address/0x39bea96e13453ed52a734b6aceed4c41f57b2271?ref=binance.ghost.io#analytics) ($3M USD) at that level of usage, posing a substantial barrier to usability and sustainability of this game. The immense transaction loads from a dApp on such a large scale seem infeasible for BSC to handle efficiently in its current form. Significant optimizations and scaling solutions would likely be required for BSC to support such a dApp without network-wide performance degradation and unreasonably high costs. --- ## Why OP Stack > Source: https://docs.bnbchain.org/bnb-opbnb/core-concepts/why-opstack/ # Why OP Stack as the Foundation of opBNB Our team had extensive discussions and research before we embarked on the mission of creating a high performance optimistic rollup for BNB Smart Chain. ### Our goals: - Achieve a remarkable capacity of 100M gas per second. We conducted thorough research and optimization work for the BSC client, covering various aspects such as storage, execution and security. We applied these enhancements to the opBNB project as well, aiming to set a new standard for the layer 2 solution performance at 100M per second. - Provide a truly low cost layer 2 solution. Ethereum upgrades such as Proto-Danksharding and eventually full Danksharding will significantly lower the cost of posting data to Ethereum. However, until ethereum upgrades become a reality, we needed to find a flexible solution to reduce the calldata cost as posting data to Layer-1 is the main bottleneck for fees on rollups. - Contribute to the open source community. All research and optimization we introduced to the opBNB can be traced back to the Ethereum community to boost the ecosystem. The OP Stack is a framework for building scalable and interoperable layer-2 solutions based on the utility, simplicity and extensibility principles. By choosing OP Stack as the bedrock of opBNB, we can achieve several benefits, such as: - **Flexible execution client options for decentralisation and performance optimization:** opBNB can execute smart contracts using different client options, thanks to its modular replaceable execution design. This design allows opBNB to interact with the blockchain network in various ways, and increases the platform's decentralisation. opBNB can not only build the execution layer on top of the BSC execution client, but also does not depend on a single client implementation, which strengthens the decentralisation of the opBNB network. - **Replaceable DA for lower gas fee:** One of the key issues for layer-2 solutions is to guarantee that the data of the transactions can be accessed and verified by anyone. OP Stack addresses this issue by separating the DA layer from the execution layer, and enabling us to select from various DA options. With OP Stack, we can seamlessly switch between different DA schemes based on our security and performance needs. As a member of the BNB ecosystem, we can leverage BNB greenfield as a DA layer, which will bring down the cost even further. - **Open ecosystem:** OP Stack also fosters an open and collaborative ecosystem where different projects can work together and benefit from each other. By using OP Stack, we can join a network of chains that share the same tech stack and interoperate with each other. For example, we can connect with Optimism, which is another layer-2 platform based on OP Stack that supports EVM and Solidity. By being part of this ecosystem, we can increase our network effects, security and innovation. --- ## Optimizations on OP Stack > Source: https://docs.bnbchain.org/bnb-opbnb/core-concepts/optimisations-on-opstack/ This document discusses the various optimizations made to OP Stack that enhances its performance and helps in offering super cheap gas fees. ## opBNB offers enhanced performance and cheap gas fees opBNB enhances the performance of the "Execution Layer" and the "Derivation Layer" of the OP Stack as highlighted in [OP Stack landscape](https://stack.optimism.io/docs/understand/landscape/?ref=binance.ghost.io#existing-landscape). ## Optimization of Execution Layer One of the main challenges in developing the opBNB protocol was to ensure a high throughput of transactions. To achieve this, opBNB leveraged execution optimization techniques that had [previously been implemented for BSC](https://nodereal.io/blog/en/bnb-smart-chain-performance-anatomy-series-chapter-ii-99-cache-hit-rate/?ref=binance.ghost.io). ## EVM State Data Access Optimization Before we dive into the details of the optimisations, let's see how EVM handles the state data. The diagram below illustrates how the EVM accesses state data. The EVM first checks the cache in memory for the data. If the data is not there, the EVM uses the LevelDB, which involves disk IO. By improving cache efficiency and accelerating database reads and writes, opBNB realizes substantial performance and scalability gains that benefit both node operators and end users. (Compared with standard Ethereum world state data storage model, BNB introduced the “SharedPool” as L1.5 cache to improve the hit rate of cache) ## Increased accuracy of [Bloom Filter](https://en.wikipedia.org/wiki/Bloom_filter?ref=binance.ghost.io) in L2: Diff Layer Avoiding unnecessary recursive accesses to cache by increasing the accuracy of [Bloom Filter](https://en.wikipedia.org/wiki/Bloom_filter?ref=binance.ghost.io) in L2: Diff Layer Bloom filters are a probabilistic data structure that can rapidly verify if an element exists within a data set. To access the state data, EVM uses the bloom filter to verify if the key-value pair is in the Diff Layer and then searches the cache recursively until it finds them, otherwise, EVM directly reads the data from the levelDB. However, bloom filters may yield false positives. Moreover, the rate of false positives increases as the dataset bloom filters evaluate expands. Given the opBNB dataset is larger than Ethereum's, the potential for false positives could be greater as well. The false positive can result in the unnecessary recursive access. To mitigate this, opBNB reduced the diff layer level from the default of 128 to a configurable parameter set at 32. This reduction decreases the size of the dataset, in turn diminishing the possibility of false positives to avoid the unnecessary time consuming operations to increase the efficiency of state retrieval. ## Effective Prefetch in the cache model of L1.5 and its upper layers Prefetch is a technique that enhances the performance of transaction execution by loading data from disk to cache in advance. When a block needs to be processed in full sync mode or mined in mining mode, the opBNB node launches N threads to perform state prefetch. The threads execute the transactions of a block or TxPool and discard the results, but keep the data items in the cache. This way, when the node needs to access the data, it is more likely to find it in the cache rather than on disk, which improves the cache hit rate. However, the original prefetch design had a performance limitation. It used separate state databases for the prefetch and the main processes. The prefetch threads could only store the prefetched data in the L2 diff layer (See the 3 layer cache model that was explained before). To access this data, the main process had to traverse the L1, L2, and probably L3 layers, which was too slow for a high performance layer 2 chain. The new design improves performance by sharing a pool that holds the whole world state (originStorage) between the prefetch and the main EVM processes. This way, the prefetch threads can put the prefetched data right into the L1.5 (the upper layer of the cache model), which makes it faster for the main process to access. See the detailed process below. ## Mining Process Optimization The process of mining L2 blocks of OP Stack is illustrated in the [diagram](https://github.com/ethereum-optimism/optimism/blob/33741760adce92c8bdf61f693058144bb6986e30/specs/assets/engine.svg?ref=binance.ghost.io). It involves a loop where the Rollup Driver (opNode) imports the previous blocks and then invokes the Engine API (op-geth) to produce new blocks on Layer 2. The Rollup Driver (opNode) initiates the block generation process on op-geth by calling the engine_forkChoiceUpdatedv1 API of the Engine API(op-geth). This instructs Engine API(op-geth) to start producing an initial block by executing the transactions. (See “**Engine API: Initiate block production**” in the [diagram](https://github.com/ethereum-optimism/optimism/blob/33741760adce92c8bdf61f693058144bb6986e30/specs/assets/engine.svg?ref=binance.ghost.io)). The Engine API(op-geth) then returns a payload ID to the Rollup Driver (opNode). However, when Engine API(op-geth) receives the engine_newPayloadV1 call from the Rollup Driver (opNode) to commit the block, it has to execute the transactions again, which is redundant and time-consuming. It can take hundreds of milliseconds to complete. To optimize the performance, we added a cache layer to store the execution results during the initial block production step. This way, when op-geth receives the engine_newPayloadV1 call, it can retrieve the data from the cache instead of executing the transactions again. This saves time and resources for the system. ## Optimization of Derivation Layer The batcher performance bottleneck was caused by the need to wait for 15 blocks (45 seconds) on Layer 1 (BSC) to confirm each batch of transactions before submitting the next one. This was due to the possibility of reorg on Layer 1 chain. To solve this problem, we introduced the asynchronous submission feature, which allows the batcher to submit batches without waiting for confirmation. A separate monitor process keeps track of Layer 1 and notifies the batcher if a reorg happens, so that the batcher can resubmit the affected transactions. This feature improves the efficiency of the batcher. It is not yet available on testnet and is still under development, but it will be deployed on opBNB mainnet. --- ## Metrics > Source: https://docs.bnbchain.org/bnb-opbnb/core-concepts/opbnb-metrics/ # opBNB Metrics Compared with other L2 solutions on the Ethereum, like **OP Mainnet** and **Arbitrum**, **opBNB** has lower gas fee, and higher block gas limit, which means the gas fee will be more stable when traffic of Layer 2 increases. I listed the Ethereum EIP-1559 parameters as a reference. Arbitrum gas mechanism is based on the ArbOS, it is not applicable here. **Gas Parameter Differences** | **Parameter** | **opBNB value** | **Optimism value** | |---------------------------------------|---------------------|--------------------| | Block gas limit | **100,000,000 gas** | 30,000,000 gas | | Block gas target | **50,000,000 gas** | 5,000,000 gas | | EIP-1559 elasticity multiplier | 2 | 6 | | EIP-1559 denominator | 8 | 50 | | Maximum base fee increase (per block) | 12.5% | 10% | | Maximum base fee decrease (per block) | 12.5% | 2% | **Metrics Differences** | | **opBNB** | **Optimism** | **Arbitrum** | |------------------------|-----------------------|--------------|--------------| | **Gas Token** | BNB | ETH | ETH | | **VM** | EVM | EVM | EVM | | **Gas Fee** | **$0.001** | $0.05 | $0.1 | | **Block Gas Limit** | **100M(150M 2024Q1)** | 30M | 32M | | **Block time** | **0.25s** | 2s | 0.25s(Min) | | **Withdraw/ Finality** | 7 days | 7 days | 7 days | | **TPS (Transfer)** | **4500+** | 700+ | 4000+ | OP Stack has some minor differences, so does opBNB. I just listed the differences here for your reference, for details you can refer to the [OP Stack documents](https://stack.optimism.io/docs/releases/bedrock/differences/#opcode-differences). Our goal is to provide a scaling solution for network congestion problems for highly active applications on the BSC, such as DeFi, NFTs and gaming. opBNB is based on OP Stack and with optimizations of the mining process and the cache data access to achieve a capacity of 100M gas per second, which is much higher than BSC. | | **opBNB** | **BSC** | **Ethereum** | |----------------------|------------|-----------------------------------------------------|--------------| | **Gas Token** | BNB | BNB | ETH | | **VM** | EVM | EVM | EVM | | **Gas Price Model** | EIP-1559 | [Gas Price Auction](https://bscscan.com/gastracker) | EIP-1559 | | **Block Gas Limit** | **50M** | [55M](https://www.bscscan.com/chart/gaslimit) | 30M | | **Block time** | **0.25s** | 0.45s | 12s | | **Transaction Cost** | **$0.001** | ~$0.005 | $1 | *Unlike opBNB and OP Mainnet, which have fixed blocktimes, Arbitrum has a variable blocktime that depends on the number and gas of transactions in a block. The more transactions and gas a block contains, the longer it takes to mine. The minimum blocktime on Arbitrum is 0.25 seconds, which means that the fastest block can be mined in a quarter of a second.* --- ## Gas and Fees > Source: https://docs.bnbchain.org/bnb-opbnb/core-concepts/gas-and-fees/ # Gas and Fees OpBNB is a Layer 2 scaling solution that aims to achieve higher throughput and lower cost for transactions on the BNB Smart Chain. The cost of opBNB transactions consists of two components: the Layer 2 gas fee and the Layer 1 gas fee. The Layer 2 gas fee reflects the computational complexity of the transaction. The Layer 1 gas fee covers the expense of submitting batches of transactions to the BSC for verification and finality. **Gas price = base price + priority price** **Layer 2 transaction cost = Layer 2 gas price x Layer 2 gas consumed + Layer 1 gas price x Layer 1 gas consumed.** ## Current configuration | Name | Floor Base Price | Minimum Priority Price | | ------------- | ---------------- | ---------------------------- | | opBNB Testnet | 8 wei (dynamic) | 1001 wei | | opBNB Mainnet | 8 wei (dynamic) | 1001 wei | | BSC Testnet | 0 | 0.1 Gwei (standard) | | BSC Mainnet | 0 | 0.05 Gwei (standard) | ## What does this means Please note the floor base price is the minimum base price opBNB can set, and according to the usage, the base price can fluctuate. For example, according to the current configuration, if the usage of a block reaches 50% of 100M gas, the base price will increase by 12.5%. The minimum priority price is preconfigured, and users can give any priority price that is higher than this number. Usually users will get the estimate gas price by calling the API of “estimate gas price”. It is a recommended gas price according to the current average gas price of history blocks. BNB Chain aims to reduce the transaction cost to the level that enable the mass adoption, for opBNB, the target of the transfer transaction is lower than $0.001. ## How opBNB keep reducing the cost of L2 transactions 1. **Enhanced Data Compression**: Implementing more advanced data compression algorithms to reduce the size of L2 transaction data before submitting it to L1. 2. **Efficient Transaction Batching**: Optimizing how transactions are batched together to maximize space efficiency and reduce costs per transaction. 3. **Data Availability Solutions**: Utilizing solutions like those in BNB Greenfield for offloading some data storage from the main chain, thereby reducing data costs. 4. **Zero-Knowledge Proofs**: Employing zero-knowledge proofs to validate transactions without disclosing full transaction data, thus minimizing L1 data load. 5. **Protocol-Level Optimizations**: Making improvements at the protocol level to reduce overhead in transaction processing on L2. --- ## Account Abstraction > Source: https://docs.bnbchain.org/bnb-opbnb/core-concepts/account-abstraction-on-opbnb/ # Account Abstraction ## opBNB is a cost-efficient solution for AA The primary allure of opBNB lies in its ability to significantly reduce the gas costs associated with AA (ERC4337) transactions. This efficiency is achieved through optimized transaction processing and a more streamlined approach to handling complex operations typically found in AA transactions. AA transactions, with their intricate operations and smart contract interactions, traditionally require more computational resources. opBNB, however, utilizes innovative methods to simplify these processes, ensuring that the complexity does not translate into prohibitive costs for users and developers. ## Enhanced transaction speed with lower costs Not only does opBNB address the cost issue, but it also offers higher Transaction Per Second (TPS) rates. This combination of low cost and high speed is particularly crucial for dApps that require both efficiency and scalability, making opBNB a ideal choice for High-Frequency DeFi and web3 games. By integrating opBNB, dApp developers can offer their users a seamless experience without the burden of high transaction fees. This user-friendly approach, coupled with cost-effective operations, positions opBNB as a preferred choice in the AA landscape. ## opBNB AA Infrastructure Notably, platforms like [Biconomy](https://docs.biconomy.io/supportedchains/) and [Particle Wallet](https://docs.particle.network/overview/available-networks) have already adopted opBNB's AA solutions. Their integration showcases the practical application and effectiveness of opBNB in managing the complexity and cost of AA transactions in real-world scenarios. For details, please refer to the blog of [Account Abstraction current and future development on BNB Chain](https://www.bnbchain.org/en/blog/account-abstraction-current-and-future-development-on-bnbchain-part-one). --- ## Protocol Addresses > Source: https://docs.bnbchain.org/bnb-opbnb/core-concepts/opbnb-protocol-addresses/ # opBNB Protocol addresses The opBNB protocol contracts are smart contracts that enable the execution of transactions on the opBNB network. The main contracts are: - batchInbox: This contract receives batches of transactions from the Sequencer on L1. - batchSender: This contract is the authorised sender of batches to the batchInbox. It can be changed by the SystemConfig contract, which governs the parameters of the opBNB network. - outputProposer: This contract proposes outputs for the opBNB nodes to execute. It receives inputs from the batchInbox and other sources, and generates outputs that are consistent with the opBNB protocol rules. **Testnet:** | **Name** | **Address** | | --------------- | ------------------------------------------------------------ | | Batch Sender | [0x1Fd6A75CC72f39147756A663f3eF1fc95eF89495](https://testnet.bscscan.com/address/0x1fd6a75cc72f39147756a663f3ef1fc95ef89495) | | Batch Inbox | [0xfF00000000000000000000000000000000005611](https://testnet.bscscan.com/address/0xff00000000000000000000000000000000005611) | | Output Proposer | [0x4aE49f1f57358c13A5732cb12e656Cf8C8D986DF](https://testnet.bscscan.com/address/0x4ae49f1f57358c13a5732cb12e656cf8c8d986df) | **Mainnet:** | **Name** | **Address** | | --------------- | ------------------------------------------------------------ | | Batch Sender | [0xef8783382eF80Ec23B66c43575A6103dECA909c3](https://bscscan.com/address/0xef8783382eF80Ec23B66c43575A6103dECA909c3) | | Batch Inbox | [0xff00000000000000000000000000000000000204](https://bscscan.com/address/0xff00000000000000000000000000000000000204) | | Output Proposer | [0xc235c904AD9EfcABfF4628E3279994A4c0A9d591](https://bscscan.com/address/0xc235c904AD9EfcABfF4628E3279994A4c0A9d591) | ### ## L1 Contract Addresses **Testnet** | **Name** | **Description** | **Address** | | --------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | | L1CrossDomainMessenger | responsible for facilitating cross-domain communication on Layer 1 (L1) | [0x5b0c605c707979e8bDc2Ad9271A0388b3fD4Af3E](https://testnet.bscscan.com/address/0x5b0c605c707979e8bDc2Ad9271A0388b3fD4Af3E) | | L1ERC721Bridge | This contract is likely an ERC-721 bridge that enables the transfer of non-fungible tokens (NFTs) between L1 and L2 | [0xad39e2cfa7d8d8B6c2d56244Bfb88990EC31Bb79](https://testnet.bscscan.com/address/0xad39e2cfa7d8d8B6c2d56244Bfb88990EC31Bb79) | | L1ERC721BridgeProxy | A proxy contract that may provide additional functionalities for the L1ERC721Bridge contract. | [0x17e1454015bFb3377c75bE7b6d47B236fd2ddbE7](https://testnet.bscscan.com/address/0x17e1454015bFb3377c75bE7b6d47B236fd2ddbE7) | | L1StandardBridge | A standard bridge contract that enables the transfer of fungible tokens between L1 and L2. | [0xddB9EB847971DaA82e5dbe2745C429A3B2715B46](https://testnet.bscscan.com/address/0xddB9EB847971DaA82e5dbe2745C429A3B2715B46) | | L2OutputOracle | This contract is an oracle on Layer 2 that provides output data to be used in smart contracts and applications | [0xD92aEF4473093C67A7696e475858152D3b2acB7c](https://testnet.bscscan.com/address/0xD92aEF4473093C67A7696e475858152D3b2acB7c) | | L2OutputOracleProxy | A proxy contract related to the L2OutputOracle, providing an interface or additional functionality. | [0xFf2394Bb843012562f4349C6632a0EcB92fC8810](https://testnet.bscscan.com/address/0xFf2394Bb843012562f4349C6632a0EcB92fC8810) | | Lib_AddressManager | This contract is a library used to manage addresses for various contracts in the system. | [0x4d07b9B1ffC70Fc824587573cfb6ef1Cc404AaD7](https://testnet.bscscan.com/address/0x4d07b9B1ffC70Fc824587573cfb6ef1Cc404AaD7) | | OptimismMintableERC20Factory | This is a factory contract for creating mintable ERC-20 tokens on the Layer 2 network. | [0x1AD11eA5426bA3A11c0bA8c4B89fd1BCa732025E](https://testnet.bscscan.com/address/0x1AD11eA5426bA3A11c0bA8c4B89fd1BCa732025E) | | OptimismMintableERC20FactoryProxy | A proxy contract related to the OptimismMintableERC20Factory, providing an interface or additional functionality. | [0x182cE4305791744202BB4F802C155B94cb66163B](https://testnet.bscscan.com/address/0x182cE4305791744202BB4F802C155B94cb66163B) | | OptimismPortal | This contract serves as a portal or gateway for interacting with the Optimism Layer 2 network. | [0x2d5D7bEe8ebEf17DE14dd6ADAE8271507994a6E0](https://testnet.bscscan.com/address/0x2d5D7bEe8ebEf17DE14dd6ADAE8271507994a6E0) | | OptimismPortalProxy | A proxy contract related to the OptimismPortal, providing an interface or additional functionality. | [0x4386C8ABf2009aC0c263462Da568DD9d46e52a31](https://testnet.bscscan.com/address/0x4386C8ABf2009aC0c263462Da568DD9d46e52a31) | | PortalSender | This contract is involved in sending data or messages to a portal or gateway on the L1. | [0x02B668393Bc41415Dbb973C9dC144fDD42B8fA2D](https://testnet.bscscan.com/address/0x02B668393Bc41415Dbb973C9dC144fDD42B8fA2D) | | ProxyAdmin | This contract is responsible for managing proxy contracts, allowing for upgrades and access control. | [0xE4925bD8Ac30b2d4e2bD7b8Ba495a5c92d4c5156](https://testnet.bscscan.com/address/0xE4925bD8Ac30b2d4e2bD7b8Ba495a5c92d4c5156) | | Proxy__OVM_L1CrossDomainMessenger | This contract is a proxy for the L1CrossDomainMessenger contract on the Layer 2, enabling interaction with the Layer 2 contract from Layer 1. | [0xD506952e78eeCd5d4424B1990a0c99B1568E7c2C](https://testnet.bscscan.com/address/0xD506952e78eeCd5d4424B1990a0c99B1568E7c2C) | | Proxy__OVM_L1StandardBridge | This is a proxy for the L1StandardBridge contract on the Layer 2 network, allowing interaction with the Layer 2 bridge from Layer 1. | [0x677311Fd2cCc511Bbc0f581E8d9a07B033D5E840](https://testnet.bscscan.com/address/0x677311Fd2cCc511Bbc0f581E8d9a07B033D5E840) | | SystemConfig | This contract is responsible for managing system configurations, settings, or parameters in the protocol. | [0x8Fc086Ec0ac912D5101Fec3E9ac6D910eBD5b611](https://testnet.bscscan.com/address/0x8Fc086Ec0ac912D5101Fec3E9ac6D910eBD5b611) | | SystemConfigProxy | A proxy contract related to the SystemConfig contract, providing an interface or additional functionality. | [0x406aC857817708eAf4ca3A82317eF4ae3D1EA23B](https://testnet.bscscan.com/address/0x406aC857817708eAf4ca3A82317eF4ae3D1EA23B) | | SystemDictator | This contract has a role in managing or governing certain aspects of the system or protocol. | [0x281cc8F04AE5bb873bADc3D89059423E4c664834](https://testnet.bscscan.com/address/0x281cc8F04AE5bb873bADc3D89059423E4c664834) | | SystemDictatorProxy | A proxy contract related to the SystemDictator contract, providing an interface or additional functionality. | [0xB9Edfded1254ca07085920Af22BeCE0ce905F2AB](https://testnet.bscscan.com/address/0xB9Edfded1254ca07085920Af22BeCE0ce905F2AB) | ### **Mainnet** | **Name** | **Description** | **Address** | | --------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | | L1CrossDomainMessenger | responsible for facilitating cross-domain communication on Layer 1 (L1) | [0x09525eB7eEd671582dDc6f02f8D9082cbd55A606](https://bscscan.com/address/0x09525eB7eEd671582dDc6f02f8D9082cbd55A606) | | L1ERC721Bridge | This contract is likely an ERC-721 bridge that enables the transfer of non-fungible tokens (NFTs) between L1 and L2 | [0xCB4CD5B74A2f2D75076Fb097Da70cEF5FEaC0428](https://bscscan.com/address/0xCB4CD5B74A2f2D75076Fb097Da70cEF5FEaC0428) | | L1ERC721BridgeProxy | A proxy contract that may provide additional functionalities for the L1ERC721Bridge contract. | [0xC7c796D3B712ad223Bc29Bf85E6cdD3045D998C4](https://bscscan.com/address/0xC7c796D3B712ad223Bc29Bf85E6cdD3045D998C4) | | L1StandardBridge | A standard bridge contract that enables the transfer of fungible tokens between L1 and L2. | [0x6df37de57D50eC5a0600510eB8F563F538BDc403](https://bscscan.com/address/0x6df37de57D50eC5a0600510eB8F563F538BDc403) | | L2OutputOracle | This contract is an oracle on Layer 2 that provides output data to be used in smart contracts and applications | [0x0d61A015BAeF63f6740afF8294dAc278A494f6fA](https://bscscan.com/address/0x0d61A015BAeF63f6740afF8294dAc278A494f6fA) | | L2OutputOracleProxy | A proxy contract related to the L2OutputOracle, providing an interface or additional functionality. | [0x153CAB79f4767E2ff862C94aa49573294B13D169](https://bscscan.com/address/0x153CAB79f4767E2ff862C94aa49573294B13D169) | | Lib_AddressManager | This contract is a library used to manage addresses for various contracts in the system. | [0x29cfb9A803589Ff5C37f955ead83b45311F15b12](https://bscscan.com/address/0x29cfb9A803589Ff5C37f955ead83b45311F15b12) | | OptimismMintableERC20Factory | This is a factory contract for creating mintable ERC-20 tokens on the Layer 2 network. | [0x6560F2822c9dFb9801F5E9A7c7CE1564c8c2b461](https://bscscan.com/address/0x6560F2822c9dFb9801F5E9A7c7CE1564c8c2b461) | | OptimismMintableERC20FactoryProxy | A proxy contract related to the OptimismMintableERC20Factory, providing an interface or additional functionality. | [0xAa53ddCDC64A53F65A5f570cc13eB13529d780f1](https://bscscan.com/address/0xAa53ddCDC64A53F65A5f570cc13eB13529d780f1) | | OptimismPortal | This contract serves as a portal or gateway for interacting with the Optimism Layer 2 network. | [0x7e2419F79c9546B9A0E292Fd36aC5005ffed5495](https://bscscan.com/address/0x7e2419F79c9546B9A0E292Fd36aC5005ffed5495) | | OptimismPortalProxy | A proxy contract related to the OptimismPortal, providing an interface or additional functionality. | [0x1876EA7702C0ad0C6A2ae6036DE7733edfBca519](https://bscscan.com/address/0x1876EA7702C0ad0C6A2ae6036DE7733edfBca519) | | PortalSender | This contract is involved in sending data or messages to a portal or gateway on the L1. | [0xEDa034A4B7806e1283e99F8522eFd08d855B9b72](https://bscscan.com/address/0xEDa034A4B7806e1283e99F8522eFd08d855B9b72) | | ProxyAdmin | This contract is responsible for managing proxy contracts, allowing for upgrades and access control. | [0x27a591Ec09AAfEEb39d7533AEf7C64E0305D1576](https://bscscan.com/address/0x27a591Ec09AAfEEb39d7533AEf7C64E0305D1576) | | Proxy__OVM_L1CrossDomainMessenger | This contract is a proxy for the L1CrossDomainMessenger contract on the Layer 2, enabling interaction with the Layer 2 contract from Layer 1. | [0xd95D508f13f7029CCF0fb61984d5dfD11b879c4f](https://bscscan.com/address/0xd95D508f13f7029CCF0fb61984d5dfD11b879c4f) | | Proxy__OVM_L1StandardBridge | This is a proxy for the L1StandardBridge contract on the Layer 2 network, allowing interaction with the Layer 2 bridge from Layer 1. | [0xF05F0e4362859c3331Cb9395CBC201E3Fa6757Ea](https://bscscan.com/address/0xF05F0e4362859c3331Cb9395CBC201E3Fa6757Ea) | | SystemConfig | This contract is responsible for managing system configurations, settings, or parameters in the protocol. | [0x0be96fcB5eCCA87c775344fB76A3A1C6146cA5Fd](https://bscscan.com/address/0x0be96fcB5eCCA87c775344fB76A3A1C6146cA5Fd) | | SystemConfigProxy | A proxy contract related to the SystemConfig contract, providing an interface or additional functionality. | [0x7AC836148C14c74086D57F7828F2D065672Db3B8](https://bscscan.com/address/0x7AC836148C14c74086D57F7828F2D065672Db3B8) | | SystemDictator | This contract has a role in managing or governing certain aspects of the system or protocol. | [0x0744F61646DdE7Bc2d2c18B13D08a8fba597666b](https://bscscan.com/address/0x0744F61646DdE7Bc2d2c18B13D08a8fba597666b) | | SystemDictatorProxy | A proxy contract related to the SystemDictator contract, providing an interface or additional functionality. | [0xEb23CCD85eF040BdAf3CBf962C816cD9Cb691F35](https://bscscan.com/address/0xEb23CCD85eF040BdAf3CBf962C816cD9Cb691F35) | ### ## L2 Contract Addresses | **Name** | **Description** | **Address** | | ----------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | | WBNB | This contract represents Wrapped BNB, a token that is pegged to BNB on the opBNB network. | [0x4200000000000000000000000000000000000006](https://opbnbscan.com/address/0x4200000000000000000000000000000000000006) | | L2CrossDomainMessenger | This contract is responsible for facilitating cross-domain communication on Layer 2 of the opBNB network. | [0x4200000000000000000000000000000000000007](https://opbnbscan.com/address/0x4200000000000000000000000000000000000007) | | L2StandardBridge | This contract is a standard bridge on Layer 2, enabling the transfer of fungible tokens between different chains or networks. | [0x4200000000000000000000000000000000000010](https://opbnbscan.com/address/0x4200000000000000000000000000000000000010) | | SequencerFeeVault | This contract serves as a vault for collecting fees from sequencers, who are responsible for submitting transactions on opBNB. | [0x4200000000000000000000000000000000000011](https://opbnbscan.com/address/0x4200000000000000000000000000000000000011) | | OptimismMintableERC20Factory | This is a factory contract for creating mintable ERC-20 tokens on the Layer 2 network. | [0x4200000000000000000000000000000000000012](https://opbnbscan.com/address/0x4200000000000000000000000000000000000012) | | GasPriceOracle | This contract may provide gas price data to be used in transactions and fee calculations on the opBNB network. | [0x420000000000000000000000000000000000000F](https://opbnbscan.com/address/0x420000000000000000000000000000000000000F) | | L1Block | This contract represents a block on Layer 1 in the context of interacting with opBNB. | [0x4200000000000000000000000000000000000015](https://opbnbscan.com/address/0x4200000000000000000000000000000000000015) | | L2ToL1MessagePasser | This contract is responsible for passing messages from Layer 2 to Layer 1 on the opBNB network. | [0x4200000000000000000000000000000000000016](https://opbnbscan.com/address/0x4200000000000000000000000000000000000016) | | L2ERC721Bridge | This contract is a bridge for transferring ERC-721 non-fungible tokens on Layer 2. | [0x4200000000000000000000000000000000000014](https://opbnbscan.com/address/0x4200000000000000000000000000000000000014) | | OptimismMintableERC721Factory | This is a factory contract for creating mintable ERC-721 tokens on the Layer 2 network. | [0x4200000000000000000000000000000000000017](https://opbnbscan.com/address/0x4200000000000000000000000000000000000017) | | ProxyAdmin | This contract is responsible for managing proxy contracts on the opBNB network, allowing for upgrades and access control. | [0x4200000000000000000000000000000000000018](https://opbnbscan.com/address/0x4200000000000000000000000000000000000018) | | BaseFeeVault | This contract acts as a vault for collecting base fees on the opBNB network. | [0x4200000000000000000000000000000000000019](https://opbnbscan.com/address/0x4200000000000000000000000000000000000019) | | L1FeeVault | This contract serves as a vault for collecting fees on Layer 1 in the context of interacting with opBNB. | [0x420000000000000000000000000000000000001a](https://opbnbscan.com/address/0x420000000000000000000000000000000000001a) | ## reference --- ## BNB Chain Rollup as Service > Source: https://docs.bnbchain.org/bnb-opbnb/core-concepts/raas/ # What is Rollup as a Service Rollup-as-a-Service (RaaS) represents a transformative approach in the blockchain sphere, akin to Software-as-a-Service (SaaS) in the cloud computing domain, tailored specifically for decentralized applications (dApps) and blockchain projects. This innovative service model offers a cost-effective and efficient pathway for projects to build and deploy rollup networks. ## Alignment with BNB Chain's Roadmap and Ecosystem Growth The demand for RaaS within the BNB Chain ecosystem is not just a trend; it's a strategic response to the need for higher transaction throughput and enhanced scalability. As the chain eyes substantial growth, RaaS stands out as an essential service that supports this expansion. It does so by enabling developers to deploy scalable applications with ease, leveraging rollup technology to process transactions on Layer 2 network before finalizing them on the main blockchain(BSC). # Building with RaaS Aligned with BNB Chain’s Future Building with Rollup as a Service (RaaS) on the BNB Chain involves leveraging specialized services from providers like [AltLayer](https://altlayer.io/), [Movement Labs](https://movementlabs.xyz/), [Lumoz](https://lumoz.org/rollups), and [4everland](https://docs.4everland.org/raas-beta/whats-rollups), each offering unique tools to enhance blockchain application development. By adopting these specialized RaaS solutions, developers can leverage the strengths of the BNB Chain ecosystem to create innovative, reliable, and user-centric blockchain applications. | Service Provider | Developer tools and tech stack | How to Start | | ---------------- | ------------------------------------------------------------ | -------------------------------------------------- | | Altlayer | Versatile rollup-up stack support and no-code setup dashboard | https://altlayer.io/ | | Movement Labs | Move based L2 on BSC support | https://movementlabs.xyz/ | | Lumoz | Support zkevm on BSC | https://lumoz.org/rollups | | 4EVERLAND | One-click deplopyment of rollups on BSC | https://docs.4everland.org/raas-beta/whats-rollups | --- ## Quick Guide > Source: https://docs.bnbchain.org/bnb-opbnb/developers/quick-guide/ If you're a developer seeking to build on opBNB, you've come to the right place. This document provides all the information you need to develop opBNB applications. ## Getting Started The opBNB network is the Layer 2 scaling solution for the BNB Smart Chain(BSC) powered by [OP Stack](https://docs.optimism.io/). If you are brand new to opBNB, you can try start with the guide on [creating a fullstack dapp](../advanced/full-stack-dapp.md) on opBNB. It will familiarize you with the basic steps of deploying a smart contract on opBNB and interacting with it from a dapp. opBNB is [EVM equivalent](https://web.archive.org/web/20231127160757/https://medium.com/ethereum-optimism/introducing-evm-equivalence-5c2021deb306) so you can feel confident that your existing Ethereum smart contract skills will transfer seamlessly to opBNB. There are a few small differences between Ethereum and opBNB, so make sure to be aware of them. You can refer to the [optimism documentation](https://docs.optimism.io/chain/differences) for more information. ## Connecting Here are some resources to help you get connected to the opBNB network: - [Network Information and RPC Providers](../get-started/network-info.md) - [Wallet Configuration](../get-started/wallet-configuration.md) ## Get Tokens opBNB is a Layer 2 on BSC, so tokens can be moved between the two chains using bridges. For the testnet, you can use the faucet to obtain some test tokens on BSC and then bridge them to opBNB using the official bridge. For the mainnet, you can bridge tokens from BSC to opBNB using various bridges, or you can withdraw tokens directly from a centralized exchange (CEX) which supports opBNB network(e.g. Binance). - [opBNB Testnet Faucet](./network-faucet.md) - bridges - [opBNB Official bridge](https://opbnb-bridge.bnbchain.org) - [zkBridge](https://www.zkbridge.com/opbnb/token) - [rhino.fi](https://app.rhino.fi/bridge?token=BNB&chainOut=OPBNB&chain=BINANCE) - If you need to bridge tokens that are not supported by the bridges and CEXs yet, you can deploy your own L2 mirror token contract on opBNB and bridge them according to [this guide](../developers/bep20-crosschain.md). ## Cross-Chain Interoperability To build cross-chain applications between BSC and opBNB, you should understand how cross-chain message passing works. You can refer to the [sending data between L1 and L2](https://docs.optimism.io/builders/app-developers/bridging/messaging) guide for more information. ## Developer Tools - Explorer - [NodeReal opBNB Scan](https://mainnet.opbnbscan.com) - [BSCScan](https://opbnb.bscscan.com/) - SDK. If you are only using the SDK for Ethereum-compatible functions, then all Ethereum SDKs should work with opBNB. If you want to use opBNB-specific functions, it's recommended to use [op-viem with OP Stack Extensions](https://viem.sh/op-stack). - [ethers.js](https://docs.ethers.io) - [web3.js](https://web3js.readthedocs.io) - [viem](https://viem.sh/) - Tools - [Remix](https://remix.ethereum.org) - [Hardhat](https://hardhat.org) - [Foundry](https://book.getfoundry.sh/) - [BNB Chain Multi-Sig Wallet](./multisig-wallet.md) - Wallets - [Binance Web3 Wallet](https://www.binance.com/en/web3wallet) - [Metamask](https://metamask.io/) - [TrustWallet](https://trustwallet.com/) - [Particle Network](https://wallet.particle.network/) - [Gem Wallet](https://gemwallet.com/) - [OKX Wallet](https://www.okx.com/nl/web3) - [MathWallet](https://mathwallet.org/en-us/) - [Sequence.build](https://sequence.build/landing) - [Avatar](https://avatarwallet.io/) - Oracle - [Binance Oracle](https://oracle.binance.com/docs/) - Account Abstraction - [Particle Network](https://wallet.particle.network/) - [Biconomy](https://docs.biconomy.io/supportedchains/) - [CyberConnect](https://cyberconnect.me/) - Storage - [BNB Greenfield](https://greenfield.bnbchain.org/en) - Data Analytics - [DefiLlama](https://defillama.com/chain/opBNB) - [CoinGecko](https://www.coingecko.com/en/chains/opbnb) - [DappBay](https://dappbay.bnbchain.org/ranking/chain/opbnb) For more tools and details, you can refer to [this doc](./developer-tools.md). --- ## Developer Tools > Source: https://docs.bnbchain.org/bnb-opbnb/developers/developer-tools/ One of our main objectives is to expand the adoption and utility of opBNB as a high performance and low cost Layer 2 chain on the BNB Smart Chain. To achieve this goal, we have to ensure that our underlying technology is robust, scalable and user-friendly. That is why we are committed to developing and improving the core infrastructure and tools that support opBNB and its community of users, hosts and developers. Below are the ecosystem we are building for the opBNB. # Summary | Categories | Sub Categories | Infrastructure and Toolings | | ------------------- | --------------------- |--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | DAO Governance | DAO Governance | [XDao](https://www.xdao.app/204),[Snapshot](https://snapshot.org/#/?filter=networks&q=opbnb) | | Node Providers | Node Provider | [NodeReal](https://nodereal.io/meganode) | | Explorer | Explorer | [NodeReal opBNB Scan](https://mainnet.opbnbscan.com), [BSCScan](https://opbnb.bscscan.com/) | | | Developer Platforms | [Truffle](https://trufflesuite.com/), [Foundry](https://book.getfoundry.sh/), [Hardhat](https://hardhat.org/), [Remix](https://remix.ethereum.org/) | | Use Access Tooling | Wallet | [Binance Web3 Wallet](https://www.binance.com/en/web3wallet), [Metamask](https://metamask.io/), [TrustWallet](https://trustwallet.com/), [Particle Network](https://wallet.particle.network/), [Gem Wallet](https://gemwallet.com/), [OKX Wallet](https://www.okx.com/nl/web3), [MathWallet](https://mathwallet.org/en-us/), [Sequence.build](https://sequence.build/landing), [Avatar](https://avatarwallet.io/), [Openfort](https://openfort.xyz) | | | Bridges | [opBNB Bridge](https://opbnb-bridge.bnbchain.org/deposit),[PolyHedra](https://zkbridge.com/), [rhino.fi](https://app.rhino.fi/bridge?token=BNB&chainOut=OPBNB&chain=BINANCE) | | | dApp Store | [dApp Bay](https://dappbay.bnbchain.org/ranking/chain/opbnb) | | Oracles | Price Feeds, VRF | [Binance Oracle](https://oracle.binance.com/), [Supra](https://supraoracles.com/) | | Storage | Decentralized Storage | [BNB Greenfield](https://greenfield.bnbchain.org/en) | | Security | | [AvengerDAO](https://www.avengerdao.org/) | | Account Abstraction | | [Particle Network](https://wallet.particle.network/), [Biconomy](https://docs.biconomy.io/supportedchains/), [CyberConnect](https://cyberconnect.me/), [Openfort](https://openfort.xyz) | | MultiSig | | [BNB Chain Multi-Sig Wallet](multisig-wallet.md) | | Data Analytics | | [DefiLlama](https://defillama.com/chain/opBNB), [CoinGecko](https://www.coingecko.com/en/chains/opbnb), [DappBay](https://dappbay.bnbchain.org/ranking/chain/opbnb) | | Indexing | | NodeReal’s opBNB Graph QL | | NFT | NFT Marketplace | [Element’s NFT Marketplace](https://element.market/opbnb) | ## Binance Exchange Support Binance has supported deposit and withdrawal on **7th Nov, 2023**. The initial list is BNB, FDUSD, and USDT as a start. ## Node Providers Needless to mention that the stability of RPC nodes is crucial to any blockchain, in this instance BNB Chain has **NodeReal** who is one of opBNB early and core contributors to anchor this task. NodeReal RPC can be accessed through their [API marketplace](https://nodereal.io/api-marketplace/explore?chains=opbnb). For common/public nodes, communities can access[ BNB ChainList](https://www.bnbchainlist.org/). ## Wallet Crypto/Digital wallet serves as an entry point for users to access blockchain. opBNB have known wallets providing access to opBNB such as [Metamask and Trustwallet](../get-started/wallet-configuration.md), leading the front. On **Account Abstraction(AA)**, [CyberConnect](https://cyberconnect.me/), [Particle Network](https://wallet.particle.network/), [Biconomy](https://docs.biconomy.io/supportedchains/), [Openfort](https://openfort.xyz/docs) has already integrated with opBNB. **MultiSig** wallet BNB Chain has provided its own [Safe Multi-Sig Wallet](multisig-wallet.md). ## Wallet as a Service[WaaS] Wallet-as-a-Service (WaaS) streamlines the integration of digital wallets into applications, allowing businesses to manage cryptocurrencies and tokens effortlessly. By handling the complexities of wallet infrastructure, WaaS enables a secure and user-friendly experience for managing digital assets, fostering wider blockchain adoption and enhancing operational efficiency. Below wallet have supported Wallet-as-a-Service (WaaS) platforms on the BNB Smart Chain and opBNB, facilitating seamless integration of digital wallet functionalities into applications for managing opBNB and other assets. | **Project Name** | **Main Website** | **WaaS Document** | | ---------------- | ------------------------- | ------------------------------------------------- | | Particle Network | https://particle.network/ | https://particle.network/wallet-introduction.html | | Sequence.build | https://sequence.xyz/ | https://sequence.build/landing | | Avatar Wallet | https://avatarwallet.io/ | https://docs.avatarwallet.io/docs/introduction | | Openfort | https://openfort.xyz/ | https://openfort.xyz/docs | ## Bridges For bridges opBNB has its own default [bridge](https://opbnb-bridge.bnbchain.org/deposit), which is built mirroring OP Stack. This also means that it has the 7 days challenge period, similar to OP bridge, BASE bridge. But opBNB does have 3rd party bridge providers, such as [Polyhedra](https://zkbridge.com/opbnb) and [Rhino.Fi](https://app.rhino.fi/bridge?token=BNB&chainOut=OPBNB&chain=BINANCE) that provide shorter withdrawal periods. ## Data Analytics Several known industry platform already started supporting opBNB, i.e. [DefiLlama](https://defillama.com/chain/opBNB) , [CoinGecko](https://www.coingecko.com/en/chains/opbnb), [DappBay](https://dappbay.bnbchain.org/ranking/chain/opbnb). For listing on DappBay, projects can fill up this [form](https://dappbay.bnbchain.org/submit-dapp). ## Data Indexing opBNB currently has NodeReal’s opBNB Graph QL as the initial support[**Beta Version**] as current players such as TheGraph have their pipeline full for the rest of the year. For projects needing such services, projects can liaise with NodeReal on specs, requirements. [[Process Link](https://docs.google.com/document/d/1R0RcHKU27lBPMaSmwhwijlXLTQhs0Haa9LtKsxJbeAc/edit)] ## DAO Essential component as the BNB Chain moves towards decentralization. [XDao](https://www.xdao.app/204) and [Snapshot](https://snapshot.org/#/?filter=networks&q=opbnb) are now supporting opBNB. # For DeFi Specific ## Oracle [Binance Oracle](https://oracle.binance.com/docs/) has started supporting opBNB since Day1. Feel free to reach Binance Oracle for product support and demo. # For Game/Social Media ## VRF [Binance Oracle](https://oracle.binance.com/docs/vrf/overview) has support for opBNB VRF. Feel free to reach Binance Oracle for product support and demo. ## NFT Marketplace & Minting [Element’s NFT Marketplace](https://element.market/opbnb) is already live on opBNB. Minting feature will be ready soon in Nov. --- ## Network Faucet > Source: https://docs.bnbchain.org/bnb-opbnb/developers/network-faucet/ ## Testnet Faucet If you want to test the functionality of the BNB Smart Chain, you will need some testing tokens, such as tBNB and other major tokens like USDC, BUSD, DAI, and wrapped Bitcoin. There are two ways to claim these testing tokens. Please refer to the BSC [faucet doc](../../bnb-smart-chain/developers/faucet.md) for details. After you claim your tokens, you can transfer your testing assets to opBNB to start testing through [testnet bridge](https://opbnb-testnet-bridge.bnbchain.org). --- ## Wallet Gas Price Setting > Source: https://docs.bnbchain.org/bnb-opbnb/developers/set-gas-price/ This document shows you how to set the priority price and base price for opBNB transactions in wallet. These prices determine how much you are willing to pay for your transaction to be included in the next block (Priority Gas Price) and how much you are willing to pay for the gas used by your transaction. Setting these prices correctly can help you save money and avoid delays. To set the priority price and base price, follow these steps: Metamask: 1. Open your metamask wallet and click on the opBNB network at the top right corner. 2. Click on the send button and enter the recipient address and the amount of opBNB you want to send. 3. Before you confirm your transaction, click on the **advanced->edit** button next to the gas fee section. 4. You will see two sliders: one for the **Max base fee(Gwei)** price and one for the **Priority Fee(Gwei)**. The priority price is the amount of opBNB you are willing to pay per unit of gas for your transaction to be included in the next block. The base price is the amount of opBNB you are willing to pay per unit of gas for the gas used by your transaction. The total gas fee is the sum of these two prices multiplied by the gas consumed. The base fee for opBNB transactions is dynamic and depends on the demand for block space. The minimum possible base fee is 0.000000008 gwei. The priority fee, which is paid to the sequencer who includes the transaction in a block, can also be as low as 0.000000001 gwei. However, these fees may vary depending on the network congestion and the urgency of the transaction. 5. You can adjust the sliders according to your preferences. The higher the priority price, the faster your transaction will be confirmed, but the more expensive it will be. The lower the base price, the cheaper your transaction will be, but the more likely it will fail if the gas limit is too low. 6. Once you are satisfied with your settings, click on save and then confirm your transaction. --- ## Multi-sig Wallet > Source: https://docs.bnbchain.org/bnb-opbnb/developers/multisig-wallet/ --- title: BNB Chain Safe Multi-Sig Wallet Service index: yes --- # BNB Chain Safe Multi-Sig Wallet Service BNB Chain deployed a multi-sig wallet service based on the Gnosis Safe protocol on opBNB mainnet, opBNB testnet and BSC testnet. It provides users with a secure and convenient way to manage their digital assets and transactions. # How to Use the BNB Chain Multi-Sig Wallet Service To use the BNB Chain multi-sig wallet service, connect with your own EOA wallet to start. Visit [https://multisig.bnbchain.org/welcome](https://multisig.bnbchain.org/welcome) Read the [Safe Doc](https://docs.safe.global/getting-started/readme) for details. # Safe Transaction Service API To create or list safe transactions programmatically, use the Safe Transaction Service API. Here are the endpoints for the opBNB testnet and opBNB mainnet: Testnet: [https://safe-transaction-opbnb-testnet.bnbchain.org/](https://safe-transaction-opbnb-testnet.bnbchain.org/) Mainnet: [https://safe-transaction-opbnb-mainnet.bnbchain.org/](https://safe-transaction-opbnb-mainnet.bnbchain.org/) Read the [api-kit Doc](https://docs.safe.global/safe-core-aa-sdk/api-kit/reference) for details. --- ## BEP20 CrossChain Introduction > Source: https://docs.bnbchain.org/bnb-opbnb/developers/bep20-crosschain/ # Arbitrary BEP20 Cross-chain You can use the [opBNB bridge](https://opbnb-bridge.bnbchain.org/deposit) or third-party bridges like [zkBridge](https://zkbridge.com/opbnb) and [rhino.fi](https://app.rhino.fi/bridge?token=BNB&chainOut=OPBNB&chain=BINANCE) to easily deposit and withdraw most mainstream BEP20 tokens on BSC. If a token is not supported by these bridges, you have the option to deploy your own L2 mirror token contract on opBNB. This allows for permissionless cross-chain transfer of these tokens. This guide will help you deploy your L2 mirror token contract on opBNB and demonstrate how to use it for transferring tokens between BSC and opBNB. ## Deploying a L2 Mirror Token Contract There is a pre-deployed [OptimismMintableERC20Factory contract](https://github.com/bnb-chain/opbnb/blob/develop/packages/contracts-bedrock/contracts/universal/OptimismMintableERC20Factory.sol) on opBNB that allows you to deploy a L2 token by calling a function of the factory contract. The address of the contract is `0x4200000000000000000000000000000000000012`. The function signature and the emitted event are as follows: ``` /** * @notice Emitted whenever a new OptimismMintableERC20 is created. * * @param localToken Address of the created token on the local chain. * @param remoteToken Address of the corresponding token on the remote chain. * @param deployer Address of the account that deployed the token. */ event OptimismMintableERC20Created( address indexed localToken, address indexed remoteToken, address deployer ); /** * @notice Creates an instance of the OptimismMintableERC20 contract. * * @param _remoteToken Address of the token on the remote chain. * @param _name ERC20 name. * @param _symbol ERC20 symbol. * * @return Address of the newly created token. */ function createOptimismMintableERC20( address _remoteToken, string memory _name, string memory _symbol ) public returns (address) {} ``` `_remoteToken` is the address of the token on the remote chain, which is BSC in this case. `_name` and `_symbol` should be the same with the name and symbol of the token on BSC. The decimal of the token on opBNB is always 18. Here is the [transaction](https://opbnbscan.com/tx/0x4e3da7329cdf0ad67fb82a2a02978518f988125221229747afe90886f7e6512b) that generates the [FDUSD token](https://opbnbscan.com/address/0x50c5725949a6f0c72e6c4a641f24049a917db0cb) on opBNB. **Warning**: It does not support certain BEP20 configurations: - [Fee on transfer tokens](https://github.com/d-xo/weird-erc20#fee-on-transfer) - [Tokens that modify balances without emitting a Transfer event](https://github.com/d-xo/weird-erc20#balance-modifications-outside-of-transfers-rebasingairdrops) ## Cross-chain Transfer with JS SDK Once you have deployed your own L2 mirror token contract, you can use the JS SDK to transfer tokens between BSC and opBNB. The following script is a TypeScript demo script. It uses `ethers.js` and `@eth-optimism/sdk` to transfer tokens between BSC and opBNB. You can save the script as `erc20CrosschainTransfer.ts` and run it with the following command(ensure that you have installed [deno](https://docs.deno.com/runtime/manual#install-deno)): ```bash deno run -A erc20CrosschainTransfer.ts ``` Feel free to modify the script to suit your needs. ```typescript import { Contract, ethers, Signer, Wallet } from "npm:ethers@^5"; import "https://deno.land/x/dotenv/load.ts"; import { CrossChainMessenger, ETHBridgeAdapter } from "npm:@eth-optimism/sdk"; import * as optimismSDK from "npm:@eth-optimism/sdk"; const gwei = BigInt(1e9); const BridgeConfigTestnet = { l1URL: "https://bsc-testnet.bnbchain.org", l2URL: "https://opbnb-testnet-rpc.bnbchain.org", l1ChainID: 97, l2ChainID: 5611, contracts: { AddressManager: "0x0000000000000000000000000000000000000000", StateCommitmentChain: "0x0000000000000000000000000000000000000000", CanonicalTransactionChain: "0x0000000000000000000000000000000000000000", BondManager: "0x0000000000000000000000000000000000000000", L1CrossDomainMessenger: "0xD506952e78eeCd5d4424B1990a0c99B1568E7c2C", L1StandardBridge: "0x677311Fd2cCc511Bbc0f581E8d9a07B033D5E840", OptimismPortal: "0x4386C8ABf2009aC0c263462Da568DD9d46e52a31", L2OutputOracle: "0xFf2394Bb843012562f4349C6632a0EcB92fC8810", }, l1GasPrice: 5n * gwei, l1Explorer: "https://testnet.bscscan.com", l2Explorer: "https://testnet.opbnbscan.com", }; const BridgeConfigMainnet = { l1URL: "https://bsc-dataseed.bnbchain.org", l2URL: "https://opbnb-mainnet-rpc.bnbchain.org", l1ChainID: 56, l2ChainID: 204, contracts: { AddressManager: "0x0000000000000000000000000000000000000000", StateCommitmentChain: "0x0000000000000000000000000000000000000000", CanonicalTransactionChain: "0x0000000000000000000000000000000000000000", BondManager: "0x0000000000000000000000000000000000000000", L1CrossDomainMessenger: "0xd95D508f13f7029CCF0fb61984d5dfD11b879c4f", L1StandardBridge: "0xF05F0e4362859c3331Cb9395CBC201E3Fa6757Ea", OptimismPortal: "0x7e2419F79c9546B9A0E292Fd36aC5005ffed5495", L2OutputOracle: "0x0d61A015BAeF63f6740afF8294dAc278A494f6fA", }, l1GasPrice: 3n * gwei, l1Explorer: "https://bscscan.com", l2Explorer: "https://opbnbscan.com", }; const BridgeConfig = BridgeConfigTestnet; const privateKey = Deno.env.get("PRIVATE_KEY")!; const l1RpcProvider = new ethers.providers.JsonRpcProvider(BridgeConfig.l1URL); const l2RpcProvider = new ethers.providers.JsonRpcProvider(BridgeConfig.l2URL); const wallet = new Wallet(privateKey); const l1Signer = wallet.connect(l1RpcProvider); const l2Signer = wallet.connect(l2RpcProvider); let crossChainMessenger: CrossChainMessenger; const l1BUSDAddr = "0xeD24FC36d5Ee211Ea25A80239Fb8C4Cfd80f12Ee"; const l2BUSDAddr = "0xa9aD1484D9Bfb27adbc2bf50A6E495777CC8cFf2"; function setup() { crossChainMessenger = new CrossChainMessenger({ l1ChainId: BridgeConfig.l1ChainID, l2ChainId: BridgeConfig.l2ChainID, l1SignerOrProvider: l1Signer, l2SignerOrProvider: l2Signer, bedrock: true, contracts: { l1: BridgeConfig.contracts, l2: optimismSDK.DEFAULT_L2_CONTRACT_ADDRESSES, }, }); const ethBridgeAdapter = new ETHBridgeAdapter( { messenger: crossChainMessenger, l1Bridge: BridgeConfig.contracts.L1StandardBridge, l2Bridge: "0x4200000000000000000000000000000000000010", }, ); crossChainMessenger.bridges.ETH = ethBridgeAdapter; } async function depositERC20() { const tx = await crossChainMessenger.depositERC20(l1BUSDAddr, l2BUSDAddr, 1, { overrides: { gasPrice: BridgeConfig.l1GasPrice, }, }); await tx.wait(); console.log( `depositBNB Transaction hash (on L1): ${BridgeConfig.l1Explorer}/tx/${tx.hash}`, ); console.log( `please check ${BridgeConfig.l2Explorer}/address/${l1Signer.address}?tab=deposit&p=1 for the deposit txn on L2`, ); } async function withdrawERC20(): Promise { const tx = await crossChainMessenger.withdrawERC20( l1BUSDAddr, l2BUSDAddr, 1, { overrides: { maxPriorityFeePerGas: 1, maxFeePerGas: 10000, }, }, ); await tx.wait(); console.log( `withdrawBNB Transaction hash (on L2): ${BridgeConfig.l2Explorer}/tx/${tx.hash}`, ); return tx.hash; } async function proveWithdrawal(hash: string, wait: boolean = true) { while (true) { try { const tx = await crossChainMessenger.proveMessage(hash, { overrides: { gasPrice: BridgeConfig.l1GasPrice, }, }); await tx.wait(); console.log( `proveWithdrawal Transaction hash (on L1): ${BridgeConfig.l1Explorer}/tx/${tx.hash}`, ); break; } catch (error) { console.log(error.message); if (error.message.includes("state root for message not yet published")) { if (wait) { console.log( `Waiting for status to be READY_TO_PROVE, current time: ${new Date()}`, ); } else { throw error; } } else { throw error; } } } } async function finalizeWithdrawal(hash: string, wait: boolean = true) { while (true) { try { const tx = await crossChainMessenger.finalizeMessage(hash, { overrides: { gasPrice: BridgeConfig.l1GasPrice, }, }); await tx.wait(); console.log( `finalizeWithdrawal Transaction hash (on L1): ${BridgeConfig.l1Explorer}/tx/${tx.hash}`, ); break; } catch (error) { if ( error.message.includes( "proven withdrawal finalization period has not elapsed", ) ) { if (wait) { console.log( `Waiting for status to be READY_TO_FINALIZE, current time: ${new Date()}`, ); } else { throw error; } } else { throw error; } } } } async function main() { console.log("opbnbBridge demo"); setup(); // deposit ERC20 await depositERC20() // withdraw ERC20 const hash = await withdrawERC20(); await proveWithdrawal(hash); await finalizeWithdrawal(hash); } await main(); ``` --- ## Geth P2P Sync Feature > Source: https://docs.bnbchain.org/bnb-opbnb/developers/geth-sync/ # Geth P2P Sync Feature We're excited to introduce a new feature in this release: The Geth P2P Sync Feature. This feature significantly enhances the speed of block data synchronization by leveraging peer-to-peer syncing among geth nodes, as opposed to the previous method of deriving transactions from L1 for each synchronization. ## Benefits of Geth P2P Sync Feature The Geth P2P Sync Feature greatly accelerates block data synchronization. Our tests on the testnet have shown impressive results: * In `full` mode, the sync time has been reduced from the previous 7 days to approximately 15 hours. * In `snap` mode, syncing can be accomplished in about 1 hour. These improvements can save considerable time and resources, thus improving the overall performance of your operations. ## Configurations for Geth P2P Sync Feature ### New Configurations (op-node) * `l2.engine-sync=true` * `l2.skip-sync-start-check = true` The above settings are essential for enabling the Geth P2P Sync Feature. Please ensure that these settings are correctly configured in your op-node. ### Existing Configurations (op-geth) * `syncmode=snap/full` * `bootnodes=${bootnode_addr}` You can select either of the two options for the `syncmode`: 1. `full` (Recommended): This mode performs a full sync and executes each block. The sync time has been significantly reduced with the new Geth P2P Sync Feature, taking about 15 hours on the testnet (latest height: 10 million). 2. `snap`: This mode performs a snapshot sync, which does not execute transactions but still maintains data completeness. This mode is recommended when your P2P peer nodes are trustworthy. The sync time is about 1 hour on the testnet. For the `bootnodes` configuration, you can use the following geth bootnode nodes: * Testnet * `enr:-KO4QKFOBDW--pF4pFwv3Al_jiLOITj_Y5mr1Ajyy2yxHpFtNcBfkZEkvWUxAKXQjWALZEFxYHooU88JClyzA00e8YeGAYtBOOZig2V0aMfGhE0ZYGqAgmlkgnY0gmlwhDREiqaJc2VjcDI1NmsxoQM8pC_6wwTr5N2Q-yXQ1KGKsgz9i9EPLk8Ata65pUyYG4RzbmFwwIN0Y3CCdl-DdWRwgnZf` * `enr:-KO4QFJc0KR09ye818GT2kyN9y6BAGjhz77sYimxn85jJf2hOrNqg4X0b0EsS-_ssdkzVpavqh6oMX7W5Y81xMRuEayGAYtBSiK9g2V0aMfGhE0ZYGqAgmlkgnY0gmlwhANzx96Jc2VjcDI1NmsxoQPwA1XHfWGd4umIt7j3Fc7hKq_35izIWT_9yiN_tX8lR4RzbmFwwIN0Y3CCdl-DdWRwgnZf` * Mainnet * `enr:-KO4QHs5qh_kPFcjMgqkuN9dbxXT4C5Cjad4SAheaUxveCbJQ3XdeMMDHeHilHyqisyYQAByfdhzyKAdUp2SvyzWeBqGAYvRDf80g2V0aMfGhHFtSjqAgmlkgnY0gmlwhDaykUmJc2VjcDI1NmsxoQJUevTL3hJwj21IT2GC6VaNqVQEsJFPtNtO-ld5QTNCfIRzbmFwwIN0Y3CCdl-DdWRwgnZf` * `enr:-KO4QKIByq-YMjs6IL2YCNZEmlo3dKWNOy4B6sdqE3gjOrXeKdNbwZZGK_JzT1epqCFs3mujjg2vO1lrZLzLy4Rl7PyGAYvRA8bEg2V0aMfGhHFtSjqAgmlkgnY0gmlwhDbjSM6Jc2VjcDI1NmsxoQNQhJ5pqCPnTbK92gEc2F98y-u1OgZVAI1Msx-UiHezY4RzbmFwwIN0Y3CCdl-DdWRwgnZf` Ensure the above configurations are correctly set up to fully benefit from the new Geth P2P Sync Feature in this release. We hope you find this feature advantageous. Your feedback is always welcome. --- ## Developers Cheat Sheet > Source: https://docs.bnbchain.org/bnb-opbnb/developers/cheat-sheet/ # Hardware Requirements Setting up a node in the BNB Chain ecosystem requires understanding hardware requirements. The Minimum Hardware Requirement ensures efficient management of average transaction volumes, while the Recommended Hardware Requirement caters to high performance, capable of processing up to 100 million gas per second and handling 1k QPS (Query Per Second), ideal for heavy transaction loads or peak efficiency. ## Processor CPU Type: Intel Xeon Scalable processors (Ice Lake) or newer **op-node:** - Minimum: 4 cores - Recommended: 8 cores or more **op-geth:** - Minimum: 12 cores - Recommended: 16 cores or more ## Memory **op-node:** - Minimum: 4 GB - Recommended: 16 GB **op-geth:** - Minimum: 10 GB - Recommended: 32 GB ## Storage **op-node:** - No additional permanent storage required **op-geth:** - Requires 3000 IOPS or above - 1TB or more for extended transaction history ## Network - Stable network with 125MB/s or higher bandwidth # Running Your Own opBNB Node - Local development node setup: [Running a Local Development Environment](../advanced/local-dev-env.md) - Mainnet/testnet node setup: [Running a Local Node](../advanced/local-node.md) - Smart Contract Verification: [opBNBScan Verify with Hardhat & Truffle](../advanced/verify-on-opbnbscan.md) # Performance Stability Optimization **L1 RPC Configuration:** Configure multiple L1 RPC endpoints for op-node setups on L2 solutions like opBNB to ensure synchronization with the L1 chain, security, data integrity, and reduced risk of single point of failure. For example: ```bash export L1_RPC1=https://bsc-dataseed.bnbchain.org export L1_RPC2=https://bsc-dataseed2.bnbchain.org --l1=rpc1,rpc2… ``` Optimize L1 receipt retrieval performance - **op-node:** `--l1.rpckind=bsc_fullnode` **L2 Sync Mode Settings:** - **op-geth:** `--gcmode=archive` - **op-node:** `--l2.engine-sync=true` # Node Health Monitoring ## Import JSON Model Monitor your node's health by importing the [rpc_nodes.json](./rpc_nodes.json) model. ## Important Metrics - **chain_head_header:** Indicates the current unsafe block number of the node. A non-increasing number suggests syncing issues; a decreasing number indicates reorgs. - **rpc_duration_all:** Histogram of RPC server request durations. - **rpc_requests:** Total requests to the RPC server. - **p2p_peers:** Number of peers connected to op-geth. Essential for syncing through the engine. If zero, the op-geth cannot sync. - **op_node_default_peer_count:** Number of peers connected to op-node. Without peers, the op-node cannot sync unsafe blocks, leading to lag behind the sequencer due to reliance on L1 syncing. --- --- ## Local Development > Source: https://docs.bnbchain.org/bnb-opbnb/advanced/local-dev-env/ # Running a local development environment Install and start the entire opbnb system locally, including L1 (BNB Smart Chain) and L2 development nodes. Running a local development environment is a great way to test the behavior of your code and contracts. ## How to do it 1. Make sure the following software is installed: golang, nodejs 16+, make, pnpm, python3, docker, foundry, poetry, jq Tips: Install Foundry by following [the instructions located here](https://getfoundry.sh/). Please make sure your Foundry version matches the one described in opbnb/versions.json. If they do not match, please use a command such as `foundryup -C xxxxxx` to modify it. 2. Clone opbnb monorepo: ```shell git clone git@github.com:bnb-chain/opbnb.git cd opbnb ``` 3. Running `pnpm install` and then running `pnpm build`. 4. Running `make devnet-up` and wait for the docker container to start.(The first run will be relatively slow because it needs to download the image and deploy the contract, and then it will be fast) 5. Through the `docker ps` command, you can see that 5 containers have been started: `ops-bedrock_l1_1`, `ops-bedrock_l2_1`, `ops-bedrock_op-node_1`, `ops-bedrock_op-batcher_1`, `ops-bedrock_op-proposer_1` Now L1 is accessible at `http://localhost:8545`, and L2 is accessible at `http://localhost:9545` ## Stop or clean To stop, run (in the root directory of the monorepo) `make devnet-down`. To clean everything, run (in the root directory of the monorepo) `make devnet-clean`. To view logs, run `make devnet-logs` # Notes 1. When executing for the first time, please be patient if you see the message "Waiting for RPC server at...", as the BSC network takes time to initialize. 2. If you encounter an error during the "Deploying contracts" step, please try again as it usually recovers. ## Additional Information L1 chain ID is `714`. L2 chain ID is `901`. L1 test account: - address: `0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266` - Private key: `ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80` L2 test account: - Address: `0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266` - Private key: `ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80` --- ## Build a Full Stack dApp on opBNB > Source: https://docs.bnbchain.org/bnb-opbnb/advanced/full-stack-dapp/ # Create a Full Stack dapp using Truffle and React on opBNB In this tutorial, we'll deploy a simple HelloWorld smart contract on opBNB and build a Web3 frontend using React to interact with the deployed smart contract, i.e., read from and write to the opBNB blockchain. ## What are we building opBNB is essentially an optimized layer-2 solution that delivers lower fees and higher throughput to unlock the full potential of the BNB Chain. For this tutorial, we will deploy a simple `HelloWorld` smart contract on the opBNB network and build a frontend using Reactjs to interact with the deployed smart contract for reading and writing data onto the opBNB blockchain. The `HelloWorld` smart contract is a simple string variable message that will be used for storing the user-defined messages, e.g., `Hello, opBNB User`. The `updateMessage` function will be used for updating the message variable to any user-defined string value. This smart contract will then be deployed on the opBNB network using [Truffle IDE](https://trufflesuite.com/). We will then use the [Reactjs boilerplate](https://create-react-app.dev/) to build a front end to communicate with the smart contract. [Web3.js library](https://web3js.readthedocs.io/en/v1.10.0/#) is used for interacting with the smart contract and reading and writing data to the opBNB blockchain. We further use [TrustWallet](https://trustwallet.com/) or [Metamask](https://metamask.io/) for signing transactions and paying any gas costs. *This is a basic example for educational purposes, and it assumes familiarity with [Truffle](https://trufflesuite.com/), [React](https://react.dev/), [TrustWallet](https://trustwallet.com/), and [MetaMask](https://metamask.io/).* ## Learning Takeaways By the end of this tutorial, you will be able to achieve the following - Use Truffle IDE to spin up a project template and write, compile, and deploy a simple smart contract on the opBNB. - Create a front end for interacting with the deployed smart contract using ReactJS. - Interact with smart contracts deployed on opBNB via ReactJS frontend using Web3.js library. ## Pre-requisites - [Node.js (Node v18.14.2)](https://nodejs.org/en/download/) - [TrustWallet](https://trustwallet.com/) - [Metamask Web Wallet](https://metamask.io/) - [Truffle v5.10.0](https://trufflesuite.com/docs/truffle/how-to/install/) - Get tBNB in your wallet configured with opBNB Testnet - [Wallet Configuration for opBNB.](../get-started/wallet-configuration.md) - [Deposit tBNB to your opBNB account](../get-started/deposit-to-opbnb.md) ## Demo Step-by-Step Guide For this tutorial, we will be using Truffle IDE to develop, compile and deploy a simple `HelloWorld` smart contract on the opBNB network. For building the front end, we will be using the `create-react-app` React boilerplate. Further, to connect our dapp to the web3 world, we will be using the Metamask wallet. ### Step 1: Set up the project 1. Make sure you have Node.js and npm installed on your machine. 2. Install Truffle globally by running the following command ```shell npm install -g truffle ``` 3. Create a new directory for your project and navigate into it ```shell mkdir HelloWorldDapp cd HelloWorldDapp ``` 4. Initialize a new Truffle project. Create a [bare Truffle project](https://trufflesuite.com/docs/truffle/getting-started/creating-a-project.html) which generates the required directory structure to test and deploy contracts: ```shell truffle init ``` Truffle creates the following directory structure for your project: - `contracts/`: directory for your [Solidity contracts](https://trufflesuite.com/docs/truffle/getting-started/interacting-with-your-contracts). - `migrations/`: directory for the [scriptable deployment files](https://trufflesuite.com/docs/truffle/getting-started/running-migrations#migration-files). - `test/`: directory for files that [test your application and contracts](https://trufflesuite.com/docs/truffle/testing/testing-your-contracts). - `truffle-config.js`: the Truffle [configuration file](https://trufflesuite.com/docs/truffle/reference/configuration). 5. Install Create React App globally by running the following command ```shell npm install -g create-react-app ``` 6. Create the React app frontend using the following command ```shell npx create-react-app frontend ``` 7. Navigate into the client directory using the following command ```shell cd frontend ``` ### Step#2: Install `hdwallet-provider​` `hdwallet-provider` is a separate package that signs transactions for addresses derived from a 12 or 24-word mnemonic. By default, the `hdwallet-provider` uses the first address generated from the mnemonic. However, this is configurable. For more information, refer to the Truffle `hdwallet-provider` repository. Run the following command to install `hdwallet-provider` ```shell npm install @truffle/hdwallet-provider ``` ### Step#3: Create the `.env` file​ - Install the `dotenv` package using the following command ```shell npm install dotenv ``` - Create a file named `.env` in your project directory to store the Metamask Secret Phrase. Refer to the MetaMask instructions on [how to reveal a secret recovery phrase](https://metamask.zendesk.com/hc/en-us/articles/360015290032-How-to-Reveal-Your-Seed-Phrase). ```js MNEMONIC = ""; ``` - Ensure you replace the following values in the `.env` file - `` with the mnemonic of your MetaMask wallet. This phrase is used by the [Truffle hdwallet-provider](https://github.com/trufflesuite/truffle/tree/develop/packages/hdwallet-provider) to sign transactions. *Never disclose your secret recovery phrase. Anyone with your recovery phrase can steal any assets held in your wallet.* ### Step#4: Create the smart contract Inside the contracts directory, create a new file named `HelloWorld.sol` and add the following code ```jsx // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; contract HelloWorld { string public message; constructor(string memory _message) { message = _message; } function updateMessage(string memory _newMessage) public { message = _newMessage; } } ``` ### Step#5: Configure Truffle for use with opBNB 1. Open the `truffle-config.js` file and add the following code: ```jsx const HDWalletProvider = require("@truffle/hdwallet-provider"); // create a file at the root of your project and name it .env -- there you can set process variables // like the mnemonic etc. Note: .env is ignored by git to keep your private information safe require("dotenv").config(); const mnemonic = process.env["MNEMONIC"].toString().trim(); module.exports = { networks: { development: { host: "127.0.0.1", // Localhost (default: none) port: 8545, // Standard Ethereum port (default: none) network_id: "*", // Any network (default: none) }, opBNBTestnet: { provider: () => new HDWalletProvider( mnemonic, `https://opbnb-testnet-rpc.bnbchain.org` ), network_id: 5611, confirmations: 3, timeoutBlocks: 200, skipDryRun: true, }, }, // Set default mocha options here, use special reporters etc. mocha: { // timeout: 100000 }, // Configure your compilers compilers: { solc: { version: "0.8.19", }, }, }; ``` ### Step#6: Deploy the smart contract on opBNB 1. In the root directory of your project, create a new file named `1_deploy_contract.js` inside the `migrations` directory and add the following code: ```jsx const HelloWorld = artifacts.require("HelloWorld"); module.exports = function (deployer) { deployer.deploy(HelloWorld, "Hello, World!"); }; ``` 2. Deploy the smart contract to the opBNB testnet by running the following command ```shell truffle migrate --network opBNBTestnet ``` ### Step#7: Set up the React frontend 1. Inside the `frontend/src` directory, replace the contents of the `App.js` file with the following code: ```jsx import React, { useEffect, useState } from "react"; import Web3 from "web3"; import HelloWorldContract from "./contracts/HelloWorld.json"; import "./App.css"; function App() { const [contract, setContract] = useState(null); const [message, setMessage] = useState(""); const [newMessage, setNewMessage] = useState(""); const [loading, setLoading] = useState(false); useEffect(() => { const loadBlockchainData = async () => { try { const web3 = new Web3(window.ethereum); const networkId = await web3.eth.net.getId(); const deployedNetwork = HelloWorldContract.networks[networkId]; const instance = new web3.eth.Contract( HelloWorldContract.abi, deployedNetwork && deployedNetwork.address ); setContract(instance); } catch (error) { console.error(error); } }; loadBlockchainData(); }, []); const getMessage = async () => { if (contract) { try { setLoading(true); const message = await contract.methods.message().call(); setMessage(message); } catch (error) { console.error(error); } finally { setLoading(false); } } }; const updateMessage = async () => { if (contract && newMessage !== "") { try { setLoading(true); await contract.methods .updateMessage(newMessage) .send({ from: (await window.ethereum.enable())[0] }); setNewMessage(""); } catch (error) { console.error(error); } finally { setLoading(false); } } }; return ( ); } export default App; ``` 2. Replace the contents of the `App.css` file with the following code: ```css .App { text-align: center; } .header { background-color: #f3ba2f; min-height: 20vh; display: flex; flex-direction: column; align-items: center; justify-content: center; font-size: calc(40px + 2vmin); color: white; } .content { display: flex; justify-content: center; align-items: center; padding: auto; text-align: center; } .message, .update { padding: auto; margin: 20px; } .messageValue { color: whitesmoke; font-size: large; } .inputMessage { float: center; padding: 10px; width: 100%; font-family: "IBM Plex Sans", "Raleway", "Source Sans Pro", "Arial"; } button { float: center; margin: 1em 0; padding: 10px 3em; font-weight: bold; max-width: fit-content; font-family: "IBM Plex Sans", "Raleway", "Source Sans Pro", "Arial"; } body { background-color: #292929; color: #f3ba2f; align-items: center; font-family: "IBM Plex Sans", "Raleway", "Source Sans Pro", "Arial"; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } ``` ### Step#8: Start the development server 1. In the frontend directory, install the required dependencies by running the following command ```shell npm install ``` 2. Start the React development server: ```shell npm start ``` 3. Visit `http://localhost:3000` in your browser, and you should see the `HelloWorld` dApp with the current message and the ability to update it. *Make sure you have the MetaMask extension installed and set to the opBNB testnet.* 4. When you enter a new message and click the update button, if your dapp is already not connected to Metamask wallet, you will get a Metamask notification asking for permission to connect your wallet to the dapp. 5. It will also ask for your confirmation to confirm the transaction. Proceed by clicking the confirm button. 6. Once the transaction is confirmed, click the `Refresh` button to load the new message. ## Conclusion In this tutorial, we provided a step-by-step guide on how to develop, deploy, and interact with a smart contract on the opBNB network. We used the Truffle IDE for compiling and deploying the smart contract. We also build a React frontend to interact with the deployed smart contract, i.e., read from and write to the opBNB blockchain. --- ## Verify Smart Contract on opBNBScan explorer > Source: https://docs.bnbchain.org/bnb-opbnb/advanced/verify-on-opbnbscan/ # Use opBNBScan to verify your contract via Hardhat and Truffle opBNBScan provides a convenient and user-friendly platform for developers to verify their smart contracts using popular developer tools like Truffle and Hardhat. Here are the step-by-step instructions to get started with opBNBScan's smart contract verification APIs. 1. Go to the [NodeReal](http://nodereal.io) portal and click the **Login** button. 2. Login with your github account or discord account. 3. And create your API key by clicking the **create new key** button. 4. Copy your API key to your clipboard and and use it as your key of smart verification contract APIs. ## **Hardhat** You can use the [hardhat-verify](https://hardhat.org/hardhat-runner/docs/guides/verifying) plugin to verify your deployed smart contract. You can follow the steps in the hardhat document. Below is an example of how to configure your hardhat.config.js. Pay attention to the network's configuration settings, and replace the corresponding settings that meet your requirements. ```typescript require("@nomicfoundation/hardhat-toolbox"); require("@nomicfoundation/hardhat-verify"); /** @type import('hardhat/config').HardhatUserConfig */ module.exports = { solidity: "0.8.19", //replace your own solidity compiler version networks: { opbnb: { url: "https://opbnb-testnet-rpc.bnbchain.org/", chainId: 5611, // Replace with the correct chainId for the "opbnb" network accounts: ["{{YOUR-PRIVATE-KEY}}"], // Add private keys or mnemonics of accounts to use gasPrice: 20000000000, }, }, etherscan: { apiKey: { opbnb: "{{YOUR-NODEREAL-API-KEY}}", //replace your nodereal API key }, customChains: [ { network: "opbnb", chainId: 5611, // Replace with the correct chainId for the "opbnb" network urls: { apiURL: "https://open-platform.nodereal.io/{{YOUR-NODEREAL-API-KEY}}/op-bnb-testnet/contract/", browserURL: "https://testnet.opbnbscan.com/", }, }, ], }, }; ``` ## **Truffle** You can also use truffle to verify your smart contract on opBNBScan. Please make sure the truffle-plugin-verify is installed correctly, and in the plugin, add the 'truffle-plugin-verify' ```typescript module.exports = { plugins: [ 'truffle-plugin-verify' ], networks: { development: { host: "127.0.0.1", // Localhost (default: none) port: 8545, // Standard port (default: none) network_id: "*", // Any network (default: none) }, dashboard: { verify: { apiUrl: 'https://open-platform.nodereal.io/{{YOUR-NODEREAL-API-KEY}}/op-bnb-testnet/contract/', apiKey: '{{YOUR-NODEREAL-API-KEY}}', explorerUrl: 'https://testnet.opbnbscan.com/', }, host: "127.0.0.1", port: 24012, network_id: "*" }, }, // Set default mocha options here, use special reporters, etc. mocha: { // timeout: 100000 }, // Configure your compilers compilers: { solc: { version: "0.8.15", // Fetch exact version from solc-bin (default: truffle's version) } }, ``` Make sure your smart contract is deployed first. I am using the dashboard to avoid saving your private credentials to your local machine. ```shell npx truffle migrate –network dashboard ``` And then you can verify your smart contract by specifying your contract name ```shell npx truffle run verify {{Your-Contract-Name}} --network dashboard ``` Then you can go to the [opBNBScan explorer](https://testnet.opbnbscan.com/address/0x57996bA7FC3F0C61E7A949ac050b9E2437eA1972?p=1&tab=Contract) to check if your smart contract has been verified. !!!info For the mainnet contract verification, please change the following URLs: url: "https://opbnb-testnet-rpc.bnbchain.org/" change to "https://opbnb-mainnet-rpc.bnbchain.org/" apiUrl: 'https://open-platform.nodereal.io/{{YOUR-NODEREAL-API-KEY}}/op-bnb-testnet/contract/' change to 'https://open-platform.nodereal.io/{{YOUR-NODEREAL-API-KEY}}/op-bnb-mainnet/contract/' --- ## Node Best Practices > Source: https://docs.bnbchain.org/bnb-opbnb/advanced/node-best-practices/ # Best Practices for opBNB Node Configuration ## Selecting the Appropriate Mode and Storage Scheme opBNB accommodates various node modes: Full, Fast, and Archive. Two storage schemes are available: HBSS (Hash-Based Scheme Storage) and PBSS (Path-Based Scheme Storage). The principal distinctions between them lie in their methods of preserving history trie data. The Merkle Patricia Trie (MPT), an advanced data structure, is adept at storing and retrieving key-value pairs with efficiency. It amalgamates the principles of a Patricia trie and a Merkle tree to forge a secure and immutable representation of data within the Ethereum Virtual Machine (EVM). The MPT endows the following capabilities: - Access to historical data: Enables retrieval of an account's balance at a specified block height, simulation of calls, and debugging of traces at particular block heights, among others. - Verification of Inclusion and Exclusion: The MPT facilitates proofs of both inclusion and exclusion of key-value pairs, a pivotal feature for transaction verification and blockchain integrity maintenance. Nevertheless, the preservation of entire history trie data on disk can demand substantial resources and may be superfluous for certain applications. opBNB introduces diverse node modes and storage schemes to accommodate a range of requirements. The variances between the modes and storage schemes are encapsulated as follows: - Archive node mode conserves the complete history trie data. Full node mode archives recent trie data (128 blocks), whereas the fast node mode retains only the current state, excluding trie data. - Functions such as block, transaction, receipt, and log retrieval are supported across all node modes. Since block data is preserved in the block database, it remains unaffected by the trie data storage scheme. - The capability to access historical state data varies by node mode. Archive nodes support comprehensive historical state data retrieval, whereas full and fast nodes facilitate access to recent 128 blocks' state data. - Trie data-dependent functions like `eth_getProof`, `eth_getStorageAt`, etc., are fully supported by Archive nodes. Full nodes offer queries for recent 128 blocks, whereas fast nodes lack this support. - Specifically, given that the transfer from Layer 2 to Layer 1 necessitates `eth_getProof` data corresponding to the most recent root hash height, we have implemented certain enhancements within the full node configuration to facilitate `eth_getProof` for the latest root hash height, irrespective of it surpassing the 128-block threshold. Should you require the utilization of your personal node for the assembly of withdrawal proof, the full node mode is at your disposal. - PBSS archives trie nodes on disk utilizing encoded paths and specific key prefixes as keys. This method permits PBSS's Merkle Patricia Trie (MPT) to supersede older data due to the shared key between the account trie and storage trie, enabling **online pruning** and significantly **diminishing data redundancy**. - Archive node mode is only compatible with HBSS, whereas Full and Fast node modes support both HBSS and PBSS. - For further details, please consult the [PBSS document](./run-with-pebbledb-and-pbss.md). Comparative Analysis of Node Modes and Storage Schemes: | **Mode** | **Full Node (PBSS)** | **Full Node (HBSS)** | **Fast Node** | **Archive Node** | |--------------------------------|----------------------|----------------------|----------------------------------------------------------|------------------| | **Preserve Trie Nodes** | Latest 128 blocks | Latest 128 blocks | None | All | | **Disk Consumption** | Moderate-Low | Moderate-High | Lowest | Highest | |**Auto Prune History Trie Data**| Yes | No | Not Applicable | Not Applicable | | **Performance** | Moderate-High | Moderate-Low | Highest | Lowest | | **Security** | High | High | Lower than others since it doesn't verify the state root | High | ### Fast Node For most applications, operating a fast node is advisable. This mode maintains only the current state, sans trie data, making it suitable for tasks such as querying the current state and processing transactions. To activate the fast node, include `--allow-insecure-no-tries` in the `op-geth` startup command. ``` ./geth --config ./config.toml --datadir ./node --syncmode full --allow-insecure-no-tries ``` To prune the MPT state (e.g., when transitioning from a full to a fast node), prune the node as follows: ``` ./geth db delete-trie-state --datadir ./datadir ``` *Fast Node does not generate Trie Data when syncing. Once the Fast Node is running, there is no way to switch back to Full Node. Need to re-download snapshot data to restore it to Full Node.* For implementation details and further information, refer to [the PR](https://github.com/bnb-chain/op-geth/pull/75). ### Full Node Operating a full node is recommended if you require: - Enhanced security and reliability assurances. The full node meticulously executes and locally verifies all blocks. - The facility to query trie data of the most recent 128 blocks, such as retrieving an account's balance at a specific block height, simulating calls, and debugging traces. To enable the full node, set the `--syncmode full` flag in the `geth` command. It is particularly advised to operate a full node with PBSS and pebble to minimize data redundancy and enhance performance. ``` --state.scheme path --db.engine pebble ``` For comprehensive details, consult the [PBSS document](./run-with-pebbledb-and-pbss.md). ## Snapshots The latest snapshot data is accessible via the [opbnb-snapshot](https://github.com/bnb-chain/opbnb-snapshot) repository. Employing snapshot data can drastically curtail the time required for node synchronization. ## Performance Optimization In order to enhance the performance of `op-geth`, it is crucial to configure the cache settings appropriately. Allocating approximately one-third of the physical memory to the cache is advisable. For instance, if the system has 64GB of physical memory, the cache setting can be configured as: ``` --cache 20000 ``` This allocation ensures that the cache is optimized for efficient use of system resources, ultimately leading to improved performance of `op-geth`. ## Running Server as a Daemon To ensure continuous operation, it is important to keep `op-node` and `op-geth` running at all times. One of the simplest and recommended solutions is to register them as systemd service. By doing so, they will automatically start upon system reboots and other relevant events, ensuring seamless operation without manual intervention. ## Security ### Securing Your Full Node RPC from Hackers It is imperative to safeguard your Full Node RPC endpoints from unauthorized access. Exposing RPC endpoints to the public network can pose security risks, making it essential to restrict access and implement appropriate security measures to prevent unauthorized intrusion. ### Software Vulnerabilities To ensure the security of your node and assets, it is crucial to download software only from official sources. Additionally, it is important to consistently update the software to the latest, most secure version available. By adhering to these practices, you can mitigate the risk of potential vulnerabilities and safeguard your node and assets from security threats. ## FAQ ### Why does my node experience offline status or block height lag after an abrupt termination? After running a synchronized node for an extended period of time, abruptly terminating the node(op-geth process) can result in a period of offline status upon restart. Specifically, only archived nodes are expected to quickly re-synchronize after such an event. The reason for this behavior lies in the nature of Geth's functionality. When Geth experiences a crash or is not shut down gracefully, the recent state that was held in memory is lost and must be regenerated. As a result, it can take Geth a considerable amount of time to restore these states. The root cause of this prolonged restoration process can be attributed to the fact that Geth does flush the state trie periodically. The frequency of this flushing is defined by the trieTimeout parameter in the configuration file (config.toml). This periodic flushing is intended to maintain consistency and integrity within the node's state, but it also contributes to the time required for state regeneration in the event of an abrupt shutdown. --- ## Local Node > Source: https://docs.bnbchain.org/bnb-opbnb/advanced/local-node/ # Running a Local Testnet or Mainnet Node If you're looking to build an app on opBNB you'll need access to an opBNB node. You can simply use the public rpc(Testnet: , Mainnet: ) or run your own node. This guide will walk you through setting up your own Testnet/Mainnet node. ## Hardware requirements Replicas must store the transaction history of opBNB and run Geth. For optimal performance, they should be powerful machines (real or virtual) with at least 16 GB RAM and an SSD drive with 500 GB free space (for production network). ### Fast Node For users that just to run normal rpc node without debug functions, you can run the fast node which has faster sync speed and less hardware requirements. The fast node don't have MPT states and only use the snapshot to sync the latest state. The security is not as good as the full node, but it's enough for most of the users and validated in many production nodes. The advantage of the fast node is that it's faster to sync for it doesn't need to calculate the MPT states and store and query the MPT trees. You can start the fast node with the flags `--allow-insecure-no-tries`. The gc mode should not be `archive` if you start with the fast node. For more information, you can refer to the [fast node pr](https://github.com/bnb-chain/op-geth/pull/75). ## Run with Docker There are official Docker images available for the opBNB node. You can use the latest versions of these images from the following links: - [op-node](https://github.com/bnb-chain/opbnb/pkgs/container/op-node) - [op-geth](https://github.com/bnb-chain/op-geth/pkgs/container/op-geth) Additionally, you can find a docker-compose file example in this [repository](https://github.com/bnb-chain/opbnb-node-docker) to run the opBNB node with Docker. This allows you to set up a Testnet/Mainnet node quickly, within minutes. If you use different infrastructure providers, please consult the docker-compose file and adjust the configuration as needed. ## Run with Binaries ### Build op-node and op-geth dependencies - golang 1.20+ - make - git - gcc - libc-dev You can refer to the Docker files for Alpine Linux: [op-node](https://github.com/bnb-chain/opbnb/blob/develop/op-node/Dockerfile) and [op-geth](https://github.com/bnb-chain/op-geth/blob/develop/Dockerfile). If you are using a different OS, please find the alternative packages for your OS. ```bash export OPBNB_WORKSPACE=/tmp/opbnb mkdir -p $OPBNB_WORKSPACE cd $OPBNB_WORKSPACE git clone https://github.com/bnb-chain/opbnb.git cd opbnb/op-node git checkout develop make op-node mkdir -p $OPBNB_WORKSPACE/op-node-data cp ./bin/op-node $OPBNB_WORKSPACE/op-node-data cd $OPBNB_WORKSPACE git clone https://github.com/bnb-chain/op-geth.git cd op-geth git checkout develop make geth mkdir -p $OPBNB_WORKSPACE/op-geth-data cp ./build/bin/geth $OPBNB_WORKSPACE/op-geth-data/op-geth ``` ### Data Preparation ```bash cd $OPBNB_WORKSPACE # for testnet cp $OPBNB_WORKSPACE/opbnb/assets/testnet/genesis.json $OPBNB_WORKSPACE/op-geth-data # for mainnet # cp $OPBNB_WORKSPACE/opbnb/assets/mainnet/genesis.json $OPBNB_WORKSPACE/op-geth-data openssl rand -hex 32 > jwt.txt cp jwt.txt $OPBNB_WORKSPACE/op-geth-data cp jwt.txt $OPBNB_WORKSPACE/op-node-data # init op-geth genesis cd $OPBNB_WORKSPACE/op-geth-data mkdir datadir ./op-geth --datadir ./datadir init genesis.json ``` ### Start components op-geth ```bash #! /usr/bin/bash cd $OPBNB_WORKSPACE/op-geth-data # for testnet export CHAIN_ID=5611 export L2_RPC=https://opbnb-testnet-rpc.bnbchain.org export P2P_BOOTNODES="enr:-KO4QKFOBDW--pF4pFwv3Al_jiLOITj_Y5mr1Ajyy2yxHpFtNcBfkZEkvWUxAKXQjWALZEFxYHooU88JClyzA00e8YeGAYtBOOZig2V0aMfGhE0ZYGqAgmlkgnY0gmlwhDREiqaJc2VjcDI1NmsxoQM8pC_6wwTr5N2Q-yXQ1KGKsgz9i9EPLk8Ata65pUyYG4RzbmFwwIN0Y3CCdl-DdWRwgnZf,enr:-KO4QFJc0KR09ye818GT2kyN9y6BAGjhz77sYimxn85jJf2hOrNqg4X0b0EsS-_ssdkzVpavqh6oMX7W5Y81xMRuEayGAYtBSiK9g2V0aMfGhE0ZYGqAgmlkgnY0gmlwhANzx96Jc2VjcDI1NmsxoQPwA1XHfWGd4umIt7j3Fc7hKq_35izIWT_9yiN_tX8lR4RzbmFwwIN0Y3CCdl-DdWRwgnZf" # for mainnet # export CHAIN_ID=204 # export L2_RPC=https://opbnb-mainnet-rpc.bnbchain.org # export P2P_BOOTNODES="enr:-KO4QHs5qh_kPFcjMgqkuN9dbxXT4C5Cjad4SAheaUxveCbJQ3XdeMMDHeHilHyqisyYQAByfdhzyKAdUp2SvyzWeBqGAYvRDf80g2V0aMfGhHFtSjqAgmlkgnY0gmlwhDaykUmJc2VjcDI1NmsxoQJUevTL3hJwj21IT2GC6VaNqVQEsJFPtNtO-ld5QTNCfIRzbmFwwIN0Y3CCdl-DdWRwgnZf,enr:-KO4QKIByq-YMjs6IL2YCNZEmlo3dKWNOy4B6sdqE3gjOrXeKdNbwZZGK_JzT1epqCFs3mujjg2vO1lrZLzLy4Rl7PyGAYvRA8bEg2V0aMfGhHFtSjqAgmlkgnY0gmlwhDbjSM6Jc2VjcDI1NmsxoQNQhJ5pqCPnTbK92gEc2F98y-u1OgZVAI1Msx-UiHezY4RzbmFwwIN0Y3CCdl-DdWRwgnZf" ./op-geth \ --datadir="./datadir" \ --verbosity=3 \ --http \ --http.corsdomain="*" \ --http.vhosts="*" \ --http.addr=0.0.0.0 \ --http.port=8545 \ --http.api=net,eth,engine \ --ws \ --ws.addr=0.0.0.0 \ --ws.port=8545 \ --ws.origins="*" \ --ws.api=eth,engine \ --syncmode=full \ --maxpeers=10 \ --networkid=$CHAIN_ID \ --triesInMemory=32 \ --txpool.globalslots=20000 \ --txpool.globalqueue=5000 \ --txpool.accountqueue=64 \ --txpool.accountslots=16 \ --txpool.pricelimit=1 \ --txpool.nolocals=true \ --pathdb.nodebuffer=list \ --pathdb.proposeblock=3600 \ --cache 6000 \ --cache.preimages \ --journalfile \ --history.transactions=0 \ --allow-insecure-unlock \ --authrpc.addr="0.0.0.0" \ --authrpc.port="8551" \ --authrpc.vhosts="*" \ --authrpc.jwtsecret=./jwt.txt \ --gcmode=archive \ --metrics \ --metrics.port 6060 \ --metrics.addr 0.0.0.0 \ --rollup.sequencerhttp=$L2_RPC \ --bootnodes=$P2P_BOOTNODES ``` op-geth runs with [PBSS(Path-Base Scheme Storage) and PebbleDB](./run-with-pebbledb-and-pbss.md) by adding the flags `--state.scheme path` and `--db.engine pebble`. **It's recommended to start a new node with this mode, which provides better performance and less disk space usage.** To start the op-geth node for a fast node, you can add the flag `--allow-insecure-no-tries`. but the `gcmode` should be `full`. op-node ```bash #! /usr/bin/bash set -ex cd op-node-data export L2_RPC=http://localhost:8551 # replace the p2p private key with yours # you can generate a new one with `openssl rand -hex 32` export P2P_PRIV_KEY=ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff # for testnet # it's better to replace the L1_RPC with your own BSC Testnet RPC Endpoint for stability export L1_RPC=https://bsc-testnet.bnbchain.org export P2P_BOOTNODES="enr:-J24QGQBeMsXOaCCaLWtNFSfb2Gv50DjGOKToH2HUTAIn9yXImowlRoMDNuPNhSBZNQGCCE8eAl5O3dsONuuQp5Qix2GAYjB7KHSgmlkgnY0gmlwhDREiqaHb3BzdGFja4PrKwCJc2VjcDI1NmsxoQL4I9wpEVDcUb8bLWu6V8iPoN5w8E8q-GrS5WUCygYUQ4N0Y3CCIyuDdWRwgiMr,enr:-J24QJKXHEkIhy0tmIk2EscMZ2aRrivNsZf_YhgIU51g4ZKHWY0BxW6VedRJ1jxmneW9v7JjldPOPpLkaNSo6cXGFxqGAYpK96oCgmlkgnY0gmlwhANzx96Hb3BzdGFja4PrKwCJc2VjcDI1NmsxoQMOCzUFffz04eyDrmkbaSCrMEvLvn5O4RZaZ5k1GV4wa4N0Y3CCIyuDdWRwgiMr" # for mainnet # export L1_RPC=https://bsc-dataseed.bnbchain.org # export P2P_BOOTNODES="enr:-J24QA9sgVxbZ0KoJ7-1gx_szfc7Oexzz7xL2iHS7VMHGj2QQaLc_IQZmFthywENgJWXbApj7tw7BiouKDOZD4noWEWGAYppffmvgmlkgnY0gmlwhDbjSM6Hb3BzdGFja4PMAQCJc2VjcDI1NmsxoQKetGQX7sXd4u8hZr6uayTZgHRDvGm36YaryqZkgnidS4N0Y3CCIyuDdWRwgiMs,enr:-J24QPSZMaGw3NhO6Ll25cawknKcOFLPjUnpy72HCkwqaHBKaaR9ylr-ejx20INZ69BLLj334aEqjNHKJeWhiAdVcn-GAYv28FmZgmlkgnY0gmlwhDTDWQOHb3BzdGFja4PMAQCJc2VjcDI1NmsxoQJ-_5GZKjs7jaB4TILdgC8EwnwyL3Qip89wmjnyjvDDwoN0Y3CCIyuDdWRwgiMs" ./op-node \ --l1.trustrpc \ --sequencer.l1-confs=15 \ --verifier.l1-confs=15 \ --l1.http-poll-interval 3s \ --l1.epoch-poll-interval 3s \ --l1.rpc-max-batch-size 20 \ --rollup.config=./rollup.json \ --rpc.addr=0.0.0.0 \ --rpc.port=8546 \ --p2p.sync.req-resp \ --p2p.listen.ip=0.0.0.0 \ --p2p.listen.tcp=9003 \ --p2p.listen.udp=9003 \ --snapshotlog.file=./snapshot.log \ --p2p.bootnodes=$P2P_BOOTNODES \ --metrics.enabled \ --metrics.addr=0.0.0.0 \ --metrics.port=7300 \ --pprof.enabled \ --rpc.enable-admin \ --l1=${L1_RPC} \ --l2=${L2_RPC} \ --l2.jwt-secret=./jwt.txt \ --syncmode=execution-layer \ --l1.max-concurrency=20 \ --log.level=debug ``` ## Run with Snapshots To improve the synchronization speed of the node, you can utilize snapshots to initialize it. The most recent snapshot is maintained in the repository [opbnb-snapshot](https://github.com/bnb-chain/opbnb-snapshot). Please visit the repository for download links and usage instructions. ## Check status Wait for the node to sync. You'll see log in `op-geth` if there's any new block. ``` INFO [11-15|10:10:05.569] Syncing beacon headers downloaded=1,762,304 left=11,403,991 eta=27m1.039s INFO [11-15|10:10:06.440] Forkchoice requested sync to new head number=13,164,499 hash=d78cb3..a2e94d finalized=unknown ``` You can check the block number with curl: ``` $ curl -X POST -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' http://localhost:8545 ``` Once all headers have been downloaded, the node will begin downloading the blocks. You will notice that the block height is increasing. ``` {"jsonrpc":"2.0","id":1,"result":"0x1a"} ``` To verify if the node has synchronized to the latest height, you can compare the block with the one requested from public endpoints. ```bash # local $ curl -X POST -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"eth_getBlockByNumber","id": 1, "params": ["0x1a", false]}' http://localhost:8545 # testnet $ curl -X POST -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"eth_getBlockByNumber","id": 1, "params": ["0x1a", false]}' https://opbnb-testnet-rpc.bnbchain.org # mainnet $ curl -X POST -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"eth_getBlockByNumber","id": 1, "params": ["0x1a", false]}' https://opbnb-mainnet-rpc.bnbchain.org ``` ## Troubleshooting If the problem you are facing is not addressed here, please open an issue on GitHub by visiting this link: [open an issue](https://github.com/bnb-chain/opbnb/issues). ### Not synced for a long time The default sync mechanism involves two P2P networks, the op-node network and op-geth network. If you are not connected to the op-node network, you can not receive the latest blocks from broadcast, and can't trigger the engine sync of op-geth. If you are not connected to the op-geth network, you can receive the latest blocks from broadcast, but can't get the historical blocks from op-geth P2P network. Check the op-geth logs. If you can find the following logs, it means that the op-node network is connected successfully and you are receiving the latest blocks from broadcast. ``` INFO [11-15|10:32:02.801] Forkchoice requested sync to new head number=8,290,596 hash=1dbff3..9a306a finalized=unknown ``` If you can find the following logs, it means that the op-geth network is connected successfully and you are receiving the historical block headers from op-geth P2P network. ``` INFO [11-15|10:32:52.240] Syncing beacon headers downloaded=210,432 left=8,084,773 eta=31m39.748s ``` Check the op-node p2p network with the command below: ``` $ curl -X POST -H "Content-Type: application/json" --data \ '{"method":"opp2p_peers","params":[true],"id":1,"jsonrpc":"2.0"}' \ http://localhost:8546 ``` Check the op-geth p2p network with the command below. You have to enable admin API in op-geth to use this API. Refer to for more details. ``` $ curl -X POST -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"admin_peers","params":[],"id":1}' http://localhost:8545 | jq . ``` ### The local node's chain has forked from the canonical chain If your local node is already running and tracking blocks, the following situations may indicate that your local node's chain has forked from the canonical chain: 1. The block hash at the same height obtained through the `eth_getBlockByNumber` method does not match the data returned by the public node. 2. Your local chain consistently lags behind a fixed number of blocks and cannot catch up with the latest block height. In this case, we recommend that you check the code version of the running node through the following steps: ```bash $ op-node -v op-node version v0.0.0-515ebd51-1698742099 $ op-geth version Geth Version: 0.1.0-unstable Git Commit: f8871fc80dbf2aa0178b504e76c20c21b890c6d5 Git Commit Date: 20231026 Upstream Version: 1.11.5-stable Architecture: arm64 Go Version: go1.20.2 Operating System: darwin GOPATH= ``` Please make sure to use the latest code version. If the code version is incorrect, please completely clear the node data and run the new node again according to this guide. You also need to check if the `genesis.json` and `rollup.json` files are up to date. In the latest code, we hardcoded the configuration of rollup.json. Instead of using `--rollup.config=./rollup.json`, you just need to use `--network=opBNBTestnet` (for the mainnet network it is opBNBMainnet). This change ensures that the contents of rollup.json will not be incorrect. ### Node block is stuck and op-geth log prints: Database compacting, degraded performance database=/data/geth/chaindata If your node suddenly gets stuck and cannot grow, and your op-geth log keeps printing: Database compacting, degraded performance database=/data/geth/chaindata, then you need to consider upgrading your machine specifications, increasing CPU, memory, and disk maximum throughput. This is because the current OP Stack only supports the archive mode of Geth, and the disk space usage increases over time. The Leveldb that Geth relies on requires more machine resources to complete the compact process. We are working hard to support full mode Geth, and further support PBSS and Pebble to completely solve this problem. If you don't want to upgrade your machine's specifications, You can choose to download the pruned snapshot from the [opbnb-snapshot](https://github.com/bnb-chain/opbnb-snapshot) repository, and use it to start a new node. The new node will not have this issue, but it will lose all state data before a certain block height. If you are an advanced player, you can also try to perform offline pruning on your nodes (Note that this is a dangerous operation and after pruning, the state data of the blocks before the target block height will no longer be available). You can follow these steps: 1. Shut down your machine and make sure that op-geth prints the following log: "Blockchain stopped". 2. Search for the keyword "Chain head was updated" in the logs to confirm the block height of the last inserted block before the node was shut down. For the sake of explanation, let's assume the block height is 16667495. 3. Wait for 16667495 to become the final state on the chain, ensuring that no reorganization has occurred. You can go to the blockchain explorer (https://opbnbscan.com/) to query this block height, and compare the block height hash with the one in the log. If the hashes match and a long time has passed, then we believe that this block height will not be reorganized. 4. Get the state root hash of this block height through JSON-RPC. 5. To execute pruning, use the following command: `geth snapshot prune-state --datadir {yourDataDir} --triesInMemory=32 {targetBlockStateRootHash}`, making sure to replace {yourDataDir} and {targetBlockStateRootHash} with your own values. 6. Be patient and observe the logs. The entire process may take dozens of hours. 7. Restart your node after pruning is complete. !!!info Pruning is very dangerous and may damage the data of the node. This could result in having to rerun the new node. Please only perform this operation if you are familiar with the process. --- ## Run with PebbleDB and PBSS > Source: https://docs.bnbchain.org/bnb-opbnb/advanced/run-with-pebbledb-and-pbss/ # How to Run op-geth with PBSS and PebbleDB To start op-geth with PBSS and PebbleDB, include the following flags: ```bash --state.scheme path --db.engine pebble ``` !!!info We recommend using version v0.3.1-alpha or later to activate this feature. Upon successful startup, the logs will confirm the initiation of PBSS and PebbleDB: ```bash INFO [03-21|07:00:25.684] Using pebble as the backing database INFO [03-21|07:00:47.039] State scheme set by user scheme=path ``` ## PBSS (Path-Based Scheme Storage) PBSS stores trie nodes on disk using the encoded path and a specific key prefix as the key. This approach allows PBSS's Merkle Patricia Trie (MPT) to overwrite older data due to the shared key between the account trie and storage trie. This feature not only enables **online pruning** but also significantly **reduces data redundancy**. PBSS architecture comprises 128 difflayers (in memory) and one disk layer, as depicted below. Difflayers store only the state data changes. ```plaintext +-------------------------------------------+ | Block X+128 State | +-------------------------------------------+ | Block X+127 State | +-------------------------------------------+ | ....... | +-------------------------------------------+ | Block X+1 State, Bottom-most diff layer | +-------------------------------------------+ | Block X State, Disk layer (singleton trie)| +-------------------------------------------+ ``` **PBSS offers superior read performance**, with faster trie access and iteration. It maintains a single version of the state trie on disk and keeps new tries (changes to the state/storage/account trie) only in memory. ### Restrictions * **Supports queries for only the last 129 blocks' state data** RPC requests requiring data beyond this range will return an error: `missing trie node ${hash} (path ${path})`. Only RPC methods that need to query trie data, such as `eth_getProof`, will be impacted by this limitation, while others will remain unaffected. * **The withdrawal function of opBNB might not be supported** This function might require querying state data from an hour earlier to obtain a withdrawal proof, which is not supported yet. Future versions will address this limitation. ## PebbleDB PebbleDB, now the default database for the community, has been integrated into go-ethereum. It replaces LevelDB, which lacks a throttle mechanism for flushes and compactions, leading to latency spikes during intense read and write operations. Conversely, PebbleDB features separate rate limiters for flushes and compactions, conducting operations as needed and **reducing unnecessary disk bandwidth consumption**. ## FAQ ### Can I change the `state.scheme` or `db.engine` for an existing node? No, you cannot change the `state.scheme` or `db.engine` for an existing node. You must start a new node with the desired configuration. --- ## Run your own opBNB on BSC > Source: https://docs.bnbchain.org/bnb-opbnb/advanced/run-your-own-l2-with-opbnb/ # Creating Your Own L2 Rollup Testnet This tutorial is designed for developers who want to create l2 rollup testnet chain. You'll walk through the full deployment process and teach you all of the components that make up the l2 rollup, and you'll end up with your own l2 rollup testnet. You can use this testnet to experiment and perform tests, or you can choose to modify the chain to adapt it to your own needs. # Introduction The opBNB stack is the Layer 2 scaling framework for the BNB Smart Chain powered by[ bedrock version](https://community.optimism.io/docs/developers/bedrock/) of Optimism OP Stack. It works by offloading transaction processing and resource usage from the BNB Smart Chain, while still posting data to the underlying mainnet. Users can build their own L2 network with the framework. And then they can interact with the network by depositing funds from BSC and using applications and contracts on the network. Sequencers then aggregate transactions, compute state transitions and submit them to the rollup contract on BSC. Provers generate cryptographic proofs that prove the validity of these state transitions, and Verifiers check the proofs to verify the L2 network’s state is correct. At its core, it allows users to deposit and withdraw funds, use smart contracts, and view network data with high throughput and low fees. # What You're Going to Deploy ## Deployment Architecture Sequencer Proposer Batcher Bridge node RPC node When deploying a l2 rollup chain, you'll be setting up four different components. It's useful to understand what each of these components does before you start deploying your chain. ## Smart Contracts The l2 rollup gives you the ability to deploy your own l2 rollup that use a Layer 1 blockchain to host and order transaction data. The l2 rollup uses several smart contracts on the L1 blockchain to manage aspects of the Rollup. You'll be using the L1 smart contracts found in the [contracts-bedrock package](https://github.com/bnb-chain/opbnb/tree/develop/packages/contracts-bedrock) within the [opbnb](https://github.com/bnb-chain/opbnb). ## Sequencer Node The l2 rollup uses Sequencer node to gather proposed transactions from users and publish them to the L1 blockchain. ### Consensus Client The l2 rollup has a consensus client. The consensus client is responsible for determining the list and ordering of blocks and transactions that are part of your blockchain. In this tutorial you'll be using the [op-node](https://github.com/bnb-chain/opbnb/tree/develop/op-node) found within the [opbnb](https://github.com/bnb-chain/opbnb). ### Execution Client The l2 rollup has an execution client. The execution client is responsible for executing transactions and storing/updating the state of the blockchain. In this tutorial you'll be using the [op-geth](https://github.com/bnb-chain/op-geth) found within the [op-geth](https://github.com/bnb-chain/op-geth) repository. Each of the Sequencer, Bridge, and RPC nodes runs both an op-node and an op-geth process—the sequencer start op-node process with a miner flag and the others run with fullnode flag . The key difference between an RPC node and a bridge node is that an RPC node exposes a public endpoint for external users to access, while a bridge node is not externally reachable. The bridge node functions like a cache for sequencer node : it forwards incoming transactions to the sequencer, helping prevent the sequencer’s transaction pool from being overloaded. ## Batcher The Batcher is a service that publishes transactions from the Sequencer to the L1 blockchain. The Batcher runs continuously alongside the Sequencer and publishes transactions in batches (hence the name) on a regular basis. You'll be using the [op-batcher](https://github.com/bnb-chain/opbnb/tree/develop/op-batcher) of the Batcher component found within the [opbnb](https://github.com/bnb-chain/opbnb). ## Proposer The Proposer is a service responsible for publishing transactions results (in the form of L2 state roots) to the L1 blockchain. This allows smart contracts on L1 to read the state of the L2, which is necessary for cross-chain communication and reconciliation between state changes. You'll be using the [op-proposer](https://github.com/bnb-chain/opbnb/tree/develop/op-proposer) of the Proposer component found within the [opbnb](https://github.com/bnb-chain/opbnb). # Software Dependencies | Dependency | Version | Version Check Command | |:----------:|:-------:|:---------------------:| | git | ^2 | git --version | | go | ^1.21 | go version | | node | ^20 | node --version | | pnpm | ^8 | pnpm --version | | foundry | ^0.2.0 | forge --version | | make | ^3 | make --version | | jq | ^1.6 | jq --version | | direnv | ^2 | direnv --version | | gcc | ^13 | gcc --version | | libc-dev | ^2.35 | ldd --version | # Hardware requirements **CPU**: 4 × 2 GHz (or faster) 64‑bit processor cores **Memory**: 16 GB DDR4 RAM **For `op-geth` (execution layer)**: - High‑performance SSD with sustained IOPS ≥ 20,000, **or** an enterprise-grade NVMe SSD (to ensure low latency under heavy state‑healing workloads) [gist.github](https://gist.github.com/yorickdowne/f3a3e79a573bf35767cd002cc977b038?utm_source=chatgpt.com)[docs.optimism](https://docs.optimism.io/operators/node-operators/tutorials/mainnet?utm_source=chatgpt.com) - ≥ 3 TB capacity **For `op-node` (consensus & aggregation)**: - Standard SSD (SATA or consumer NVMe) is sufficient, ≥ 500 GB ## Notes on Specific Dependencies `node` We recommend using the latest LTS version of Node.js (currently v20). [nvm](https://github.com/nvm-sh/nvm) is a useful tool that can help you manage multiple versions of Node.js on your machine. You may experience unexpected errors on older versions of Node.js. `foundry` It's recommended to use the scripts in the [opbnb's](https://github.com/bnb-chain/opbnb) package.json for managing foundry to ensure you're always working with the correct version. This approach simplifies the installation, update, and version checking process. Make sure to clone the [opbnb](https://github.com/bnb-chain/opbnb) locally before proceeding. `direnv` Parts of this tutorial use [direnv](https://direnv.net/) as a way of loading environment variables from `.envrc` files into your shell. This means you won't have to manually export environment variables every time you want to use them. `direnv` only ever has access to files that you explicitly allow it to see. After [installing direnv](https://direnv.net/docs/installation.html), you will need to make sure that `direnv` is [hooked into your shell](https://direnv.net/docs/hook.html). Make sure you've followed [the guide on the `direnv` website](https://direnv.net/docs/hook.html), then close your terminal and reopen it so that the changes take effect (or source your config file if you know how to do that). # Get Access to a BSC testnet Node You'll be deploying a BSC l2 rollup that uses a Layer 1 blockchain to host and order transaction data. This guide uses the BSC testnet as an L1 chain. You can also use other EVM-compatible blockchains, but you may run into unexpected errors. If you want to use an alternative network, make sure to carefully review each command and replace any BSC testnet values with the values for your network. Since you're deploying your l2 rollup on BSC testnet, you'll need to have access to a BSC testnet node. # Build the Source Code You're going to be creating your own l2 rollup directly from source code instead of using a container system like [Docker](https://www.docker.com/). Although this adds a few extra steps, it means you'll have an easier time modifying the behavior of the l2 rollup if you'd like to do so. If you want a summary of the various components you'll be using, take another look at the [What You're Going to Deploy](#what-youre-going-to-deploy) section above. ## Build the opbnb ### Clone the opbnb ``` cd ~ git clone https://github.com/bnb-chain/opbnb.git ``` ### Enter the opbnb ``` cd opbnb ``` ### Check out the correct branch You can choose the appropriate version according to your needs. The develop branch has the latest features. ``` git checkout -b develop origin/develop ``` ### Install dependencies ``` pnpm install ``` ### Build the various packages inside of the opbnb ``` make op-node op-batcher op-proposer ``` ## Build `op-geth` ### Clone op-geth ``` cd ~ git clone https://github.com/bnb-chain/op-geth.git ``` ### Check out the correct branch You can choose the appropriate version according to your needs. The develop branch has the latest features. ``` git checkout -b v0.5.7 ``` ### Enter op-geth ``` cd op-geth ``` ### Build op-geth ``` make geth ``` # Fill Out Environment Variables You'll need to fill out a few environment variables before you can start deploying your chain. ### Enter the opbnb ``` cd ~/opbnb ``` ### Duplicate the sample environment variable file ``` cp .envrc.example .envrc ``` ### Fill out the environment variable file Open up the environment variable file and fill out the following variables: | Variable Name | Description | |:----------:|:-----------------------------------------------------------------------------------------------------:| | L1_RPC_URL | URL for your L1 node | | L1_RPC_KIND | Kind of L1 RPC you're connecting to, used to inform optimal transactions receipts fetching(Optional). | | L1_CHAIN_ID | The Chain id of L1 chain ( bsc testnet is 97) | | L1_BLOCK_TIME | The block interval value of L1 CHAIN | | L2_CHAIN_ID | The Chain id of Layer 2 chain | | L2_BLOCK_TIME | The block interval value of L2 CHAIN | # Generate Addresses You'll need four addresses and their private keys when setting up the chain: * The Admin address has the ability to upgrade contracts. * The Batcher address publishes Sequencer transaction data to L1. * The Proposer address publishes L2 transaction results (state roots) to L1. * The Sequencer address signs blocks on the p2p network. ## Enter the opbnb ``` cd ~/opbnb ``` ## Generate new addresses ``` ./packages/contracts-bedrock/scripts/getting-started/wallets.sh ``` ## Check the output Make sure that you see output that looks something like the following: ``` Copy the following into your .envrc file: # Admin account export GS_ADMIN_ADDRESS=0xC18e23D98F121c48a56E19302D1B7FB9b82A0F2E export GS_ADMIN_PRIVATE_KEY=0x5d5e555305c69711eb31dd24dd1530b137489c54ddc83afd421f581c3fbf6c67 # Batcher account export GS_BATCHER_ADDRESS=0x7527Cc2860B71E654a98235c8CF5D8Ca792040FE export GS_BATCHER_PRIVATE_KEY=0xf6c2a7cf909a41fc227b03cf6474c66eaff5e05b36a89394f5a5129598fa8d13 # Proposer account export GS_PROPOSER_ADDRESS=0xeE7579518904123AE4b3BaB729A4B9c9c08D5658 export GS_PROPOSER_PRIVATE_KEY=0x95176e9e67c1b97b4b7aaedf66e0b34b446f8683d545b44214240f6f1cfa6891 # Sequencer account export GS_SEQUENCER_ADDRESS=0xeCF961D156a2ce02E98Ad26E79De62BcFd403cfd export GS_SEQUENCER_PRIVATE_KEY=0xbb019ddc5f081b2be0c1c9406f89887ba90f4c8efbe5c4073ee067e56d3107ea ``` ## Save the addresses Copy the output from the previous step and paste it into your `.envrc` file as directed. ## Fund the addresses You will need to send BNB to the Admin, Proposer, and Batcher addresses. The exact amount of BNB required depends on the L1 network being used. You do not need to send any BNB to the Sequencer address as it does not send transactions. It's recommended to fund the addresses with the following amounts when using BSC testnet: * Admin — 1 BNB * Proposer — 2 BNB * Batcher — 15 BNB Estimated monthly consumption: \- **Batcher**: ~30 tBNB (testnet) / ~2 BNB (mainnet) \- **Proposer**: ~5 tBNB (testnet) / ~0.1 BNB (mainnet) # Load Environment variables Now that you've filled out the environment variable file, you need to load those variables into your terminal. ## Enter the opbnb ``` cd ~/opbnb ``` ## Load the variables with direnv You're about to use `direnv` to load environment variables from the `.envrc` file into your terminal. Make sure that you've [installed `direnv`](https://direnv.net/docs/installation.html) and that you've properly hooked `direnv` into your shell. Next you'll need to allow `direnv` to read this file and load the variables into your terminal using the following command. ``` direnv allow ``` `direnv` will unload itself whenever your `.envrc` file changes. You must rerun the following command every time you change the `.envrc` file. ## Confirm that the variables were loaded After running `direnv allow` you should see output that looks something like the following (the exact output will vary depending on the variables you've set, don't worry if it doesn't look exactly like this): ``` direnv: loading ~/optimism/.envrc direnv: export +DEPLOYMENT_CONTEXT +ETHERSCAN_API_KEY +GS_ADMIN_ADDRESS +GS_ADMIN_PRIVATE_KEY +GS_BATCHER_ADDRESS +GS_BATCHER_PRIVATE_KEY +GS_PROPOSER_ADDRESS +GS_PROPOSER_PRIVATE_KEY +GS_SEQUENCER_ADDRESS +GS_SEQUENCER_PRIVATE_KEY +IMPL_SALT +L1_RPC_KIND +L1_RPC_URL +PRIVATE_KEY +TENDERLY_PROJECT +TENDERLY_USERNAME ``` If you don't see this output, you likely haven't properly configured `direnv`. Make sure you've configured `direnv` properly and run `direnv allow` again so that you see the desired output. If you don't want to use `direnv`, you can also set variables manually. # Configure your network Once you've built both repositories, you'll need to head back to the opbnb to set up the configuration file for your chain. Currently, chain configuration lives inside of the [contracts-bedrock package](https://github.com/bnb-chain/opbnb/tree/develop/packages/contracts-bedrock) in the form of a JSON file. ## Enter the opbnb ``` cd ~/opbnb ``` ## Move into the contracts-bedrock package ``` cd packages/contracts-bedrock ``` ## Generate the configuration file Run the following script to generate the `getting-started.json` configuration file inside of the `deploy-config` directory. ``` ./scripts/getting-started/config.sh ``` The script-based approach shown above is the one officially recommended by OP, and the generated configuration is the official version. However, we strongly recommend using the template method instead. A template is provided at the end of this document. You can use the information from getting-started.json together with the template to generate an OPBNB-style configuration. The following is an example our config template. In the template, You need to replace the following variables with the ones from your environment.:$l2ChainId,$l1ChainId,$GS_SEQUENCER_ADDRESS,$GS_BATCHER_ADDRESS,$GS_PROPOSER_ADDRESS,$GS_ADMIN_ADDRESS, $GS_ADMIN_ADDRESS . It is recommended to set `l2OutputOracleSubmissionInterval` to **3600** (default is **240**) to provide a greater buffer for module startup delays. ```python { "l1ChainID": $l1ChainId, "l2ChainID": $l2ChainId, "l2BlockTime": 1, "maxSequencerDrift": 600, "sequencerWindowSize": 57600, "channelTimeout": 1200, "p2pSequencerAddress": $GS_SEQUENCER_ADDRESS, "batchInboxAddress": '0xff0000000000000000000000000000000000'+str($l2ChainId), "batchSenderAddress": $GS_BATCHER_ADDRESS, "cliqueSignerAddress": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", "l1UseClique": false, "l1StartingBlockTag": $l1BlockTag, "l2OutputOracleSubmissionInterval": 3600, "l2OutputOracleStartingBlockNumber": 0, "l2OutputOracleStartingTimestamp" $l2OutputOracleStartingTimestamp, "l2OutputOracleProposer": $GS_PROPOSER_ADDRESS, "l2OutputOracleChallenger": $GS_ADMIN_ADDRESS, "l2GenesisBlockGasLimit": "0x5f5e100", "l1BlockTime": 3, "baseFeeVaultMinimumWithdrawalAmount": "0x8ac7230489e80000", "l1FeeVaultMinimumWithdrawalAmount": "0x8ac7230489e80000", "sequencerFeeVaultMinimumWithdrawalAmount": "0x8ac7230489e80000", "baseFeeVaultWithdrawalNetwork": 0, "l1FeeVaultWithdrawalNetwork": 0, "sequencerFeeVaultWithdrawalNetwork": 0, "proxyAdminOwner": "$GS_ADMIN_ADDRESS", "baseFeeVaultRecipient": "$GS_ADMIN_ADDRESS", "l1FeeVaultRecipient": "$GS_ADMIN_ADDRESS", "sequencerFeeVaultRecipient": "$GS_ADMIN_ADDRESS", "finalSystemOwner": "$GS_ADMIN_ADDRESS", "superchainConfigGuardian": "$GS_ADMIN_ADDRESS", "finalizationPeriodSeconds": 3, "fundDevAccounts": true, "l2GenesisBlockBaseFeePerGas": "0x5F5E100", "gasPriceOracleOverhead": 2100, "gasPriceOracleScalar": 1000000, "gasPriceOracleBaseFeeScalar": 1368, "gasPriceOracleBlobBaseFeeScalar": 810949, "enableGovernance": false, "governanceTokenSymbol": "OPBNB", "governanceTokenName": "OPBNB", "governanceTokenOwner": "$GS_ADMIN_ADDRESS", "eip1559Denominator": 8, "eip1559DenominatorCanyon": 8, "eip1559Elasticity": 2, "l1GenesisBlockTimestamp": $l2GenesisBlockTimestamp, "l2GenesisRegolithTimeOffset": "0x0", "l2GenesisDeltaTimeOffset": "0x0", "l2GenesisCanyonTimeOffset": "0x0", "systemConfigStartBlock": 0, "requiredProtocolVersion": "0x0000000000000000000000000000000000000000000000000000000000000000", "recommendedProtocolVersion": "0x0000000000000000000000000000000000000000000000000000000000000000", "faultGameAbsolutePrestate": "0x03c7ae758795765c6664a5d39bf63841c71ff191e9189522bad8ebff5d4eca98", "faultGameMaxDepth": 50, "faultGameClockExtension": 0, "faultGameMaxClockDuration": 1200, "faultGameGenesisBlock": 0, "faultGameGenesisOutputRoot": "0xDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF", "faultGameSplitDepth": 14, "faultGameWithdrawalDelay": 604800, "preimageOracleMinProposalSize": 10000, "preimageOracleChallengePeriod": 120, "proofMaturityDelaySeconds": 12, "disputeGameFinalityDelaySeconds": 6, "respectedGameType": 254, "useFaultProofs": false, "usePlasma": false, "daCommitmentType": "KeccakCommitment", "daChallengeWindow": 160, "daResolveWindow": 160, "daBondSize": 1000000, "daResolverRefundPercentage": 0, "fermat": 0, "L2GenesisEcotoneTimeOffset": "0x0", "l2GenesisFjordTimeOffset": "0x0", "snowTimeOffset": "0x0", "haberTimeOffset": "0x0", "wrightTimeOffset": "0x0" } ``` in addition to replacing the Chain Info , you must also specify the following three parameters: 1. l1StartingBlockTag 2) l2OutputOracleStartingTimestamp 3. l2GenesisBlockTimestamp You can also fetch the three values via the following script (here shown against BSC Testnet), ```bash #!/bin/bash # RPC endpoint of bsc testnet RPC_URL="https://data-seed-prebsc-2-s2.bnbchain.org:8545" # Function to convert hex string to decimal hex_to_dec() { printf "%d\n" "$(( $1 ))" } # Loop until a valid milliTimestamp is found while true; do # Get latest block number block_tag_hex=$(curl -s -X POST "$RPC_URL" -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":74}' | jq -r .result) # Get block info block_info=$(curl -s -X POST "$RPC_URL" -H "Content-Type: application/json" \ -d "{\"jsonrpc\":\"2.0\",\"method\":\"eth_getBlockByNumber\",\"params\":[\"$block_tag_hex\", false],\"id\":74}") timestamp_hex=$(echo "$block_info" | jq -r .result.timestamp) milli_timestamp_hex=$(echo "$block_info" | jq -r .result.milliTimestamp) timestamp_dec=$(hex_to_dec "$timestamp_hex") milli_timestamp_dec=$(hex_to_dec "$milli_timestamp_hex") # Check if milliTimestamp is divisible by 1000 ,If we need to set a 500ms block time ( op 500ms need to be enabled in bsc testnet and mainnet ), it's important to note that the selected `milliTimestamp` must be divisible by 1000. if (( milli_timestamp_dec % 1000 == 0 )); then break fi sleep 1 done # Print final result echo "l1StartingBlockTag=$block_tag_hex" echo "l2GenesisBlockTimestamp=$timestamp_hex" echo "l2OutputOracleStartingTimestamp=$timestamp_dec" ``` Once you have retrieved the values of the three variables, insert them into the configuration template. After updating the configuration file, assign its path to the `DEPLOY_CONFIG_PATH` environment variable. ## Review and change the configuration file (Optional) If you'd like, you can review the configuration file that was just generated by opening up `deploy-config/getting-started.json` in your favorite text editor. You can change configuration values to fit your specific needs. Please refer the [Chain Configuration](./Chain-Configuration.md). It's recommended to keep this file as-is for now so you don't run into any unexpected errors. # Deploy the Create2 Factory (Optional) If you're deploying opBNB to a network other than BSC testnet, you may need to deploy a Create2 factory contract to the L1 chain. This factory contract is used to deploy opBNB smart contracts in a deterministic fashion. ## Check if the factory exists The Create2 factory contract will be deployed at the address `0x4e59b44847b379578588920cA78FbF26c0B4956C`. You can check if this contract has already been deployed to your L1 network with a block explorer or by running the following command: ``` cast codesize 0x4e59b44847b379578588920cA78FbF26c0B4956C --rpc-url $L1_RPC_URL ``` If the command returns 0 then the contract has not been deployed yet. If the command returns 69 then the contract has been deployed and you can safely skip this section. ## Fund the factory deployer You will need to send some BNB to the address that will be used to deploy the factory contract, `0x3fAB184622Dc19b6109349B94811493BF2a45362`. This address can only be used to deploy the factory contract and will not be used for anything else. Send at least 1 BNB to this address on your L1 chain. ## Deploy the factory Using `cast`, deploy the factory contract to your L1 chain: ``` cast publish --rpc-url $L1_RPC_URL 0xf8a58085174876e800830186a08080b853604580600e600039806000f350fe7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf31ba02222222222222222222222222222222222222222222222222222222222222222a02222222222222222222222222222222222222222222222222222222222222222 ``` ## Wait for the transaction to be mined Make sure that the transaction is included in a block on your L1 chain before continuing. ## Verify that the factory was deployed Run the code size check again to make sure that the factory was properly deployed: ``` cast codesize 0x4e59b44847b379578588920cA78FbF26c0B4956C --rpc-url $L1_RPC_URL ``` # Deploy the L1 contracts Once you've configured your network, it's time to deploy the L1 contracts necessary for the functionality of the chain. ## Deploy the L1 contracts Add .env file in the current directory where you run the script or export follow content to .envrc file to make sure the following info can be loaded. The most important variable is DEPLOY_CONFIG_PATH, which should point to the configuration file you generated above. For example: ~~~bash cat .env ``` DEPLOYMENT_OUTFILE="./deployments/L1/.deploy" // The contract address information entered after deployment. DEPLOY_CONFIG_PATH="./deploy-config/devnet.json" // config file ~~~ ``` forge script scripts/Deploy.s.sol:Deploy --private-key $GS_ADMIN_PRIVATE_KEY --with-gas-price 1000000000 --broadcast --rpc-url $L1_RPC_URL --slow ``` If you see a nondescript error that includes `EvmError: Revert` and `Script failed` then you likely need to change the `IMPL_SALT` environment variable. This variable determines the addresses of various smart contracts that are deployed via [CREATE2](https://eips.ethereum.org/EIPS/eip-1014). If the same `IMPL_SALT` is used to deploy the same contracts twice, the second deployment will fail. You can generate a new `IMPL_SALT` by running `direnv` allow anywhere in the opbnb. You can check the DEPLOYMENT_OUTFILE after deployed successfully. The contract address will be printed when the script running and the address can searched in https://testnet.bscscan.com/ . ### L1 Contracts | **Contracts** | **Description** | **comments** | | ---------------------- | ------------------------------------------------------------ | ------------ | | SystemConfig | Responsible for saving the system configuration and providing the ability to change it online.These configurations will be used by L2 block derivation process including overhead, scalar, batcherHash, gasLimit, resourceConfig,etc. | | | L1StandardBridge | Responsible for the transfer of ERC20 tokens between L1 and L2. | | | L1ERC721Bridge | Responsible for the transfer of ERC721 tokens between L1 and L2. | | | L1CrossDomainMessenger | Responsible for delivering messages and being more user friendly. | | | OptimismPortal | Responsible for passing messages between L1 and L2, which is equivalent to the portal of the optimistic network. Validate output root to execute L2 to L1 message call. | | | L2OutputOracle | Responsible for storing the output root of each block of the L2 network. Other contracts or users can verify the validity of L2 data according to the output root. | | ## Generate L2 Genesis Allocs A foundry script is used to generate the L2 genesis allocs. This is a JSON file that represents the L2 genesis state. The `CONTRACT_ADDRESSES_PATH` env var represents the deployment artifact that was generated during a contract deployment. The value should be same with DEPLOYMENT_OUTFILE. The `STATE_DUMP_PATH` env var represents the filepath at which the allocs will be written to on disk. You can set the value in .env or envrc. ``` DEPLOY_CONFIG_PATH="./deploy-config/devnetL1-v2.json" CONTRACT_ADDRESSES_PATH="./deployments/L1/.deploy" // same with DEPLOYMENT_OUTFILE STATE_DUMP_PATH="./deploy-config/state.json" ``` ```bsch CONTRACT_ADDRESSES_PATH= \ DEPLOY_CONFIG_PATH= \ STATE_DUMP_PATH= \ forge script scripts/L2Genesis.s.sol:L2Genesis \ --sig 'runWithStateDump()' ``` The L2 genesis allocs file will generated in the path of DEPLOY_CONFIG_PATH after the script beed deployed successfully. ## Generate the L2 config files Now that you've set up the L1 smart contracts you can automatically generate several configuration files that are used within the Consensus Client and the Execution Client. You need to generate three important files: 1. `genesis.json` includes the genesis state of the chain for the Execution Client (sequencer). 2. `rollup.json` includes configuration information for the Consensus Client (bridage node, rpcnode ,p2p node). 3. `jwt.txt` is a [JSON Web Token](https://jwt.io/introduction) that allows the Consensus Client and the Execution Client to communicate securely (the same mechanism is used in Ethereum clients). ## Navigate to the op-node package ``` cd ~/opbnb/op-node ``` ## Create genesis files Now you'll generate the `genesis.json` and `rollup.json` files within the op-node folder: --deploy-config and --l1-deployments flag info needs to be replaced by th DEPLOY_CONFIG_PATH and DEPLOYMENT_OUTFILE of .env or .envrc ``` go run cmd/main.go genesis l2 \ --deploy-config $DEPLOY_CONFIG_PATH \ --l1-deployments $DEPLOYMENT_OUTFILE \ --outfile.l2 genesis.json \ --outfile.rollup rollup.json \ --l1-rpc $L1_RPC_URL \ --l2-allocs $STATE_DUMP_PATH ``` Note that since op-geth does not support bsc 7702 yet, if the deployed l1 genesis height is after the bsc 7702 feature, the l1 hash in rollup.json is wrong and you need to manually execute rpc to get the correct value to replace it. Following is a example of rollup.json. ```bash { "genesis": { "l1": { "hash": "0x79060df30c6c3377962184f28f88340616b8bc737e6af79bc17da55ac78e41bd", "number": 49953684 }, "l2": { "hash": "0xb9d33b0e69bb67c857d59568f38011f4104e2747b6fcf8aff84fb4e419f73f4d", "number": 0 }, "l2_time": 1744341397, "system_config": { "batcherAddr": "0xb6e487a3cecde5e0e1793c98c2de1999a1319a2b", "overhead": "0x0000000000000000000000000000000000000000000000000000000000000834", "scalar": "0x00000000000000000000000000000000000000000000000000000000000f4240", "gasLimit": 100000000 } }, "block_time": 1, "max_sequencer_drift": 600, "seq_window_size": 57600, "channel_timeout": 1200, "l1_chain_id": 97, "l2_chain_id": 4255, "regolith_time": 0, "canyon_time": 0, "delta_time": 0, "ecotone_time": 0, "fjord_time": 0, "volta_time": 0, (advised) "fermat": 0, "snow_time": 0, "batch_inbox_address": "0xff00000000000000000000000000000000000901", "deposit_contract_address": "0xf098dadd3f3cfabd9e773c7639dbef5e57308683", "l1_system_config_address": "0x644b2da606901ba67ff797168194708c0c3f7221", "protocol_versions_address": "0x0000000000000000000000000000000000000000", "da_challenge_contract_address": "0x0000000000000000000000000000000000000000" } ``` You need to manually add `"volta_time": 0` to the configuration file to ensure the block time is set to 500ms. The latest op code supports the `volta_time` configuration to 0 support Volta fork which makes the block time as 500ms. Since the BSC L1 block time will be reduced to under 1 second, the 500ms configuration is required. ## Create an authentication key Next you'll create a [JSON Web Token](https://jwt.io/introduction) that will be used to authenticate the Consensus Client and the Execution Client. This token is used to ensure that only the Consensus Client and the Execution Client can communicate with each other. You can generate a JWT with the following command: ``` openssl rand -hex 32 > jwt.txt ``` ## Copy genesis files into the op-geth directory Finally, you'll need to copy the `genesis.json` file and `jwt.txt` file into `op-geth` so you can use it to initialize and run `op-geth`: ``` cp genesis.json ~/op-geth cp jwt.txt ~/op-geth ``` # Initialize `op-geth` You're almost ready to run your chain! Now you just need to run a few commands to initialize `op-geth`. You're going to be running a Sequencer node, so you'll need to import the `Sequencer` private key that you generated earlier. This private key is what your Sequencer will use to sign new blocks. ## Navigate to the op-geth directory ``` cd ~/op-geth ``` ## Create a data directory folder ``` mkdir datadir ``` ## Initialize op-geth ``` build/bin/geth init --datadir=datadir --state.scheme path --db.engine pebble genesis.json ``` you can also init with hash scheme by "--state.schme hash" , we recommend pathdb for better performance # Start `Sequencer` Now you'll start `op-geth`, your Execution Client. Note that you won't start seeing any transactions until you start the Consensus Client in the next step. ## Open up a new terminal You'll need a terminal window to run `op-geth` in or you can run it in nohup m. ## Navigate to the op-geth directory ``` cd ~/op-geth ``` ## Run op-geth You're using `--gcmode=archive` to run `op-geth` here because this node will act as your Sequencer. It's useful to run the Sequencer in archive mode because the `op-proposer` requires access to the full state. Feel free to run other (non-Sequencer) nodes in full mode if you'd like to save disk space. It's important that you've already initialized the geth node at this point as per the previous section. Failure to do this will cause startup issues between `op-geth` and `op-node`. The parameters related to metrics, logging levels, and txpool performance in the following startup configuration are optional. You may adjust them based on the specific requirements of your blockchain. ```000 ./build/bin/op-geth \ --datadir ./datadir \ --http \ --http.corsdomain="*" \ --http.vhosts="*" \ --http.addr=0.0.0.0 \ --http.api=web3,debug,eth,txpool,net,engine \ --ws \ --ws.addr=0.0.0.0 \ --ws.port=8546 \ --ws.origins="*" \ --ws.api=debug,eth,txpool,net,engine \ --syncmode=full \ --gcmode=archive \ --mine \ --miner.newpayload-timeout=650ms \ --miner.gaslimit=150000000 \ --miner.gasprice=1 \ --miner.etherbase=$GS_SEQUENCER_ADDRESS \ --nodiscover \ --maxpeers=10 \ --networkid=$L2_CHAIN_ID \ --authrpc.vhosts='*' \ --authrpc.addr=0.0.0.0 \ --authrpc.port=8551 \ --txpool.globalslots=20000 \ --txpool.globalqueue=10000 \ --txpool.accountqueue=500 \ --txpool.accountslots=500 \ --txpool.pricelimit=1 \ --txpool.nolocals=true \ --txpool.reannouncetime=3m \ --txpool.reannounceremotes=true \ --cache=20000 \ --cache.preimages \ --authrpc.jwtsecret=./jwt.txt \ --rollup.disabletxpoolgossip=false \ --journalfile \ --pathdb.nodebuffer=list \ --pathdb.proposeblock=3600 \ --pathdb.enableproofkeeper \ --metrics \ --metrics.port=6060 \ --metrics.addr=0.0.0.0 \ --verbosity=3 // replace with $L2_CHAIN_ID with your real chainid ``` Please note that if you set `--pathdb.proposeblock=3600`, the proposer processor must start within 3600 seconds after op-geth of sequencer is launched. The value of pathdb.proposeblock need to be same with l2OutputOracleSubmissionInterval of DEPLOY_CONFIG_PATH . If you are using hash db instead of pathdb , you can ignore the config begin with --pathdb. Once you've got `op-geth` running you'll need to run `op-node`. Like Ethereum, the opBNB has a Consensus Client (`op-node`) and an Execution Client (`op-geth`). The Consensus Client "drives" the Execution Client over the Engine API. Each of the Sequencer, Bridge, P2P, and RPC nodes runs both an op-node and an op-geth process—the only distinction is the set of startup parameters supplied to the op-node. ## Navigate to the op-node directory ``` cd ~/opbnb/op-node ``` ## Run op-node in miner mode ``` ./bin/op-node \ --l1.trustrpc \ --l2=http://localhost:8551 \ --l2.jwt-secret=./jwt.txt \ --sequencer.enabled=true \ --sequencer.l1-confs=15 \ --sequencer.combined-engine \ --verifier.l1-confs=15 \ --l1.http-poll-interval=3s \ --l1.epoch-poll-interval=3s \ --l1.rpc-max-batch-size=20 \ --rollup.config=./rollup.json \ --rpc.addr=0.0.0.0 \ --rpc.port=8547 \ --rpc.enable-admin \ --sequencer.priority \ --l1.max-concurrency=20 \ --p2p.sequencer.key=$GS_SEQUENCER_PRIVATE_KEY \ --l1=$L1_RPC_URL \ --l1.rpckind=$L1_RPC_KIND(optional) \ --metrics.enabled \ --metrics.port=7070 \ --metrics.addr=0.0.0.0 ``` Once you run this command, you should start seeing the `op-node` begin to sync L2 blocks from the L1 chain. Once the `op-node` has caught up to the tip of the L1 chain, it'll begin to send blocks to `op-geth` for execution. At that point, you'll start to see blocks being created inside of `op-geth`. # Start `Bridge node` It is recommended to run the bridge node and the sequencer node on different machines or Kubernetes pods. Therefore, you need to copy the sequencer's `genesis.json` and `rollup.json` files to the corresponding runtime environment. ## Run op-geth as bridge node You need to init op-geth datadir first the same way as the op-geth of sequencer and than start op-geth with full node mode. You can adjust the flags by your environment. ``` ./op-geth \ --datadir ./datadir \ --http \ --http.corsdomain="*" \ --http.vhosts="*" \ --http.addr=0.0.0.0 \ --http.api=web3,debug,eth,txpool,net,engine \ --ws \ --ws.addr=0.0.0.0 \ --ws.port=8546 \ --ws.origins="*" \ --ws.api=debug,eth,txpool,net,engine \ --syncmode=full \ --gcmode=full \ --nodiscover \ --maxpeers=10 \ --networkid=$L2_CHAIN_ID \ --authrpc.vhosts="*" \ --authrpc.addr=0.0.0.0 \ --authrpc.port=8551 \ --txpool.globalslots=10000 \ --txpool.globalqueue=5000 \ --txpool.accountqueue=500 \ --txpool.accountslots=500 \ --txpool.reannouncetime=3m \ --txpool.reannounceremotes=true \ --txpool.pricelimit=1 \ --txpool.nolocals=true \ --cache=10000 \ --cache.preimages \ --authrpc.jwtsecret=./jwt.txt \ --rollup.disabletxpoolgossip=false \ --history.transactions=0 \ --journalfile \ --metrics \ --metrics.port=6060 \ --metrics.addr=0.0.0.0 \ --verbosity 4 ``` ## Run op-node To run a Bridge node , you can refer to this command, you need to adjust the flags by your environment.. ```bash ./bin/op-node \ --l1.trustrpc \ --l2=http://localhost:8551 \ --l2.jwt-secret=./jwt.txt \ --verifier.l1-confs=15 \ --l1.http-poll-interval=3s \ --l1.epoch-poll-interval=3s \ --l1.rpc-max-batch-size=20 \ --rollup.config=./rollup.json \ --rpc.addr=0.0.0.0 \ --rpc.port=8547 \ --rpc.enable-admin \ --l1.max-concurrency=20 \ --l1=$L1_RPC_URL \ --metrics.enabled \ --metrics.port=7070 \ --metrics.addr=0.0.0.0 \ --log.level=debug ``` ## Config p2p peer for op-node and op-geth By default, your `op-node` will try to use a peer-to-peer to speed up the synchronization process. Once you have multiple nodes, you may want to enable peer-to-peer synchronization. You can add the following options to the `op-node` command to enable peer-to-peer synchronization with specific nodes: ``` --p2p.no-discovery \ --p2p.static= \ --p2p.listen.ip=0.0.0.0 \ --p2p.listen.tcp=9003 \ --p2p.listen.udp=9003 \ ``` You can alternatively also remove the `--p2p.static` option. Through configuring `p2p static`, you can ensure: 1. Transactions sent to bridge nodes or RPC nodes can be relayed to the sequencer via P2P, without needing to send them directly to the sequencer ( need also ensure that rollup.disabletxpoolgossip=false). This reduces traffic pressure on the sequencer. 2. The sync progress between the bridge node and the sequencer node will not lag below is an example of starting a node with `p2p` parameters: ``` ./op-node --l1.trustrpc --l2=http://localhost:8551 --l2.jwt-secret=./jwt.txt --sequencer.enabled=true --sequencer.l1-confs=15 --verifier.l1-confs=15 --l1.http-poll-interval=3s --l1.epoch-poll-interval=3s --l1.rpc-max-batch-size=20 --rollup.config=./rollup.json --rpc.addr=0.0.0.0 --rpc.port=8547 --rpc.enable-admin --sequencer.priority --l1.max-concurrency=20 --p2p.sequencer.key=0x... --l1=https:/.. --metrics.enabled --metrics.port=7070 --metrics.addr=0.0.0.0 --log.level=debug --p2p.no-discovery --p2p.listen.ip=0.0.0.0 --p2p.listen.tcp=9003 --p2p.listen.udp=9003 --p2p.static=/ip4/10.180.41.12/tcp/9003/p2p/16Uiu2HAm1LN4CHrSj27HT64qeg4dQ7ZdS9WmPk6uTV7jVcpFU4e3,/ip4/10.180.41.97/tcp/9003/p2p/16Uiu2HAkw3os1Ynusda8TpEVNGHuzGj85gEiwwnHyEeY2Y6Df1HH ``` Before starting the node, we don’t yet know the `p2p static` addresses. You can first start all the nodes, then run the following `opp2p_self` command on each machine where the nodes are deployed to get each op-node’s corresponding P2P address: ``` curl localhost:8547 -X POST --data '{"jsonrpc":"2.0","method":"opp2p_self","params":[],"id":74}' -H 'Content-Type: application/json' {"jsonrpc":"2.0","id":74,"result":{"peerID":"..,"addresses":["/ip4/10.180.41.12/tcp/9003/p2p/16Uiu2HAm1LN4CHrSj27HT64qeg4dQ7ZdS9WmPk6uTV7jVcpFU4e3","/ip4/127.0.0.1/tcp/9003/p2p/16Uiu2HAm1LN4CHrSj27HT64qeg4dQ7ZdS9WmPk6uTV7jVcpFU4e3"],":0,"rejectedPayloads":0}}}} ``` Extract the first address under `addresses` in the JSON string, which is the corresponding P2P address of the node. Once we obtain the P2P addresses of all nodes deployed in the OP Stack, we can concatenate them together and use the result as the value of the `--p2p.static` parameter. After that, restart all `op-node` processes one by one with `--p2p.static`. `op-geth` also needs to be configured with `p2p` settings to ensure the whole system functions correctly. Below is an example `config.toml`. You need to restart `op-geth` with the `--config=config.toml` parameter to load the `Node.p2p` settings. ``` # cat config.toml [Node.P2P] StaticNodes = [ "enode://23394b676e64450ed7c6f845c57adec339d62ac34d0116e73a847e8c694c1888e40f83dcadbc2f6a45e4f542564c560b00773a6f3aa2ae5d28e0504bc2e68ca0@127.0.0.1:30303", "enode://1c69ec667509e84107c3758ff58a4618dd40b7912d019051265f10938b92228cad54906185ab1e4ffc00f3a025dd55580ff7e115c7b78aca264c4e99b940d331@127.0.0.1:30303", ] ``` You can obtain the node’s `enode` ID by running the following command in the `op-geth` working directory. Then gather all nodes’ `enode` IDs and write them into `config.toml`: ``` ./op-geth attach -exec "admin.nodeInfo" /geth.ipc { enode: "enode://23394b676e64450ed7c6f845c57adec339d62ac34d0116e73a847e8c694c1888e40f83dcadbc2f6a45e4f542564c560b00773a6f3aa2ae5d28e0504bc2e68ca0@127.0.0.1:30303?discport=0" //remove ?discport0 // we got the encode ID as "enode://23394b676e64450ed7c6f845c57adec339d62ac34d0116e73a847e8c694c1888e40f83dcadbc2f6a45e4f542564c560b00773a6f3aa2ae5d28e0504bc2e68ca0@127.0.0.1:30303" // You need to replace 127.0.0.1 with your real IP or domain name ``` After completing the configuration and restarting the op-geth and op-node of both sequencer and bridge node, you can execute the following command in the same directory as the `op-geth` data directory to retrieve peer information. ``` ./op-geth attach -exec "admin.peers" /geth.ipc ``` # Start `op-batcher` The `op-batcher` takes transactions from the Sequencer and publishes those transactions to L1. Once these Sequencer transactions are included in a finalized L1 block, they're officially part of the canonical chain. The `op-batcher` is critical! It's best to give the `Batcher` address at least 2 BNB to ensure that it can continue operating without running out of BNB for gas. Keep an eye on the balance of the `Batcher` address because it can expend BNB quickly if there are a lot of transactions to publish. ## Open up a new terminal You'll need a terminal window to run `op-batcher` in. ## Navigate to the op-batcher directory ``` cd ~/opbnb/op-batcher ``` ## Run op-batcher ``` ./bin/op-batcher \ --l2-eth-rpc=http://localhost:8545 \ --rollup-rpc=http://localhost:8547 \ --poll-interval=5s \ --sub-safety-margin=30 \ --num-confirmations=4 \ --safe-abort-nonce-too-low-count=3 \ --resubmission-timeout=30s \ --rpc.addr=0.0.0.0 \ --rpc.port=8548 \ --batch-type=1 \ --data-availability-type=auto \ --target-num-frames=2 \ --rpc.enable-admin \ --max-channel-duration=20 \ --l1-eth-rpc=$L1_RPC_URL \ --private-key=$GS_BATCHER_PRIVATE_KEY ``` The `--max-channel-duration=n` setting tells the `batcher` to write all the data to L1 every n L1 blocks. When it is low, transactions are written to L1 frequently and other nodes can synchronize from L1 quickly. When it is high, transactions are written to L1 less frequently and the `batcher` spends less BNB. If you want to reduce costs, either set this value to 0 to disable it or increase it to a higher value. # Start `op-proposer` ## Open up a new terminal You'll need a terminal window to run `op-proposer` in. ## Navigate to the op-proposer directory ``` cd ~/opbnb/op-proposer ``` ## Run op-proposer Please note that if you set `--pathdb.proposeblock=3600`, the proposer must start within 3600 seconds after op-geth is launched. ``` ./bin/op-proposer \ --poll-interval=1s \ --rpc.port=8560 \ --rollup-rpc=http://localhost:8547 \ --l2oo-address=$(cat ../packages/contracts-bedrock/deployments/getting-started/.deploy | jq -r .L2OutputOracleProxy) \ --private-key=$GS_PROPOSER_PRIVATE_KEY \ --l1-eth-rpc=$L1_RPC_URL ``` # Check the status of blockchain You can use the following method to check the block height of a node. In OP Stack, there are different types of block heights: **safe**, **unsafe**, and **finalized**. > **The Safe Head** represents the most recent L2 block that has been confirmed on L1, while > **The Unsafe Head** represents the highest unconfirmed L2 block that the rollup node is aware of. > The `derivation` process gradually turns `unsafe` blocks into `safe` ones, and then promotes `safe` blocks to the `finalized` state. If all three heights are continuously increasing, and the lag between `safe` and `unsafe` is minimal, it indicates that your system is producing blocks normally. Run the following command on a **sequencer** or **bridge node**: ``` wget http://localhost:7070/debug/metrics cat metrics | grep op_node_default_refs_number # TYPE op_node_default_refs_number gauge op_node_default_refs_number{layer="l1",type="l1_derived"} 5.0707611e+07 op_node_default_refs_number{layer="l1",type="l1_finalized"} 5.0707625e+07 op_node_default_refs_number{layer="l1",type="l1_head"} 5.0707627e+07 op_node_default_refs_number{layer="l1",type="l1_safe"} 5.0707626e+07 op_node_default_refs_number{layer="l1_origin",type="l2_backup_unsafe"} 0 op_node_default_refs_number{layer="l1_origin",type="l2_finalized"} 5.0707576e+07 op_node_default_refs_number{layer="l1_origin",type="l2_pending_safe"} 5.0707583e+07 op_node_default_refs_number{layer="l1_origin",type="l2_safe"} 5.0707583e+07 op_node_default_refs_number{layer="l1_origin",type="l2_unsafe"} 5.070761e+07 op_node_default_refs_number{layer="l2",type="l2_backup_unsafe"} 0 op_node_default_refs_number{layer="l2",type="l2_finalized"} 170436 // finalized block height op_node_default_refs_number{layer="l2",type="l2_pending_safe"} 170460 op_node_default_refs_number{layer="l2",type="l2_safe"} 170460 // safe block height op_node_default_refs_number{layer="l2",type="l2_unsafe"} 170543 // unsafe block height ``` # Connect Your Wallet to Your Chain You now have a fully functioning l2 rollup chain with a Sequencer node running on http://localhost:8545. You can connect your wallet to this chain the same way you'd connect your wallet to any other EVM chain. # Get BNB On Your Chain Once you've connected your wallet, you'll probably notice that you don't have any BNB to pay for gas on your chain. The easiest way to deposit BNB into your chain is to send BNB directly to the `L1StandardBridge` contract. ## Navigate to the contracts-bedrock directory ``` cd ~/opbnb/packages/contracts-bedrock ``` ## Get the address of the L1StandardBridgeProxy contract ``` cat deployments/getting-started/.deploy | jq -r .L1StandardBridgeProxy ``` ## Send some BNB to the L1StandardBridgeProxy contract Grab the L1 bridge proxy contract address and, using the wallet that you want to have BNB on your l2 rollup chain, send that address a small amount of BNB on L1. This will trigger a deposit that will mint BNB into your wallet on L2. It may take up to some minutes for that BNB to appear in your wallet on L2. # See Your opBNB in Action You can interact with your l2 the same way you'd interact with any other EVM chain. Send some transactions, deploy some contracts, and see what happens! # Deploy config example ```bash { "l1ChainID": 97, "l2ChainID": 4274, "l2BlockTime": 1, "maxSequencerDrift": 600, "sequencerWindowSize": 57600, "channelTimeout": 1200, "p2pSequencerAddress": "0x3224F068Fd97D2d4a91800D450EE19bfBCD6B6Ee", "batchInboxAddress": "0xff00000000000000000000000000000000004274", "batchSenderAddress": "0xB6e487a3cEcDe5e0E1793C98c2de1999a1319A2b", "cliqueSignerAddress": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", "l1UseClique": false, "l1StartingBlockTag": "0x304dee2", "l2OutputOracleSubmissionInterval": 3600, "l2OutputOracleStartingBlockNumber": 0, "l2OutputOracleStartingTimestamp": 1745389366, "l2OutputOracleProposer": "0x254811af494550Ee5e0945C23EC5E4E17c9dF1bC", "l2OutputOracleChallenger": "0x5E8fe030B465b448a78bA5Ef3c674Da25fDf67f5", "l2GenesisBlockGasLimit": "0x5f5e100", "l1BlockTime": 3, "baseFeeVaultMinimumWithdrawalAmount": "0x8ac7230489e80000", "l1FeeVaultMinimumWithdrawalAmount": "0x8ac7230489e80000", "sequencerFeeVaultMinimumWithdrawalAmount": "0x8ac7230489e80000", "baseFeeVaultWithdrawalNetwork": 0, "l1FeeVaultWithdrawalNetwork": 0, "sequencerFeeVaultWithdrawalNetwork": 0, "proxyAdminOwner": "0x5E8fe030B465b448a78bA5Ef3c674Da25fDf67f5", "baseFeeVaultRecipient": "0x5E8fe030B465b448a78bA5Ef3c674Da25fDf67f5", "l1FeeVaultRecipient": "0x5E8fe030B465b448a78bA5Ef3c674Da25fDf67f5", "sequencerFeeVaultRecipient": "0x5E8fe030B465b448a78bA5Ef3c674Da25fDf67f5", "finalSystemOwner": "0x5E8fe030B465b448a78bA5Ef3c674Da25fDf67f5", "superchainConfigGuardian": "0x5E8fe030B465b448a78bA5Ef3c674Da25fDf67f5", "finalizationPeriodSeconds": 3, "fundDevAccounts": true, "l2GenesisBlockBaseFeePerGas": "0x5F5E100", "gasPriceOracleOverhead": 2100, "gasPriceOracleScalar": 1000000, "gasPriceOracleBaseFeeScalar": 1368, "gasPriceOracleBlobBaseFeeScalar": 810949, "enableGovernance": false, "governanceTokenSymbol": "OPBNB", "governanceTokenName": "OPBNB", "governanceTokenOwner": "0x5E8fe030B465b448a78bA5Ef3c674Da25fDf67f5", "eip1559Denominator": 8, "eip1559DenominatorCanyon": 8, "eip1559Elasticity": 2, "l1GenesisBlockTimestamp": "0x68088736", "l2GenesisRegolithTimeOffset": "0x0", "l2GenesisDeltaTimeOffset": "0x0", "l2GenesisCanyonTimeOffset": "0x0", "systemConfigStartBlock": 0, "requiredProtocolVersion": "0x0000000000000000000000000000000000000000000000000000000000000000", "recommendedProtocolVersion": "0x0000000000000000000000000000000000000000000000000000000000000000", "faultGameAbsolutePrestate": "0x03c7ae758795765c6664a5d39bf63841c71ff191e9189522bad8ebff5d4eca98", "faultGameMaxDepth": 50, "faultGameClockExtension": 0, "faultGameMaxClockDuration": 1200, "faultGameGenesisBlock": 0, "faultGameGenesisOutputRoot": "0xDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF", "faultGameSplitDepth": 14, "faultGameWithdrawalDelay": 604800, "preimageOracleMinProposalSize": 10000, "preimageOracleChallengePeriod": 120, "proofMaturityDelaySeconds": 12, "disputeGameFinalityDelaySeconds": 6, "respectedGameType": 254, "useFaultProofs": false, "usePlasma": false, "daCommitmentType": "KeccakCommitment", "daChallengeWindow": 160, "daResolveWindow": 160, "daBondSize": 1000000, "daResolverRefundPercentage": 0, "fermat": 0, "L2GenesisEcotoneTimeOffset": "0x0", "l2GenesisFjordTimeOffset": "0x0", "snowTimeOffset": "0x0", "haberTimeOffset": "0x0", "wrightTimeOffset": "0x0" } ``` # Configuration explain ## Chain Configuration | **Item** | **Type** | **Description** | **中文补充描述** | **Default Value** | | ----------------------- | ----------- | ------------------------------------- | -------------------------- | ----------------- | | Chain ID | number | Chain id | 链id | | | Gas limit | number | The maximum gas usage of the block | 区块最大gas使用量 | 100M | | Public RPC | url | Rpc domain name | 公开的Rpc 域名 | | | Internal RPC | URL | URL | 内部使用的RPC域名 | | | l2BlockTime | number | L2 block time | l2 区块时间 | 0.5 second | | Withdraw time | Time period | Withdraw challenge period | Withdraw的挑战期 | 7 days | | Batcher Commit interval | Time period | Batcher interval for submitting data | Batcher 提交数据的最大间隔 | 1 mins | | ProposerCommit interval | Time period | Proposer interval for submitting data | Proposer 提交数据的间隔 | 1 hour | ## Gas fee Configuration | **Item** | **Type** | **Description** | **中文补充描述** | **Default Value** | | ----------- | -------- | ------------------------------------------------------------ | ------------------------------------------------------------ | ----------------- | | l1FeeScalar | number | Gas fee to be Submitted to layer 1, can be configured by Layer 2 operators, which will decide whether layer 2 is profitable | 提交给 Layer 1 的 Gas 费用,可由 Layer 2 运营商配置,这将决定 Layer 2 是否盈利 | 1000000 | ## Governance Configuration | **Item** | **Type** | **Description** | **中文补充描述** | **Default Value** | | ------------------------ | ---------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | -------------------- | | Support Governance Token | bool | Whether need to support Governance Token | 是否需要支持Governance Token | false | | Governance Token Symbol | String | Symbol for the token deployed by default to each OP Stack chain. | 默认部署到每个 OP BNB 链的代币符号。 | | | Governance Token Name | Governance Token Owner | L2 Address | Address that will own the token contract deployed by default to every OP Stack based chain.Multisig address supported | 管理Governance Token | ## Custom Gas Token Configuration | **Item** | **Type** | **Description** | **中文补充描述** | **Default Value** | | ---------------- | ---------- | ------------------------------------------------------------ | ------------------------------------------- | ----------------- | | Token Name | String | Token name | Token 名称 | | | Symbol | String | The symbol for the token is deployed by default. | Token 符号 | | | Decimal | Number | decimal | 小数位 | 18 | | Total Supply | Number | Total supply | 总供应量 | 100,000,000 | | Token Owner | L2 Address | L2 Address that holds all the minted token Multisig address supported | 用于持有发行出来的token可以准备一个多签地址 | | | Token icon image | | | | | ## Address Configuration 1) System Admin L1 Address multisig wallet address is needed 2) Proposer Challenger L1 Address Reuse System Admin L1 Address | Item | Type | Description | 中文补充描述 | Value | | --------------------- | ---------- | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------ | | System Admin | L1 Address | Address that will own all ownable contracts on L1 once the deployment is finished, including the ProxyAdmin contract. aka finalSystemOwner. | 管理l1的合约 | 使用多签地址 | | L2 Proxy Admin | L2 Address | Address that will own the ProxyAdmin contract on L2. The L2 ProxyAdmin contract owns all of the Proxy contracts for every predeployed contract in the range 0x42...0000 to 0x42..2048. This makes predeployed contracts easily upgradeable. aka proxyAdminOwner. | 管理l2的合约可以使用多签地址 | 使用多签地址 | | Base Fee Recipient | L1 Address | L1 address that the base fees from all transactions on the L2 can be withdrawn to. aka baseFeeVaultRecipient. | Base fee的收款账户 | | | Tip Fee Recipient | L1 Address | L1 address that the tip fees from all transactions on the L2 can be withdrawn to. aka sequencerFeeVaultRecipient. | 矿工费收款账户 | | | L1 Data Fee Recipient | L1 Address | L1 address that the L1 data fees from all transactions on the L2 can be withdrawn to. aka l1FeeVaultRecipient. | 数据由l2提交到l1的收费,这笔收费接受的账户 | | | Proposer Challenger | L1 Address | Address that is allowed to challenge output proposals submitted to the L2OutputOracle. aka l2OutputOracleChallenger. | 可以删除withdraw index可以使用多签,例如NR占有2/5席位,可以直接操作 | | | portalGuardian | L1 Address | Address that has the ability to pause and unpause withdrawals | 可以停止withdraw *(和**Challenger共用一个地址**)* | | # --- ## Protocol FAQs > Source: https://docs.bnbchain.org/bnb-opbnb/faq/protocol-faqs/ ### How does opBNB achieve high performance and cheap gas fees? opBNB testnet enhances the performance of the "Execution Layer" and the "Derivation Layer" of the OP Stack as highlighted in [OP Stack landscape](https://stack.optimism.io/docs/understand/landscape/?ref=binance.ghost.io#existing-landscape). ### How do you expect the TPS of the opBNB? The TPS of opBNB can be estimated to be around **4,761** transactions per second based on the calculations. This is significantly higher than Ethereum's current TPS and can enable more frequent daily transactions. ### What impact opBNB can bring to web3 games? Performance is important for games because gamers expect a highly responsive experience. Any lag, delay or choppiness can hamper enjoyment and immersion in the game. For blockchain games, fast transaction speeds and throughput are crucial to enable a seamless user experience. Gamers expect in-game assets and currencies to be transferred instantly, so the underlying blockchain network must be high performance ### What is the difference between opBNB and other Optimism based layer 2 solution, like Base? opBNB is the first layer 2 optimistic rollup on BSC, and BSC layer 1 cost is much lower than ETH, so the cost of layer 2 on BSC will give application developers a more affordable solution. Another difference is the opBNB will include the performance optimization techniques that have been used in BSC to have a much better performance. ### We already have the zkBNB as a scaling solution, why opBNB is needed? zkBNB is not EVM-comptatible, which means it is more suitable for NFT and token transactions, not for generic dApps. opBNB`s programmability is to support applications that need more flexibility. ### Is opBNB connected to the superchain or is unrelated? Can opBNB be considered as just optimistic rollups on the BNB Smart Chain? opBNB can be considered as just rollups on BSC, not superchain. Please check [this](https://bnbchain.org/en/blog/opbnb-high-performance-and-low-cost-layer-2-based- on-optimism-op-stack/) blog for more details. We may expand opBNB to superchain or L3 in the future. ### What are the differences between opBNB, the OP Stack, and Arbitrum Orbit? What are the pros and cons of these different tech stacks? Check [this](https://bnbchain.org/en/blog/opbnb-high-performance-and-low-cost-layer-2-based- on-optimism-op-stack/) blog for more details on the differences between opBNB, the OP Stack, and Arbitrum Orbit. ### Why OP Stack is used for the implementation of opBNB instead of zkEVM? OP Stack is a reliable and robust solution that has been verified through rigorous testing. OP Stack is designed with modularity in mind, allowing it to support multiple clients and different data access layers without affecting other parts of the code. opBNB leverages OP Stack as a solid foundation to explore various ways to lower the cost and enhance the user experience. ### Are transactions nonce-order enforced? Yes, on opBNB transactions, nonce-order enforced. ### How does opBNB prevent front-running and other transaction-related attacks? Front-running and other transaction-related attacks are challenges faced by many blockchain systems. opBNB uses mechanisms like transaction ordering and timestamping to mitigate these attacks. Aggregators are incentivized to order transactions fairly and not prioritize their own transactions, reducing the potential for front-running. ### Can I run my own validator or aggregator node on the opBNB network? The opBNB network currently does not support running validator or aggregator nodes by individual users. However, we are working on this feature and plan to release it in the future. Please keep following opBNB for the latest updates. ### How does opBNB handle reentrancy attacks within its optimistic rollup framework? opBNB employs a combination of security measures, including strict transaction ordering and careful state management, to prevent reentrancy attacks. By enforcing a controlled and deterministic execution order, reentrancy attacks are mitigated. ### What's the mechanism for preventing long-range attacks on the opBNB network? opBNB implements a checkpointing mechanism that anchors its state onto the main BNB chain. This helps prevent long-range attacks by ensuring that the latest valid state is preserved on-chain, making any attempted reorganizations infeasible. ### How does opBNB ensure the ordering of transactions in a decentralized manner without central coordination? The opBNB team is responsible for operating the sequencer, which ensures the correct order of transactions on the network. The sequencer is a centralized component that provides a reliable and efficient service for the users. ### How does opBNB handle disputes arising from cases where the fraud proof itself is malicious or incorrect? opBNB employs a challenge mechanism to resolve disputes. If a malicious fraud proof is submitted, honest participants can submit counter-fraud proofs to correct the situation. The challenge period provides time for these proofs to be evaluated. ### What is the challenge period on opBNB? During the challenge period, any participant on the blockchain can raise challenges against the validity of the transactions or the execution results provided by the L2 sequencer. This mechanism is crucial for ensuring the integrity and correctness of the L2 execution. ### What is the difference between validity proof and fraud proof? The validity proof is efficient at verifying, verifiers just need to check the “proof” once and confirm the correctness, but the disadvantage is that it is hard to generate the proof, both in algorithm and in efficiency. A popular validity proof solution is zero knowledge proof. On the other hand, the fraud proof is efficient at execution since it doesn’t generate any proof at execution time, but the shorthand is that a specific time window must be established for participants to challenge the correctness of the L2 state, which will highly affect the finality of the L2 results. ### What is the duration of the challenge period? The challenge window is shorter on the testnet of opBNB, so you can test the withdrawal process faster. On the mainnet of opBNB, the challenge window will be 7 days long. 21. What are the penalties for dishonest sequencers? In case a sequencer is proven to be dishonest or provides incorrect execution results, penalties are applied. The sequencer's bond may be slashed as a form of punishment. Additionally, the state roots from the problematic transaction onwards will be erased and re-computed to ensure accuracy. ### How to check if a smart contract is verified on opBNB using an API GET request? With the [API key](https://nodereal.io/meganode) and smart contract address, you can retrieve the contract's verification status, source code & ABI. - For opBNB mainnet, https://open-platform.nodereal.io/{{yourAPIkey}}/op-bnb-mainnet/contract/?action=getsourcecode&address={{contract address}}. - For opBNB testnet, https://open-platform.nodereal.io/{{yourAPIkey}}/op-bnb-testnet/contract/?action=getsourcecode&address={{contract address}}. ### How to get the finalized block height on opBNB and why is it always hundreds blocks behind the latest? The difference between latest and finalized by more than 200 blocks is expected. This is the concept in the OP design. The latest is defined as the latest unsafe block. The finalized means that the L2 block has been committed to L1 and the corresponding L1 block is finalized (by fast finality or natural finality). --- ## Gas and Fees FAQs > Source: https://docs.bnbchain.org/bnb-opbnb/faq/gas-and-fees-faqs/ ### What is the cost of transfer transaction on opBNB and why opBNB hold capacity to enable the mass adoption of daily small amount transactions? opBNB can make small daily transactions possible because the transaction fees are very low, around **$0.005** per transaction. This is much lower than traditional payment methods like credit cards which charge around **1-3%** per transaction. The low fees on opBNB make it economical for small purchases and daily transactions. ### What is the link to the canonical bridge for gas/stables? - **For Testnet:** - **For Mainnet:** ### Where can we get the token pricing for the BNB token on opBNB? You can get the token pricing for BNB on opBNB from [Coinmarketcap](https://coinmarketcap.com/currencies/bnb/) ### What is the block gas limit on opBNB? The block gas limit on opBNB is **100M/block**, and the block time of opBNB is **1 second**. ### How are transaction fees calculated on opBNB? You can details about the transaction fee calculation from [opBNB official docs](../core-concepts/gas-and-fees.md) ### Are there any overheads to include in the gas calculation? Yes, there is a _fixed overhead_ for L1 data fee is **2100**, and _dynamic_overhead(L1 Fee Scala)_ is **1**. ### How are data storage fees for rollups calculated? The data storage fees for rollups are calculated using the following formula. ```math l1_data_fee = l1_gas_price * (tx_data_gas + fixed_overhead) * dynamic_overhead fixed_overhead = 2100 dynamic_overhead = 1 tx_data_gas = count_zero_bytes(tx_data) * 4 + count_non_zero_bytes(tx_data) * 16 ``` ### What gas fees are associated with withdrawing opBNB assets from the main chain back to the layer 2 network? Gas fees associated with withdrawing assets from the main chain back to the layer 2 network depend on the BNB chain's gas price at the time of withdrawal. These fees cover the cost of anchoring data on-chain and updating the network state. ### where can I find out more information about L2 gas fees? Prominent Layer 2 mainnet gas fees resource. * [opBNB](https://opbnbscan.com/tx/0xa9f32fc3ef0b3338032bffc95f1c93e4d4bf6bdf6f0225b47e3b543b5421fdc0) * [Optimism](https://l2fees.info/) * [Arbitrum](https://l2fees.info/) * [Base](https://basescan.org/tx/0xd360162fb3474308acdf707f730cbff993168ef46610f5453b3a10d7d76deaa2) * [Starknet](https://l2fees.info/) * [Linea](https://l2fees.info/) * [Polygon zkEVM](https://l2fees.info/) * [zkSync](https://l2fees.info/) To also check BNB Chain’s Layer 1, BSC visit [here](https://bscscan.com/tx/0x1515e830b352a76bab8468d39c4924e1d220578ab0bf69eb09914e877c0713e5). ### Why is my opbnb transaction rejected or pending? There are several possible reasons why your transaction of opBNB may be rejected or pending. Here are some of the most common ones: * You have insufficient funds in your wallet to cover the transaction fee or the amount of opBNB you want to send. * You have set a gas price or gas limit that is too low for the network congestion level, resulting in a slow or failed transaction. * You have made a mistake in the contract interaction, such as calling a function that does not exist or sending an unsupported token type. * You have encountered a technical issue with your wallet provider, the opBNB network, or the smart contract you are interacting with. To troubleshoot your transaction, you can do the following: * Check your wallet balance and make sure you have enough funds to cover the transaction fee and the amount of opBNB you want to send. * Check the network status and adjust your gas price and gas limit accordingly. Sometimes the wallet like Trust Wallet or Metamask recommends the "max base fee" or "max priority fee" to "0". This is not accepted by the opBNB Mainnet and will result in a failed transaction. Please check your transaction details carefully before signing/confirming. If you see a "0" in the "max base fee" or "max priority fee" fields, do not proceed with the transaction. Instead, cancel it and try again until you see a normal fee recommendation. * Check the recipient address and make sure it is correct and valid. You can use a tool like https://opbnbscan.com/ to verify the address and see if it has any transactions history or contract code. * Contact your wallet provider, the opBNB network, or the smart contract developer for technical support if you suspect there is an issue on their end. ### Why the estimated transaction fee is zero in my wallet? It is because wallets are not well adapted to L2 networks. Wallets are designed for L1 networks, where the total transaction cost is calculated differently from L2 networks. For example, suppose you want to send some opBNB tokens on the opBNB network. When you use your wallet to approve the transaction, you will see that the estimated gas fee is 0BNB. This may seem like a great deal, but it is not the whole story. The gas fee you see in your wallet is based on the L2 part of the transaction, which is very low because it uses a batch processing technique to aggregate many transactions into one. The L2 part of the transaction consists of two components: the base fee and the priority fee. The base fee is a fixed amount that depends on the network congestion, and the priority fee is a variable amount that you can set to increase or decrease the speed of your transaction. For example, in our case, the base fee is 0.000000008 gwei and the priority fee is 0.00001 gwei, so the total L2 gas price is 0.000010008 gwei. The gas used is 21000, which is the standard amount for a transfer transaction. Therefore, the total L2 gas fee is 0.000010008 * 21000 = 0.210168 gwei, which is too small to be displayed in your wallet. However, this is not the only cost you have to pay for your transaction. There is also a layer 1 (L1) part of the transaction, which is the data cost. This is because every L2 transaction has to be recorded on the blockchain as data, and data storage on the blockchain is not free. The L1 part of the transaction depends on the size of the data and the L1 gas price at the time of submission. For example, in our case, the size of the data is 68 bytes and the L1 gas price is 249 gwei, so the total L1 gas fee is 68 * 249 = 16.932 gwei. Therefore, the actual cost of your transaction is the sum of the L2 and L1 parts, which is 0.210168 + 16.932 = 17.142168 gwei, or about 0.00001698 BNB, or about 0.003 USD at current prices. This is still very cheap compared to other blockchains, but it is not zero as your wallet shows. To verify this, you can check your transaction details on the opBNB explorer, where you will see both the L2 and L1 costs clearly displayed. We hope this helps you understand how opBNB works and why your wallet only shows the L2 cost. ### Why is one of transaction's gas fees so much higher than the rest? A known issue that can cause irregularly high gas prices in opBNB transactions could be due to a high L1 gas price which is calculated by averaging block transaction gas prices using the formula: ```(Txn Fee = Gas Price * Gas + L1 Gas Price * L1 Gas Used * L1 Fee Scalar)``` This means that if there is an L1 block with an unusual high gas price, it will cause the gas price to be higher for a specific L2 block. This will be fixed going forward by introducing a static L1 gas price. --- ## opBNB Bridge FAQs > Source: https://docs.bnbchain.org/bnb-opbnb/faq/opbnb-bridge-faqs/ ### What is the status of the integration between opBNB and Optimism's Superchain? opBNB is a project that aims to bring the benefits of L2 scaling and user-friendly UX to the BNB ecosystem. It will enable fast and cheap transactions on BNB L2, as well as smooth interoperability with Greenfield, a decentralized platform for building and running applications. Superchain is an innovative solution that leverages OP Stack to provide L2/L3 scaling and security for Ethereum. It allows users to access various L2 protocols with a single wallet and enjoy low fees and high throughput. opBNB is interested in collaborating with Superchain and integrating OP Stack into BNB Chain. ### What is the reason for the discrepancy in the estimated cost of withdraw/deposit transactions between the opBNB bridge page and my wallet? When you use the bridge to deposit or withdraw assets from opBNB, the bridge will estimate the gas cost for your transaction. This is done by simulating the execution of the transaction on the blockchain, without actually sending it or changing the state of the network. The simulation returns a number that indicates how much gas units the transaction would use if it was executed in the current network state. To get this number, the bridge uses a function called estimateGas, which implements a binary search algorithm between a lower and an upper bound of gas units. The lower bound is usually 21,000, which is the minimum gas required for a simple ether transfer. The upper bound is either specified by the user or derived from the block gas limit of the pending block. The function tries to execute the transaction with different gas values within this range until it finds the smallest gas value that does not cause an out-of-gas exception. This is the estimated gas usage of the transaction. For example: In this example, the bridge estimate of gas is around 0.0008 BNB, which is around $0.17. However, the wallet that you use to interact with the bridge may use a different method to calculate the estimated transaction cost. It may use the gas limit, which is the maximum amount of gas that you are willing to spend on the transaction. This is usually higher than the estimate given by the bridge. For example: The wallet estimate of the transaction is around 0.002 BNB, which is around $0.47. Once the transaction is executed on the chain, you can see the actual cost of the transaction in the opBNB explorer, which usually is similar to the estimate given by the bridge. ### Why your tokens on BSC are not received after 7 days of withdrawal request? You might have forgotten to sign the proof in the transaction history. This is a necessary step to initiate the 7 days challenge window. Without signing the proof, the bridge will not proceed with the challenge window and your withdrawal will be postponed. ### Why do I need to sign the proof to start the 7 days challenge window? When you withdraw tokens from opBNB to BSC, you need to provide a proof withdrawal to verify that your transaction on L2 is valid and consistent with the world state of L2. This is because L1 does not have access to the full world state of L2, only the data availability (DA) data and periodic snapshots of the world state from L2. The DA data is a compressed representation of the transactions on L2, which can be used to reconstruct the world state of L2 if needed. However, this process is expensive and time-consuming, so it is not done for every withdrawal. Instead, you need to submit a proof withdrawal, which is a cryptographic proof that your transaction on L2 matches the world state of L2 at a certain point in time. This way, you can ensure that your withdrawal is secure and accurate, and that no one can cheat or double-spend on L2. --- ## Cross Chain FAQs > Source: https://docs.bnbchain.org/bnb-opbnb/faq/cross-chain-faqs/ ### How does opBNB ensure data availability and security for off-chain transactions? opBNB relies on a mechanism called "fraud proofs" to ensure data availability and security. Users can submit proofs on-chain that demonstrate any malicious behavior or incorrect transaction processing on the off-chain optimistic rollup. If a fraud proof is valid, the system can penalize the malicious actor and revert any incorrect state changes. ### Who is responsible for gathering and bundling off-chain transactions into bundles on opBNB network? Sequencers are responsible for the aggregation of transactions, computation of the state transitions and submission of these to the rollup contract on BSC. ### What is the role of the aggregator in the opBNB network? Aggregators are entities responsible for gathering and bundling off-chain transactions into batches. They play a crucial role in opBNB by forming these transaction batches and submitting them to the main BNB chain for validation. Aggregators also generate Merkle proofs for the data they submit, which are essential for the anchoring process. ### Can opBNB handle smart contracts and complex computations like the main BNB Chain? The opBNB network is EVM compatible and works identically to BSC from a smart contract developer’s perspective. This means that developers can easily deploy their existing Ethereum or BSC smart contracts on opBNB with minimal changes. ### How does opBNB handle cross-contract interactions and composability? Cross-contract interactions and composability are challenging aspects for optimistic rollups. While opBNB can facilitate cross-contract interactions, the limitations of off-chain processing mean that certain complex composability scenarios might be less efficient or not supported at all. Developers and projects using opBNB need to carefully consider these limitations when designing their applications. ### What happens if there's a dispute about an off-chain transaction's validity? In the event of a dispute, a "challenge" period is initiated. During this period, anyone can submit a fraud proof to challenge the validity of an off-chain transaction. If the fraud proof is valid and proves that the transaction was incorrect or malicious, the transaction is reverted on-chain, and the malicious actor might face penalties. ### Can smart contracts deployed on the main BNB Smart Chain interact seamlessly with applications on opBNB? If yes, how? Yes, this is achieved through a set of smart contracts that enable the execution of transactions on the opBNB network. The main contract is the `batchInbox` contract, which receives batches of transactions from the Sequencer on L1. ### How to allow smart contract cross chain communication between L1 and L2? Directly interacting with smart contract functions that exist on L2(opBNB) from L1(BSC), is not possible as all smart contracts on L2 are isolated from L1. With that said, there is a way for developers to allow arbitrary message sending by writing their own contracts to build their required business logic. More details [here](https://community.optimism.io/docs/developers/bridge/messaging/#communication-basics-between-layers). ### Can I directly transfer assets between opBNB and Greenfield? Currently, direct cross-chain transfers between opBNB and Greenfield are not supported. However, users can achieve cross-chain transfers between these two networks by conducting a two-step process through the BNB Smart Chain (BSC). This involves transferring assets from opBNB to BSC and then from BSC to Greenfield. --- ## Build on opBNB FAQs > Source: https://docs.bnbchain.org/bnb-opbnb/faq/build-on-opbnb-faqs/ ### How to check if a smart contract is verified on opBNB using an API GET request? With the [API key](https://nodereal.io/meganode) and smart contract address, you can retrieve the contract's verification status, source code & ABI. - For opBNB mainnet, `https://open-platform.nodereal.io/{{yourAPIkey}}/op-bnb-mainnet/contract/?action=getsourcecode&address={{contract address}}` - For opBNB testnet, `https://open-platform.nodereal.io/{{yourAPIkey}}/op-bnb-testnet/contract/?action=getsourcecode&address={{contract address}}` ### Why does token info (like name, symbol) is not displayed on opBNBscan despite having contract verified? If the deployed contract is a proxy contract, then the info. will not be displayed as opBNBscan uses enhanced API to fetch the token details like name, symbol etc. In this case, enhanced API needs to call the implementation contract to fetch the token details. Currently, this feature is under development where enhanced API will make call to implementation contract when token info. returned from proxy contract is empty. ### Are there any grants or financial support for projects on opBNB? Yes, we provide the same support for opBNB as for BNB Smart Chain when it comes to grants or financing projects. Check [here](https://www.bnbchain.org/en/developers/developer-programs) for the complete details. ### Is there an ability to run nodes on opBNB? Check out the official [documentation](../advanced/local-node.md) to learn how to run nodes on opBNB. ### Can a native project on opBNB issues its token natively on opBNB? Yes, it is up to the project. ### What is the recommended approach for launching projects, should the project be natively launched on opBNB and then bridged to L1 or the other way around? The choice of L2 or L1 depends on the specific needs of the project. L2 offers better performance and lower cost, so it is advisable to use L2 as the starting point if these factors are important for the project. ### Is there a possibility of a shared sequencer/liquidity with other chains built on OPStack in the future? Unfortunately, no, in short term, this is BNB Chain team`s goal yet. ### What programming language is used for the opBNB chain and contracts? The pre-deployed smart contracts are written in Solidity, and opBNB is built with OP Stack framework. For details, please refer to [official docs](../core-concepts/why-opstack.md) for more details. ### Are there any airdrops for opBNB? We want to clarify that there is NO airdrop planned for opBNB as of now. Please be cautious and aware of any claims or messages suggesting otherwise. Protect yourself from potential scams by staying vigilant and verifying information from official sources. ### What oracles and VRF does opBNB support? opBNB is a permissionless chain that allows any VRF and oracle services to be integrated. The first two services that have been launched on opBNB are Binance Oracle and Polythera, which provide reliable and secure data feeds for smart contracts. ### What to do if there is trouble verifying smart contract with all available methods using the Try using the alternative explorer for verifying your smart contracts. ### How do we set hardhat verification parameters for opBNB? Refer to the official Hardhat documentation [here](https://hardhat.org/hardhat-runner/plugins/nomicfoundation-hardhat-verify#adding-support-for-other-networks) ### How does opBNB handle the storage and execution of metadata associated with NFTs on its optimistic rollup? The process of creating and storing NFTs on the opBNB is similar to other blockchains. You need to have a smart contract that defines the properties and functions of your NFT, and then deploy it on the opBNB. To store the metadata of your NFT, such as the name, description, image, and other attributes, you can use various storage solutions. Some examples are BNB Greenfield, IPFS, and Filecoin. ### Why my opBNB node is unable to catch up with current blocks? There is a possibility that the node's chain has been forked and is different from other nodes. In the event that the chain is forked due to a hard fork, it is recommended to reset the blockchain and synchronize it with the latest version of the program: 1. Clear the data directory in OP Geth 2. Update the opbnb to latest version: `git clone -b v0.x.x git@github.com:bnb-chain/opbnb.git` 3. Update the op-geth to latest version: `git clone -b v0.x.x git@github.com:bnb-chain/op-geth.git` Follow the instructions [here](../advanced/local-node.md) to re-sync the node. Just note that make sure to use the latest version of opbnb and op-geth, and use the new version `genesis.json` and `rollup.json`. ### How to verify ERC1967Proxy upgradeable contract on opbnb-testnet by Hardhat? You can follow the instructions from How to verify a contract on [Etherscan/BscScan/PolygonScan](https://forum.openzeppelin.com/t/how-to-verify-a-contract-on-etherscan-bscscan-polygonscan/14225#if-proxy-is-not-verified-10) to use the solc-input.json to verify the proxy. ### How to get proxy's constructor arguments for verification? To form _data argument we need: 1. Function name. 2. Owner address + argument1 + argument2 + etc. Then copy "Encoded data", add "0x" at the beginning of the text and past it as _data (Bytes) argument. For details, please refer to [openzeppelin docs](https://forum.openzeppelin.com/t/how-to-verify-upgradeable-contract-on-opbnb-testnet-by-hardhat/39495/6?u=serghd). An easier way is to look at the input data of the creation transaction for your proxy: https://testnet.opbnbscan.com/tx/0xa287b0b69472cb4961c528b16e799136a520f700b5407595314c3cdd0a21f8d6?tab=overview 3. You can see that the encoded constructor arguments are at the last portion of the bytecode. --- ## BNB Greenfield > Source: https://docs.bnbchain.org/bnb-greenfield/ Dive into what is BNB Greenfield and start the journey with Greenfield. Start building dapps to create value based on the data assets and its related economy. The real power of the Greenfield lies in its programmability to support the creation of value based on the data assets and its related economy. Get familiar with the Greenfield Blockchain and explore its main modules. Explore the Storage Provider. Utilize the APIs and SDKs to build the app --- ## Overview > Source: https://docs.bnbchain.org/bnb-greenfield/introduction/ --- title: BNB Greenfield Introduction description: BNB Greenfield is a decentralized storage and blockchain storage solution that simplifies data management and access while connecting data ownership with the DeFi context of BNB Chain. keywords: [BNB Greenfield, decentralized storage, blockchain storage solution, decentralized storage providers] sidebar_label: What is BNB Greenfield --- # BNB Greenfield Overview BNB Greenfield is a decentralized storage and blockchain storage solution platform that aims to revolutionize data ownership and the data economy. ## What is BNB Greenfield BNB Greenfield is a cutting-edge decentralized storage and blockchain storage solution, designed to harness the power of decentralized technology in the field of data ownership and the data economy. The platform focuses on providing decentralized data management and access, to revolutionize the data economy by simplifying the process of storing and managing data, while connecting data ownership with the DeFi context of BNB Chain. What sets Greenfield apart from existing centralized and decentralized storage systems are its three key components: - It allows Ethereum-compatible addresses to create and manage both data and token assets. - It natively links data permissions and management logic onto BSC as exchangeable assets and smart contract programs with all other assets. - It provides developers with similar API primitives and performance as popular existing Web2 cloud storage. The ultimate goal of Greenfield is to establish a foundation for new data economy and dApp models, which will undoubtedly aid in the development and evolution of the foundation for Web3. ## Why BNB Greenfield The cryptocurrency industry has experienced significant growth and adoption, with the likes of tokens, stablecoins, and DeFi covering various economic scenarios. However, certain areas like credit, real-world asset (RWA) tokenizations, and data remain inadequately innovated. Consequently, BNB Greenfield has been created to focus on ***data***. A crucial issue that the BNB Greenfield project aims to address is that the value of a data asset is not self-evident when held by one person. The value of data assets increases when shared and leveraged by multiple parties, which stems from the ability to write, read, grant rights for sharing data, and even execute data to generate another. These abilities have financial traits that are tradable, and such trades can produce even more value and benefit two parties rather than just one. We foresee the need to create a new Web3 infrastructure for data, as two major features are still missing: a performant, convenient, and friendly decentralized storage infra, and the data-focused smart contract synergy. Hence, we aim to create "BNB Greenfield," a new BNB side blockchain and relevant infrastructure that allows users and developers to: 1. "login" with anonymous cryptographic-based keys (IDs); 2. create, read, share, and even execute data, with a user experience that is on par with the state-of-the-art cloud storage services today, and at a low cost; 3. fully own their data assets and control who can use them and how; 4. easily put their data assets into a wide, smart-contract-based economic context to gain financial value with them. In summary, BNB Greenfield seeks to offer users greater freedom in creating, owning, sharing, executing, and trading their data assets, while also providing transparency on how their data is owned and used. ## How BNB Greenfield Works BNB Greenfield operates on two layers: 1. It is built on a new, storage-focused blockchain; and 2. It consists of a network of "storage providers". The [BNB Greenfield Blockchain](./for-validator/overview.md) maintains the ledger for users and records the storage metadata as the common blockchain state data. Its native token for gas and governance is BNB, which is transferred from BNB Smart Chain. Additionally, BNB Greenfield blockchain has its own staking logic designed for governance. The [Storage Providers (SP)](./storage-provider/overview.md) are storage service infrastructures provided by organizations or individuals that use Greenfield as the ledger and the single source of truth. Each SP is responsible for responding to user requests to upload and download data, while also serving as the gatekeeper for user rights and authentications. Together, BNB Greenfield blockchain and the SPs comprise a decentralized object storage system that serves as the core of this new economy. Developers can construct decentralized applications (dApps) using the BNB Greenfield platform, which can act as client tools that facilitate user interactions with Greenfield; or applications that provide significant value to users' real lives using Greenfield as their infrastructure. These applications will use blockchain addresses as user identifiers and connect with features and smart contracts on the Greenfield blockchain, Greenfield SPs, and BNB Chain. A native cross-chain bridge exists between BSC and BNB Greenfield blockchain. While it is cheaper to create and access data on Greenfield, the relevant data operation can be transferred to BSC and integrated with DeFi smart contract systems to generate new business models. ## Ecosystem From Storage Providers and BNB staker to developers, there are a variety of individuals and entities that play a critical role in the growth and success of Greenfield. We'll dive into the unique contributions and responsibilities of each group, and explore how they work together to shape the future of Greenfield. ### Greenfield Actors #### Validators The Greenfield blockchain operates as a Proof-of-Stake (PoS) blockchain and has its own set of validators chosen through an election process based on PoS logic. The Validators have a vital responsibility of ensuring the security of the Greenfield blockchain. They are actively involved in the governance and staking of the blockchain, and their role is similar to other PoS blockchain networks. Additionally, they form a peer-to-peer network that plays a crucial role in the overall functioning of the blockchain. In addition to their governance responsibilities, validators also accept and process transactions, which enables users to operate on the objects stored on the Greenfield blockchain. They are responsible for maintaining the metadata of Greenfield and ensure that the blockchain state acts as a control panel for both Storage Providers (SPs) and users. Both parties rely on the validators to accurately update and utilize this state in order to operate, store, and access their object storage. #### Storage Providers (SPs) Storage Providers (SPs) are a crucial part of the Greenfield blockchain. They offer storage service infrastructures to individuals and organizations. Using the Greenfield blockchain as the ledger and single source of truth, SPs maintain secure and reliable storage. Each Service Provider (SP) is accountable for handling user requests to upload and download data. They act as gatekeepers for user rights and authentications, which makes them integral in ensuring the security and accessibility of user data at all times. For further details on storage providers, kindly explore our dedicated [Storage Provider's page](https://github.com/bnb-chain/greenfield/blob/master/docs/modules/storage-provider.md). ### Greenfield Features #### dApps Greenfield dApps are applications that leverage the unique features of the Greenfield blockchain to solve various problems for their users. These dApps are designed to utilize Greenfield storage and related economic traits, providing a reliable and secure platform for creating and managing data. Users can interact with the BNB Greenfield Core Infrastructure through the use of BNB Greenfield dApps, which are decentralized applications that enable seamless interaction with the Greenfield ecosystem. Furthermore, the Greenfield blockchain provides an intuitive smart contract library on the cross-chain facility, making it easy for dApp developers to integrate these features into their applications. This user-friendly approach allows developers to efficiently build and deploy dApps that can solve real-world problems. #### Relayers The Greenfield Relayer is a powerful bi-directional relaying service designed to facilitate seamless communication between Greenfield and BSC/opBNB. It can only be operated by Greenfield validators and functions as a standalone process. This innovative system independently monitors and tracks cross-chain events that take place on both the Greenfield and BSC/opBNB networks, storing this data securely in a database. When an event is confirmed, the relayer generates a Boneh–Lynn–Shacham (BLS) signed message that is then shared through the P2P network on the Greenfield network, known as "the vote". As more votes are collected, the Greenfield Relayer assembles the necessary cross-chain package transaction and submits it to either the BSC/opBNB or Greenfield network. This streamlined process ensures that communication between the two networks is efficient and error-free. #### Challenge Verifier Challenge Verifier is an off-chain service that verifies data availability, data integrity and service quality by monitoring storage provider’s activities. This mechanism works by penalizing and gradually eliminating storage providers with poor service quality, in order to ensure the good performance and reliability of the entire network. To elaborate, Challenge Verifier constantly checks the storage providers in the network by tasking them with challenges to prove their reliability. The challenges may include storing specific pieces of data or responding to requests within a certain time limit. Providers that fail these challenges will be punished by slash their staked BNB. By using Challenge Verifier, the network can ensure that only reliable and trustworthy storage providers are allowed to participate, protecting the network from any potential data loss, corruption, or low-quality service. Additionally, Challenge Verifier creates a competitive environment for storage providers, motivating them to continuously improve their services to avoid penalties and stay in the network. Challenge Verifier can only be operated by Greenfield validators right now, and will open to public in the future. ### Explore and Participate in BNB Greenfield - [Quick Start with BNB Greenfield](getting-started/wallet-configuration.md) - [Overview about Greenfield Blockchain](for-validator/overview.md) - [Overview about Storage Provider](storage-provider/overview.md) - [Pricing Calculator](https://dcellar.io/pricing-calculator) - [Become a Validator](https://github.com/bnb-chain/greenfield/blob/master/docs/blockchain-cli/validator-staking.md) - [Become a Storage Provider](https://github.com/bnb-chain/greenfield/blob/master/docs/blockchain-cli/storage-provider.md) - [Own Your Data](https://github.com/bnb-chain/greenfield/blob/master/docs/blockchain-cli/storage.md) --- ## Wallet Configuration > Source: https://docs.bnbchain.org/bnb-greenfield/getting-started/wallet-configuration/ # Wallet Configuration In this guide, you will learn how to use the extension wallets to interact with Greenfield. You can also add BNB Greenfield network according to the [RPC Endpoints](../for-developers/network-endpoint/endpoints.md) manually. ## Supported Wallets * [Trust wallet](https://trustwallet.com/) * [MetaMask](https://metamask.io/) * [Ledger](https://www.ledger.com/) We assume you have installed Trust Wallet or MetaMask and have an account, if not, please refer to the download link of [Trust Wallet](https://chrome.google.com/webstore/detail/trust-wallet/egjidjbpglichdcondbcbdnbeeppgdph) and [MetaMask](https://metamask.io/download/) to install it. ## Add Greenfield Network 1. Visit [BNB Chain List](https://www.bnbchainlist.org/). 2. Click **Connect Wallet**. 3. Find **Greenfield Mainnet** or **Greenfield Testnet**, and click **Add To Wallet** to add new RPC in Trust Wallet or Metamask. 4. When extension wallet prompts a window, click **Approve**. --- ## Bridge and Transfer BNB > Source: https://docs.bnbchain.org/bnb-greenfield/getting-started/token-transfer/ # Bridge and Transfer BNB The address formats of Greenfield and BSC are fully compatible. Users can transfer BNB between Greenfield and BSC freely. However, Greenfield only supports BNB and does not support BEP20 tokens currently. This is a comprehensive guide detailing the process of transferring BNB between Greenfield Blockchain and BSC. ## Transfer from BSC to Greenfield To perform a cross-chain transfer from BNB Smart Chain (BSC) to Greenfield, follow these steps: 1. Visit [Greenfield Bridge](https://greenfield.bnbchain.org/en/bridge?type=transfer-in). 2. Connect your wallet and switch to the BSC network. 3. Specify the desired amount and click the `Transfer In` button. 4. Confirm the transaction and wait for the transfer to be processed on BSC. 5. Once the transaction is confirmed, the funds will be transferred from BSC to Greenfield. The transferred funds will reflect in the same account on Greenfield within a few seconds. You can also use [DCellar](https://dcellar.io/) and follow [How to Transfer In](https://docs.nodereal.io/docs/dcellar-get-started#transfer-in) to transfer BNBs from BSC to Greenfield. ## Transfer from Greenfield to BSC To perform a cross-chain transfer from Greenfield to BNB Smart Chain (BSC), you will need to: 1. Visit [Greenfield Bridge](https://greenfield.bnbchain.org/en/bridge?type=transfer-out). 2. Connect your wallet and switch to the Greenfield network. 3. Specify the desired amount and click the `Transfer Out` button. 4. Confirm the transaction and wait for the transfer to be processed on Greenfield. 5. Once the transaction is confirmed, the funds will be transferred from Greenfield to BSC. The transferred funds will reflect in the same account on BSC within a few seconds. You can also use [DCellar](https://dcellar.io/) and follow [How to Transfer Out](https://docs.nodereal.io/docs/dcellar-get-started#transfer-out) to transfer BNBs from Greenfield to BSC. !!! note One thing to note is if the value of the cross-chain transfer is over 1000BNB, the funds will be locked in `TokenHub` for 12 hours before they can be withdrawn. Usually, a third-party server will help withdraw the unlocked token to the recipient, and users can also withdraw to the recipient themselves by following [unlock document](https://github.com/bnb-chain/greenfield-contracts#large-transfer-unlock) ## BNB Transfers in Greenfield Greenfield allows for easy and secure transfers between different accounts. However, due to the particularity of the transaction format, it is currently not possible to transfer tokens through the built-in Send function in the wallet, like MetaMask. To conduct an internal transfer within Greenfield, please adhere to the following steps: 1. Visit [DCellar](https://dcellar.io/). 2. Click the `Get Started` button located at the top right. 3. Connect your wallet and sign in. 4. Go to the `Wallet` page on the left sidebar, then proceed to the `Send` page. 5. Fill in the destination address where you want to transfer, specify the amount, and click the `Send` button. 6. Confirm the transfer and wait for the transaction to be processed. 7. Once the transfer is confirmed, the funds will be moved from the source account to the destination account within Greenfield. --- ## Use Greenfield in Dcellar > Source: https://docs.bnbchain.org/bnb-greenfield/getting-started/dcellar/ # Use Greenfield in Dcellar DCellar is a powerful tool that allows users to initiate their decentralized data management journey on the Greenfield platform. It is developed based on Greenfield by [Nodereal](https://nodereal.io/). With DCellar, users can store and share their data, as well as manage their account assets. ## Login Simply open the web browser and navigate to [dcellar.io](https://dcellar.io/). You will be greeted with a Welcome Screen that provides a simple and user-friendly interface. To get started, click on the **Get Started** button, and your wallet extension will automatically be activated. This will log you in with your current wallet account, allowing you to access all the features and functions of DCellar. With this easy and straightforward process, even first-time users can quickly get started with decentralized data management on the Greenfield platform. For first time users, you will need to add Greenfield Network to your Wallet, and you will be asked to switch your network to Greenfield Network to start following operations. You can also add Greenfield Network to your wallet manually, you can find it at [bnbchainlist](https://www.bnbchainlist.org/) For returning users, you will stay logged in for a default time period. During the default time period, you will stay logged in when you come back. After that, you will need to login with wallet again. If you want to switch to your other wallet accounts, you can try **Disconnect** first, and then login again with another account. ## Transfer In Before you can begin storing your objects with DCellar, you'll need to transfer several amounts of BNB tokens from your BSC account to your Greenfield account. These two accounts share the same account address, making the transfer process straightforward and hassle-free. By transferring BNB tokens to your Greenfield account, you'll be able to cover the transaction fees associated with storing and managing your objects on the Greenfield platform. Once you've completed this step, you'll be ready to start using DCellar and taking advantage of all its powerful features and benefits. Once you've logged in to DCellar, you can access the Transfer In tab by navigating to the Wallet Page. Before you begin the transfer process, it's important to ensure that you're currently using the BSC . If you're using the Greenfield Network, the Transfer In page will be displayed differently. To avoid any confusion, make sure that you're on the correct network before proceeding with the transfer process. By following these simple steps, you can quickly and easily transfer BNB tokens to your Greenfield account and start using DCellar to manage your decentralized data. Click **Switch to BNB Smart Chain**, your wallet will be notified, informing you to switch network, by clicking **Switch Network** button on wallet pop-up, you will be able to switch to BSC . If you haven't added a BSC network yet, wallet will ask you to add a network first, then switch to this network. You will be able to Transfer a certain amount of BNB token from your BSC account to your Greenfield account which shares the same address. Transfer In will cost you two kinds of fees, all charged by BNB token: - **Gas fee**: covers the gas cost for sending your transfer on the destination chain. - **Relayer fee**: paid to relayers for handling cross-chain packets. Input the amount you want to Transfer In, Click **Transfer In**, your transaction will be sent. You can view your transaction details in explorer. ## Create Bucket Before you start using DCellar to manage your objects, you should make sure you are currently under Greenfield Network. If you are under another network, you will be asked to **Switch to BNB Greenfield** first. A bucket is a logical container for storing objects in Greenfield. Once a bucket has been created, you can upload your objects to a certain bucket. After Login, you can see the New Bucket button at your bucket list page. After clicking **New Bucket**, a pop-up will show and you will be asked to enter a bucket name. Each bucket has a unique name that is assigned by the user when the bucket is created. Please follow the naming rules, carefully select your bucket name: - Bucket names must be between 3 (min) and 63 (max) characters long. - Bucket names can consist only of lowercase letters, numbers, and hyphens (-). - Bucket names must begin and end with a letter or number. - Bucket names must be global unique in Greenfield - A bucket name cannot be used by another Greenfield account until the bucket is deleted. By selecting a primary storage provider, you will decide the main storage service provider for all the datas within this particular bucket. By selecting a payment account, all storage service fee will be charged from this selected payment account, while gas fee will charged from your current login account, which is also your owner account. If your balance is insufficient, you will be informed to Transfer In first. For more information about Owner Account and Payment Account, Please Go to Greenfield Doc- [Greenfield Documentation](../core-concept/billing-payment.md). ## Upload Object Choose one bucket on your bucket list page, you can see the objects within this bucket. Click **Upload** , you will be able to choose a locally stored object. When you are uploading a object, gas fee will be charged from your current login account, which is also your owner account. Besides, once your object is uploaded successfully, you will be charging a storage fee under a certain flow rate. Therefore, when you are uploading a object, you need to make sure that your owner account has enough balance to cover the storage fee for the following six months. which will be shown as Prepaid fee as follows. !!! info Please notice that the prelocked fee is not charged at the beginning, it is still in your owner account. But you are not allowed to use it for other purposes because it's "locked". Besides prepaid fee, each operation will bring settlement, which might generate settlement fee. Learn more about [Greenfield Settlement](../core-concept/billing-payment.md). Moreover, you can select the permission property of the selected object, DCellar will set your object as private by default. After you successfully upload your data, Greenfield will start to charge storage fee from your locked fee in your account. You can view your total "locked fee" at your account page. ## Create Folder You can create folders to better organize your objects. carefully choose your folder name, avoid "/" in your folder name. Create folder will cost you some gas fee. Also, every operation will bring settlement, so there might be settlement fee. Settlement fee will be charged from the payment account, while gas fee will be charged from owner account. ## Download Object When you are downloading a object, gas fee will not be charged. But it will cost your some Download bandwidth. !!! info Each download operation will consume Download Quota, which is related to object size. In the current testing phase, each bucket will be given 1G's free quota. You can check your bucket's remaining quota at Bucket Detail page When your remaining quota is smaller than the required quota for a certain object you are downloading, your download will fail, you will be reminded to buy more quota. ## Manage Quota You can buy quota by month. Choose the amount you want to buy. Please notice that when you download objects, the system will automatically use the free quota first, which will not expire during your usage period. After your free quota is used out, system will start to use the download quota you bought. If your purchased quota is not use out before the end of the month, your monthly quota will expire. When you buy monthly quota, it means you agree to buy monthly quota in the following month, if you want to stop buying monthly quota, you need to update your monthly quota, set monthly quota amount to 0. ## Delete Object When you are deleting a object, gas fee will be charged from your owner account. If your balance is insufficient, you will be informed to Transfer In first. Besides, when your object is deleted, your flow rate will be recalculated, and part of your prepaid fee will be refund. So you can see your "Prepaid fee refund" as follows when deleting a object. !!! info Please notice if your data has been stored less than 6 months, your prepaid fee will not be refund. Also, every operation will bring settlement, so there might be settlement fee. Settlement fee will be charged from the payment account. ## Delete Bucket You can delete the bucket created by you. Please notice you are only allowed to delete an empty bucket, which means you need to delete all your objects in the bucket before you delete the bucket. When you are deleting a bucket, gas fee will be charged from your current login account, which is also your owner account. If you have bought monthly quota for the bucket, when you delete bucket, system will refund your prepaid fee for monthly quota no matter when you decide to delete your bucket. This is a bit different with prepaid fee refund when deleting objects, which has 6 6-month min lock time. ## Monitor Usage With DCellar, you can Monitor your usage through your Dashboard. Besides, you can also view your expenses via account and account detail. ## Send With the DCellar, you can easily send BNB tokens from your Greenfield owner account to another Greenfield owner account. However, before you initiate any token transfers, it's important to ensure that you're currently using the correct network. If you're using the BSC instead of the Greenfield , the Send page will be displayed differently. To avoid any mistakes or confusion, always double-check that you're on the correct network before sending tokens to another user. By taking this simple precaution, you can ensure that your token transfers are executed smoothly and efficiently, enabling you to manage your decentralized data with ease using DCellar. To switch to the BNB Greenfield network, simply click on the "Switch to BNB Greenfield" button within DCellar. This will automatically activate your wallet extension, which will display a pop-up informing you that you need to switch networks. To proceed, simply click on the "Switch Network" button within the wallet pop-up. This will allow you to switch to the Greenfield . !!! info Before Sending, please make sure the address you enter is a valid Greenfield account address. Enter the receiver's address and the amount you want the send, click **Send**, your transaction will be sent to Greenfield , and you will need to pay the gas fee on Greenfield . ## Transfer Out With DCellar, you can transfer out BNB token from your Greenfield account to your BSC account which shares the same address. Before you Transfer Out, you should make sure you are currently under Greenfield . If you are under BSC , your Transfer Out page will be shown as follows: To switch to the BNB Greenfield network, simply click on the **Switch to BNB Greenfield** button within DCellar. This will automatically activate your wallet extension, which will display a pop-up informing you that you need to switch networks. To proceed, simply click on the **Switch Network** button within the wallet pop-up. This will allow you to switch to the Greenfield , where you can begin managing your decentralized data with DCellar. By following these simple steps, you can quickly and easily switch networks and access all the powerful features and functions of DCellar on the Greenfield platform. Transfer Out will cost you two kinds of fees, all charged by BNB token: - **Gas fee**: covers the gas cost for sending your transfer on the destination chain. - **Relayer fee**: paid to relayers for handling cross-chain packets. Input the amount you want to Transfer Out, Click Transfer Out, your transaction will be sent. You can view your transaction details in [GreenfieldScan](https://greenfieldscan.com/). --- ## Greenfield Command > Source: https://docs.bnbchain.org/bnb-greenfield/getting-started/greenfield-command/ # Greenfield Command [Greenfield Command](https://github.com/bnb-chain/greenfield-cmd) is a powerful command line for you to manage your resources on Greenfield and interact with Greenfield. ## Command Tool Guide This command tool supports basic storage functions, including creating buckets, uploading and downloading files, and deleting resources. It also supports related operations such as groups, policies, banks, accounts and so on. To make the command display clearer, commands of different categories are implemented as subcommands of different categories. You can use "gnfd-cmd -h" to view the supported command categories. The command tool supports the "--home" option to specify the path of the config file and the keystore, the default path is a directory called ".gnfd-cmd" under the home directory of the system. When running commands that interact with the greenfield, if there is no config/config.toml file under the path and the commands runs without "--config" flag, the tool will generate the config/config.toml file automatically which is consistent with the testnet configuration under the path. Below is examples of the config file of Testnet and Mainnet. The rpcAddr and chainId should be consistent with the Greenfield network. For Greenfield Mainnet, you can refer to [Greenfield Mainnet RPC Endpoints](../for-developers/network-endpoint/endpoints.md). The rpcAddr indicates the Tendermint RPC address with the port info. The command has the ability to intelligently select the correct storage provider to respond to the request. The user only needs to set the storage provider operator-address if they want to create a bucket on a specific SP. For example, the user can run "gnfd-cmd storage put test gnfd://bucket1/object1" to upload a file to bucket1 and then run "gnfd-cmd storage put test gnfd://bucket2/object" to upload a file to bucket2, which is stored on another SP without changing the config. ## Basic Operations ### Account Operations Before using the rich features of the command tool, you need to init account info and generate keystore by "account import" or "account new" command . All the other commands need to load the keystore content before running. The "import" command imports account info from private key file and generate a keystore by following four steps: 1. Export your private key from MetaMask and write it into a local file as plaintext (You can select "Account Details" from the dropdown menu of MetaMask. Click on the "Export Private Key" button at the bottom of the page.) 2. Generate a keystore by the "account import [keyfile]" command. Users need set the private key file path, which is created by step 1. ```shell // import key and generate a keystore file gnfd-cmd account import key.txt ``` 3. The terminal will prompt user to enter the password information. Users can also specify the password file path by using the "--passwordfile". Users are responsible for managing their password information. The keystore will be generated in the path "keystore/keyfile" under the home directory of the system or the directory set by "-home". And it is also the path to load keystore when running other commands. 4. Delete the private key file which is created in step 1. It is not needed after the keystore has been generated. If the user has no private key to import, he can use "account new" create a new greenfield account and the keystore. After creating the account, the user needs to transfer token to the address of this account before using other commands to send transactions or use storage-related functions. ```shell // new account and generate keystore key.json gnfd-cmd account account new ``` To obtain the account and keystore info, users can use "account export" to print the private key info and "account ls" to display the accounts information. ```shell // list the account info and keystore path gnfd-cmd account ls // display the encrypted keystore or the private key gnfd-cmd account export --unarmoredHex --unsafe ``` Users can create multiple accounts using the "account import" or "account new" command. You can use the "set-default" command to specify which account to use for running other commands by default. When executing commands using the default account, there is no need to specify the keystore. ```shell // set the default account. gnfd-cmd account set-default [address] ``` ### SP Operations Before making a bucket and uploading files, we need to select a storage provider to store the files in the bucket. By executing the following command, we can obtain a list of storage providers on Greenfield. ```shell $ gnfd-cmd sp ls name operator address endpoint status bnbchain 0x231099e40E1f98879C4126ef35D82FF006F24fF2 https://greenfield-sp.bnbchain.org:443 IN_SERVICE defibit 0x05b1d420DcAd3aB51EDDE809D90E6e47B8dC9880 https://greenfield-sp.defibit.io:443 IN_SERVICE ninicoin 0x2901FDdEF924f077Ec6811A4a6a1CB0F13858e8f https://greenfield-sp.ninicoin.io:443 IN_SERVICE nariox 0x88051F12AEaEC7d50058Fc20b275b388e15e2580 https://greenfield-sp.nariox.org:443 IN_SERVICE lumibot 0x3131865C8B61Bcb045ed756FBe50862fc23aB873 https://greenfield-sp.lumibot.org:443 IN_SERVICE voltbot 0x6651ED78A4058d8A93CA4979b7AD516D1C9010ac https://greenfield-sp.voltbot.io:443 IN_SERVICE nodereal 0x03c0799AD70d19e723359E036a83E8f44f4B8Ba7 https://greenfield-sp.nodereal.io:443 IN_SERVICE ``` And the Users can obtain detailed information about a certain SP by "sp head" and "sp get-price" commands. Here is an example of obtaining information about an SP with endpoint [https://greenfield-sp.nodereal.io:443](https://greenfield-sp.nodereal.io:443). ```shell // get storage provider info $ gnfd-cmd sp head https://greenfield-sp.nodereal.io:443 // get quota and storage price info of storage provider: $ gnfd-cmd sp get-price https://greenfield-sp.nodereal.io:443 get bucket read quota price: 0.1469890427 wei/byte get bucket storage price: 0.02183945725 wei/byte get bucket free quota: 1073741824 ``` You can take note of the operator-address information for the storage provider to which is intended to be uploaded. This parameter will be required for making the bucket in the next step. ### Bucket Operation You can run "./gnfd-cmd bucket -h " to get help of the bucket operations. The below command can be used to create a new bucket called testbucket: ```shell gnfd-cmd bucket create gnfd://testbucket ``` The command supports "-primarySP" flag to select the storage provider on which you want to create a bucket. The content of the flag should be the operator address of the storage provider. If this value is not set, the first SP in the storage provider list will be selected as the upload target by default. The user can update the bucket meta by the "bucket update" command. It supports updating bucket visibility, charged quota, or payment address. ```shell // update bucket charged quota gnfd-cmd bucket update --chargedQuota 50000 gnfd://testbucket // update bucket visibility gnfd-cmd bucket update --visibility=public-read gnfd://testbucket ``` The user can use list the buckets which belong to him with "bucket ls" commands. ```shell gnfd-cmd bucket ls ``` ### Upload/Download Files (1) put Object The user can upload the local file to the bucket by the "object put" command. The following command example uploads an object named 'testobject' to the 'testbucket' bucket. The file payload for the upload is read from the local file indicated by 'file-path'. ```shell gnfd-cmd object put --contentType "text/xml" file-path gnfd://testbucket/testobject ``` If the object name has not been set, the command will use the file name as object name. After the command is executed, it will send createObject txn to the chain and uploads the payload of the object to the storage provider. The command will return after object completes sealing. Users can also choose to interrupt the sealing process, which does not affect the final completion of the object. During the upload process, the terminal will print the upload progress and upload speed. (2) download object The user can download the object into the local file by the "object get" command. The following command example downloads 'testobject' from 'testbucket' to the local 'file-path' and prints the length of the downloaded file. The filepath can be a specific file path, a directory path, or not set at all. If the file-path is not set, the command will download the content to a file with the same name as the object name in the current directory. ```shell gnfd-cmd object get gnfd://testbucket/testobject file-path ``` After the command is executed, it will send a download request to the storage provider and download the object. The terminal will print the download progress and speed. (3) list object and delete object The user can use list the objects of the specific bucket with "object ls" command. ```shell gnfd-cmd object ls gnfd://testbucket ``` The user can delete the object with "object delete" command. ```shell gnfd-cmd object delete gnfd://testbucket/testobject ``` ### Group Operation Users can run "./gnfd-cmd group -h " to get help of group operations. The user can create a new group by the "group create" command. Note that this command can set the initialized group member through the --initMembers parameter. After the command executes successfully, the group ID and transaction hash information will be returned. You can add or remove members from a group using the "group update" command. The user can use '--addMembers' to specify the addresses of the members to be added or '--removeMembers' to specify the addresses of the members to be removed. ```shell // create group gnfd-cmd group create gnfd://testGroup // update member gnfd-cmd group update --groupOwner 0x.. --addMembers 0x.. gnfd://testGroup ``` ### Policy Operation Users can run "./gnfd-cmd policy -h " to get help of permission operations. Users can use the "policy put [RESOURCE-URL]" command to assign resource permissions to other accounts or groups (called principal), such as the permission to delete objects. After the command executes successfully, the object policy information of the principal will be returned. The principal is set by --groupId which indicates the group or --grantee which indicates the account. The resource url can be the follow types: 1) "**grn:**b::bucket-name", it indicates the bucket policy 2) "**grn:**o::bucket-name/object-name", it indicates the object policy 3) "**grn:**g:owner-address:group-name", it indicates the group policy ```shell // put object policy gnfd-cmd policy put --groupId 11 --actions get,delete grn:o::gnfd-bucket/gnfd-object // put bucket policy gnfd-cmd policy put --grantee 0x.. --actions delete grn:b::gnfd-bucket ``` Users can also revoke permission by "policy delete" command ```shell // delete the bucket policy from a group gnfd-cmd policy delete --groupId 11 grn:b::gnfd-bucket // delete the object policy from an grantee gnfd-cmd policy delete --grantee 0.. grn:o::gnfd-bucket/gnfd-object ``` Users can list the policy of the grantee or group-id by "policy ls" command ```shell // list policy info of a group gnfd-cmd policy ls --groupId 11 grn:o::gnfd-bucket/gnfd-object ``` In addition to the basic commands mentioned above, the Greenfield Command also supports functions such as transferring tokens and payment account operations. You can find more examples in the readme file of [Greenfield Command](https://github.com/bnb-chain/greenfield-cmd). --- ## Faucet > Source: https://docs.bnbchain.org/bnb-greenfield/getting-started/get-test-bnb/ # Faucet You can claim the test tBNB tokens on BSC Testnet by the faucet, and bridge it to Greenfield Testnet. ## Claim tBNB from BSC Faucet 1. Vist [BSC faucet](https://www.bnbchain.org/en/testnet-faucet). 2. Switch to the BSC Testnet in your wallet and check your balance. ## Bridge to Greenfield You can use [BNB Greenfield Bridge](https://greenfield.bnbchain.org/en/bridge) or [DCellar Testnet](https://testnet.dcellar.io/) to transfer BNB from BSC to Greenfield and vice versa. You can follow [How to Transfer In](https://docs.nodereal.io/docs/dcellar-get-started#transfer-in) to bridge tBNBs from BSC Testnet to Greenfield Testnet, and [How to Transfer Out](https://docs.nodereal.io/docs/dcellar-get-started#transfer-out) to bridge tBNBs from Greenfield Testnet to BSC Testnet. --- ## General FAQ > Source: https://docs.bnbchain.org/bnb-greenfield/getting-started/general-faqs/ ### Why can't I send BNB tokens on BNB Greenfield using my wallet? Wallet does not support transfers on BNB Greenfield because BNB Greenfield uses a different transaction format than other EVM chains. You may encounter the following error when you transfer your token with your wallet. To send BNB tokens on BNB Greenfield, you need to use [dCellar Transfer function](token-transfer.md#bnb-transfers-in-greenfield). ### How to understand the amount field in the signature message when using BNB Greenfield? When users perform actions on the BNB Greenfield, such as creating buckets or uploading files, they need to sign a message that contains the amount of BNB they are spending. However, this amount is not in BNB units, but in WEI units, which are much smaller. One WEI is equal to 10^-18 BNB. Therefore, the amount field in the signature message may look very large, but it is actually a very small fraction of a BNB. ### Does Greenfield have a token? How can I get it? BNB remains the main utility token on Greenfield, no other token on Greenfield. You can acquire BNB in multiple ways: 1. [Buy BNB](https://www.binance.com/en/how-to-buy/bnb) if you never own it. 2. Cross-chain transfer BNB from BSC network to Greenfield using [DCellar](https://dcellar.io/) if you already own any BNB. You can read the detailed steps [here](https://docs.nodereal.io/docs/dcellar-get-started). The cross-chain token transfer is really fast, you are supposed to receive your BNB within a minute. 3. Receive BNB from other Greenfield users with [internal transactions](token-transfer.md#bnb-transfers-in-greenfield) ### What is the utility of BNB on Greenfield? BNB is used as a staking token, gas token, storage service fee token, and governance token. Refer to [token economics](../core-concept/billing-payment.md#gas-and-fees) for more details. ### Does Greenfield support smart contract? The Greenfield blockchain does not support smart contracts, but the native cross-chain between BSC and Greenfield brings programmability to the ecosystem. More tech details are explained [here](../core-concept/programmability.md), you can start integrating smart contracts with Greenfield following the [tutorial](../for-developers/tutorials/access-control/cross-chain-access-control-by-cmd.md). ### What consensus algorithm does Greenfield run on? [Tendermint is the consensus engine](https://blog.cosmos.network/tendermint-explained-bringing-bft-based-pos-to-the-public-blockchain-domain-f22e274a0fdb) that powers Greenfield BPoS. ### Is the file permanently stored in Greenfield? No. Currently, Greenfield charges storage fees in a stream manner, so if a user's account balance is insufficient and in arrears, it is possible that their data may be lost and cannot be recovered. Greenfield may support permanent storage in the future. ### Can I update the files after it is uploaded? The update is not yet supported, but it can be accomplished through deletion and upload. ### Can I enjoy lower price for the data I previously stored if the storage price goes down? Sure, but it requires any transaction that modifies the payment flow, such as uploading or deleting files, to trigger it. ### Will I also have to pay more for the data I have previously stored if the storage price goes up? In theory, yes. However, Greenfield will strictly limit the frequency and magnitude of price adjustments by storage providers to minimize the impact on users. ### If the storage provider loses my data or refuses to provide service, what can I do? This situation is usually unlikely to happen because Greenfield uses redundant error-correction coding to keep your data safe across multiple storage providers. If such a scenario occurs, you can initiate a data availability challenge, and validators will verify the integrity, availability, and service quality of your data while penalizing the corresponding storage provider. You can continue to receive rewards until the storage provider fully recovers your data or provides the service. ### How can I make my valuable data circulate? You can mirror your data and access permissions to the BNB Smart Chain network, and trade your data through various DApps and data trading platforms. ### How long can the data uploaded to the testnet be saved? Testnet is used for testing, so it won't keep user's data for a long time. It is expected to be dropped after 7 days. ### What to do if you are unable to upgrade Greenfield in time? Since this is a hardfork, your `gnfd` binary cannot continue running if it’s not upgraded in time. Add the following filed in `app.toml`: ``` # chain-id for op bnb destination chain `dest-op-chain-id = 204` ``` Stop the binary, then execute the rollback command: `gnfd rollback --hard` Finally, restart your binary. ### How much does it cost to store files in Greenfield? If you're interested in knowing the real-time pricing for storage and querying on Greenfield, we invite you to the [Price Calculator](https://dcellar.io/pricing-calculator). ### How is my billing calculated? In Greenfield, bsides transaction fee, users are required to pay two kinds of storage service fees: `storage fee` and `download quota fee`. These storage service fees are charged by Storage Providers (SPs) in a [stream payment](https://github.com/bnb-chain/greenfield/blob/master/docs/modules/billing-and-payment.md). Users need to lock some BNB when they start using the service. ```math Storage Fee = sum(ChargedSize) * (PrimaryStorePrice + SecondaryStorePrice*SecondarySPNumber) * (1+Validator Tax Rate) * ReserveTime ``` ```math Download Quota Fee = ChargedReadQuota * ReadPrice * (1 + Validator Tax Rate) * ReserveTime ``` Currently, `ReserveTime` is 180 days and `Validator Tax Rate` is 1% ### What is Charged Size? The ChargeSize is calculated from the object's payload size, if the payload size is less than 128k then ChargeSize is 128k, otherwise ChargeSize is equal to payload size. If Data Size < 128K, ChargedSize = 128K; else, ChargedSize = Data Size If object is an empty folder, ChargedSize = 128K You can query the value from [this API](https://greenfield-chain.bnbchain.org/openapi#/Query/StorageParams) ### What is Primary/Secondary Store Price? Every SP can set their own suggested store price and read price via on-chain transactions. At the first block of each month, the median all SPs' store prices will be calculated as the Primary SP Store Price, the Secondary SP Store Price will be calculated as [SecondaryPriceRatio](https://greenfield-chain.bnbchain.org/openapi#/Query/SpParams) (e.g. 12%, which can be governed) multiply the Primary SP Store Price , and the median of all SPs' read prices will be calculated as the Primary SP Read Price. To learn more about it, please refer to [this](https://github.com/bnb-chain/greenfield/blob/master/docs/modules/billing-and-payment.md#storage-fee-price-and-adjustment) ### What is Validator Tax Rate? For each data related operation on Greenfield, validators can get some rewards for protecting the security and integrity of data (i.e. challenge). Through charging validator tax, part of user's cost will go to validator tax pool, and then become validators' rewards. You can query the value from [this API](https://greenfield-chain.bnbchain.org/openapi#/Query/PaymentParams) ### What is Read Price? A storage provider can update its free read quote and monthly gree read quota, suggested primary store price and read price. All SPs' suggested primary store and read prices will be used to generate the global primary/secondary store price and read price. ### What is Reserve Time? The storage fee will be charged on Greenfield in a steam payment style. The fees are paid on Greenfield in the style of "Stream" from users to receiver accounts at a constant rate. By reseveing some balance, users do not need to payment the fee in a very high frequency. Currently, the reserve time is 6 months and it can be governed. You can query the value from [this API](https://greenfield-chain.bnbchain.org/openapi#/Query/PaymentParams) ### What's best practice to store small files in Greenfield? * The more data bundled, the more $BNB saved If a single transaction only store a small size file to the Greenfield Network, it is like separate packages being sent through the mail – even though they were all going to the same destination. It's recommended to take all of the files to reach the `Charged Size` and put them together to get sent as one transaction to the network. * Be Mindful to Delete Currently, the reserve time to be charged on Greenfield is 6 months. It means a six-month storage fee will charged even for deleted items. ### What shall I do if my account is frozen? The reason for a frozen account and the way to resolve it are explained in detail in the [Force Settlement, Freeze and Resume](https://docs.bnbchain.org/bnb-greenfield/core-concept/billing-payment/#force-settlement-freeze-and-resume) section. To deposit funds into your frozen account and unfreeze it, you can follow these methods: #### Using the Greenfield Command * Refer to the [Account Operations](https://docs.bnbchain.org/bnb-greenfield/getting-started/greenfield-command/#account-operations) section to set up the environment locally. * Once set up, execute the following two commands to deposit to your account: ```shell gnfd-cmd payment-account create gnfd-cmd payment-account deposit --toAddress [your_fronzen_account_address] --amount [amount_of_bnb_in_wei] ``` #### Using the Greenfield Go SDK * Refer to the [Go SDK Example](https://docs.bnbchain.org/bnb-greenfield/for-developers/apis-and-sdks/sdk-go) section to set up the environment locally. * Once set up, use [deposit](https://pkg.go.dev/github.com/bnb-chain/greenfield-go-sdk@v1.7.4/client#Client.Deposit) method to deposit to your account. --- ## Accounts and Keys > Source: https://docs.bnbchain.org/bnb-greenfield/core-concept/accounts/ ## Accounts Each Greenfield user has their own address as the identifier for his/her account. The addresses can create objects to store on Greenfield, bear and manage the permissions, and pay fees. Greenfield defines its account in the same format as BSC and Ethereum. It starts with ECDSA secp256k1 curve for keys and is compliant with [EIP84](https://github.com/ethereum/EIPs/issues/84) for full [BIP44](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki) paths. The root HD path for Greenfield-based accounts is m/44'/60'/0'/0. In the readable presentation, a Greenfield address is a 42-character hexadecimal string derived from the last 20 bytes of the public key of the controlling account with 0x as the prefix. With this compatible address scheme, the users can reuse existing accounts and infrastructure from BSC on Greenfield. For example, they can use TrustWallet and Metamask (or other compatible wallets) to deposit their BNB from BSC to Greenfield and interact with dApps on Greenfield. It is also easy to identify the same owner by referring to the same addresses on both BSC and Greenfield. ### User Balance The account can hold a balance of BNB. These BNBs can be used to participate in staking, pay for gas fees of Greenfield transactions, and pay for Greenfield services. This balance can be added via native BNB transfer on Greenfield, or cross-chain transfer between Greenfield and BSC. ### Account Definition In the Greenfield, an **account** designates a pair of `PubKey` and `PrivKey`. The `PubKey` can be derived to generate various `Addresses`, which are used to identify users (among other parties) in the application. ### Signatures The principal way of authenticating a user is done using [digital signatures](https://en.wikipedia.org/wiki/Digital_signature). Users sign transactions using their own private key. Signature verification is done with the associated public key. For on-chain signature verification purposes, we store the public key in an `Account` object (alongside other data required for a proper transaction validation). In the node, all data is stored using [Protocol Buffers](https://protobuf.dev/) serialization. Greenfield only supports [secp256k1](https://en.bitcoin.it/wiki/Secp256k1) key schemes for creating digital signatures: | | Address length in bytes | Public key length in bytes | Used for transaction authentication | Used for consensus (Tendermint) | | :---------: | :---------------------: | :------------------------: | :---------------------------------: | :-----------------------------: | | `secp256k1` | 20 | 33 | yes | no | ### Addresses `Addresses` and `PubKey`s are both public information that identifies actors in the application. `Account` is used to store authentication information. The basic account implementation is provided by a `BaseAccount` object. To identify users, Greenfield uses the variable `AccAddress`. The address format follows [ERC-55](https://eips.ethereum.org/EIPS/eip-55). ## Key Management Greenfield blockchain is an application-specific chain without EVM. As a result, its transaction data structure and API are different from those of BSC. Greenfield will not support full functions in existing wallets, e.g. Transfer, Send Transactions, etc. However, these wallets can still sign transactions using the [EIP712](https://eips.ethereum.org/EIPS/eip-712) standard. This standard allows wallets to display data in signing prompts in a structured and readable format. This is an [example](https://medium.com/metamask/eip712-is-coming-what-to-expect-and-how-to-use-it-bb92fd1a7a26) of how to use it in Metamask. Eventually, wallets will start supporting Greenfield directly. ### EIP-712 Support The greenfield chain supports and only supports EIP-712 structured transaction. These enable the existing wallet infrastructure to interact with Greenfield at the beginning naturally. To achieve this, the following changes have been made. 1. An Ethereum-compatible RPC backend. Be noted that we only support necessary methods to connect a wallet(`eth_chainId`, `eth_networkId`, `eth_blockNumber`, `eth_getBlockByNumber` and `eth_getBalance`). Other RPC methods are not implemented. 2. Same signing algorithm(`eth_scep256k1`) as Ethereum. For developers, they can refer to [greenfield-go-sdk](https://github.com/bnb-chain/greenfield-go-sdk) and [greenfield-js-sdk](https://github.com/bnb-chain/greenfield-js-sdk) for easy integration. ### Keyring Interface The `Keyring` interface is the primary interface for key management in the greenfield-cosmos-sdk. It defines the methods that a type needs to implement to be used as a key storage backend. These methods include: - `Get`: retrieves a key by name. - `List`: lists all keys stored in the keyring. - `Delete`: deletes a key by name. - `Sign`: signs a message using a key. By implementing these methods, you can create a custom key storage backend that meets the specific needs of your application. !!! tip It means you don't have to follow the `Keyring` interface to manage your key, any existing Ethereum wallets are applicable to Greenfield as well. ### Backend Options The greenfield-cosmos-sdk provides different options for key storage, each with its own strengths and weaknesses. The choice of backend will depend on your specific use case. Here are the available options: #### System Options - **os**: This backend uses the `operating system`'s default credentials store to handle key storage operations securely. The keyring may be kept unlocked for the whole duration of the user session. - **memory**: This backend uses a transient storage, meaning that Keys are discarded when the process terminates or the type instance is garbage collected. #### Tools Options - **file**: This backend stores the keyring encrypted within the app's configuration directory. This keyring will request a password each time it is accessed, which may occur multiple times in a single command resulting in repeated password prompts. - **kwallet**: This backend uses the `KDE Wallet Manager` as a credentials management application. - **pass**: This backend uses the `pass` command line utility to store and retrieve keys. - **test**: This backend stores keys insecurely to disk. It does not prompt for a password to be unlocked and should only be used for testing purposes. ### Supported Sign Algorithms The greenfield-cosmos-sdk supports as many sign algorithms as users want, but in Greenfield context, we only support `eth_secp256k1` and `ed25519`. These algorithms were chosen for their security and compatibility with the Ethereum and Tendermint ecosystems. --- ## BNB Token Model > Source: https://docs.bnbchain.org/bnb-greenfield/core-concept/bnb-token-model/ # BNB Token Model **BNB** remains the main utility token on Greenfield. **BNB** can be transferred from BSC to Greenfield blockchain, and vice versa. It is used as: - **Staking token**: This token allows user to self-delegate and delegate as stake, which can earn gas rewards but may result in slash for improper behavior. - **Gas token**: This token is used to pay the gas to submit transactions on the Greenfield blockchain. This includes both Greenfield local transactions or cross-chain transactions between Greenfield and BSC. The fee is charged at the time of transaction submission and dispatched to Greenfield `validators`, and potentially to Greenfield `Storage Providers` for certain transactions. The fee distribution is done in-protocol and a protocol specification is [described here](https://github.com/bnb-chain/greenfield-cosmos-sdk/blob/master/docs/spec/fee_distribution/f1_fee_distr.pdf). - **Storage service fee token**: This token is used to pay fees for object storage and download bandwidth data package. Fees are charged as time goes on and dispatched to Greenfield `Storage Providers`. - **Governance token**: BNB holders may govern the Greenfield by voting on proposals with their staked BNB (not available at launch). ## Revenue Sharing The main economic drive of Greenfield comes from their `storage providers` who charge users fees for their storage services. Meanwhile, `validators` play a crucial role in supervising the network's security, maintaining stability and ensuring service quality. While `validators` may earn transaction fees, this alone may not be enough to guarantee sufficient staking for network security. Therefore, Greenfield has designed `validators` to receive a reasonable proportion of fees from the storage services they provide. This approach ensures that users' data is not only stored but that the network is also safe and secure. ## Circulation Model In Greenfield, there is no inflation of BNB because of its dual-chain structure. Instead, cross-chain transfers are used to allow BNB to flow bi-directionally between Greenfield and Smart Chain. As a result, the total circulation of BNB on Greenfield can fluctuate. Greenfield use Lock/Unlock mechanism to ensure the total circulation of BNB on both chain is always less than the initial total supply: 1. The transfer-out blockchain will lock the amount from source owner addresses into a module account or smart contract. 2. The transfer-in blockchain will unlock the amount from module account or contract and send it to target addresses. 3. Both networks will never mint BNB. Refer to [cross chain model](../core-concept/programmability.md) to get more details about the mechanism. ## Genesis Setup BNB is transferred from BSC to Greenfield as the first cross-chain action. The initial validator set and `storage provider` of Greenfield at the genesis will first lock a certain amount of BNB into the "Greenfield Token Hub" contract on BSC. This contract is used as part of the native bridge for BNB transferring after the genesis. These initial locked BNB will be used as the self-stake of `validators`, the deposit of `storage provider` and early days gas fees. The initial BNB allocation on greenfield is around 500K BNB. !!! tip No initial donors, foundation, or company will get funds in the genesis setup. --- ## Billing and Payment > Source: https://docs.bnbchain.org/bnb-greenfield/core-concept/billing-payment/ # Billing and Payment In Greenfield, users are required to pay two different types of fees: - Firstly, every transaction will require gas fees to pay the Greenfield validator to write the metadata on-chain as described in [Gas and Fee](#gas-and-fees) part. - Secondly, the Storage Providers (SPs) charge the users for their storage service. Such payment also happens on the Greenfield. The storage service fee will be charged on Greenfield in a steam payment style like [Superfluid](https://docs.superfluid.finance/superfluid/protocol-overview/in-depth-overview/super-agreements/constant-flow-agreement-cfa). ## Storage Service Fee There are two kinds of storage service fees in Greenfield: **object storage fee** and **data package fee**. For storage, every object stored on Greenfield is charged at the price calculated by size, replica numbers, a base price ratio, and other parameters. Once the object is stored, the total charge of storage will be mainly only related to time and the base price. The storage fee calculation is: ```math Storage Fee = sum(ChargedSize) * (PrimaryStorePrice + SecondaryStorePrice*SecondarySPNumber) * (1+Validator Tax Rate) * ReserveTime ``` Users are granted a free, time-based quota for downloading data, with each bucket corresponding to a set of their objects. If the quota is exceeded, users can upgrade their data package to obtain an additional quota. The price for each data package is fixed for a certain period (unless the read price has been changed and the user takes some actions to reflect the price change), during which users will only be charged based on the amount of time they spend downloading and the package price. This charging scheme remains in effect until the user modifies their data package settings. The download quota fee calculation is: ```math Download Quota Fee Fee = ChargedReadQuota * ReadPrice * (1 + Validator Tax Rate) * ReserveTime ``` ### Global Virtual Group Family & Global Virtual Group For storage fees, it will be not streamed to storage providers directly. It will be streamed to: - Global Virtual Group Family's virtual funding address for **data package fee** and primary sp's **object storage fee** - Global Virtual Group's virtual funding address for all secondary sp's **object storage fee** - Validator tax pool for extra tax fee (e.g. 1%), which will be used for rewarding data availability challenge submitters. When storage providers want to get their income, they can withdraw from Global Virtual Group Family and Global Virtual Group they are in. The validator tax pool cannot be controlled via any private key, and is used for challenge reward. ### Payment Account By default, the object owner's address will be used to pay for the objects it owns. But users can also create multiple "payment accounts" and associate objects to different payment accounts to pay for storage and bandwidth. The address format of the payment account is the same as normal accounts. It's derived by the hash of the user address and payment account index. However, the payment accounts are only logical ones and only exist in the storage payment module. Users can deposit into, withdraw from, and query the balance of payment accounts on the Greenfield blockchain, but users cannot use payment accounts to perform staking or other on-chain transactions. Payment accounts can be set as "non-refundable". Users cannot withdraw funds from such payment accounts. ### Paymaster Besides using the owner's address or payment accounts to pay for the storage and bandwidth, users can also use others' address or payment account by setting the payment account for the bucket. The owner of payment account need to set the flow rate limit for the bucket before the bucket can be used. This will lower the barrier for users to use Greenfield since they don't need to have BNB to pay for the storage and bandwidth and they don't need to understand the charging mechanism of Greenfield which is quite complex. It will also provide a possibility for projects to sponsor the storage and bandwidth for their users. For more details, you can refer to the [BEP of the paymaster](https://github.com/bnb-chain/BEPs/pull/362). ### Force Settlement, Freeze and Resume If a user doesn't deposit for a long time, his previous deposit may be all used up for the stored objects. Greenfield has a forced settlement mechanism to ensure enough funds are secured for further service fees. There are two configurations, `ReserveTime` and `ForcedSettleTime`. Let's take an example where the `ReserveTime` is 7 days and the `ForcedSettleTime` is 1 day. If a user wants to store an object at the price of approximately $0.1 per month($0.00000004/second), he must reserve fees for 7 days in the buffer balance, which is `$0.00000004 * 7 * 86400 = $0.024192`. If the user deposits is $1 initially, the stream payment record will be as below: - **CRUD Timestamp**: 100; - **Static Balance**: $0.975808; - **Netflow Rate**: -$0.00000004/sec; - **Buffer Balance**: $0.024192. After 10000 seconds, the dynamic balance of the user will be `0.975808 - 10000 * 0.00000004 = 0.975408`. After 24395200 seconds(approximately 282 days), the dynamic balance of the user will become negative. Users should have some alarms for such events that remind them to supply more funds in time. If no more funds are supplied and the dynamic balance plus buffer balance is under the forced settlement threshold, the account will be forcibly settled. All payment streams of the account will be closed and the account will be marked as frozen. The download speed for all objects associated with the account or payment account will be downgraded. If someone deposits BNB tokens into a frozen payment account and the static balance is enough for reserved fees, the account will be resumed automatically (be noted, the deposit is payment deposit, not the general transfer). Usually, the payment account will be "active" quickly. However, if there are many outflows associated to the payment account, the payment account will be queued for resume and handled in the following blocks. ### Downgraded service Once the payment accounts run out of BNB, the objects associated with these payment accounts will suffer from a downgraded service of downloading, i.e. the download speed and connection numbers will be limited. Once the fund is transferred to the payment accounts, the service quality can be resumed right away. If the service is not resumed for a long time, it is the SPs' discretionary decision to clear the data out, in a similar way to how SPs claim to stop services to certain objects. In such a case, the data may be gone from Greenfield completely. !!! warning If users fail to renew their subscription on time, **there is a risk of their stored data being permanently deleted.** ### Trust or Shift In Greenfield, there is trust between the users and the SPs for data download. Since downloading bandwidth incurs additional fees and the download journal is not completely stored on the Greenfield blockchain, SPs offer an endpoint interface for users to access detailed logs and downloaders' signatures for download billing. If the users and the SPs cannot agree on the bill, users may just select another Primary SP. For more tech details, please refer to the [stream payment module design](https://github.com/bnb-chain/greenfield/blob/doc-refactor/docs/modules/billing-and-payment.md). ## Gas and Fees This document describes how Greenfield charge fee to different transaction types and the token economics of BNB Greenfield. ### Introduction to `Gas` and `Fees` In the Cosmos SDK, `gas` unit is designated to track resource consumption during execution. On application-specific blockchains such as Greenfield, computational cost of storage is no longer the main factor in determining transaction fees, but rather, it is the incentive mechanism of Greenfield. For instance, creating and deleting a storage object use similar I/O and computational resources, but Greenfield encourages users to delete unused storage objects to optimize storage space, resulting in lower transaction fees. **Greenfield Blockchain has taken a different approach from the gas meter design in Cosmos SDK. Instead, it has redesigned the gashub module to calculate gas consumption based on the type and content of the transaction, rather than just the consumption of storage and computational resources.** Unlike networks like Ethereum, Greenfield transactions do not feature a gas price field. Instead, they consist of a fee and a gas-wanted field. The gas price is inferred during the transaction pre-execution process by fee/gas-wanted, and the transactions are queued based on the gas price, besides that the gas price should not be less than the minimum gas price on Greenfield: 5gwei. !!! warning This means that Greenfield does not refund any excess gas fees to the transaction sender. Therefore, when constructing transactions, it is important to exercise caution when specifying the fees. ### GasHub All transaction types need to register their gas calculation logic to gashub. Currently, four types of calculation logic are supported: **MsgGasParams_FixedType**: ```go type MsgGasParams_FixedType struct { FixedType *MsgGasParams_FixedGasParams } ``` **MsgGasParams_GrantType**: ```go type MsgGasParams_GrantType struct { GrantType *MsgGasParams_DynamicGasParams } ``` **MsgGasParams_MultiSendType**: ```go type MsgGasParams_MultiSendType struct { MultiSendType *MsgGasParams_DynamicGasParams } ``` **MsgGasParams_GrantAllowanceType**: ```go type MsgGasParams_GrantAllowanceType struct { GrantAllowanceType *MsgGasParams_DynamicGasParams } ``` #### Block Gas Meter `ctx.BlockGasMeter()` serves as the gas meter designed to monitor and restrict gas consumption per block. However, certain types of transactions may incur a high cost in Greenfield, leading to significant gas consumption. Consequently, Greenfield refrains from imposing any gas usage constraints on a block. Instead, Greenfield sets a block size limit, preventing blocks from exceeding 1MB in size and mitigating the risk of excessively large blocks. !!! info There is no gas limitation of a block on Greenfield Blockchain. ### Fee Table Please note that the gas fee can be updated through governance and may not be immediately reflected in this documentation. | Msg Type | Gas Used | Gas Price | Expected Fee(assuming BNB $200) | |---------------------------------------------|--------------------|-----------|---------------------------------| | /cosmos.auth.v1beta1.MsgUpdateParams | 0 | 5 gwei | $0.00000000 | | /cosmos.bank.v1beta1.MsgUpdateParams | 0 | 5 gwei | $0.00000000 | | /cosmos.consensus.v1.MsgUpdateParams | 0 | 5 gwei | $0.00000000 | | /cosmos.crisis.v1.MsgUpdateParams | 0 | 5 gwei | $0.00000000 | | /cosmos.crosschain.v1.MsgUpdateParams | 0 | 5 gwei | $0.00000000 | | /cosmos.crosschain.v1.MsgUpdateChannelPermissions | 0 | 5 gwei | $0.00000000 | | /cosmos.distribution.v1beta1.MsgUpdateParams | 0 | 5 gwei | $0.00000000 | | /cosmos.gashub.v1beta1.MsgUpdateParams | 0 | 5 gwei | $0.00000000 | | /cosmos.gov.v1.MsgUpdateParams | 0 | 5 gwei | $0.00000000 | | /cosmos.mint.v1beta1.MsgUpdateParams | 0 | 5 gwei | $0.00000000 | | /cosmos.oracle.v1.MsgUpdateParams | 0 | 5 gwei | $0.00000000 | | /cosmos.slashing.v1beta1.MsgUpdateParams | 0 | 5 gwei | $0.00000000 | | /cosmos.staking.v1beta1.MsgUpdateParams | 0 | 5 gwei | $0.00000000 | | /greenfield.bridge.MsgUpdateParams | 0 | 5 gwei | $0.00000000 | | /greenfield.sp.MsgUpdateParams | 0 | 5 gwei | $0.00000000 | | /greenfield.storage.MsgUpdateParams | 0 | 5 gwei | $0.00000000 | | /greenfield.payment.MsgUpdateParams | 0 | 5 gwei | $0.00000000 | | /greenfield.challenge.MsgUpdateParams | 0 | 5 gwei | $0.00000000 | | /greenfield.permission.MsgUpdateParams | 0 | 5 gwei | $0.00000000 | | /cosmos.authz.v1beta1.MsgExec | 1200 | 5 gwei | $0.00120000 | | /cosmos.authz.v1beta1.MsgRevoke | 1200 | 5 gwei | $0.00120000 | | /cosmos.bank.v1beta1.MsgSend | 1200 | 5 gwei | $0.00120000 | | /cosmos.distribution.v1beta1.MsgSetWithdrawAddress | 1200 | 5 gwei | $0.00120000 | | /cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward | 1200 | 5 gwei | $0.00120000 | | /cosmos.distribution.v1beta1.MsgWithdrawValidatorCommission | 1200 | 5 gwei | $0.00120000 | | /cosmos.feegrant.v1beta1.MsgRevokeAllowance | 1200 | 5 gwei | $0.00120000 | | /cosmos.gov.v1.MsgDeposit | 1200 | 5 gwei | $0.00120000 | | /cosmos.gov.v1.MsgSubmitProposal | 2000000 | 5 gwei | $2.00000000 | | /cosmos.gov.v1.MsgVote | 2000000 | 5 gwei | $2.00000000 | | /cosmos.gov.v1.MsgVoteWeighted | 2000000 | 5 gwei | $2.00000000 | | /cosmos.oracle.v1.MsgClaim | 1000 | 5 gwei | $0.00100000 | | /cosmos.slashing.v1beta1.MsgUnjail | 1200 | 5 gwei | $0.00120000 | | /cosmos.staking.v1beta1.MsgBeginRedelegate | 1200 | 5 gwei | $0.00120000 | | /cosmos.staking.v1beta1.MsgCancelUnbondingDelegation | 1200 | 5 gwei | $0.00120000 | | /cosmos.staking.v1beta1.MsgCreateValidator | 2000000 | 5 gwei | $2.00000000 | | /cosmos.staking.v1beta1.MsgDelegate | 1200 | 5 gwei | $0.00120000 | | /cosmos.staking.v1beta1.MsgEditValidator | 2000000 | 5 gwei | $2.00000000 | | /cosmos.staking.v1beta1.MsgUndelegate | 1200 | 5 gwei | $0.00120000 | | /greenfield.bridge.MsgTransferOut | 1200 | 5 gwei | $0.00120000 | | /greenfield.sp.MsgCreateStorageProvider | 2000000 | 5 gwei | $2.00000000 | | /greenfield.sp.MsgDeposit | 1200 | 5 gwei | $0.00120000 | | /greenfield.sp.MsgEditStorageProvider | 2000000 | 5 gwei | $2.00000000 | | /greenfield.sp.MsgUpdateSpStoragePrice | 2000000 | 5 gwei | $2.00000000 | | /greenfield.sp.MsgUpdateStorageProviderStatus | 1200 | 5 gwei | $0.00120000 | | /greenfield.storage.MsgCreateBucket | 2400 | 5 gwei | $0.00240000 | | /greenfield.storage.MsgDeleteBucket | 1200 | 5 gwei | $0.00120000 | | /greenfield.storage.MsgMirrorBucket | 1200 | 5 gwei | $0.00120000 | | /greenfield.storage.MsgUpdateBucketInfo | 1200 | 5 gwei | $0.00120000 | | /greenfield.storage.MsgCreateObject | 1200 | 5 gwei | $0.00120000 | | /greenfield.storage.MsgSealObject | 120 | 5 gwei | $0.00012000 | | /greenfield.storage.MsgMirrorObject | 1200 | 5 gwei | $0.00120000 | | /greenfield.storage.MsgRejectSealObject | 12000 | 5 gwei | $0.01200000 | | /greenfield.storage.MsgDeleteObject | 1200 | 5 gwei | $0.00120000 | | /greenfield.storage.MsgCopyObject | 1200 | 5 gwei | $0.00120000 | | /greenfield.storage.MsgCancelCreateObject | 1200 | 5 gwei | $0.00120000 | | /greenfield.storage.MsgUpdateObjectInfo | 1200 | 5 gwei | $0.00120000 | | /greenfield.storage.MsgDiscontinueObject | 2400 | 5 gwei | $0.00240000 | | /greenfield.storage.MsgDiscontinueBucket | 2400 | 5 gwei | $0.00240000 | | /greenfield.storage.MsgCreateGroup | 2400 | 5 gwei | $0.00240000 | | /greenfield.storage.MsgDeleteGroup | 1200 | 5 gwei | $0.00120000 | | /greenfield.storage.MsgLeaveGroup | 1200 | 5 gwei | $0.00120000 | | /greenfield.storage.MsgUpdateGroupMember | 1200 | 5 gwei | $0.00120000 | | /greenfield.storage.MsgUpdateGroupExtra | 1200 | 5 gwei | $0.00120000 | | /greenfield.storage.MsgRenewGroupMember | 1200 | 5 gwei | $0.00120000 | | /greenfield.storage.MsgMirrorGroup | 1200 | 5 gwei | $0.00120000 | | /greenfield.storage.MsgPutPolicy | 2400 | 5 gwei | $0.00240000 | | /greenfield.storage.MsgDeletePolicy | 1200 | 5 gwei | $0.00120000 | | /greenfield.storage.MsgMigrateBucket | 1200 | 5 gwei | $0.00120000 | | /greenfield.storage.MsgCancelMigrateBucket | 1200 | 5 gwei | $0.00120000 | | /greenfield.storage.MsgCompleteMigrateBucket | 1200 | 5 gwei | $0.00120000 | | /greenfield.payment.MsgCreatePaymentAccount | 200000 | 5 gwei | $0.20000000 | | /greenfield.payment.MsgDeposit | 1200 | 5 gwei | $0.00120000 | | /greenfield.payment.MsgWithdraw | 1200 | 5 gwei | $0.00120000 | | /greenfield.payment.MsgDisableRefund | 1200 | 5 gwei | $0.00120000 | | /greenfield.challenge.MsgSubmit | 1200 | 5 gwei | $0.00120000 | | /greenfield.challenge.MsgAttest | 100 | 5 gwei | $0.00010000 | | /greenfield.virtualgroup.MsgCreateGlobalVirtualGroup | 1000000 | 5 gwei | $1.00000000 | | /greenfield.virtualgroup.MsgDeleteGlobalVirtualGroup | 1200 | 5 gwei | $0.00120000 | | /greenfield.virtualgroup.MsgDeposit | 1200 | 5 gwei | $0.00120000 | | /greenfield.virtualgroup.MsgWithdraw | 1200 | 5 gwei | $0.00120000 | | /greenfield.virtualgroup.MsgSettle | 1200 | 5 gwei | $0.00120000 | | /greenfield.virtualgroup.MsgSwapOut | 24000 | 5 gwei | $0.02400000 | | /greenfield.virtualgroup.MsgCompleteSwapOut | 24000 | 5 gwei | $0.02400000 | | /greenfield.virtualgroup.MsgCancelSwapOut | 1200 | 5 gwei | $0.00120000 | | /greenfield.virtualgroup.MsgReserveSwapIn | 1200 | 5 gwei | $0.00120000 | | /greenfield.virtualgroup.MsgCancelSwapIn | 1200 | 5 gwei | $0.00120000 | | /greenfield.virtualgroup.MsgCompleteSwapIn | 1200 | 5 gwei | $0.00120000 | | /greenfield.virtualgroup.MsgStorageProviderExit | 1200 | 5 gwei | $0.00120000 | | /greenfield.virtualgroup.MsgStorageProviderForcedExit | 1200 | 5 gwei | $0.00120000 | | /greenfield.virtualgroup.MsgCompleteStorageProviderExit | 1200 | 5 gwei | $0.00120000 | | /greenfield.virtualgroup.MsgUpdateParams | 1200 | 5 gwei | $0.00120000 | | cosmos.authz.v1beta1.MsgGrant | 800 + 800 per item | 5 gwei | $0.0008 per item | | cosmos.bank.v1beta1.MsgMultiSend | 800 + 800 per item | 5 gwei | $0.0008 per item | | cosmos.feegrant.v1beta1.MsgGrantAllowance | 800 + 800 per item | 5 gwei | $0.0008 per item | For more details, you can refer to [Greenfield Gas Params](https://greenfield-chain.bnbchain.org/cosmos/gashub/v1beta1/msg_gas_params). --- ## Simple Storage Service > Source: https://docs.bnbchain.org/bnb-greenfield/core-concept/data-storage/simple-storage-service/ # Simple Storage Service Greenfield Simple Storage Service offers developers comparable API primitives and storage models to the AWS S3 cloud storage which is most utilized in Web2. ## Features ### Storage Management Greenfield has storage management features thart you can use to manage your resources, such as buckets, objects and groups. All the metadata of the resources are on-chain and can be only changed through transactions onto the greenfield blockchain. * Basic Operations - Create, Delete, Update, Delete, Get and List for buckets, objects and groups * Miragte Bucket(**WIP**) - Users can easily migrate bucket to other Primary Storage Provider (PrimarySP) through a single transaction. For more information, please see [Bucket Migration](https://github.com/bnb-chain/greenfield/blob/doc-refactor/docs/modules/virtual-group.md#bucket-migration-workflow) for more information, see [Storage Module Design](https://github.com/bnb-chain/greenfield/blob/doc-refactor/docs/modules/storage-module.md). ### Permission Management Greenfield Providers features for managing permissions to your buckets and objects. By default, Greenfield buckets and the objects in them are private. You only has the permissions to the resources you create. To grant granular resource permissions that support your specific use case of your resources, you can use the following features: * Ownership - The bucket owner take ownership of every objects in his bucket. * Public Access - If the bucket or object set to public, every one can access it but not modify it. * Resource-Based Policy - The owner can configure resource-based permissions for his buckets and the objects in them. for more information, see [Permission Module Design](https://github.com/bnb-chain/greenfield/blob/doc-refactor/docs/modules/permission.md). ## Keys ### Bucket In Greenfield, a bucket is a virtual container for storing objects. Users must assign each bucket a unique name that complies with DNS naming conventions, consisting of one or more labels separated by periods. It's crucial that the bucket name be globally unique within the Greenfield namespace to prevent two buckets from sharing the same name. Here are the bucket name rules for Greenfield: * The bucket name should be between 3 (minimum) and 63 (maximum) characters in length. * The bucket name should only include lowercase letters, numbers, dots (.), and hyphens (-). * The bucket name should start and end with a letter or number. * The bucket name should not have two consecutive periods. * The bucket name should not be in the format of an IP address (e.g., 192.168.5.4). Once a bucket has been created, objects can be uploaded to it using various methods such as the `gnfd` command line or the `SDKs`. Objects within a bucket can be organized and managed like folders (also called "prefixes"). Additionally, it's possible to assign a unique key (a string value) to each object within the bucket to distinguish it from other objects. Every user account can create several buckets. The account will become the "owner" of the bucket. Each bucket should be associated with its own Primary SP, and the payment accounts for Read and Store functions. The owner's address will be the default payment account. ### Object An object is a fundamental unit of storage in Greenfield, which represents a file consisting of data and its associated metadata. Each object is uniquely identified within a bucket by its object name (a string value). Here are the object name rules for Greenfield: * The object name should be between 1 (minimum) and 1024 (maximum) characters in length. * The object name should only include UTF-8 characters. * The object name should not include "./", "../", "//", "..", or "\\". * The object name should not be "/". * The object name should be free of patterns that could be exploited for SQL injection attacks. While objects are commonly used to store files, they can contain any type of data, including text, images, videos, and program binaries. Users can upload objects to Greenfield using various methods, including the `gnfd` command line and `SDKs`. They can also download, copy, or move objects in a similar way. Objects in Greenfield have several important characteristics, including: - name and ID - owner - bucket that hosts it - size and timestamps - content type - checkSums for the storage pieces - storage status - associated SP information Object metadata is stored with the bucket name as the prefix of the key. It is possible to iterate through all objects under the same bucket, but it may be a heavy-lifting job for a large bucket with lots of objects. ### Group A Group is a collection of accounts with the same permissions. Here are the group name rules for Greenfield: * The group name should be between 3 (minimum) and 64 (maximum) characters in length. * The group name should only include UTF-8 characters. The group name is not allowed to be duplicated under the same user. However, a group can not create or own any resource. A group can not be a member of another group either. A resource can only have a limited number of groups associated with it for permissions. This ensures that the on-chain permission check can be finished within a constant time. ### Group Member A Group Member is an account that is associated with a group. A group member can be added to multiple groups. Group Member has a expiration time which is set by the group owner. After the expiration time, the group member will still in the group, but the permission will be revoked. ### Resource-Based Policy The user can use Resource-Based Policy to grant permissions to other accounts. Any resources, such as buckets, objects and groups, can associate several policy. Only the resource owner can put a policy which associate to a resource he owned. - A policy associate to a bucket can allow grantee to operate the bucket or the specific objects. - A policy associate to a object/group can only allow to operator the object/group. In the reousrce-based policy, the user can use wildcard characters Greenfield Resource Names(GRNS) and other values to grant permission to a subset of objects. For Example, the user can only allow the grantee to access to the objects that begin with a common prefix or end with a given extension, such as `.html`. ## Life Cycle To store your data in Greenfield, the user should work with resources known as buckets and objects. A bucket is a container for objects, and an object is a file along with any metadata that describes that file. To store an object in Greenfield, the user creates a bucket and then uploads the object to that bucket. Once the object is in the bucket, it can be opened, downloaded, and moved. When the user no longer needs an object or a bucket, they can clean up their resources. ### Bucket - Create: Users send `CreateBucket` transactions to the blockchain, and the corresponding metadata will be created on the chain. - Update: Users can modify Bucket-related metadata, such as payment accounts and quotas, by sending the `UpdateBucketInfo` transaction to the blockchain. - Delete: Users send `DeleteBucket` transactions to the blockchain to delete the bucket, but they need to ensure that all objects in the bucket have been deleted. - Migration: Users send `MigrateBucket ` transactions to the blockchain to migrate the bucket, and the corresponding bucket will be moved to the dest sp. ### Object * Create: Users send `CreateObject` transactions to the blockchain, and the corresponding metadata will be created on the chain. The object is in the Created state. * CancelCreate: Users send `CancelCreateObject` transactions to the blockchain to cancel the object, and the corresponding metadata will be deleted on the chain. * Update: Users can modify Object-related metadata, such as visibility, by sending the `UpdateObjectInfo` transaction to the blockchain. * Put: Users can use the `PutObject RESTful API` to interact with the SP and upload data to the primary SP. * Seal: After the PrimarySP and secondary SPs store user data, the PrimarySP will send a `SealObject` transaction to the blockchain, and the status of the object will be updated to Sealed, indicating that the object has been successfully uploaded and can be accessed externally. * RejectSeal: The PrimarySP can reject sealing the object for any reason by sending `RejectSealObject` transactions to the blockchain, and the corresponding metadata will be deleted on the chain. --- ## Underlying Storage Model > Source: https://docs.bnbchain.org/bnb-greenfield/core-concept/data-storage/data-storage/ An object on the Greenfield is stored among multi-SPs like below, for example, 50MB: We will introduce some concepts about data storage before describing in detail. ## Segment Segment is the basic storage unit of an object. An object payload is composed of one or many segments in sequence. The segment size is globally configured on the Greenfield blockchain. The default segment size is 16MB. For larger objects, the payload data will be broken into many segments. If the object's size is less than 16MB, it has only one segment and the segment size is the same as the object's size. Please note the payload data of an object will be split into the same size segment but the last segment, which is the actual size. For example, if one object has a size 50MB, only the size of the last segment is 2 MB and the other segments' sizes are all 16MB. ## EC Chunk Erasure Code (EC) is introduced to get efficient data redundancy on Greenfield. A segment is the boundary to perform erasure encoding. Some EC chunks are generated by erasure encoding one segment at a time. EC strategy is globally configured on the Greenfield blockchain. The default EC strategy is 4+2, 4 data chunks, and 2 parity chunks for one segment. The data chunk size is ¼ of the segment. As one typical segment is 16M, one typical data chunk of EC is 4M. ## Piece Piece is the basic storage unit for backend storage on Greenfield. Each segment or EC chunk can be regarded as one data piece. And the key for each piece is generated based on the policy on the Greenfield chain. ## Primary SP Each bucket on the Greenfield is bound with one SP, which is called primary SP. And the user needs to select an SP as the primary SP when creating a bucket. For all the objects stored under the bucket, primary SP will store one complete copy, all segments of the objects’ payload data. And only the primary SP serves users’ read or download requests. ## Secondary SP EC chunks of an object payload data are stored on some SPs, which are called secondary SPs. Each secondary SP stores part of payload data, which is used for better data availability. The object payload can be recovered from EC chunks. ## Redundancy Strategy Redundancy strategy defines how an object payload is stored among SPs, which is globally configured on the Greenfield blockchain. Below is the current strategy: * The data stream of the file will be split into segments according to the granularity of the segment size. If the size of the data is less than the segment size, it will be split according to the size of the data itself. The default segment size is 16MB; * Greenfield uses Reed-Solomon algorithm [Reed-Solomon](https://en.wikipedia.org/wiki/Reed%E2%80%93Solomon_error_correction) as its EC strategy, the default data blocks are 4, and the default parity blocks are 2 . * All the segment pieces of an object are stored on the Primary SP; * After EC encoding with the segment, the EC encoding module will generate six EC chunk pieces. All the EC chunk pieces of the segment will be stored to the six chosen secondary SPs. For example, when processing a 32MB file, the object is split into two segments. These two segments are stored in the primary storage provider, and each segment is encoded using erasure coding to generate six 4MB pieces. These six pieces are stored in six secondary storage providers in numerical order. ## Integrity Hash The integrity hashes include a root hash of the primary SP and several root hashes for each secondary SP which based on the EC strategy. The number of secondary hashes is equal dataBlocks plus parityBlock (it is six for now). Each piece's hash is computed by using hash algorithm (default is sha256) on the data piece's content. The pieces' root hash is computed based on all the pieces' hashes. The calculation process can be represented as follows: ``` // secondaryHashN represents the Integrity Hash calculated by the Nth secondary SP. // segmentN_pieceN represents the Nth piece of the Nth segment of the object after EC encoding IntegrityHashes = [primaryHash, secondaryHash1 ...secondaryHash6] primaryHash := hash(hash(segment1)+hash(segment2)..+hash(segmentN)) secondaryHashN := hash(hash(segment1_pieceN)+hash(segment2_pieceN)..+hash(segmentN_pieceN)) ``` For example, when processing a 32MB file, we got two segments called segment1 and segment2. The integrity hash of the primary SP is equal with hash(hash(segment1) + hash(segment2)). For each secondary SP, it stored piece1 and piece2 which is the encoding result by the segments. The integrity hash of the first secondary SP is equal with hash(hash(segment1_piece1) + hash(segment2_piece1)). Integrity hash is an important metadata of objects on the chain. During the process of creating an object, the integrity hash of each object is calculated and this information is recorded on the blockchain to ensure the accuracy of the data. --- ## Data Integrity and Availability > Source: https://docs.bnbchain.org/bnb-greenfield/core-concept/data-storage/data-availability/ # Data Integrity and Availability There are three crucial aspects of data management: **integrity**, **availability**, and **redundancy**. Below are some key points to ensure each aspect is met: - The primary storage provider must correctly store the object uploaded by the user. - The assigned data segments in both primary and secondary storage providers must be free of any loss, corruption, or counterfeit data. - Erasure coding pieces in secondary providers should enable recovery of the original data in the primary storage provider. To ensure data integrity and redundancy, checksum and redundancy setups must be established for objects. These setups constitute part of the objects' metadata and must be verified by the storage providers and users upon creating objects. The metadata will be stored on the Greenfield blockchain. Collaboration between Greenfield and storage providers is crucial to ensure data integrity and availability, particularly in assigning data segments to primary and secondary storage providers. To increase user confidence that their data is stored as promised, Greenfield has introduced a ["Proof-of-Challenge"](https://github.com/bnb-chain/greenfield/blob/master/docs/modules/data-availability-challenge.md) approach. !!! info "Proof-of-Challenge" is proposed based on the assumptions: **Greenfield is a self-sustained, service-oriented ecosystem.** Stakeholders can trigger challenges in various ways, such as through users or via random events on the Greenfield blockchain. Following a challenge, [Challenge Verifier](../../introduction.md#challenge-verifier) must conduct an **off-chain audit** of challenged data from storage providers. The Verifier Consortium will vote on the challenge results, and the failed outcomes will reduce the corresponding storage providers' staked BNB. Participants who submitted the challenge and the verifier received rewards for their involvement in this process. Data that failed to pass a challenge will not face another challenge for a specific time to allow storage providers to restore the data. [Data challenger module](https://github.com/bnb-chain/greenfield/blob/doc-refactor/docs/modules/data-availability-challenge.md) will elaborate further on challenges associated with data availability. --- ## Cross-Chain Programmability > Source: https://docs.bnbchain.org/bnb-greenfield/core-concept/programmability/ # Cross-Chain Programmability The Greenfield ecosystem leverages cross-chain programmability to enhance data asset value through innovative permission management and smart code execution. This platform supports the creation, management, and operation of data-intensive, trustless computing environments across different blockchains. !!! info It does not mean developers have to build dapp based on BSC network. Excellent infrastructure, applications, and tools can be built directly on the Greenfield network. ## Framework The Greenfield ecosystem is structured into three primary layers, each serving a distinct purpose in facilitating cross-chain interactions and asset management. - **Cross-Chain Communication Layer**: Securely transfers data between BSC and Greenfield, enabling interoperability. - **Resource Mirror Layer**: Facilitates smart contract interactions by mirroring Greenfield's resources onto BSC. - **Application Layer**: Utilizes smart contracts on BSC to develop decentralized applications leveraging Greenfield's infrastructure. This layered architecture ensures robust cross-chain capabilities, enabling developers to create innovative applications while utilizing Greenfield's unique features. ## Key Features - **Native Cross-Chain Bridge**: Ensures seamless interoperability with enhanced security through a multisig scheme among validators. More details are discussed in [Cross Chain Module design](https://github.com/bnb-chain/greenfield/blob/doc-refactor/docs/modules/cross-chain.md). - **Resource Mirroring**: Allows on-chain management of Greenfield objects/buckets/groups via BSC, expanding operational possibilities. - **EVM Contract Programming**: Enables most native Greenfield transactions on BSC, except for file uploads, which require off-chain interactions. - **Multi Message**: Allows for the execution of multiple cross-chain operations within a single transaction. This is facilitated by the `MultiMessage` contract, which aggregates various operations into a cohesive unit. It is important to note that the MultiMessage contract is limited to supporting existing cross-chain operations such as bucket, object, group, permission, and token cross chain transfer. ## Get Started with building dapp - [Learn more about the cross-chain mechanism](https://github.com/bnb-chain/greenfield/blob/doc-refactor/docs/modules/cross-chain.md) - [Start building dapps with Greenfield](../for-developers/tutorials/overview.md) --- ## Quick Guide > Source: https://docs.bnbchain.org/bnb-greenfield/for-developers/get-started-dev/ Here’s a quick guide to get you from zero to hero. This doc provides a guide to the following ideas: * Greenfield & Programmability concepts * Understand what you need to build your project * Access resources to get you started ## Greenfield & Programmability Concepts ### Greenfield 101 Read Greenfield Overview [here](../introduction.md) ### Uniform Address Format Greenfield defines its [account](../core-concept/accounts.md) in the same format as BSC and Ethereum. It starts with ECDSA secp256k1 curve for keys and is compliant with [EIP84](https://github.com/ethereum/EIPs/issues/84) for full [BIP44](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki) paths. ### Account Operation Create a greenfield account, deposit BNB, and program [token transfers](../getting-started/token-transfer.md). * [GO-SDK Example](https://github.com/bnb-chain/greenfield-go-sdk/blob/master/examples/basic.go) * [JS-SDK Example](https://docs.bnbchain.org/greenfield-js-sdk/api/account) ### Data storage Create a public bucket to upload and share objects. * [Greenfield CLI Example](./tutorials/file-management-overview.md) * [GO-SDK Example 1](tutorials/app/file-management/basic-file-management.md) and [GO-SDK Example 2](https://github.com/bnb-chain/greenfield-go-sdk/blob/v1.1.1/examples/storage.go) * [JS-SDK Bucket API](https://docs.bnbchain.org/greenfield-js-sdk/api/bucket) and [JS-SDK Object API](https://docs.bnbchain.org/greenfield-js-sdk/api/object) ### Permission control Create a private bucket and share it with specific individuals. * [Greenfield CLI Example](./tutorials/access-control/cmd-access-control.md) * [GO-SDK Example](https://github.com/bnb-chain/greenfield-go-sdk/blob/v1.1.1/examples/permission.go) * [JS-SDK Example](https://docs.bnbchain.org/greenfield-js-sdk/api/bucket#putbucketpolicy-) and [JS-SDK API](https://docs.bnbchain.org/greenfield-js-sdk/api/object#putobjectpolicy-) ### Enhanced permission control - Create a group, add members, and share the private bucket. * [GO-SDK Example](https://github.com/bnb-chain/greenfield-go-sdk/blob/v1.1.1/examples/group.go) * [JS-SDK Group API](https://docs.bnbchain.org/greenfield-js-sdk/api/group) - Resource management with smart contracts: Understand the concepts of [resource mirroring](../for-developers/cross-chain-integration/mirror-concept.md) ### Cross-chain Programmability - Understand the [programmability concepts](../core-concept/programmability.md) - Understand [mirror resource from Greenfield to EVM chains](./cross-chain-integration/mirror-concept.md) - Understand [program resource through Smart Contract](./cross-chain-integration/interface.md) - Follow Smart Contract SDK [tutorial](tutorials/access-control/cross-chain-access-control-by-cmd.md) - Showcase: [Data Marketplace](tutorials/app/data-marketplace.md) ## Developer Starter Kit ### API - [Greenfield Chain API Docs](https://greenfield.bnbchain.org/openapi) - [Greenfield SP API Docs](https://github.com/bnb-chain/greenfield-storage-provider/tree/master/docs/storage-provider-rest-api) ### SDK - [Greenfield Go SDK](apis-and-sdks/sdk-go.md), more details refer to [Go SDK Docs](https://pkg.go.dev/github.com/bnb-chain/greenfield-go-sdk). - [Greenfield Javascript SDK](apis-and-sdks/sdk-js.md), more details refer to [JS SDK Docs](https://docs.bnbchain.org/greenfield-js-sdk/). ## Setup - [Key management](../core-concept/accounts.md#key-management) - [Transfer](../getting-started/token-transfer.md) between greenfield address - [Token bridge](https://dcellar.io/wallet) ### Developer Resource - [Developer Tooling](https://www.bnbchain.org/en/dev-tools?chain=greenfield) - Explore datasets with [explorer](https://greenfieldscan.com/) or [dcellar.io ](https://dcellar.io/) - [RPC list](network-endpoint/endpoints.md) - [Bundle service](https://docs.nodereal.io/docs/greenfield-bundle-service) - [Web hosting](https://docs.4everland.org/hositng/what-is-hosting/greenfield-hosting#id-4everland-greenfield-hosting) - Data Marketplace boilerplate - [Frontend](https://github.com/bnb-chain/greenfield-data-marketplace-frontend) - [Smart Contracts](https://github.com/bnb-chain/greenfield-data-marketplace-contracts) ### Storage onramp [https://dcellar.io/](https://dcellar.io/) --- ## Network Info > Source: https://docs.bnbchain.org/bnb-greenfield/for-developers/network-endpoint/network-info/ # Network Information ## RPC Endpoints The [RPC Endpoints](endpoints.md) you may need to know to connect to Greenfield. ## Bridge Greenfield and BSC account systems are fully compatible, using the same address format. This allows users to easily transfer their BNBs between Greenfield and BSC. The following cross-chain bridges are available. ### Mainnet - [BNB Greenfield Bridge](https://greenfield.bnbchain.org/en/bridge), switch to Mainnet. - [DCellar](https://dcellar.io), switch to the Wallet part. ### Testnet - [BNB Greenfield Bridge](https://greenfield.bnbchain.org/en/bridge), switch to Testnet. - [DCellar for Testnet](https://testnet.dcellar.io/), switch to the Wallet part. ## Block Explorers ### Mainnet - [Greenfield Explorer](https://greenfieldscan.com), developed by TraceReal. - [BSC Explorer](https://bscscan.com/) ### Testnet - [Greenfield Testnet Explorer](https://testnet.greenfieldscan.com/), developed by TraceReal. - [BSC Testnet Explorer](https://testnet.bscscan.com) ## DCellar [DCellar](https://dcellar.io), as the inaugural application built on the BNB Greenfield, serves as an ultimate client of the BNB Greenfield network. Besides Basic file management and asset management functions, DCellar can also greatly assist developers in comprehending the functionalities of Greenfield: - **Basic File & Asset Management**: With Dcellar, both developers and normal users can upload, store and share files very easily, as well as transfer in/out tokens easily. Besides, DCellar supports batch operations, you can upload, download, delete multiple files at a time. [Check it out →](https://docs.nodereal.io/docs/dcellar-get-started) - **NFT Storage and Minting**: With DCellar, developers and users can conveniently store their NFT resources and associated metadata, enabling them to easily mint their own NFTs. Compared to alternative solutions, DCellar provides a more intuitive interaction process, ensuring a seamless experience for users. [Check it out →](https://docs.nodereal.io/docs/dcellar-as-developer-tool#nft-metadata-and-medium-storage) - **SP Connectivity Verification**: Greenfield network clients can leverage DCellar to upload and download files to their Service Provider (SP), thereby verifying the correct connection of the SP to the network. This feature enables users to ensure smooth and reliable communication with their chosen SP.[Check it out →](https://docs.nodereal.io/docs/dcellar-as-developer-tool#nft-metadata-and-medium-storage) - **Web Server Functionality**: DCellar also functions as a web server, allowing users to effortlessly upload their frontend code to the platform. By setting the uploaded content to public access, anyone can access your web application simply by opening the universal link. This feature simplifies the process of hosting and sharing web applications.[Check it out →](https://docs.nodereal.io/docs/dcellar-as-developer-tool#web-hosting) Here are the domain names for DCellar: - **Mainnet**: `https://dcellar.io` - **Testnet**: `https://testnet.dcellar.io/` ## Related Projects - [Greenfield-Blockchain](https://github.com/bnb-chain/greenfield): official Golang implementation of the Greenfield Blockchain. - [Greenfield-Cosmos-sdk](https://github.com/bnb-chain/greenfield-cosmos-sdk) a cosmos-sdk fork for greenfield. - [Greenfield-Tendermint](https://github.com/bnb-chain/greenfield-tendermint): the consensus layer of Greenfield blockchain. - [Greenfield-Contract](https://github.com/bnb-chain/greenfield-contracts): the cross chain contract for Greenfield that deployed on BSC network. - [Greenfield-Relayer](https://github.com/bnb-chain/greenfield-relayer): the service that relay cross chain package to both chains. - [Greenfield-Storage-Provider](https://github.com/bnb-chain/greenfield-storage-provider): the storage service infrastructures provided by either organizations or individuals. - [Greenfield-Cmd](https://github.com/bnb-chain/greenfield-cmd): the most powerful command line to interact with Greenfield system. - [Greenfield-Common](https://github.com/bnb-chain/greenfield-common): a common library for different repos of greenfield. ## Other - [awesome-cosmos](https://github.com/cosmos/awesome-cosmos): A community curated list of awesome projects related to the Cosmos ecosystem --- ## RPC Endpoints > Source: https://docs.bnbchain.org/bnb-greenfield/for-developers/network-endpoint/endpoints/ ## Mainnet ### Greenfield (chain-id: greenfield_1017-1) - **Blockchain RPC:** - `https://greenfield-chain-ap.bnbchain.org` - `https://greenfield-chain-us.bnbchain.org` - `https://greenfield-chain-eu.bnbchain.org` - `https://greenfield-chain.bnbchain.org` - **Open API:** - `https://greenfield.bnbchain.org/openapi` - **SP Endpoints:** - `https://greenfield-sp.bnbchain.org` - `https://greenfield-sp.nodereal.io` - `https://greenfield-sp.ninicoin.io` - `https://greenfield-sp.defibit.io` - `https://greenfield-sp.nariox.org` - `https://greenfield-sp.lumibot.org` - `https://greenfield-sp.voltbot.io` The above SPs are joined in the genesis state. For more SP endpoints, you can refer to [GreenfieldScan SPs](https://greenfieldscan.com/storage-providers). ### BSC (chain-id: 56) - **RPC Endpoints:** - `https://bsc-dataseed.bnbchain.org` - `https://bsc-dataseed.nariox.org` - `https://bsc-dataseed.defibit.io` - `https://bsc-dataseed.ninicoin.io` - `https://bsc.nodereal.io` - `https://bsc-dataseed-public.bnbchain.org` You could find more endpoints from [here](https://chainlist.org/chain/56). ### opBNB (chain-id: 204) - **RPC Endpoints:** - `https://opbnb-mainnet-rpc.bnbchain.org` - `https://opbnb-mainnet.nodereal.io/v1/64a9df0874fb4a93b9d0a3849de012d3` - `https://opbnb-mainnet.nodereal.io/v1/e9a36765eb8a40b9bd12e680a1fd2bc5` For more details, you can refer to [here](network-info.md). ### Blob hub - **Ethereum:** - `https://gnfd-blobhub.bnbchain.org` - **BSC:** - `https://gnfd-blobhub-bsc.bnbchain.org` ### Block Hub - **BSC:** - `https://gnfd-bsc-archiver-mainnet.bnbchain.org/` Refer to the [Block-Hub documentation](../data-archive/block-hub.md) for more details. ## Testnet ### Greenfield Testnet (chain-id: greenfield_5600-1) - **Blockchain RPC:** - `https://gnfd-testnet-fullnode-tendermint-us.bnbchain.org` - `https://gnfd-testnet-fullnode-tendermint-ap.bnbchain.org` - **Open API:** - `https://greenfield.bnbchain.org/openapi` - **SP Endpoints:** - `https://gnfd-testnet-sp1.bnbchain.org` - `https://gnfd-testnet-sp2.bnbchain.org` - `https://gnfd-testnet-sp3.bnbchain.org` - `https://gnfd-testnet-sp4.bnbchain.org` - `https://gnfd-testnet-sp1.nodereal.io` - `https://gnfd-testnet-sp2.nodereal.io` - `https://gnfd-testnet-sp3.nodereal.io` The above SPs are joined in the genesis state. For more SP endpoints, you can refer to [GreenfieldScan Testnet SPs](https://testnet.greenfieldscan.com/storage-providers). ### BSC Testnet (chain-id: 97) - **RPC Endpoints:** - `https://data-seed-prebsc-1-s1.bnbchain.org:8545` - `https://data-seed-prebsc-2-s1.bnbchain.org:8545` - `https://data-seed-prebsc-1-s2.bnbchain.org:8545` - `https://data-seed-prebsc-2-s2.bnbchain.org:8545` - `https://data-seed-prebsc-1-s3.bnbchain.org:8545` - `https://data-seed-prebsc-2-s3.bnbchain.org:8545` ### opBNB (chain-id: 5611) - **RPC Endpoints:** - `https://opbnb-testnet-rpc.bnbchain.org` - `https://opbnb-testnet.nodereal.io/v1/64a9df0874fb4a93b9d0a3849de012d3` - `https://opbnb-testnet.nodereal.io/v1/e9a36765eb8a40b9bd12e680a1fd2bc5` For more details, you can refer to [here](network-info.md). ### Block Hub - **BSC:** - `https://gnfd-bsc-archiver-testnet.bnbchain.org` --- ## Interact with the Chain > Source: https://docs.bnbchain.org/bnb-greenfield/for-developers/interact-node/ # Interact with the Chain There are multiple ways to interact with a node: using the CLI, using gRPC or using the REST endpoints. !!! info Since Greenfield Blockchain is based on Cosmos, The majority of the content in this page is copied from the [Cosmos SDK](https://docs.cosmos.network/main/run-node/interact-node). ## Using the CLI Now that your chain is running, it is time to try sending tokens from the first account you created to a second account. In a new terminal window, start by running the following query command: ```bash gnfd query bank balances $MY_VALIDATOR_ADDRESS ``` You should see the current balance of the account you created, equal to the original balance of `BNB` you granted it minus the amount you delegated via the `gentx`. Now, create a second account: ```bash gnfd keys add recipient --keyring-backend test # Put the generated address in a variable for later use. RECIPIENT=$(gnfd keys show recipient -a --keyring-backend test) ``` The command above creates a local key-pair that is not yet registered on the chain. An account is created the first time it receives tokens from another account. Now, run the following command to send tokens to the `recipient` account: ```bash gnfd tx bank send $MY_VALIDATOR_ADDRESS $RECIPIENT 1000000BNB --keyring-backend test # Check that the recipient account did receive the tokens. gnfd query bank balances $RECIPIENT ``` ## Using gRPC The Protobuf ecosystem developed tools for different use cases, including code-generation from `*.proto` files into various languages. These tools allow the building of clients easily. Often, the client connection (i.e. the transport) can be plugged and replaced very easily. Since the code generation library largely depends on your own tech stack, we will only present three alternatives: * `grpcurl` for generic debugging and testing, * programmatically via Go, ### grpcurl [grpcurl](https://github.com/fullstorydev/grpcurl) is like `curl` but for gRPC. It is also available as a Go library, but we will use it only as a CLI command for debugging and testing purposes. Follow the instructions in the previous link to install it. Assuming you have a local node running (either a localnet, or connected a live network), you should be able to run the following command to list the Protobuf services available (you can replace `localhost:9000` by the gRPC server endpoint of another node, which is configured under the `grpc.address` field inside `app.toml`: ```bash grpcurl -plaintext localhost:9090 list ``` You should see a list of gRPC services, like `cosmos.bank.v1beta1.Query`. This is called reflection, which is a Protobuf endpoint returning a description of all available endpoints. Each of these represents a different Protobuf service, and each service exposes multiple RPC methods you can query against. In order to get a description of the service you can run the following command: ```bash grpcurl \ localhost:9090 \ describe cosmos.bank.v1beta1.Query # Service we want to inspect ``` It's also possible to execute an RPC call to query the node for information: ```bash grpcurl \ -plaintext -d '{"address":"$MY_VALIDATOR"}' \ localhost:9090 \ cosmos.bank.v1beta1.Query/AllBalances ``` #### Query for historical state using grpcurl You may also query for historical data by passing some [gRPC metadata](https://github.com/grpc/grpc-go/blob/master/Documentation/grpc-metadata.md) to the query: the `x-cosmos-block-height` metadata should contain the block to query. Using grpcurl as above, the command looks like: ```bash grpcurl \ -plaintext \ -H "x-cosmos-block-height: 279256" \ -d '{"address":"$MY_VALIDATOR"}' \ localhost:9090 \ cosmos.bank.v1beta1.Query/AllBalances ``` Assuming the state at that block has not yet been pruned by the node, this query should return a non-empty response. ### Programmatically via Go The following snippet shows how to query the state using gRPC inside a Go program. The idea is to create a gRPC connection, and use the Protobuf-generated client code to query the gRPC server. #### Install Greenfield GO-sdk Refer to [Go-sdk doc](https://github.com/bnb-chain/greenfield-go-sdk) to install the latest dependency. Init client without key manager, you should use it for only querying purpose. ```go client := NewGreenfieldClient("localhost:9090", "greenfield_9000-121") query := banktypes.QueryBalanceRequest{ Address: "0x76d244CE05c3De4BbC6fDd7F56379B145709ade9", Denom: "BNB", } res, err := client.BankQueryClient.Balance(context.Background(), &query) ``` Init client with key manager, for signing and sending tx ```go keyManager, _ := keys.NewPrivateKeyManager("ab463aca3d2965233da3d1d6108aa521274c5ddc2369ff72970a52a451863fbf") gnfdClient := NewGreenfieldClient("localhost:9090", "greenfield_9000-121", WithKeyManager(km), WithGrpcDialOption(grpc.WithTransportCredentials(insecure.NewCredentials())) ) ``` ## Using the REST Endpoints As described in the [gRPC guide](https://greenfield-chain.bnbchain.org/openapi), all gRPC services on the Cosmos SDK are made available for more convenient REST-based queries. The format of the URL path is based on the Protobuf service method's full-qualified name, but may contain small customizations so that final URLs look more idiomatic. For example, the REST endpoint for the `cosmos.bank.v1beta1.Query/AllBalances` method is `GET /cosmos/bank/v1beta1/balances/{address}`. Request arguments are passed as query parameters. As a concrete example, the `curl` command to make balances request is: ```bash curl \ -X GET \ -H "Content-Type: application/json" \ http://localhost:1317/cosmos/bank/v1beta1/balances/$MY_VALIDATOR ``` Make sure to replace `localhost:1317` with the REST endpoint of your node, configured under the `api.address` field. The list of all available REST endpoints is available as a Swagger specification file, it can be viewed at `localhost:1317/swagger`. Make sure that the `api.swagger` field is set to true in your `app.toml`. ### Query for historical state using REST Querying for historical state is done using the HTTP header `x-cosmos-block-height`. For example, a curl command would look like: ```bash curl \ -X GET \ -H "Content-Type: application/json" \ -H "x-cosmos-block-height: 279256" http://localhost:1317/cosmos/bank/v1beta1/balances/$MY_VALIDATOR ``` Assuming the state at that block has not yet been pruned by the node, this query should return a non-empty response. --- ## EVM Programmability > Source: https://docs.bnbchain.org/bnb-greenfield/for-developers/cross-chain-integration/interface/ # EVM Programmability This document give a detailed introduction of cross-chain primitives that have been defined on EVM-compatible chains to enable developers to manage greenfield resources on the EVM-compatible chains directly. The [Greenfield-Contracts Repo](https://github.com/bnb-chain/greenfield-contracts) is the underlying backbone of the cross chain communication protocol. It is responsible for implementing the core cross-chain communication functionality that enables seamless interaction between Greenfield and EVM-compatible chains, like BSC and opBNB. The library handles the complexities of cross-chain operations, ensuring secure and efficient communication. During the development process, developers are most likely to interact with the following contracts: `CrossChain`, `BucketHub`, `ObjectHub`, `GroupHub`, `PermissionHub`, `MultiMessage` and `GreenfieldExecutor`. ## Quick Glance | Contract name | Usage | |--------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | GovHub | Handle system governance request | | CrossChain | Handle cross-chain package | | TokenHub | Transfer BNB from BSC to Greenfield | | LightClient | Verify cross-chain package and sync light block | | RelayerHub | Relayers could claim rewards from RelayerHub | | BucketHub | Create/delete bucket | | ObjectHub | Delete object | | GroupHub | Create/delete group, update group member | | BucketERC721Token | ERC721 token address representing buckets ownership | | ObjectERC721Token | ERC721 token address representing objects ownership | | GroupERC721Token | ERC721 token address representing groups ownership | | MemberERC1155Token | ERC71155 token address representing the identity of group members | | PermissionHub | The user can use Resource-Based Policy to grant permissions to other accounts. Any resources, such as buckets, objects and groups, can associate several policy. Only the resource owner can put a policy which associate to a resource he owned. 1. A policy associate to a bucket can allow grantee to operate the bucket or the specific objects. 2. A policy associate to a object/group can only allow to operator the object/group. | | PermissionToken | ERC721 token address representing resource policy | | MultiMessage | MultiMessage provides aggregation capabilities to support the atomicity of composite operations. | | GreenfieldExecutor | Most native operations can be achieved by GreenfieldExecutor, like create payment account, deposit to payment account, withdraw from payment account, migrate bucket, cancel migrate bucket, update bucket info, toggle SP as delegated agent, set bucket flow ratelimit, copy object, update object info, set tag. | Refer to the [contract list](./contract-list.md) for detailed contract address on different network. ## CallBack Handling dApps on EVM-compatible chains, i.e. smart contracts on BSC, are allowed to implement their own logic to handle ACK and FAIL_ACK packages. The smart contracts can register callback functions to handle the ACK packages. To avoid consuming too much gas in callbacks, a gas limitation estimation should be done by the smart contracts that register the callbacks. Errors and failures can occur during cross-chain communication. dApps on EVM-compatible chains can handle these by retrying the package with a higher gas limit, skipping the package to tolerate failure, or upgrading their contract to handle corner cases. The following are the interfaces for dapps to handle failures: ```solidity // retry the first failed package in the queue function retryPackage() external; // skip the first failed package in the queue function skipPackage() external; ``` ## Permission Programmability Whether resources are created on BSC or mapped from Greenfield to BSC, such as Buckets, Objects, and Groups, by default, only the owner account of these resources can manage them. However, with proper authorization, other accounts or contracts can be allowed to operate on the owner's resources. We provide two methods of authorization: ### Role-based authorization BucketHub, ObjectHub, and GroupHub all implement the following interface. Through the `grant` interface, other accounts can be granted the permission to create, delete, and update this type of resource for a certain period. This permission can also be revoked through the `revoke` interface. ```solidity function grant(address account, uint32 acCode, uint256 expireTime) external { ... } function revoke(address account, uint32 acCode) external { ... } ``` ### NFT token authorization Since BucketHub and ObjectHub implement the NFT721 standard, and GroupHub implements the ERC1155 standard, we use `approve` and `setApprovalForAll` to authorize specific resource Token IDs without restricting the types of operations, meaning both deletion and updating are allowed. ```solidity function approve(address to, uint256 tokenId) public virtual { ... } function setApprovalForAll(address operator, bool approved) public virtual { ... } ``` ## Detailed Interface They provide the following interfaces respectively: **IGroupHub** The `GroupHub` contract provides the following interfaces to manage Group on BSC/opBNB directly. ```solidity interface IGroupHub { /** * @dev Query the contract address of group NFT. * @return The contract address of group token. * Each group will be mapped as a NFT on BSC. * Group ID and NFT token ID are the same. */ function ERC721Token() external view returns (address); /** * @dev Query the contract address of member NFT. * @return The contract address of member token. * The member inside a group will be mapped as a ERC1155 token on BSC. * The ID of the ERC1155 token is same with the group ID. */ function ERC1155Token() external view returns (address); /** * @dev create a group and send cross-chain request from BSC to GNFD. * * @param creator The group's owner. * @param name The group's name. */ function createGroup(address creator, string memory name) external payable returns (bool); /** * @dev create a group and send cross-chain request from BSC to GNFD. * Callback function will be called when the request is processed. * * @param creator The group's owner. * @param name The group's name. * @param callbackGasLimit The gas limit for callback function. * @param extraData Extra data for callback function. */ function createGroup( address creator, string memory name, uint256 callbackGasLimit, CmnStorage.ExtraData memory extraData ) external payable returns (bool); /** * @dev delete a group and send cross-chain request from BSC to GNFD. * * @param id The group's id. */ function deleteGroup(uint256 id) external payable returns (bool); /** * @dev delete a group and send cross-chain request from BSC to GNFD. * Callback function will be called when the request is processed. * * @param id The group's id. * @param callbackGasLimit The gas limit for callback function. * @param extraData Extra data for callback function. */ function deleteGroup(uint256 id, uint256 callbackGasLimit, CmnStorage.ExtraData memory extraData) external payable returns (bool); /** * @dev update a group's member and send cross-chain request from BSC to GNFD. * * @param synPkg Package containing information of the group to be updated. */ function updateGroup(GroupStorage.UpdateGroupSynPackage memory synPkg) external payable returns (bool); /** * @dev update a group's member and send cross-chain request from BSC to GNFD. * Callback function will be called when the request is processed. * * @param synPkg Package containing information of the group to be updated. * @param callbackGasLimit The gas limit for callback function. * @param extraData Extra data for callback function. */ function updateGroup( GroupStorage.UpdateGroupSynPackage memory synPkg, uint256 callbackGasLimit, CmnStorage.ExtraData memory extraData ) external payable returns (bool); /** * @dev Prepare the create group cross-chain msg data. * This function is used to assist with `MultiMessage`. * * @param sender The supposed msg sender of the cross-chain request. * @param owner The group's owner. * @param name The group's name. * * @return (ChannelID, MsgBytes, RelayerFee, AckRelayerFee, SenderAddress). */ function prepareCreateGroup( address sender, address owner, string memory name ) external payable returns (uint8, bytes memory, uint256, uint256, address); /** * @dev Prepare the delete group cross-chain msg data. * This function is used to assist with `MultiMessage`. * * @param sender The supposed msg sender of the cross-chain request. * @param id The group's id. * * @return (ChannelID, MsgBytes, RelayerFee, AckRelayerFee, SenderAddress). */ function prepareDeleteGroup( address sender, uint256 id ) external payable returns (uint8, bytes memory, uint256, uint256, address); /** * @dev Prepare the update group cross-chain msg data. * This function is used to assist with `MultiMessage`. * * @param sender The supposed msg sender of the cross-chain request. * @param synPkg Package containing information of the group to be updated. * * @return (ChannelID, MsgBytes, RelayerFee, AckRelayerFee, SenderAddress). */ function prepareUpdateGroup( address sender, GroupStorage.UpdateGroupSynPackage memory synPkg ) external payable returns (uint8, bytes memory, uint256, uint256, address); } ``` **IBucketHub** The `BucketHub` contract provides the following interfaces to manage bucket on EVM-compatible chains, like BSC and opBNB, directly. ```solidity interface IBucketHub { /** * @dev Query the contract address of bucket NFT. * @return The contract address of bucket token. * Each bucket will be mapped as a NFT on BSC. * Bucket ID and NFT token ID are the same. */ function ERC721Token() external view returns (address); /** * @dev create a bucket and send cross-chain request from BSC to GNFD * * @param synPkg Package containing information of the bucket to be created */ function createBucket(BucketStorage.CreateBucketSynPackage memory synPkg) external payable returns (bool); /** * @dev create a bucket and send cross-chain request from BSC to GNFD. * Callback function will be called when the request is processed. * * @param synPkg Package containing information of the bucket to be created. * @param callbackGasLimit The gas limit for callback function. * @param extraData Extra data for callback function. */ function createBucket( BucketStorage.CreateBucketSynPackage memory synPkg, uint256 callbackGasLimit, CmnStorage.ExtraData memory extraData ) external payable returns (bool); /** * @dev delete a bucket and send cross-chain request from BSC to GNFD. * * @param id The bucket's id. */ function deleteBucket(uint256 id) external payable returns (bool); /** * @dev delete a bucket and send cross-chain request from BSC to GNFD. * Callback function will be called when the request is processed. * * @param id The bucket's id. * @param callbackGasLimit The gas limit for callback function. * @param extraData Extra data for callback function. */ function deleteBucket(uint256 id, uint256 callbackGasLimit, CmnStorage.ExtraData memory extraData) external payable returns (bool); /** * @dev Prepare the create bucket cross-chain msg data. * This function is used to assist with `MultiMessage`. * * @param sender The supposed msg sender of the cross-chain request. * @param synPkg Package containing information of the bucket to be created. * * @return (ChannelID, MsgBytes, RelayerFee, AckRelayerFee, SenderAddress). */ function prepareCreateBucket( address sender, CreateBucketSynPackage memory synPkg ) external payable returns (uint8, bytes memory, uint256, uint256, address); /** * @dev Prepare the create bucket cross-chain msg data. * This function is used to assist with `MultiMessage`. * * @param sender The supposed msg sender of the cross-chain request. * @param synPkg Package containing information of the bucket to be created. * @param callbackGasLimit The gas limit for callback function * @param extraData Extra data for callback function. * * @return (ChannelID, MsgBytes, RelayerFee, AckRelayerFee, SenderAddress). */ function prepareCreateBucket( address sender, CreateBucketSynPackage memory synPkg, uint256 callbackGasLimit, CmnStorage.ExtraData memory extraData ) external payable returns (uint8, bytes memory, uint256, uint256, address); /** * @dev Prepare the delete bucket cross-chain msg data. * This function is used to assist with `MultiMessage`. * * @param sender The supposed msg sender of the cross-chain request. * @param id The bucket's id. * * @return (ChannelID, MsgBytes, RelayerFee, AckRelayerFee, SenderAddress). */ function prepareDeleteBucket( address sender, uint256 id ) external payable returns (uint8, bytes memory, uint256, uint256, address); /** * @dev Prepare the delete bucket cross-chain msg data. * This function is used to assist with `MultiMessage`. * * @param sender The supposed msg sender of the cross-chain request. * @param id The bucket's id. * @param callbackGasLimit The gas limit for callback function * @param extraData Extra data for callback function. * * @return (ChannelID, MsgBytes, RelayerFee, AckRelayerFee, SenderAddress). */ function prepareDeleteBucket( address sender, uint256 id, uint256 callbackGasLimit, ExtraData memory extraData ) external payable returns (uint8, bytes memory, uint256, uint256, address); } ``` **IObjectHub** The `ObjectHub` contract provides the following interfaces to manage object on EVM-compatible chains, like BSC and opBNB, directly. ```solidity interface IObjectHub { /** * @dev Query the contract address of object NFT. * @return The contract address of object token. * Each object will be mapped as a NFT on BSC. * Object ID and NFT token ID are the same. */ function ERC721Token() external view returns (address); /** * @dev delete a object and send cross-chain request from BSC to GNFD. * * @param id The object's id. */ function deleteObject(uint256 id) external payable returns (bool); /** * @dev delete a object and send cross-chain request from BSC to GNFD. * Callback function will be called when the request is processed. * * @param id The object's id. * @param callbackGasLimit The gas limit for callback function. * @param extraData Extra data for callback function. */ function deleteObject(uint256 id, uint256 callbackGasLimit, CmnStorage.ExtraData memory extraData) external payable returns (bool); /** * @dev Prepare the delete object cross-chain msg data. * This function is used to assist with `MultiMessage`. * * @param sender The supposed msg sender of the cross-chain request. * @param id The object's id. * * @return (ChannelID, MsgBytes, RelayerFee, AckRelayerFee, SenderAddress). */ function prepareDeleteObject( address sender, uint256 id ) external payable returns (uint8, bytes memory, uint256, uint256, address); /** * @dev Prepare the delete object cross-chain msg data. * This function is used to assist with `MultiMessage`. * * @param sender The supposed msg sender of the cross-chain request. * @param id The object's id. * @param callbackGasLimit The gas limit for callback function * @param extraData Extra data for callback function. * * @return (ChannelID, MsgBytes, RelayerFee, AckRelayerFee, SenderAddress). */ function prepareDeleteObject( address sender, uint256 id, uint256 callbackGasLimit, ExtraData memory extraData ) external payable returns (uint8, bytes memory, uint256, uint256, address); } ``` **IPermissionHub** The `PermissionHub` contract provides the following interfaces to manage permission on EVM-compatible chains, like BSC and opBNB, directly. ```solidity interface IPermissionHub { /** * @dev Query the contract address of permission NFT. * @return The contract address of permission token. * Each permission policy will be mapped as a NFT on BSC. * Policy ID and NFT token ID are the same. */ function ERC721Token() external view returns (address); /** * @dev delete a policy and send cross-chain request from BSC to GNFD. * * @param id The policy's id. */ function deletePolicy(uint256 id) external payable returns (bool); /** * @dev delete a policy and send cross-chain request from BSC to GNFD. * * @param id The policy's id. * @param _extraData Extra data for callback function. */ function deletePolicy(uint256 id, PermissionStorage.ExtraData memory _extraData) external payable returns (bool); /** * @dev create a policy and send cross-chain request from BSC to GNFD. * * @param data policy data encoded by protobuf. * @param _extraData Extra data for callback function. */ function createPolicy( bytes calldata _data, PermissionStorage.ExtraData memory _extraData ) external payable returns (bool); /** * @dev create a policy and send cross-chain request from BSC to GNFD. * * @param _data policy data encoded by protobuf. */ function createPolicy(bytes calldata _data) external payable returns (bool); /** * @dev Prepare the create policy cross-chain msg data. * This function is used to assist with `MultiMessage`. * * @param sender The supposed msg sender of the cross-chain request. * @param _data policy data encoded by protobuf. * * @return (ChannelID, MsgBytes, RelayerFee, AckRelayerFee, SenderAddress). */ function prepareCreatePolicy( address sender, bytes calldata _data ) external payable returns (uint8, bytes memory, uint256, uint256, address); /** * @dev Prepare the create policy cross-chain msg data. * This function is used to assist with `MultiMessage`. * * @param sender The supposed msg sender of the cross-chain request. * @param _data policy data encoded by protobuf. * @param _extraData Extra data for callback function. * * @return (ChannelID, MsgBytes, RelayerFee, AckRelayerFee, SenderAddress). */ function prepareCreatePolicy( address sender, bytes calldata _data, PermissionStorage.ExtraData memory _extraData ) external payable returns (uint8, bytes memory, uint256, uint256, address); /** * @dev Prepare the delete policy cross-chain msg data. * This function is used to assist with `MultiMessage`. * * @param sender The supposed msg sender of the cross-chain request. * @param id The policy's id. * * @return (ChannelID, MsgBytes, RelayerFee, AckRelayerFee, SenderAddress). */ function prepareDeletePolicy( address sender, uint256 id ) external payable returns (uint8, bytes memory, uint256, uint256, address); /** * @dev Prepare the delete policy cross-chain msg data. * This function is used to assist with `MultiMessage`. * * @param sender The supposed msg sender of the cross-chain request. * @param id The policy's id. * @param _extraData Extra data for callback function. * * @return (ChannelID, MsgBytes, RelayerFee, AckRelayerFee, SenderAddress). */ function prepareDeletePolicy( address sender, uint256 id, PermissionStorage.ExtraData memory _extraData ) external payable returns (uint8, bytes memory, uint256, uint256, address); ``` **IMultiMessage** `MultiMessage` provides aggregation capabilities to support the atomicity of composite operations. ```solidity interface IMultiMessage { function sendMessages( address[] calldata _targets, bytes[] calldata _data, uint256[] calldata _values ) external payable returns (bool); } ``` **IGreenfieldExecutor** Most native operations can be achieved by `GreenfieldExecutor`, like create payment account, deposit to payment account, withdraw from payment account, migrate bucket, cancel migrate bucket, update bucket info, toggle SP as delegated agent, set bucket flow ratelimit, copy object, update object info, set tag. ```solidity interface IGreenfieldExecutor { function execute(uint8[] calldata _msgTypes, bytes[] calldata _msgBytes) external payable returns (bool); } ``` --- ## Resource Mirror > Source: https://docs.bnbchain.org/bnb-greenfield/for-developers/cross-chain-integration/mirror-concept/ # Resource Mirroring # Overview Greenfield Blockchain offers resources like buckets, objects, and groups for mirroring on EVM-compatible chains (e.g., BSC, opBNB) as ERC-721 NFTs. Buckets serve as containers for objects, which are data files with metadata, while groups are sets of accounts with shared permissions. Additionally, group members' permissions can be mirrored as ERC-1155 tokens. Currently, these NFTs are non-transferable, with plans to introduce transferability soon. Mirrored resources on EVM chains can be managed via smart contracts, impacting data's storage format and access permissions. Changes on EVM chains reflect on Greenfield, enhancing data access and manipulation flexibility. This integration fosters a more efficient data management process. ## How to Mirror Mirroring objects from BNB Greenfield to BSC is not done automatically with the creation of the resource. Users have to manually trigger the mirroring process for selected objects, either at the bucket or object level or group, as it requires transaction gas. This allows users to have control over which objects are mirrored while being aware of the associated costs. - [Resources Mirroring with CLI](../../for-developers/cross-chain-integration/mirror.md) - [Resource Mirroring with SDK](https://github.com/bnb-chain/greenfield-go-sdk/blob/master/examples/crosschain.go) The changes made to mirrored objects on BSC are propagated to BNB Greenfield once the corresponding transactions are finalized on both blockchains. BSC has a block finality of 3 seconds, while BNB Greenfield has a block finality of 2 seconds. As a result, the changes should be reflected within a maximum block finality of 3 seconds, which is the longer of the two block finality times. Once an object is mirrored from BNB Greenfield to BSC, it can only be managed on BSC and cannot be reverted or "un-mirrored" back to Greenfield for management through Greenfield. However, it is worth noting that the ability to "un-mirror" objects back to Greenfield may be introduced in future releases, providing the option to manage mirrored objects through Greenfield after being mirrored to BSC. ## What can be achieved through mirroring Currently changing any metadata attributes of the object, which includes information about its properties, permissions, and other relevant attributes. For instance, to alter an object's permissions on BNB Greenfield, a user can execute an on-chain transaction on BSC. This transaction, specifying the permission changes, sends a message via relayers from BSC to Greenfield. Upon receiving the message, Greenfield updates the object's metadata as requested. During the mirroring process from BNB Greenfield to BSC, the content of the file itself is not copied. This means that neither the data nor the file metadata, which is stored on the BNB Greenfield blockchain, is transferred to BSC. Consequently, there is no size limit imposed on the mirroring process since the actual file content is not duplicated. The ownership of the resource is changed too during the mirroring process. --- ## Resources Mirroring with CLI > Source: https://docs.bnbchain.org/bnb-greenfield/for-developers/cross-chain-integration/mirror/ # Resources Mirroring with CLI ## Introduction During the mirroring process from BNB Greenfield to BSC, the content of the file itself is not copied. This means that neither the data nor the file metadata, which is stored on the BNB Greenfield blockchain, is transferred to BSC. Consequently, there is no size limit imposed on the mirroring process since the actual file content is not duplicated. ## Mirror Objects Objects can be mirrored on the BSC as ERC-721 NFTs Example command to mirror to BSC testnet: ```shell gnfd-cmd object mirror --bucketName yourBucketName --objectName yourObjectName --destChainId 97 ``` Example output: ``` mirror object succ, txHash: 0774F400EBD42FAB009A6B3C303EF8625B57AB551E0F065C546B892167938122 ``` You can go to [GreenfieldScan](https://testnet.greenfieldscan.com) to view the details of mirror operation. Then, go to [BscScan](https://testnet.bscscan.com) and you can find out that there is a NFT transferred to you. ## Mirror Buckets Mirror buckets are the same procedure and mirror objects. Example command to mirror to BSC testnet: ```shell gnfd-cmd object mirror --bucketName yourBucketName --destChainId 97 ``` Example output: ``` mirror bucket succ, txHash: 0xba1ca47a2271864b2010158b13535331301ba3289aab8e373503e91e3a41d0a7 ``` You can go to [GreenfieldScan](https://testnet.greenfieldscan.com) to view the details of mirror operation. Then, go to [BscScan](https://testnet.bscscan.com) and you can find out that there is a NFT transferred to you. ## Mirror Group The members within a group, which represent permissions to specify resources, can be mirrored as ERC-1155 token. Example command to mirror to BSC testnet: ```shell // mirror a group as NFT to BSC, you might use group id or groupName to identidy the group gnfd-cmd group mirror --id 1 // irror a group with group id gnfd-cmd group mirror --groupName yourGroupName ``` Example output: ```shel mirror_group: transaction hash: 99A749ECC3CEB8B7CF4B8132A19D1A04EF7247F8549477B6AD28CA69BD11E66A ``` You can go to [GreenfieldScan](https://testnet.greenfieldscan.com) to view the details of mirror operation. Then, go to [BscScan](https://testnet.bscscan.com) and you can find out that there is a NFT transferred to you. --- ## Integrating BSC Smart Contracts with Greenfield Projects > Source: https://docs.bnbchain.org/bnb-greenfield/for-developers/cross-chain-integration/dapp-integration/ # Contract SDK The [Smart Contract SDK](https://github.com/bnb-chain/greenfield-contracts-sdk), designed to facilitate the development of community-driven projects. The SDK serves as an upper layer wrapper for the [Greenfield-Contracts](https://github.com/bnb-chain/greenfield-contracts) library, which implements the cross-chain communication functionality. By providing a user-friendly interface to the underlying interface, the SDK simplifies the development process and enables developers to create and manage a variety of greenfield resources, like bucket, group, and object on BSC through smart contract directly. The SDK is organized into four primary parts: `BaseApp`, `BucketApp`, `ObjectApp`, and `GroupApp`. These components serve as the building blocks for developers. The `BaseApp` serves as the foundation for the other three components, providing common functions required by the `BucketApp`, `ObjectApp`, and `GroupApp`. The `BucketApp` is responsible for managing bucket-related operations, while the `ObjectApp` handles object-related actions. The `GroupApp`, being the most complex of the four, is designed to handle group-related operations. Each of these components is equipped with unique functions and virtual functions that can be implemented to suit specific project needs. ### Components 1. **BaseApp:** Contains common functions used by the other components, as well as three virtual functions that need to be implemented for specific project requirements. 2. **BucketApp:** A specialized module designed to handle bucket-related operations, such as creating and deleting buckets, and processing bucket resource calls. 3. **ObjectApp:** A specialized module focused on object-related operations, specifically object deletion since creating objects from BSC is not supported. 4. **GroupApp:** A more complex module that handles group-related operations, such as creating, deleting, and updating groups, and managing group resource calls. ### BaseApp The BaseApp contains common functions that are shared by BucketApp, ObjectApp, and GroupApp. These functions are essential for setting up and managing the environment for cross-chain operations. The BaseApp provides the following core functions: 1. `_getTotalFee():` This function returns the total value required to send a cross-chain package. 2. `Setters:` There are several setters available for configuring various aspects of the smart contract, such as: - `callbackGasLimit`: Sets the gas limit for the callback function. - `failureHandleStrategy`: Sets the strategy for handling failures during the execution of the smart contract. In addition to these functions, BaseApp provides three virtual functions: 1. `greenfieldCall(uint32 status, uint8 resourceType, uint8 operationType, uint256 resourceId, bytes calldata callbackData):` This function is a callback hook designed to handle cross-chain response. It is a virtual function that needs to be implemented by developers to define custom behaviors for different types of resources and operation types. This function is triggered when a cross-chain operation is completed on greenfield side and return a package to bsc, allowing developers to execute specific actions or update states in response to the completion of an operation. If the developers don’t need callback, this function(as well as other callback related functions) can be undefined. 2. `retryPackage(uint8 resourceType):` This function handles the retry mechanism for a package, based on its resource type. Developers should implement this function to define the behavior when a package needs to be retried. 3. `skipPackage(uint8 resourceType):` This function allows for skipping a package, based on its resource type. Developers should implement this function to define the behavior when a package needs to be skipped. By implementing these virtual functions, developers can customize the behavior of their smart contracts to meet their specific requirements. With the BaseApp component, developers have a solid foundation on which to build their smart contract applications using `BucketApp`, `ObjectApp`, and `GroupApp`. ### BucketApp The BucketApp component is a specialized module designed to handle bucket-related operations in the smart contract SDK. This component offers a range of functions to create, delete, and manage buckets, as well as to route and handle various bucket resource operations. Below, we provide a detailed overview of the functions included in the BucketApp: 1. `_bucketGreenfieldCall(uint32 status, uint8 operationType, uint256 resourceId, bytes calldata callbackData)`: This function serves as a router for bucket resource callback. It processes and directs the call based on the provided parameters. 2. `_retryBucketPackage()`: This function retries a failed bucket resource package. 3. `_skipBucketPackage()`: This function skips a failed bucket resource package. 4. `_createBucket(address _creator, string memory _name, BucketStorage.BucketVisibilityType _visibility, address _paymentAddress, address _spAddress, uint256 _expireHeight, uint32 _globalVirtualGroupFamilyId, bytes calldata _sig, uint64 _chargedReadQuota)`: This function sends a create bucket cross-chain request to greenfield without a callback. It takes various parameters, such as creator, name, visibility type, charged read quota, service provider address, expire height, global virtual family id and signature. 5. `_createBucket(address _creator, string memory _name, BucketStorage.BucketVisibilityType _visibility, address _paymentAddress, address _spAddress, uint256 _expireHeight, uint32 _globalVirtualGroupFamilyId, bytes calldata _sig, uint64 _chargedReadQuota, address _refundAddress, PackageQueue.FailureHandleStrategy _failureHandleStrategy, bytes memory _callbackData, uint256 _callbackGasLimit)`: This function sends a create bucket cross-chain request to greenfield with a callback. It takes the same parameters as the previous function, along with some additional parameters for the callback. 6. `_deleteBucket(uint256 _tokenId)`: This function sends a delete bucket cross-chain request to greenfield without a callback, using the provided token ID. 7. `_deleteBucket(uint256 _tokenId, address _refundAddress, PackageQueue.FailureHandleStrategy _failureHandleStrategy, bytes memory _callbackData, uint256 _callbackGasLimit)`: This function sends a delete bucket cross-chain request to greenfield with a callback, using the provided token ID and callback data. In addition to these functions, the BucketApp provides two virtual functions: 1. `_createBucketCallback(uint32 _status, uint256 _tokenId, bytes memory _callbackData)`: Developers can implement this function to define the behavior for the create bucket callback. The function receives the status, token ID, and callback data as parameters. 2. `_deleteBucketCallback(uint32 _status, uint256 _tokenId, bytes memory _callbackData)`: Developers can implement this function to define the behavior for the delete bucket callback. The function receives the status, token ID, and callback data as parameters. By implementing these virtual functions, developers can tailor the BucketApp component to suit their specific bucket-related operations and handle the corresponding callbacks as needed. ### ObjectApp The ObjectApp component is a specialized module designed to handle object-related operations in the smart contract SDK. This component offers a range of functions to manage objects and process object resource operations. However, please note that creating objects from BSC is currently not supported. Below, we provide a detailed overview of the functions included in the ObjectApp: 1. `_objectGreenfieldCall(uint32 status, uint8 operationType, uint256 resourceId, bytes calldata callbackData)`: This function serves as a router for object resource callback. It processes and directs the call based on the provided parameters. 2. `_retryObjectPackage()`: This function retries a failed object resource package. 3. `_skipObjectPackage()`: This function skips a failed object resource package. 4. `_deleteObject(uint256 _tokenId)`: This function deletes an object using the provided token ID. As creating objects from BSC is not supported, the ObjectApp focuses on deletion operations. 5. `_deleteObject(uint256 _tokenId, address _refundAddress, PackageQueue.FailureHandleStrategy _failureHandleStrategy, bytes memory _callbackData, uint256 _callbackGasLimit)`: This function deletes an object with a callback, using the provided token ID and callback data. In addition to these functions, the ObjectApp provides one virtual function: 1. `_deleteObjectCallback(uint32 _status, uint256 _tokenId, bytes memory _callbackData)`: Developers need to implement this function to define the behavior for the delete object callback. The function receives the status, token ID, and callback data as parameters. By implementing this virtual function, developers can customize the ObjectApp component to handle object deletion operations and manage the corresponding callbacks as needed. ### GroupApp The GroupApp component is a specialized module designed to handle group-related operations in the smart contract SDK. This component is more complex compared to the BucketApp and ObjectApp, as it offers a range of functions to create, delete, update, and manage groups. Below, we provide a detailed overview of the functions included in the GroupApp: 1. `_groupGreenfieldCall(uint32 status, uint8 operationType, uint256 resourceId, bytes calldata callbackData)`: This function serves as a router for group resource callback. It processes and directs the call based on the provided parameters. 2. `_retryGroupPackage()`: This function retries a failed group resource package. 3. `_skipGroupPackage()`: This function skips a failed group resource package. 4. `_createGroup(address _owner, string memory _groupName)`: This function creates a new group with the provided owner address and group name. 5. `_createGroup(address _refundAddress, PackageQueue.FailureHandleStrategy _failureHandleStrategy, bytes memory _callbackData,, address _owner, string memory _groupName, uint256 _callbackGasLimit)`: This function creates a new group with a callback, using the provided owner address, group name, and callback data. 6. `_deleteGroup(uint256 _tokenId)`: This function deletes a group using the provided token ID. 7. `_deleteGroup(uint256 _tokenId, address _refundAddress, PackageQueue.FailureHandleStrategy _failureHandleStrategy, bytes memory _callbackData, uint256 _callbackGasLimit)`: This function deletes a group with a callback, using the provided token ID and callback data. 8. `_updateGroup(address _owner, uint256 _tokenId, uint8 _opType, address[] memory _members, uint64[] memory _expiration)`: This function updates a group based on the provided owner address, token ID, operation type, and an array of member addresses. 9. `_updateGroup(address _owner, uint256 _tokenId, uint8 _opType, address[] memory _members, uint64[] memory _expiration, address _refundAddress, PackageQueue.FailureHandleStrategy _failureHandleStrategy, bytes memory _callbackData, uint256 _callbackGasLimit)`: This function updates a group with a callback, using the provided owner address, token ID, operation type, an array of member addresses, and callback data. In addition to these functions, the GroupApp provides three virtual functions: 1. `_createGroupCallback(uint32 _status, uint256 _tokenId, bytes memory _callbackData)`: Developers need to implement this function to define the behavior for the create group callback. The function receives the status, token ID, and callback data as parameters. 2. `_deleteGroupCallback(uint32 _status, uint256 _tokenId, bytes memory _callbackData)`: Developers need to implement this function to define the behavior for the delete group callback. The function receives the status, token ID, and callback data as parameters. 3. `_updateGroupCallback(uint32 _status, uint256 _tokenId, bytes memory _callbackData)`: Developers need to implement this function to define the behavior for the update group callback. The function receives the status, token ID, and callback data as parameters. By implementing these virtual functions, developers can customize the GroupApp component to suit their specific group-related operations and handle the corresponding callbacks as needed. ## Integration Example We will walk you through the process of creating a decentralized `Ebook` shop using the Contract SDK as an example. ### Prerequisites Before starting, make sure you have the following tools installed: - [Node.js](https://nodejs.org/) - [Foundry](https://book.getfoundry.sh/) ### Installation ```console $ npm install @bnb-chain/greenfield-contracts-sdk ``` Alternatively, you can obtain the contracts directly from the GitHub repository (`bnb-chain/greenfield-contracts-sdk`). When doing so, ensure that you specify the appropriate release. #### Steps 1. Import the desired contracts, for example in `examples/ebook-shop.sol`: ```solidity pragma solidity ^0.8.0; import "@bnb-chain/greenfield-contracts-sdk/BucketApp.sol"; import "@bnb-chain/greenfield-contracts-sdk/ObjectApp.sol"; import "@bnb-chain/greenfield-contracts-sdk/GroupApp.sol"; import "@bnb-chain/greenfield-contracts-sdk/interface/IERC1155.sol"; import "@bnb-chain/greenfield-contracts-sdk/interface/IERC721NonTransferable.sol"; import "@bnb-chain/greenfield-contracts-sdk/interface/IERC1155NonTransferable.sol"; ... contract EbookShop is BucketApp, ObjectApp, GroupApp { ... } ``` 2. Define the `initialize` function. Initialize the global variables in the init function. You can use the internal init functions: ```solidity function initialize( address _crossChain, address _bucketHub, address _objectHub, address _groupHub, address _ebookToken, address _paymentAddress, uint256 _callbackGasLimit, address _refundAddress, uint8 _failureHandleStrategy, ... ) public initializer { __base_app_init_unchained(_crossChain, _callbackGasLimit, _refundAddress, _failureHandleStrategy); __bucket_app_init_unchained(_bucketHub); __group_app_init_unchained(_groupHub); __object_app_init_unchained(_objectHub); ... } ``` 3. Define and override the `greenfieldCall`, `retryPackage` and `skipPackage` functions if your dApp needs callback. You can route calls with the help of the internal method: ```solidity function greenfieldCall( uint32 status, uint8 resoureceType, uint8 operationType, uint256 resourceId, bytes calldata callbackData ) external override(BucketApp, ObjectApp, GroupApp) { require(msg.sender == crossChain, string.concat("EbookShop: ", ERROR_INVALID_CALLER)); if (resoureceType == RESOURCE_BUCKET) { _bucketGreenfieldCall(status, operationType, resourceId, callbackData); } else if (resoureceType == RESOURCE_OBJECT) { _objectGreenfieldCall(status, operationType, resourceId, callbackData); } else if (resoureceType == RESOURCE_GROUP) { _groupGreenfieldCall(status, operationType, resourceId, callbackData); } else { revert(string.concat("EbookShop: ", ERROR_INVALID_RESOURCE)); } } function retryPackage(uint8 resoureceType) external override onlyOperator { if (resoureceType == RESOURCE_BUCKET) { _retryBucketPackage(); } else if (resoureceType == RESOURCE_OBJECT) { _retryObjectPackage(); } else if (resoureceType == RESOURCE_GROUP) { _retryGroupPackage(); } else { revert(string.concat("EbookShop: ", ERROR_INVALID_RESOURCE)); } } function skipPackage(uint8 resoureceType) external override onlyOperator { if (resoureceType == RESOURCE_BUCKET) { _skipBucketPackage(); } else if (resoureceType == RESOURCE_OBJECT) { _skipObjectPackage(); } else if (resoureceType == RESOURCE_GROUP) { _skipGroupPackage(); } else { revert(string.concat("EbookShop: ", ERROR_INVALID_RESOURCE)); } } ``` 4. Next you need to define the main functional parts of the app. You can send cross-chain request to system contracts with the help of internal functions like below: ```solidity /** * @dev Create a new series. * * Assuming the sp provider's info will be provided by the front-end. */ function createSeries( string calldata name, BucketStorage.BucketVisibilityType visibility, uint64 chargedReadQuota, address spAddress, uint256 expireHeight, bytes calldata sig ) external payable { require(bytes(name).length > 0, string.concat("EbookShop: ", ERROR_INVALID_NAME)); require(seriesId[name] == 0, string.concat("EbookShop: ", ERROR_RESOURCE_EXISTED)); bytes memory _callbackData = bytes(name); // use name as callback data _createBucket(msg.sender, name, visibility, chargedReadQuota, spAddress, expireHeight, sig, _callbackData); // send cross-chain request } /** * @dev Provide an ebook's ID to publish it. * * An ERC1155 token will be minted to the owner. * Other users can buy the ebook by calling `buyEbook` function with given price. */ function publishEbook(uint256 _ebookId, uint256 price) external { require( IERC721NonTransferable(objectToken).ownerOf(_ebookId) == msg.sender, string.concat("EbookShop: ", ERROR_INVALID_CALLER) ); require(ebookGroup[_ebookId] != 0, string.concat("EbookShop: ", ERROR_GROUP_NOT_EXISTED)); require(price > 0, string.concat("EbookShop: ", ERROR_INVALID_PRICE)); ebookPrice[_ebookId] = price; IERC1155(ebookToken).mint(msg.sender, _ebookId, 1, ""); } /** * @dev Provide an ebook's ID to buy it. * * Buyer will be added to the group of the ebook. * An ERC1155 token will be minted to the buyer. */ function buyEbook(uint256 _ebookId) external payable { require(ebookPrice[_ebookId] > 0, string.concat("EbookShop: ", ERROR_EBOOK_NOT_ONSHELF)); uint256 price = ebookPrice[_ebookId]; require(msg.value >= price, string.concat("EbookShop: ", ERROR_NOT_ENOUGH_VALUE)); IERC1155(ebookToken).mint(msg.sender, _ebookId, 1, ""); uint256 _groupId = ebookGroup[_ebookId]; address _owner = IERC721NonTransferable(groupToken).ownerOf(_groupId); address[] memory _member = new address[](1); _member[0] = msg.sender; _updateGroup(_owner, _groupId, UPDATE_ADD, _member); } /** * @dev Provide an ebook's ID to downshelf it. * * The ebook will be removed from the shelf and cannot be bought. * Those who have already purchased are not affected. */ function downshelfEbook(uint256 _ebookId) external { require( IERC721NonTransferable(objectToken).ownerOf(_ebookId) == msg.sender, string.concat("EbookShop: ", ERROR_INVALID_CALLER) ); require(ebookPrice[_ebookId] > 0, string.concat("EbookShop: ", ERROR_EBOOK_NOT_ONSHELF)); ebookPrice[_ebookId] = 0; } ... ``` 5. Besides, you may need to provide a function for user to register their own resource that were created at greenfield side and then mirrored to BSC manually: ```solidity /** * @dev Register bucket resource that mirrored from GreenField to BSC. */ function registerSeries(string calldata name, uint256 tokenId) external { require( IERC721NonTransferable(bucketToken).ownerOf(tokenId) == msg.sender, string.concat("EbookShop: ", ERROR_INVALID_CALLER) ); require(bytes(name).length > 0, string.concat("EbookShop: ", ERROR_INVALID_NAME)); require(seriesId[name] == 0, string.concat("EbookShop: ", ERROR_RESOURCE_EXISTED)); seriesName[tokenId] = name; seriesId[name] = tokenId; } ... ``` 6. Define other view functions, internal functions and access control system according to your own needs. --- ## Contract as Bucket Owner > Source: https://docs.bnbchain.org/bnb-greenfield/for-developers/cross-chain-integration/demo-contract-as-bucket-owner/ # Greenfield Demo: Contract as Bucket Owner BNB Greenfield provides the ability for a contract to manage buckets through greenfield cross-chain transactions, and we'll use a demo to briefly demonstrate the process. ## Source Code - Greenfield Demo App Contract: [GreenfieldDemo](https://github.com/bnb-chain/greenfield-contracts/blob/develop/contracts/example/GreenfieldDemo.sol) - Script to Interact with Demo: [Demo Script](https://github.com/bnb-chain/greenfield-contracts/blob/develop/scripts/11-demo-contract-approve-eoa-upload.ts) ## Greenfield Demo Contract The Demo includes the following parts: ### greenfield contracts constant: ```solidity // BSC testnet address public constant TOKEN_HUB = 0xED8e5C546F84442219A5a987EE1D820698528E04; address public constant CROSS_CHAIN = 0xa5B2c9194131A4E0BFaCbF9E5D6722c873159cb7; address public constant BUCKET_HUB = 0x5BB17A87D03620b313C39C24029C94cB5714814A; address public constant PERMISSION_HUB = 0x25E1eeDb5CaBf288210B132321FBB2d90b4174ad; address public constant SP_ADDRESS_TESTNET = 0x5FFf5A6c94b182fB965B40C7B9F30199b969eD2f; address public constant GREENFIELD_EXECUTOR = 0x3E3180883308e8B4946C9a485F8d91F8b15dC48e; ``` The addresses of Greenfield contracts deployed on the BSC testnet are available and configured here. You can find contracts deployed on other networks [contract entrypoint](https://docs.bnbchain.org/bnb-greenfield/for-developers/cross-chain-integration/contract-list) ### create bucket and set bucket flow rate limit ```solidity function createBucket(string memory bucketName, uint256 transferOutAmount, bytes memory _executorData) external payable; ``` Provides the bucket name, initial BNB amount transferred to the demo contract on Greenfield and the executor data to set bucket flow rate limit.This API will create a new bucket owned by the smart contract and set the payment for it. ### create policy to allow eoa account to upload files to the bucket ```solidity function createPolicy(bytes memory createPolicyData) external payable; ``` Construct the `createPolicyData` parameters to grant permission to the dedicated principle for the created bucket owned by the smart contract. ## Interact Script ### Installation ```shell git clone https://github.com/bnb-chain/greenfield-contracts.git cd greenfield-contracts && git checkout develop npm install npx hardhat compile cp .env.example .env # set `DeployerPrivateKey` on .env # make sure the tBNB balance of the account >= 0.5 BNB on BSC Testnet npx hardhat run scripts/11-demo-contract-approve-eoa-upload.ts --network bsc-testnet ``` ### Workflow The interact script includes 4 steps as follows: #### deploy demo contract ```typescript const demo = (await deployContract(operator, 'GreenfieldDemo')) as GreenfieldDemo; ``` #### create bucket whose owner is the demo contract set bucket flow rate limit and cross-chain transfer 0.1 BNB to demo contract ```typescript const bucketName = 'test-' + demo.address.substring(2, 6).toLowerCase(); // - transferOutAmt: 0.1 BNB to demo contract on Greenfield // - set bucket flow rate limit to this bucket // - create bucket: 'test-approve-eoa-upload', its owner is demo contract const dataSetBucketFlowRateLimit = ExecutorMsg.getSetBucketFlowRateLimitParams({ bucketName, bucketOwner: demo.address, operator: demo.address, paymentAddress: demo.address, flowRateLimit: '1000000000000000000', }); const executorData = dataSetBucketFlowRateLimit[1]; const transferOutAmt = ethers.utils.parseEther('0.1'); const value = transferOutAmt.add(relayFee.mul(3).add(ackRelayFee.mul(2))); log('- transfer out to demo contract on greenfield', toHuman(transferOutAmt)); log('- create bucket', bucketName); log('send crosschain tx!'); const receipt = await waitTx( demo.createBucket(bucketName, transferOutAmt, executorData, { value }) ); log(`https://testnet.bscscan.com/tx/${receipt.transactionHash}`); ``` #### get bucket id by name after bucket created ```typescript const bucketInfo = await client.bucket.getBucketMeta({ bucketName }); const bucketId = bucketInfo.body!.GfSpGetBucketMetaResponse.Bucket.BucketInfo.Id; log('bucket created, bucket id', bucketId); const hexBucketId = `0x000000000000000000000000000000000000000000000000000000000000${BigInt( bucketId ).toString(16)}`; log(`https://testnet.greenfieldscan.com/bucket/${hexBucketId}`); ``` #### create policy to allow EOA account upload files to the bucket through cross-chain transaction ```typescript const uploaderEoaAccount = operator.address; // TODO set your eoa account to upload files log('try to set uploader(eoa account) is', uploaderEoaAccount); const policyDataToAllowUserOperateBucket = Policy.encode({ id: '0', resourceId: bucketId, // bucket id resourceType: ResourceType.RESOURCE_TYPE_BUCKET, statements: [ { effect: Effect.EFFECT_ALLOW, actions: [ActionType.ACTION_CREATE_OBJECT], // allow upload file to the bucket resources: [], }, ], principal: { type: PrincipalType.PRINCIPAL_TYPE_GNFD_ACCOUNT, value: uploaderEoaAccount, }, }).finish(); await waitTx( demo.createPolicy(policyDataToAllowUserOperateBucket, { value: relayFee.add(ackRelayFee) }) ); ``` Now the deployer account can upload files to the bucket on Greenfield. --- ## Contract Entrypoint > Source: https://docs.bnbchain.org/bnb-greenfield/for-developers/cross-chain-integration/contract-list/ # Contract Entrypoint Greenfield is based on a cross-chain programming model. It allows for the manipulation of data models on Greenfield via smart contracts on BSC or opBNB. These data models include objects, buckets, file permissions, and more. Below are the contract addresses deployed on various networks. ## BSC Mainnet DeployCommitId: c8e6a293b628f9063918ba8cd9c00ca41ded18db | contract name | address | |--------------------|--------------------------------------------| | GovHub | 0x1c9766EbcA1f38A06A04947129B394bF7FEc4599 | | CrossChain | 0x77e719b714be09F70D484AB81F70D02B0E182f7d | | TokenHub | 0xeA97dF87E6c7F68C9f95A69dA79E19B834823F25 | | LightClient | 0x433bB48Bd86c089375e53b2E2873A9C4bC0e986B | | RelayerHub | 0x31C477F05CE58bB81A9FB4b8c00560f1cBe185d1 | | BucketHub | 0xE909754263572F71bc6aFAc837646A93f5818573 | | ObjectHub | 0x634eB9c438b8378bbdd8D0e10970Ec88db0b4d0f | | GroupHub | 0xDd9af4573D64324125fCa5Ce13407be79331B7F7 | | BucketERC721Token | 0xC92d1d4b64Aebe28042206656b9E70E571A0E5eF | | ObjectERC721Token | 0x4B92705a60d69f7A96aaDB8faa892526eB71adb7 | | GroupERC721Token | 0x943FAC6CEBE6e45CE59bA911E5B6447c1a991450 | | MemberERC1155Token | 0xAb73f243Be4d0fC5644c822351eC77e85DC2B5Ea | | PermissionHub | 0xe1776006dBE9B60d9eA38C0dDb80b41f2657acE8 | | PermissionToken | 0xE8d6aC02dB463c1463116c72A6164462B0660dEc | | MultiMessage | 0x26204702935e2D617EE75B795152B9623a7d9809 | | GreenfieldExecutor | 0xFa39D9111D927836b14D071d43e0aAD9cE83bBBf | Extra: | contract name | address | |---------------|--------------------------------------------| | Deployer | 0x4763c12b21a548BCbD22a682fb15930565e27C43 | | ProxyAdmin | 0xf9010DC773eE3961418C96dc67Fc5DcCB3EA2C08 | For more details, you can refer to [Greenfield Contracts Mainnet Deployment](https://github.com/bnb-chain/greenfield-contracts/blob/master/deployment/56-deployment.json). ## BSC Testnet DeployCommitId: 20cc1f5784a621438114847753cda289f3ed76fa | contract name | address | |--------------------|--------------------------------------------| | GovHub | 0xC8951B5DD89015DcD0606A63B23C8A67ae316302 | | CrossChain | 0xa5B2c9194131A4E0BFaCbF9E5D6722c873159cb7 | | TokenHub | 0xED8e5C546F84442219A5a987EE1D820698528E04 | | LightClient | 0xa9249cefF9cBc9BAC0D9167b79123b6C7413F50a | | RelayerHub | 0x91cA83d95c8454277d1C297F78082B589e6E4Ea3 | | BucketHub | 0x5BB17A87D03620b313C39C24029C94cB5714814A | | ObjectHub | 0x1b059D8481dEe299713F18601fB539D066553e39 | | GroupHub | 0x50B3BF0d95a8dbA57B58C82dFDB5ff6747Cc1a9E | | BucketERC721Token | 0xF6CB188D3346de442b171d015202e605B0697A2a | | ObjectERC721Token | 0xc6a7192937961622D27956F412c4ce242F159311 | | GroupERC721Token | 0x7fC61D6FCA8D6Ea811637bA58eaf6aB17d50c4d1 | | MemberERC1155Token | 0x43bdF3d63e6318A2831FE1116cBA69afd0F05267 | | PermissionHub | 0x25E1eeDb5CaBf288210B132321FBB2d90b4174ad | | PermissionToken | 0xEBda3C285f79bEAF34416732F1F8Fa1e6B4B9dF7 | | MultiMessage | 0x54be643072eB8cF38Ac0c57Abc72b9c0368C8699 | | GreenfieldExecutor | 0x3E3180883308e8B4946C9a485F8d91F8b15dC48e | Extra: | contract name | address | |---------------|--------------------------------------------| | Deployer | 0x79aC4Ce73Cf5c4896a311CD39d2EB47E604D18E3 | | ProxyAdmin | 0xdD1c0a54a9EDEa8d0821AEB5BE54c51B79fa4c2e | For more details, you can refer to [Greenfield Contracts Testnet Deployment](https://github.com/bnb-chain/greenfield-contracts/blob/master/deployment/97-deployment.json). ## opBNB Testnet DeployCommitId: 6857ebfd2fd157c776cb8fc5f3dfb42696efeed2 | contract name | address | |--------------------|--------------------------------------------| | GovHub | 0x64cB82CF53BE02fF56a3D5527beEF7302E740911 | | CrossChain | 0xF0Bcf6E4F72bCB33b944275dd5c9d4540a259eB9 | | TokenHub | 0x59614C9e9B5Df6dF4dc9e457cc7F3a67D796d3b2 | | LightClient | 0xc50791892F6528E42A58DD07869726079C71F3f2 | | RelayerHub | 0x59ACcF658CC4589C3C41720fd48e869B97A748a1 | | BucketHub | 0xCAB5728B7cc21D0056E237D371b28efEEBFd8C2d | | ObjectHub | 0xb23002c5C3DCe3312e190d9D186C4aB29F7cF26F | | GroupHub | 0xe53725ac14bD77fA4754fC5a09889135C2c7Bc25 | | BucketERC721Token | 0xCacc33C05ad335c929e62D87BB96D5c5E5A19641 | | ObjectERC721Token | 0xb3e4d757b36A76fd968C97ed922Bd77AB2c72f62 | | GroupERC721Token | 0x8C74F8e6cD4DCb307d344F358683594A68d66CD9 | | PermissionHub | 0x089e97333da0B4260131068b7492D10fbEeC67BC | | PermissionToken | 0x72705569ed3CC26dEC421f542191B8ac7F62c3e7 | | MultiMessage | 0xc461eCE1922978d0336B03942cE70aCef4C5D09C | | GreenfieldExecutor | 0x4bF975A172793FbcFff30Ffe5b3141A5C5aeBE52 | Extra: | contract name | address | |---------------|--------------------------------------------| | Deployer | 0x84b3418faA3be4Bed168E2D00C7696b21008DcfD | | ProxyAdmin | 0x9d067d0D30CA19bB24551c9b654B8b9BB83c8634 | For more details, you can refer to [Greenfield Contracts Testnet Deployment](https://github.com/bnb-chain/greenfield-contracts/blob/master/deployment/5611-deployment.json). ## opBNB Mainnet DeployCommitId: 6857ebfd2fd157c776cb8fc5f3dfb42696efeed2 | contract name | address | |--------------------|--------------------------------------------| | GovHub | 0xCc63407862619bc65e5E09aFe521C6078C7fa730 | | CrossChain | 0x7E376AEFAF05E20e3eB5Ee5c08fE1B9832b175cE | | TokenHub | 0x723987D45BA424D562b087eE032b8C27F2E7b689 | | LightClient | 0xf51ba131716776685A805E8E4Ecc95be2f923B93 | | RelayerHub | 0xEd873b460C53D22f0FF3fc511854d9b8b16C4aE2 | | BucketHub | 0xDbf8aEcB0F697A5c71baA0C1470Ba8D7f0395018 | | ObjectHub | 0x8FcE352C1971cEa4c8b7b450C84780530713AcCd | | GroupHub | 0x2968a07d24699F0Ffe1e17eCaebeF6BB50BCed68 | | BucketERC721Token | 0x18C5f966795BC105B7F1bDf3313A540a0D62c22b | | ObjectERC721Token | 0x9342750477676b257Cf28878320815dF94B78182 | | GroupERC721Token | 0x488e054cc55Ba7a97e32B73122630364d4ffc050 | | MemberERC1155Token | 0x9841F55651acd38019B8B895083F7B5f9933Ca44 | | PermissionHub | 0x979876507F1395E5D391F9Dbef68468a22162B8D | | PermissionToken | 0xb8AE22AA0B0F125B74D385261b26282a44224aCc | | MultiMessage | 0x1aA380808eCef9BA5550fadaa97f2fD682B7f03A | | GreenfieldExecutor | 0xdFc5DC31bfbf992C19C171db273A028736322Ec4 | Extra: | contract name | address | |---------------|--------------------------------------------| | Deployer | 0xC6AA4CE979fbd263B8B32b9A162cA68F44D723a3 | | ProxyAdmin | 0xD2e5D66A683d2dd67e8C9aAFb317Db96acfc3F00 | For more details, you can refer to [Greenfield Contracts Mainnet Deployment](https://github.com/bnb-chain/greenfield-contracts/blob/master/deployment/204-deployment.json). --- ## Cross Chain FAQ > Source: https://docs.bnbchain.org/bnb-greenfield/for-developers/cross-chain-integration/mirroring-faqs/ # Cross Chain Program FAQ ### What are the advantages of mirroring? By transferring control over objects to the smart contract on BSC and allowing on-chain management, object mirroring enables greater flexibility and control over decentralized storage on BNB Greenfield to all dApps on BSC. It leverages the capabilities of the BSC and its smart contract functionality to provide enhanced functionality and interoperability between the two platforms. ### How mirroring is actually implemented on BSC? Mirroring on BSC allows for the replication of resources from the Greenfield Blockchain to BSC as non-fungible tokens (NFTs). These resources include buckets, objects, and groups, which are represented as NFTs conforming to the ERC-721 standard. Additionally, the members within a group can be mirrored as ERC-1155 tokens, representing permissions. Once mirrored on BSC, these resources can be managed directly by smart contracts on the BSC network. Any operations performed on BSC will impact the storage format, access permissions, and other aspects of the data on Greenfield, ensuring that changes made on BSC are reflected on Greenfield. Currently, the mirrored NFTs are not transferable, but the ability to transfer them will be introduced in the future. ### Are objects mirrored by default over to BSC? Mirroring objects from BNB Greenfield to BSC is not done automatically with the creation of the object. Users have to manually trigger the mirroring process for selected objects, either at the bucket or object level, as it requires transaction gas. This allows users to have control over which objects are mirrored while being aware of the associated costs. ### How long the changes are propagated from mirrored BSC objects to actual change on BNB Greenfield? The changes made to mirrored objects on BSC are propagated to BNB Greenfield once the corresponding transactions are finalized on both blockchains. BSC has a block finality of 3 seconds, while BNB Greenfield has a block finality of 2 seconds. As a result, the changes should be reflected within a maximum block finality of 3 seconds, which is the longer of the two block finality times. ### If the object is renamed, does the mirroring break and need to be “remirrored”? Mirroring in BNB Greenfield is based on the unique object ID and is not influenced by changes to object metadata, including its name. Even if an object is renamed, the mirroring process remains intact, as it is unaffected by such metadata modifications. ### Can the mirrored object be migrated between storage providers? The mirroring process in BNB Greenfield allows for object migration between storage providers because the object's data and metadata always reside on BNB Greenfield. As the data is not copied over to BSC, the mirroring remains unaffected. This means that migrating the actual content from one storage provider to another does not impact the mirroring process. --- ## Overview > Source: https://docs.bnbchain.org/bnb-greenfield/for-developers/data-archive/data-archive-layer/ # What Is Data Archive Layer? Modular blockchains divide the core functions of a classic blockchain into distinct specialized layers. Data availability layer is the essential component that ensures that transaction data included in each produced block is accessible to every node in the network. This layer essentially maintains the integrity and trust of the blockchain, allowing everyone to independently verify the validity of transactions. The data availability layer guarantees access to newly created data, but it does not provide access to the entire historical data. For example, EIP4844 and Celestica will discard blob data older than 18 days. The data archive layer is an extension of the data availability layer, ensuring that all historical block data remains publicly accessible after being archived. --- ## Blob Hub > Source: https://docs.bnbchain.org/bnb-greenfield/for-developers/data-archive/blob-hub/ # Blob Hub: BNB Greenfield as Data Archive Layer for EVM L1 Chains The Greenfield community has recently launched "BlobHub," a data archive layer designed for all layer 2 blockchains and Dapps which leverages EIP4844 blobs as data availability layer. All historical blobs can be persisted into Greenfield, and users can easily access these blobs whenever they want to query them. BlobHub not only serves Ethereum but also other blockchains that enable EIP4844. While each blob can be saved as an object in Greenfield, doing so individually would not be cost-effective. Thanks to the [bundle service](https://docs.nodereal.io/docs/greenfield-bundle-service?ref=bnbchain.ghost.io), which aggregates small files into one bundle for storage in Greenfield, this service can gather blobs from a wide range of blocks, validate their correctness, and upload them to Greenfield efficiently. Note: Greenfield will charge a fee for both storing and reading objects from the bucket owner. If there is not enough balance in the bucket payment account, users will be unable to query data until the quota is refilled. # How Does Blob Hub Work The Blob Hub primarily consists of two components: the blob-syncer and the api-server. To sync blobs to Greenfield, the blob-syncer service continuously fetches blobs from Ethereum and other blockchains and persists them in Greenfield. The api-server handles historical blob query requests from users. The bundle-service can aggregate blobs together, validate their correctness, and upload them to Greenfield efficiently. The syncing process ensures that no blob is missing and each blob synced to Greenfield is consistent. This is achieved by running a post-verification process that scans all uploaded blobs again, conducts integrity checks against data already stored in Greenfield, and detects any missing data. Duplicate uploads are prevented by key naming constraints in the Bundle service and Greenfield. # Who Needs to Access the Blob Hub? ## Layer 2 Node Layer 2 nodes that need to sync from the genesis block require access to historical block data via the Blob Hub. By leveraging Greenfield's robust infrastructure, they can rest assured that the integrity and availability of the stored data remain intact. ## Analytical Platform For on-chain data analytical builders, the blob hub service offers an alternative to centralized RPC service providers. By relying on a decentralized source, these builders gain access to a wealth of historical blob data without being tethered to centralized entities. # Query Blobs from Blob Hub Blob hub released its support to Ethereum and BSC now, it is going to support as many EVM chains as possible. The API is 100% compatible with the Beacon Chain and BSC API spec. Developers can get the supported [network and endpoints](../network-endpoint/endpoints.md#blob-hub) in the doc. For more details about the API spec, please refer to [BlobHub API](https://github.com/bnb-chain/blob-hub/?tab=readme-ov-file#blob-hub-api) # Try It Out By adopting this innovative solution, stakeholders can ensure the integrity, accessibility, and longevity of blockchain data, thereby supporting a more resilient and transparent digital ecosystem. Don't miss the opportunity to revolutionize your data handling processes—join the Greenfield community today and set a new standard for blockchain data reliability and security. --- ## Block HUb > Source: https://docs.bnbchain.org/bnb-greenfield/for-developers/data-archive/block-hub/ # BlockHub BlockHub offers a lightweight, trustless, and decentralized method for accessing blockchain data. It provides a user experience that is fully consistent with the original network's RPC and P2P access, eliminating the need for users to run full nodes or rely on centralized data providers to fetch block data. Don't want to trust a third party provider to provide the block data? Greenfield Blockhub is the answer. BlockHub is alive for BSC now. Much like Blob Hub, which uses the Bundle Service to archive blobs into a single bundle, BlockHub leverages the bundle service to combine a range of blocks into a single bundle. This approach optimizes storage usage, ensures cost-effectiveness, and maintains data integrity and accessibility. Note: Greenfield charges a fee for both storing and accessing objects. If the bucket owner's payment account lacks sufficient balance, users will be unable to query data until the quota is refilled. # How BlockHub Operates The BlockHub comprises three main components: - Block Indexer: This service continuously indexes blocks from the Blockchain and stores them in Greenfield. It ensures no block is missed and that each stored block is accurate. - API Server: This component handles user requests for historical block data, providing seamless access to the stored blocks. - Light Peers: It is a blockchain client that is backed by Greenfield storage but can serve in the P2P network. Refer to the [Light Peer](./light-peer.md) documentation for more details. The indexing process ensures data integrity by running a post-verification process. This process scans all uploaded blocks, conducts validation checks against data already stored in Greenfield, and detects any missing data. # Who Needs to Access the BlockHub? ## Node Operators Node operators requiring full sync from the genesis block need access to historical block data via the BlockHub. Leveraging Greenfield's robust infrastructure, they can trust the integrity and availability of the stored data. The Greenfield community has launched the `Greenfield Peer`, a data-seed solution for those who need to run BSC nodes in fullsync mode. For more details, check out this [page](./light-peer.md). ## Data Analysts and Researchers BlockHub offers a valuable resource for data analysts and researchers who need comprehensive access to historical block data. By leveraging BlockHub, they can collect reliable data for analysis, research, and development purposes. # Accessing Block Data with BlockHub BlockHub supports BSC now and its API is fully compatible with Ethereum API specifications, ensuring ease of integration for developers. Detailed information about supported networks and endpoints can be found in [network and endpoints](../network-endpoint/endpoints.md). For more details about the API spec, please refer to [BlockHub API](https://github.com/bnb-chain/greenfield-bsc-archiver/?tab=readme-ov-file#BlockHub-api) # Try It Out Adopting this innovative solution ensures the integrity, accessibility, and longevity of blockchain data, supporting a more resilient and transparent digital ecosystem. Join the Greenfield community today and set a new standard for blockchain data reliability and security. --- ## Light Peer > Source: https://docs.bnbchain.org/bnb-greenfield/for-developers/data-archive/light-peer/ # Light Peer With the launch of the [block-hub](./block-hub.md), BSC historical block data is now accessible on Greenfield. For those operating BSC nodes in fullsync mode, connecting to the Light peer is a beneficial choice. The Light peer fetches block data from Greenfield and supplies it to BSC nodes via the P2P network. ## How The Light Peer Works The diagram below illustrates the functionality of the Light peer. While the Light peer does not participate in other operations within the BSC network, it solely provides block data to BSC nodes. It does not persist any data on its own; instead, when it receives requests (`GetBodies` and `GetHeaders`) from other BSC nodes, it fetches a bundle of blocks (# of blocks determined by the Block Indexer) from Greenfield and caches them in memory. This ensures the Light peer delivers block data to BSC nodes efficiently. ## How to interact with Light Peer Utilizing the Light Peer is straightforward. Configure your BSC node to connect to the Light peer by adjusting the settings in your configuration file. Navigate to the P2P section of your BSC node configuration file and specify the enode info of the Light peer. ```toml # other configurations are omitted ... [Node.P2P] MaxPeers = 1 NoDiscovery = true TrustedNodes = [] StaticNodes=["enode://a2c586f41d2cc6dc7445e32922305e92b4de7daad718744d12bf105a79715606330535cffae6a0d60c61567ff772796d906fcb72b9cbb578f10de3221bb34015@13.115.90.65:30303?discport=0"] ... ``` --- ## Overview > Source: https://docs.bnbchain.org/bnb-greenfield/for-developers/tutorials/overview/ # Overview: Building Decentralized Applications (dApps) with BNB Greenfield In this section, we will introduce the two main methods for developing dApps on BNB Greenfield: using smart contracts deployed to BNB Smart Chain (BSC) and interacting directly with BNB Greenfield through our Software Development Kit (SDK) or Command Line Interface (CLI). ## Data Marketplace Demo Data marketplace is a data exchange platform where users can freely create, list, trade, and sell data assets, including digital publications, scientific experimental data, and specific domain data. ### Demo Link - Mainnet: `https://marketplace.greenfield-sp.bnbchain.org/index.html` - Testnet: `https://marketplace.greenfield-sp.bnbchain.org/bsc-testnet.html` ### Source Code - Frontend: `https://github.com/bnb-chain/greenfield-data-marketplace-frontend` - Smart Contracts: `https://github.com/bnb-chain/greenfield-data-marketplace-contracts` ## Developing with smart contracts on BSC One of the primary methods for building dApps with BNB Greenfield is by deploying smart contracts to the BSC. Smart contracts are self-executing programs that facilitate and enforce the execution of agreements without the need for intermediaries. In this section, we will guide you through the process of creating, deploying, and interacting with smart contracts on BSC using popular development frameworks like Solidity and Truffle. You can find detailed tutorials and examples for developing dApps using smart contracts in the [Building Smart Contract dApps](app/overview.md) section. ## Interacting with BNB Greenfield through SDK and CLI BNB Greenfield offers two native application options for interacting with the platform without involving the development of smart contracts: ### Software Development Kit (SDK) The Software Development Kit (SDK) is a powerful set of tools, libraries, and APIs that enable seamless integration with BNB Greenfield's decentralized storage system. The SDK allows you to build dApps using only the SDK functionalities, without the need to develop smart contracts. With the SDK, you can store and retrieve data, manage access controls, and handle encryption to ensure the privacy and security of your dApp's data. ### Command Line Interface (CLI) The Command Line Interface (CLI) is another native application provided by BNB Greenfield, allowing you to interact with the platform directly from the terminal. The CLI provides various commands to perform essential tasks efficiently, such as uploading files, managing data permissions, and monitoring storage usage. As with the SDK, using the CLI does not involve the development of smart contracts. In the following sections, we will delve deeper into each native application, providing step-by-step guides, code snippets, and best practices to empower you to create powerful and innovative dApps without the need for smart contract development. You can find more information and detailed instructions in the [Building Native dApps](access-control/cmd-access-control.md) section. --- ## Basic File Management with CLI > Source: https://docs.bnbchain.org/bnb-greenfield/for-developers/tutorials/file-management-overview/ # Introduction to file management with CLI ## Introduction Backing up files is an essential practice for any development process. The benefits initially might not seem straightforward, but backups provide a safety net for disaster recovery, ensuring that data can be restored in the event of hardware failures, accidental deletions, or natural disasters. Backups often encompass local changes and experiments outside of the repository, ensuring that valuable work is not lost and can be integrated into the main codebase. Furthermore, repositories may not effectively handle non-code files and operational documentation, making backups crucial for their preservation. By providing redundancy and data integrity, backups reduce the risk of relying solely on a single repository. They also facilitate long-term archiving, ensuring access to historical data even if repository policies change or there is a switch to a different provider. Traditional cloud storage services, while convenient, are centralized and often have clauses in their terms and conditions that allow them to share your data with third parties and government agencies. This is where BNB Greenfield, a new decentralized storage on BNB Chain, comes in as a more secure and private alternative for backing up your files. In this tutorial, we will guide you through the process of setting up your environment, installing the necessary tools, and effectively backing up your files to BNB Greenfield, leveraging the benefits of decentralized storage while ensuring data security and ownership. We will also cover how to interact with the CLI tool, choose storage providers, manage your account balance, and manage buckets and uploaded files. ## Setting Up the Environment ### Installation [Greenfield Command](https://github.com/bnb-chain/greenfield-cmd) is a powerful command line to interact with Greenfield. To begin, you will need to install the BNB Greenfield command line tool follow the instruction from CLI github page. When running commands that interact with the greenfield, if there is no config/config.toml file under the path and the commands runs without "--config" flag, the tool will generate the config/config.toml file automatically which is consistent with the network configuration under the path. Config file example will set up the necessary RPC address and chain id: === "Mainnet" ``` rpcAddr = "https://greenfield-chain.bnbchain.org:443" chainId = "greenfield_1017-1" ``` === "Testnet" ``` rpcAddr = "https://gnfd-testnet-fullnode-tendermint-us.bnbchain.org:443" chainId = "greenfield_5600-1" ``` ### Impport Account and Generating Keystore To set up your identity on the local machine and generate a keystore file, you will need to create the private file which will hold the identity private key. You can export your private key from MetaMask and write it into a local file as plaintext (You can select "Account Details" from the dropdown menu of MetaMask. Click on the "Export Private Key" button at the bottom of the page. Once you have the files ready, run the following command "account import [keyfile]" : ``` // import key and generate a keystore file // key.txt indicates the private key file gnfd-cmd account import key.txt ``` The terminal will prompt user to enter the password information. Users can also specify the password file path by using the "--passwordfile". While the password doesn’t have any restriction on the length or complexity, it’s better to follow generally recommended principles. This command will create a keystore file and store it in the path "keystore/key.json" under the home directory of the system or the directory set by "-home" and will be picked up by the CLI for commands that require identity and payment. After generating the keystore file, make sure to delete the key.txt file with the private key inside. ## Interacting with BNB Greenfield BNB Greenfield is built on a distributed architecture where storage providers play a crucial role. The network consists of multiple storage providers that offer their resources to store and retrieve data from users. When using BNB Greenfield, users have the flexibility to choose which storage providers to utilize based on several factors, including price, terms and conditions, and network performance. When selecting storage providers, users can query the decentralized storage network through the CLI tool to obtain information about available providers. The list of providers will include their operator addresses and corresponding endpoints. Users can then analyze the providers based on the aforementioned factors and choose the ones that best align with their requirements. For the advanced use cases, users can diversify their storage across multiple providers to enhance redundancy and mitigate the risk of data loss. This approach distributes data among different providers, ensuring that even if one provider experiences issues, the data remains accessible from other providers. By carefully selecting storage providers based on price, terms and conditions, and network performance, users can optimize their decentralized storage experience and maintain control over their data while enjoying the benefits of enhanced security and privacy. ### Selecting Storage Providers To query the network and get a list of storage providers, execute: ``` ./gnfd-cmd sp ls ``` The result should display a list of storage providers. For mainnet, there are several active storage providers, which can be used for development purposes. ``` name operator address endpoint status bnbchain 0x231099e40E1f98879C4126ef35D82FF006F24fF2 https://greenfield-sp.bnbchain.org:443 IN_SERVICE defibit 0x05b1d420DcAd3aB51EDDE809D90E6e47B8dC9880 https://greenfield-sp.defibit.io:443 IN_SERVICE ninicoin 0x2901FDdEF924f077Ec6811A4a6a1CB0F13858e8f https://greenfield-sp.ninicoin.io:443 IN_SERVICE nariox 0x88051F12AEaEC7d50058Fc20b275b388e15e2580 https://greenfield-sp.nariox.org:443 IN_SERVICE lumibot 0x3131865C8B61Bcb045ed756FBe50862fc23aB873 https://greenfield-sp.lumibot.org:443 IN_SERVICE voltbot 0x6651ED78A4058d8A93CA4979b7AD516D1C9010ac https://greenfield-sp.voltbot.io:443 IN_SERVICE nodereal 0x03c0799AD70d19e723359E036a83E8f44f4B8Ba7 https://greenfield-sp.nodereal.io:443 IN_SERVICE ``` The price for each storage provider can be checked using the operator address, for example: ``` ./gnfd-cmd sp get-price 0x231099e40E1f98879C4126ef35D82FF006F24fF2 ``` The response will retrieve the price for reading the data, as well as for storing the data per second. ``` get bucket read quota price: 0.1469890427 wei/byte get bucket storage price: 0.02183945725 wei/byte get bucket free quota: 1073741824 ``` To deduce the price for gigabytes (GB) per month from the metric of data usage in wei/byte, one needs to multiply the result by 0.002783138807808, as there are 1,073,741,824 bytes in 1 GB, 2,592,000 seconds in a month (30 days * 24 hours * 60 minutes * 60 seconds), and 10^18 wei in 1 BNB. The result will be the price for storing or transferring data in gigabytes per month, expressed in BNB. This calculation takes into account the rate of data usage and the duration of a month. Following the returned rate of wei/byte/sec, the converted amounts are: ``` get bucket read quota price: 0.00041 BNB/GB/month get bucket storage price: 0.00006 BNB/GB/month ``` Keep in mind that the pricing model and calculations may vary depending on the specific storage provider you are using. Always refer to the documentation or provider's information for accurate and up-to-date pricing details. ### Account Management While BNB Smart Chain (BSC) and BNB Greenfield define their accounts in the same format, it's important to understand that they are two separate blockchains with distinct ledgers. As a result, users need to manage their balances separately on both BSC and BNB Greenfield blockchains. To transfer test BNB from the BSC to BNB Greenfield, users can utilize the [dCellar](https://dcellar.io/) application. By using the dCellar application, users can initiate the transfer process from their BSC address to their BNB Greenfield address. For testnet, users can acquire test BNB tokens for testing purposes by using a test faucet provided by BNB Greenfield which can be accessed at [https://gnfd-bsc-faucet.bnbchain.org/](https://gnfd-bsc-faucet.bnbchain.org/). By visiting the faucet website, users can request a certain amount of test BNB tokens to be sent to their BSC testnet address. The balance can be checked using the following command: ``` ./gnfd-cmd bank balance --address 0x14cfe3777565d942f7a3e1d1dcffd7945170c8fe ``` And the result will be the current balance: ``` balance: 10001464255952380934 weiBNB ``` ### Object Operations In BNB Greenfield objects and buckets are key components. Buckets are containers used to organize and manage data, while objects are the actual files stored within those buckets. Buckets serve as top-level storage units with unique names, and objects have unique identifiers within their respective buckets. Users can perform operations on objects, such as uploading, downloading, and deleting, while applying permissions and access controls at the bucket and object level. This structure allows for efficient storage, organization, and retrieval of data in a decentralized storage network. To create a bucket one need to call the following storage make-bucket command with the desired bucket name. ``` ./gnfd-cmd bucket create gnfd://bucket123123123 ``` The operation will automatically choose a storage provider and submit a transaction to BNB Greenfield blockchain to write the associated metadata. Alternatively you can provide storage provider address, that is operator-address, if a specific provider should be used. The result should look something similar to the following: ``` choose primary sp: https://greenfield-sp.bnbchain.org:443 create bucket bucket123123123 succ, txn hash: 0x6c89316c5912cda8b69eac6e96aa644d374c39c635e07fae4297e03496e7726a ``` As you can see, the result returns a transaction hash, which one can inspect using the block scanner, e.g. [https://greenfieldscan.com](https://greenfieldscan.com/). Going to [https://greenfieldscan.com/tx/0x6c89316c5912cda8b69eac6e96aa644d374c39c635e07fae4297e03496e7726a](https://greenfieldscan.com/tx/0x6c89316c5912cda8b69eac6e96aa644d374c39c635e07fae4297e03496e7726a), will show all the details of the transaction. Notice that we in the details we can see the bucket owner details, moi; primary storage provider address, and the payment address. Since we haven’t created a separate payment account, our default account will serve as the payment account as well. With regards to the storage provider address, if you remember, it was picked for us automatically as [https://greenfield-sp.bnbchain.org:443](https://greenfieldscan.com/account/0x231099e40E1f98879C4126ef35D82FF006F24fF2). And from Selecting Storage Providers section we can see that its address is indeed 0x231099e40E1f98879C4126ef35D82FF006F24fF2. Lastly, it’s time to upload a file, but before we upload anything, let’s create one with a sample text using the echo command as follows: ``` echo 'Random sample text' > test4.txt ``` Finally to upload the file to our newly created bucket bucket123123123, one needs to execute the following command: ``` ./gnfd-cmd object put --contentType "text/xml" --visibility private ./test4.txt gnfd://bucket123123123/test4.txt ``` Notice that we’ve provided the visibility flag and made the file private. The successful result should be similar to the following: ``` create object test4.txt on chain finish, txn Hash: 0x5a885b7da8e8eb6921c84540d29b385b2dcee1f5ebdb4bb6c9219cf82e6ca80d put object test4.txt successfully ``` Similarly, going to [https://greenfieldscan.com/tx/0x5a885b7da8e8eb6921c84540d29b385b2dcee1f5ebdb4bb6c9219cf82e6ca80d](https://greenfieldscan.com/tx/0x5a885b7da8e8eb6921c84540d29b385b2dcee1f5ebdb4bb6c9219cf82e6ca80d) will show the details of the file upload. Here, observe the transaction payload and scroll to the “visibility” attribute, which confirms the privacy status. ``` {"key":"visibility" "value":"\"VISIBILITY_TYPE_PRIVATE\"" } ``` After successfully uploading the file, let’s verify the content of the file and compare it to the one we’ve uploaded - they should be identical. ``` ./gnfd-cmd object get gnfd://bucket123123123/test4.txt ./test4-copy.txt ``` The operation will download the file and output the length of the file, as follows: ``` download object test4.txt successfully, the file path is ./test4-copy.txt, content length:19 ``` If you know the sp endpoint that object belongs to, you can optimize the download speed by add --spEndpoint flag to download cmd, such as: ``` ./gnfd-cmd object get --spEndpoint https://gnfd-testnet-sp3.nodereal.io gnfd://bucket123123123/test4.txt ./test4-copy.txt ``` To validate the integrity of the file, we can compare its content to the originally uploaded one. Empty output confirms there are no differences. ``` diff test4.txt test4-copy.txt ``` ### Upload multiple objects `gnfd-cmd` also support uploads all files from a folder recursively. Let's say that there is a folder called `website` where you store all the files for your website. ```shell $ ls index.html plato.jpeg styles.css ``` To upload all these files into your bucket, you can run the following commands: ``` gnfd-cmd object put --recursive ./website gnfd://ylatitsb ``` Please note that `--recursive` is used to put all files or objects under the specified directory or prefix in a recursive way. The default value is false The successful result should be similar to the following: ``` ================================================ Your batch upload is submitted as a task, task ID is sdgerdf-sfdgasg-1237hedfg You can check your task status and progress by using cmd as below: - List all your tasks: ./gnfd-cmd task ls - Check status: ./gnfd-cmd task status --task.id taskID - Retry (in case this process is killed accidentally): ./gnfd-cmd task retry --task.id taskID - Delete task: ... >>================================================ Upload Task building sealed index.html ``` #### Task Operations When object put --recursive is used, tasks are automatically created You can view/retry/delete tasks with `gnfd-cmd task` Using the `gnfd-cmd task` requires a new session to be opened while the `gfnd-cmd object put --recursive` is in progress. If the current session is interrupted, the put object is interrupted ``` ./build/gnfd-cmd task status --taskId abe92a9a-1aa0-45be-9e0b-4cd400c38a06 ``` Viewing Task status taskId will be generated after the `gfnd-cmd object put --recursive` ``` Folder: ./website Status: created sealed index.html wait_for_upload styles.css ``` ``` ./build/gnfd-cmd task retry --taskId abe92a9a-1aa0-45be-9e0b-4cd400c38a06 ``` `gfnd-cmd object put --recursive` will be used to retry after a failure or interruption ``` task: abe92a9a-1aa0-45be-9e0b-4cd400c38a06 folder name: ./website retrying... sealed index.html ``` ``` ./build/gnfd-cmd task delete --taskId abe92a9a-1aa0-45be-9e0b-4cd400c38a06 ``` You can delete a task by deleting it You can go to [GreenfieldScan](https://testnet.greenfieldscan.com) to view the change of your bucket. ## Conclusion Overall, backups during software development offer peace of mind, efficient recovery, and safeguarding of the project's integrity. They minimize downtime and prevent significant setbacks. After gaining familiarity with the command line tool and BNB Greenfield through this tutorial, the next step is to explore and experiment with creating files, buckets, and permission groups. By creating multiple files and organizing them into buckets, users can gain hands-on experience with the storage capabilities of BNB Greenfield. It is highly recommended for users to engage in hands-on exploration by trying out different wallets and understanding the basic operations and permissioning mechanisms. This will provide a deeper understanding of how BNB Greenfield functions and how to effectively manage and secure data within the decentralized storage system. This practical experience will pave the way for comprehending more advanced topics discussed in future articles, such as programmability and BNB Greenfield's innovative concept of flow-based billing and asset monetization. By exploring the diverse functionalities and experimenting with different configurations, users can unlock the full potential of BNB Greenfield and unlock its new data economy concepts. --- ## How to transition from S3 to Greenfield > Source: https://docs.bnbchain.org/bnb-greenfield/for-developers/tutorials/transitioning-from-s3-to-greenfield/ # How to transition from S3 to Greenfield ## Introduction Greenfield is a blockchain-based decentralized storage solution designed to enhance the decentralization of data ownership and management, allowing users to manage their own data and assets. This platform promotes the development of decentralized applications (dApps) by offering on-chain data permission management and APIs similar to those of Web2, enhancing data security and management capabilities through the introduction of Storage Providers (SPs), which are responsible for providing authentication and storage services. In terms of permission management, SPs offer a range of authentication services. Unlike AWS S3, which control user permissions through AWS Keys and AWS Secrets, SPs in Greenfield use private keys for permission control. This means that on the Greenfield platform, permission authentication is reliant on blockchain technology, ensuring security and decentralization, while also extending blockchain functionalities, including permission authentication and data storage capabilities. In Greenfield's design, users have the freedom to select any SP as their Primary SP, along with additional SPs as Secondary SPs, ensuring both performance and reliability in object storage. Primary SPs are primarily responsible for storing all data segments of an object and directly responding to user read or download requests, whereas Secondary SPs store data blocks generated by Erasure Coding (EC) technology, helping to improve data availability. Compared to AWS S3, Greenfield's distributed storage structure not only enhances data durability and recoverability but also ensures data integrity and verifiability using blockchain technology. Through this approach, Greenfield is committed to promoting a new data economy and dApp model construction, improving the transparency and efficiency of data management, and realizing data decentralization management and ownership proof through blockchain technology. **We will now showcase on the SDK through Greenfield and AWS S3.** ## Init SDK client **S3** ```go const ( AWSKey = "mock-aws-key" AWSSecret = "mock-aws-secret" Region = "us-east-1" ) cfg, err := config.LoadDefaultConfig(context.TODO(), config.WithRegion(Region), config.WithCredentialsProvider(credentials.NewStaticCredentialsProvider(AWSKey, AWSSecret, "")), ) handleErr(err, "LoadDefaultConfig") client := s3.NewFromConfig(cfg) ``` For AWS S3, the initialization uses the AWS Key and AWS Secret to create an AWS S3 client to allow user interaction. The `Region` specifies the region where the user's bucket is located. **Greenfield** ```go const ( RpcAddr = "https://gnfd-testnet-fullnode-tendermint-us.bnbchain.org:443" // Greenfield Testnet RPC Address ChainId = "greenfield_5600-1" // Greenfield Testnet Chain ID PrivateKey = "mock-private-key" ) client, primarySP, err := NewFromConfig(ChainId, RpcAddr, PrivateKey) handleErr(err, "NewFromConfig") ``` For Greenfield, the RPC Address and Chain ID are used to select the specific Greenfield network, with the example above being for the Testnet. Users need to interact using a private key exported from their wallet. > Greenfield Mainnet Chain ID: greenfield_1017-1 > > Greenfield Mainnet RPC > > https://greenfield-chain.bnbchain.org:443 > > https://greenfield-chain-ap.bnbchain.org:443 > > https://greenfield-chain-eu.bnbchain.org:443 > > https://greenfield-chain-us.bnbchain.org:443 ## Create bucket **S3** ```go const ( BucketName = "mock-bucket-name" ) _, err = client.CreateBucket(context.TODO(), &s3.CreateBucketInput{ Bucket: aws.String(BucketName), }) handleErr(err, "CreateBucket") ``` In AWS S3, the `CreateBucket` method is called with a configuration object specifying the bucket name. The operation is straightforward, reflecting S3's cloud storage focus, where the primary concern is the creation and management of storage containers in the cloud. **Greenfield** ```go const ( BucketName = "mock-bucket-name" ) _, err = client.CreateBucket(context.TODO(), BucketName, primarySP, types.CreateBucketOptions{}) handleErr(err, "CreateBucket") ``` For Greenfield, the `CreateBucket` method also requires a bucket name but includes additional parameters like `primarySP`, which is obtained during client initialization. The `primarySP` plays a crucial role in executing and storing corresponding bucket data, indicating a more complex interaction pattern likely due to the blockchain-based nature of Greenfield. ## List buckets **S3** ```go const ( BucketName = "mock-bucket-name" ) bucketsList, err := client.ListBuckets(context.TODO(), &s3.ListBucketsInput{}) handleErr(err, "ListBuckets") for _, bucket := range bucketsList.Buckets { fmt.Printf("* %s\n", aws.ToString(bucket.Name)) } ``` **Greenfield** ```go const ( BucketName = "mock-bucket-name" ) bucketsList, err := client.ListBuckets(context.TODO(), types.ListBucketsOptions{}) handleErr(err, "ListBuckets") for _, bucket := range bucketsList.Buckets { fmt.Printf("* %s\n", bucket.BucketInfo.BucketName) } ``` During the initialization of the client for both systems, user information is already obtained, allowing for the return of corresponding buckets through a `User` object. This process indicates that transitioning from AWS S3 to Greenfield can be achieved with minimal effort and cost. ## Delete bucket **S3** ```go const ( BucketName = "mock-bucket-name" ) _, err = client.DeleteBucket(context.TODO(), &s3.DeleteBucketInput{ Bucket: aws.String(BucketName), }) handleErr(err, "Delete Bucket") ``` **Greenfield** ```go const ( BucketName = "mock-bucket-name" ) _, err = cli.DeleteBucket(context.TODO(), BucketName, types.DeleteBucketOption{}) handleErr(err, "Delete Bucket") ``` The process of deleting a bucket in both AWS S3 and Greenfield is essentially identical, allowing users to easily delete a bucket by simply using its name. ## Create object **S3** ```go const ( BucketName = "mock-bucket-name" ObjectKey = "test-api.js" ) _, err = client.PutObject(context.TODO(), &s3.PutObjectInput{ Bucket: aws.String(BucketName), Key: aws.String(ObjectKey), Body: file, }) handleErr(err, "PutObject") ``` **Greenfield** ```go const ( BucketName = "mock-bucket-name" ObjectKey = "test-api.js" ) txnHash, err := cli.CreateObject(context.TODO(), BucketName, ObjectKey, file, types.CreateObjectOptions{}) handleErr(err, "CreateObject") err = cli.PutObject(context.TODO(), BucketName, ObjectKey, int64(fileInfo.Size()), file, types.PutObjectOptions{TxnHash: txnHash}) handleErr(err, "PutObject") ``` In the process of creating objects, there is a difference between Greenfield and S3. In Greenfield, it is necessary to first create the object before performing the put object operation. This is because Greenfield requires users to create metadata on the Greenfield blockchain before submitting object to the SP, in order to ensure the integrity of the object. ## List objects **S3** ```go const ( BucketName = "mock-bucket-name" ) objects, err := client.ListObjectsV2(context.TODO(), &s3.ListObjectsV2Input{ Bucket: aws.String(BucketName), }) handleErr(err, "ListObjectsV2") for _, item := range objects.Contents { fmt.Printf("* %s\n", aws.ToString(item.Key)) } ``` **Greenfield** ```go const ( BucketName = "mock-bucket-name" ) objects, err := cli.ListObjects(context.TODO(), BucketName, types.ListObjectsOptions{ }) handleErr(err, "ListObjects") for _, obj := range objects.Objects { log.Printf("* %s\n", obj.ObjectInfo.ObjectName) } ``` In both AWS S3 and Greenfield, retrieving all objects within a bucket can be easily accomplished by simply using the bucket's name. This functionality indicates a user-friendly approach to data management, allowing users to efficiently access and manage the contents of their storage without the need for intricate query parameters or complex configuration. ## Delete object **S3** ```go const ( BucketName = "mock-bucket-name" ObjectKey = "test-api.js" ) _, err = client.DeleteObject(context.TODO(), &s3.DeleteObjectInput{ Bucket: aws.String(BucketName), Key: aws.String(ObjectKey), }) handleErr(err, "Delete Object") ``` **Greenfield** ```go const ( BucketName = "mock-bucket-name" ObjectKey = "test-api.js" ) _, err = cli.DeleteObject(context.TODO(), BucketName, ObjectKey, types.DeleteObjectOption{}) handleErr(err, "Delete Object") ``` Deleting an object in both AWS S3 and Greenfield is fundamentally similar, enabling users to effortlessly remove an object by specifying both the bucket name and the object name. ## Get Object **S3** ```go const ( BucketName = "mock-bucket-name" ObjectKey = "test-api.js" ) resp, err := client.GetObject(context.TODO(), &s3.GetObjectInput{ Bucket: aws.String(BucketName), Key: aws.String(ObjectKey), }) handleErr(err, "GetObject") ``` **Greenfield** ```go const ( BucketName = "mock-bucket-name" ObjectKey = "test-api.js" ) resp, _, err := cli.GetObject(context.TODO(), BucketName, ObjectKey, types.GetObjectOptions{}) handleErr(err, "GetObject") ``` ## **Summary** AWS S3 and Greenfield offer streamlined data retrieval processes, with users specifying bucket and object names for efficient access. While AWS S3 relies on key-pair authentication and region specification for data locality and access efficiency, Greenfield adopts a blockchain-based approach, using private keys for authentication and RPC Addresses along with Chain IDs for network connectivity. Greenfield enhances service quality through regional RPC endpoints, allowing users to choose the most efficient connection based on their location. The structural similarity in SDKs for operations like bucket creation is notable, with Greenfield requiring an additional step to obtain a primarySP during client initialization. This minimal difference suggests a smooth transition for S3 users to Greenfield, highlighting the ease of adaptation due to familiar SDK code structures and metadata handling. Moreover, Greenfield introduces a two-step object management process, offering greater control over object lifecycle states than S3's more straightforward approach. Despite this, the core functionalities remain similar, ensuring that S3 users can quickly adapt to Greenfield's environment without significant hurdles. Overall, the transition from AWS S3 to Greenfield is facilitated by similar SDK coding practices and metadata management approaches, making it accessible for users familiar with S3 to migrate to Greenfield's blockchain-based storage solution with minimal learning curve. This compatibility underscores the potential for seamless adaptation, leveraging existing cloud storage knowledge while navigating the nuances of blockchain technology. ## Attached code ### Example of Greenfield Integration ```go package main import ( "bytes" "context" "fmt" "io" "log" "os" "time" "github.com/bnb-chain/greenfield-go-sdk/client" "github.com/bnb-chain/greenfield-go-sdk/types" ) // The config information is consistent with the testnet of greenfield // You need to set the privateKey, bucketName, objectName and groupName to make the basic examples work well const ( RpcAddr = "https://gnfd-testnet-fullnode-tendermint-us.bnbchain.org:443" ChainId = "greenfield_5600-1" PrivateKey = "mock-private-key" BucketName = "mock-bucket-name" ObjectKey = "api.js" UploadObjectKey = "test-api.js" DownloadPath = "/Users/Desktop/s3test/" UploadPath = "/Users/Desktop/s3test/" ) func main() { cli, primarySP, err := NewFromConfig(ChainId, RpcAddr, PrivateKey) handleErr(err, "NewFromConfig") // create bucket _, err = cli.CreateBucket(context.TODO(), BucketName, primarySP, types.CreateBucketOptions{}) handleErr(err, "CreateBucket") // list buckets bucketsList, err := cli.ListBuckets(context.TODO(), types.ListBucketsOptions { ShowRemovedBucket: false, }) handleErr(err, "ListBuckets") for _, bucket := range bucketsList.Buckets { fmt.Printf("* %s\n", bucket.BucketInfo.BucketName) } // create object file, err := os.Open(UploadPath + UploadObjectKey) handleErr(err, "PutObject") defer file.Close() fileInfo, err := file.Stat() handleErr(err, "Stat") // create object txnHash, err := cli.CreateObject(context.TODO(), BucketName, UploadObjectKey, file, types.CreateObjectOptions{}) handleErr(err, "CreateObject") var buf bytes.Buffer _, err = io.Copy(&buf, file) // put object err = cli.PutObject(context.TODO(), BucketName, UploadObjectKey, int64(fileInfo.Size()), file, types.PutObjectOptions{TxnHash: txnHash}) handleErr(err, "PutObject") // wait for object having been successfully uploaded time.Sleep(10 * time.Second) // list objects objects, err := cli.ListObjects(context.TODO(), BucketName, types.ListObjectsOptions { ShowRemovedObject: false, Delimiter: "", MaxKeys: 100, SPAddress: "", }) handleErr(err, "ListObjects") for _, obj := range objects.Objects { log.Printf("* %s\n", obj.ObjectInfo.ObjectName) } // get object reader, _, err := cli.GetObject(context.TODO(), BucketName, UploadObjectKey, types.GetObjectOptions{}) handleErr(err, "GetObject") outFile, err := os.Create(DownloadPath + ObjectKey) handleErr(err, "DownloadObject") defer outFile.Close() _, err = io.Copy(outFile, reader) handleErr(err, "DownloadObject") } func NewFromConfig(chainID, rpcAddress, privateKeyStr string) (client.IClient, string, error) { account, err := types.NewAccountFromPrivateKey("test", privateKeyStr) if err != nil { log.Fatalf("New account from private key error, %v", err) return nil, "", err } cli, err := client.New(chainID, rpcAddress, client.Option{DefaultAccount: account}) if err != nil { log.Fatalf("unable to new greenfield client, %v", err) return nil, "", err } ctx := context.Background() // get storage providers list spLists, err := cli.ListStorageProviders(ctx, true) if err != nil { log.Fatalf("fail to list in service sps") return nil, "", err } // choose the first sp to be the primary SP primarySP := spLists[0].GetOperatorAddress() return cli, primarySP, nil } func handleErr(err error, funcName string) { if err != nil { log.Fatalln("fail to " + funcName + ": " + err.Error()) } } ``` ### Example of S3 Integration ```go package main import ( "context" "fmt" "io" "log" "os" "time" "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/config" "github.com/aws/aws-sdk-go-v2/credentials" "github.com/aws/aws-sdk-go-v2/service/s3" ) const ( AWSKey = "mock-aws-key" AWSSecret = "mock-aws-secret" Region = "us-east-1" BucketName = "mock-bucket-name" ObjectKey = "mock-object-name" UploadObjectKey = "test-api.js" DownloadPath = "/Users/Desktop/s3test/" UploadPath = "/Users/Desktop/s3test/" ) func main() { // set up aws s3 config cfg, err := config.LoadDefaultConfig(context.TODO(), config.WithRegion(Region), config.WithCredentialsProvider(credentials.NewStaticCredentialsProvider(AWSKey, AWSSecret, "")), ) handleErr(err, "LoadDefaultConfig") client := s3.NewFromConfig(cfg) // create bucket _, err = client.CreateBucket(context.TODO(), &s3.CreateBucketInput { Bucket: aws.String(BucketName), }) handleErr(err, "CreateBucket") // list buckets by owner result, err := client.ListBuckets(context.TODO(), &s3.ListBucketsInput{}) handleErr(err, "ListBuckets") for _, bucket := range result.Buckets { fmt.Printf("* %s\n", aws.ToString(bucket.Name)) } // create object file, err := os.Open(UploadPath + UploadObjectKey) handleErr(err, "PutObject") defer file.Close() _, err = client.PutObject(context.TODO(), &s3.PutObjectInput { Bucket: aws.String(BucketName), Key: aws.String(UploadObjectKey), Body: file, }) handleErr(err, "PutObject") // wait for object having been successfully uploaded time.Sleep(10 * time.Second) objects, err := client.ListObjectsV2(context.TODO(), &s3.ListObjectsV2Input { Bucket: aws.String(BucketName), }) handleErr(err, "ListObjectsV2") for _, item := range objects.Contents { fmt.Printf("* %s\n", aws.ToString(item.Key)) } // download object resp, err := client.GetObject(context.TODO(), &s3.GetObjectInput { Bucket: aws.String(BucketName), Key: aws.String(UploadObjectKey), }) handleErr(err, "DownloadObject") defer resp.Body.Close() outFile, err := os.Create(DownloadPath + ObjectKey) handleErr(err, "DownloadObject") defer outFile.Close() _, err = io.Copy(outFile, resp.Body) handleErr(err, "DownloadObject") _, err = client.DeleteObject(context.TODO(), &s3.DeleteObjectInput { Bucket: aws.String(BucketName), Key: aws.String(ObjectKey), }) handleErr(err, "Delete Object") _, err = client.DeleteBucket(context.TODO(), &s3.DeleteBucketInput { Bucket: aws.String(BucketName), }) handleErr(err, "Delete Bucket") } func handleErr(err error, funcName string) { if err != nil { log.Fatalln("fail to " + funcName + ": " + err.Error()) } } ``` --- ## Hosting a Website on Greenfield > Source: https://docs.bnbchain.org/bnb-greenfield/for-developers/tutorials/hosting-websites-overview/ # Creating and uploading a website with CLI ## Introduction In today's era, having a website has become essential for individuals and businesses alike. With advancements in AI, tools like ChatGPT and Bard can help create a simple website or boilerplate with just a few sentences. This tutorial will guide you through the process of creating and uploading a website to BNB Greenfield, a decentralized storage on the BNB Chain. ## Creating a website A website typically consists of HTML pages, CSS stylesheets, and JavaScript scripts for enhanced interactivity. These files work together to create the visual layout, design, and functionality of the website. Go to the AI tool of your choice and type something like “Create a website about Plato's biography with images”. And ideally, after a few iterations, you’ll get to a decent-looking website. ## Deploying a website Deploying a website to a web hosting platform is crucial because it makes the website publicly accessible and ensures its availability to users. When a website is hosted on a cloud server it becomes accessible to anyone with an internet connection. Users can access the website by typing its URL or domain name into a web browser. In the case of BNB Greenfield, the decentralized network of storage providers contributes to increased availability by distributing the website's files across multiple nodes. Additionally, decentralized networks like BNB Greenfield provide data redundancy by storing multiple copies of the website's files on different nodes, reducing the risk of data loss. BNB Greenfield prioritizes security measures to protect websites and their data from unauthorized access, cyber threats, and data breaches. ### Creating a Bucket To start, create a separate bucket for your website on BNB Greenfield using the following command: ```bash ./gnfd-cmd bucket create --visibility=public-read gnfd://my-plato-website --primarySP 0x231099e40E1f98879C4126ef35D82FF006F24fF2 ``` The example return message is like the following: ``` make_bucket: my-plato-website transaction hash: E083FB2647D0A53640B63AD1DB8EFA0E1C5CC05454C0774E3DB2A4822E73D423 ``` You can verify the transaction in explorer [here](https://greenfieldscan.com/tx/E083FB2647D0A53640B63AD1DB8EFA0E1C5CC05454C0774E3DB2A4822E73D423). ### Uploading Supporting Files Next, upload the stylesheet and image files to your newly created bucket. Set the visibility flag as public-read to make the files accessible to everyone: ```bash ./gnfd-cmd object put --visibility=public-read ./plato.jpg gnfd://my-plato-website/plato.jpg ./gnfd-cmd object put --visibility=public-read ./styles.css gnfd://my-plato-website/styles.css ``` ### BNB Greenfield Url BNB Greenfield utilizes a specific URL format known as the BNB Greenfield Url to identify and access objects within its decentralized storage. The URL format follows the pattern: `gnfd://?[parameter]*`. Let's break down the components of this format: 1. "gnfd://" - This is the fixed leading identifier that indicates the URL is associated with BNB Greenfield. It is mandatory and serves as a marker for Greenfield URLs. 2. bucket_name - Refers to the name of the bucket where the object is stored. It is a mandatory component and helps identify the specific storage location within BNB Greenfield. 3. object_name - Represents the name of the object (e.g., file) within the bucket. It is also mandatory and allows for precise identification of the desired resource. 4. parameter - This component is optional and consists of a list of key-value pairs. Parameters provide additional information for the URI, enabling customization or specific functionality. Examples of parameters could include cache settings or other metadata. Additionally, BNB Greenfield allows Service Providers (SPs) to register multiple endpoints for accessing their services. For instance, an SP named "SP1" might request users to download objects via a URL like `https://greenfield.sp1.com/download`. The complete RESTful API for downloading an object from "SP1" would resemble: `https://greenfield.sp1.com/download/mybucket/myobject.jpg`, where "mybucket" is the bucket name and "myobject.jpg" is the specific object within that bucket. In the context of our website, the bucket was created under the SP2 service provider, and the serving endpoint for accessing the website's content is `https://gnfd-testnet-sp-2.bnbchain.org/`. This endpoint allows users to access the website's files, such as HTML, CSS, images, and more, stored within the designated bucket on BNB Greenfield. ### Updating the references Once the supporting files are uploaded, update the links in your HTML file to point to the correct URLs. Following the BNB Greenfield Url pattern, we need to update the URLs in our `index.html` file to ensure correct file retrieval. For example, if we had an image file named `plato.jpg` located in the "images" directory, previously the URL reference would be "images/plato.jpg". However, with BNB Greenfield's URL format, we need to modify it to include the serving endpoint and the specific bucket name. Instead of "images/plato.jpg", we would change it to `https://gnfd-testnet-sp-2.bnbchain.org/view/my-plato-website/images/plato.jpg`, where "my-plato-website" corresponds to the bucket name in which the file is stored. This updated URL ensures that the browser can retrieve the correct image file from BNB Greenfield. But things get better! Since the BNB Greenfield URL format remains identical for all files within the same bucket, we can simplify the URLs for files residing within the same bucket. In the case of the CSS file, we can reference it using a relative path without specifying the full URL. For example: ```html ``` Similarly, for the image file `plato.jpg`, we can use a relative path without the need to specify the full URL: ```html ``` By using relative paths, the browser will correctly fetch the CSS file and the image file from the same bucket within BNB Greenfield, eliminating the need to include the full path in these specific cases. ### Uploading HTML Files Upload the modified index.html file to your bucket using the following command: ```bash ./gnfd-cmd object put --visibility=public-read --contentType=text/html ./index.html gnfd://my-plato-website/index.html ``` Example output: ``` object index.html created on chain transaction hash: 20921F3C1DBE3F911217CE82BDC9DC2A745AF61912651A5F9D80F10989A8FC20 sealing... upload index.html to gnfd://my-plato-website/index.html ``` Now, let's eagerly click the link to view our brand new website at [https://gnfd-testnet-sp1.bnbchain.org/view/my-plato-website/index.html](https://gnfd-testnet-sp1.bnbchain.org/view/my-plato-website/index.html) and feel the anticipation building up. 🥁Drum beat... But, oh no! Something went awry. Instead of the website loading, the file started downloading automatically. Frustration sets in, and I embarked on a lengthy debugging journey, spending a good hour trying to figure out the issue. Finally, I discovered the culprit: we forgot to specify the content type for the files, making them unrecognizable and causing them to be downloaded instead of served. However, let's not forget that BNB Greenfield is an immutable storage. So to update the file, we must first delete it and then reupload it. To accomplish this, I used the power of the 'object delete' command: ```bash ./gnfd-cmd object rm gnfd://my-plato-website/index.html ``` Wait for the confirmation that the file was successfully deleted, accompanied by a transaction hash: 4B12BCF26525C1B661389529524DF14E23164D000FA47FB2E0D0BE26B131E04A. And reupload the html file, this time accompanied by the content-type flag: ```bash ./gnfd-cmd object put --visibility=public-read --contentType=text/html ./index.html gnfd://my-plato-website/index.html ``` 🥁🥁Drum beat intensifies... Oh, no! The website still looks horrendous, and worse yet, the image of Plato is nowhere to be found. Frustration turned into disappointment as we discovered that the browser was throwing an error due to an incorrect MIME type. It refused to apply the styles from [https://gnfd-testnet-sp-2.bnbchain.org/view/my-plato-website/styles.css](https://gnfd-testnet-sp-2.bnbchain.org/view/my-plato-website/styles.css) because the MIME type was set as 'text/plain', which is not a supported stylesheet MIME type when strict MIME checking is enabled. Fear not! The error looks familiar and we already know exactly what needed to be done. So swiftly deleting the problematic files and reuploading them correctly this time: ```bash ./gnfd-cmd object rm gnfd://my-plato-website/plato.jpg ./gnfd-cmd object rm gnfd://my-plato-website/styles.css ``` And then, with a determined spirit: ```bash ./gnfd-cmd object put --visibility=public-read --contentType=image/jpeg ./plato.jpg gnfd://my-plato-website/plato.jpg ./gnfd-cmd object put --visibility=public-read --contentType=text/css ./styles.css gnfd://my-plato-website/styles.css ``` 🥁🥁🥁Drum beat crescendos... And finally, we heard the triumphant sound of trumpets! However, as we gaze upon [the site](https://greenfield-sp.bnbchain.org/view/my-plato-website/index.html), we can't help but admit that it doesn't look particularly astonishing. It falls short of our grandest expectations. Yet, considering that we generated and uploaded it in just a matter of minutes, it's still a decent outcome given our investment of time and effort. The content and image look good though, it just needs more love with styling…but that’s a story for another tutorial. ## Conclusion Our journey with website development has been filled with ups and downs. We encountered challenges along the way, but with perseverance and a little debugging, we managed to deploy our website successfully. BNB Greenfield's URL format and immutable storage principles require to be mindful of content types and careful when updating files. Despite the minor setbacks, BNB Greenfield remains a valuable platform for deploying websites, offering increased availability, reliability, and quite easy command tools. Hope you enjoyed it and looking forward to see your websites on BNB Greenfield. --- ## Access Control Management with CLI > Source: https://docs.bnbchain.org/bnb-greenfield/for-developers/tutorials/access-control/cmd-access-control/ # Access Control Management with CLI ## Background In our last tutorial, we have guided you through the process of setting up your environment, installing the necessary tools, and effectively backing up your files to BNB Greenfield, leveraging the benefits of decentralized storage while ensuring data security and ownership. To dive furthur into advanced concepts of Greenfield, we will cover how to handle objects access control with the CLI tool, manage your groups and polocoes. ## Verifying the Environment Please refer to [this doc](../file-management-overview.md#installation) to make sure you have completed installation of `gnfd-cmd` and setting up your accounts. ## Query Bucket Info To query the bucket, execute: ```shell ./gnfd-cmd bucket head gnfd://website-bucket ``` You should be able to see ```shell latest bucket info: owner:"0x525482AB3922230e4D73079890dC905dCc3D37cd" bucket_name:"website-bucket" visibility:VISIBILITY_TYPE_PRIVATE id:"3101" create_at:2023-10-31 01:17:15 payment_address:"0x525482AB3922230e4D73079890dC905dCc3D37cd" global_virtual_group_family_id:40 ``` ## Access Control Management Workflow with Group To manage how users can access your files, you have to follow this process: 1. Set `Principle Address` which has the administrator role 2. Customize groups members 3. Customize access policy, which may depends on different circustances 4. Bind/unbind policy with group ### Group Operations The group commands is used to create group, update group members, delete group and query group info. To create a group one need to call the following storage `create group` command with the desired group name. ```shell // create group gnfd-cmd group create gnfd://website-group ``` The operation will submit a transaction to BNB Greenfield blockchain to write the associated metadata. The result should look something similar to the following: ```shell make_group: gnfd://website-group transaction hash: A1FD3A0E2A337716C344392B840DCC8E804553AF42504FBD6F4C46B9C5B8FAF9 group id: 712 ``` As you can see, the result returns a transaction hash, which one can inspect using the block scanner, e.g. [https://greenfieldscan.com](https://greenfieldscan.com/). Going to [https://testnet.greenfieldscan.com/tx/A1FD3A0E2A337716C344392B840DCC8E804553AF42504FBD6F4C46B9C5B8FAF9](https://testnet.greenfieldscan.com/tx/A1FD3A0E2A337716C344392B840DCC8E804553AF42504FBD6F4C46B9C5B8FAF9), will show all the details of the transaction. Add a new member to the group ```shell // update group member gnfd-cmd group update --addMembers 0x843e77D639b6C382e91ef489881963209cB238E5 gnfd://website-group ``` To verify the new member is indeed part of the group ```shell // head group member gnfd-cmd group head-member 0x843e77D639b6C382e91ef489881963209cB238E5 website-group ``` The result should look something similar to the following: ```shell the user 0x843e77D639b6C382e91ef489881963209cB238E5 is a member of the group: gnfd://website-group ``` ### Policy Operations The `gnfd-cmd policy` command supports the policy for put/delete resources policy(including objects, buckets, and groups) to the principal. The principal is need to be set by `--grantee` which indicates a greenfield account or `--groupId` which indicates group id. The object policy action can be "create", "delete", "copy", "get" , "execute", "list" or "all". The bucket policy actions can be "update", "delete", "create", "list", "update", "getObj", "createObj" and so on. The group policy actions can be "update", "delete" or all, update indicates the update-group-member action. In this example, the principal grants the `delete bucket`, `update bucket` access to this group ```shell // grant bucket operation permissions to a group gnfd-cmd policy put --groupId 712 --actions delete,update,createObj,getObj grn:b::website-bucket ``` The result should look something similar to the following: ```shell put policy of the bucket:website-bucket succ, txn hash: 63735FBF6BDFF95AEED9B8BC8D794474431C77E7EBF768BFAA9E3F7CFB25FF97 latest bucket policy info: id:"2316" principal: resource_type:RESOURCE_TYPE_BUCKET resource_id:"3101" statements: ``` As you can see, the result returns a transaction hash, which one can inspect using the block scanner, e.g. [https://greenfieldscan.com](https://greenfieldscan.com/). Going to [https://testnet.greenfieldscan.com/tx/63735FBF6BDFF95AEED9B8BC8D794474431C77E7EBF768BFAA9E3F7CFB25FF97](https://testnet.greenfieldscan.com/tx/63735FBF6BDFF95AEED9B8BC8D794474431C77E7EBF768BFAA9E3F7CFB25FF97), will show all the details of the `put policy` transaction. Upload a private file with principal account: ```shell gnfd-cmd object put --contentType "text/xml" --visibility private ./website/index.html gnfd://website-bucket/index.html ``` In this example, the principal grants the `delete object`, `update object` access to this group ```shell // grant object operation permissions to a group gnfd-cmd policy put --groupId 712 --actions get,delete grn:o::website-bucket/index.html ``` The result should look something similar to the following: ```shell put policy of the object:index.html succ, txn hash: BD2E3F74B2FBD18300B2C313E8F0393426C851EC3A9153F37DFD6CDC10F92FF8 latest object policy info: id:"2318" principal: resource_type:RESOURCE_TYPE_OBJECT resource_id:"187293" statements: ``` To verify the group policy is working, you can try view the private object with account `0x843e77D639b6C382e91ef489881963209cB238E5`. 1. Go to explorer and find the detail page of the private object. 2. Click on "Preview" button 3. Unlock your wallet and choose the right address. Then, you should be able to view the html file. or you can download the file with `gnfd-cmd` ```shell ./gnfd-cmd object get gnfd://website-bucket/index.html ``` ### Update Access Control with Group The command to update a group is very simple. #### Remove a member from group: ```shell // update group member gnfd-cmd group update --removeMembers 0xca807A58caF20B6a4E3eDa3531788179E5bc816b gnfd://groupname ``` #### Add expiretime for membership You can set the expire timestamp for the newly added member. The default value is no experiation. ```shell // update group member gnfd-cmd group update --removeMembers 0xca807A58caF20B6a4E3eDa3531788179E5bc816b gnfd://groupname --expireTime 1699699763 ``` #### Remove Policy Here is an example to delete a policy * Delete a policy for an adress ```shell gnfd-cmd policy rm --grantee 0x843e77D639b6C382e91ef489881963209cB238E5 --actions get grn:o::website-bucket/index.html ``` * Delete a policy for a group ```shell gnfd-cmd policy rm --groupId 111 --actions get grn:o::website-bucket/index.html ``` ## Conclusion Overall, the access control management of Greenfield is very powerful and can be used in many scenarios. It is highly recommended for users to engage in hands-on exploration by trying out different account group management operations and permissioning mechanisms. This will provide a deeper understanding of how BNB Greenfield functions and how to effectively manage and secure data within the decentralized storage system. --- ## Cross Chain Access Control by CMD > Source: https://docs.bnbchain.org/bnb-greenfield/for-developers/tutorials/access-control/cross-chain-access-control-by-cmd/ # Cross Chain Access Control by CMD In this guide, we will walk you through the process of data permission management using the BSC smart contract as a simple howcase of cross chain program-ability of Greenfield. ## Prerequisites Before starting, make sure you have the following tools installed: - [gnfd-cmd](https://github.com/bnb-chain/greenfield-cmd) - [gnfd-contract](https://github.com/bnb-chain/greenfield-contracts) Please follow the readme of the above two repositories to install the tools and configure the environment. Ensure you get an account that get funds on both BSC and Greenfield network. ### Steps In the following example, Account A(0x0fEd1aDD48b497d619EF50160f9135c6E221D5F0, stored in `keyA.json`) will grant Account B(0x3bD70E10D71C6E882E3C1809d26a310d793646eB, stored in `keyB.json`) the access to his private file through BSC contract. Besides, you can save the password to a file and use `-p` to specify the password file. For example, `gnfd-cmd -p password.txt ...`. Before starting, please make sure you created related accounts by `gnfd-cmd account import` or `gnfd-cmd account new` and have the config.toml file in the current directory. Please note that the account should have enough balance before sending transactions to greenfield. The content of the `config.toml` is as follows: === "Mainnet" ``` rpcAddr = "https://greenfield-chain.bnbchain.org:443" chainId = "greenfield_1017-1" ``` === "Testnet" ``` rpcAddr = "https://gnfd-testnet-fullnode-tendermint-us.bnbchain.org:443" chainId = "greenfield_5600-1" ``` 1. Prepare environment ```shell $ export AccountA=0x0fEd1aDD48b497d619EF50160f9135c6E221D5F0 $ export AccountB=0x3bD70E10D71C6E882E3C1809d26a310d793646eB ``` 2. Create a temporary file `story.txt` ```shell $ echo "this is a fun story" > story.txt ``` 3. Create a bucket named `funbucket`. ```shell $ gnfd-cmd -c config.toml -k keyA.json -p password.txt bucket create gnfd://funbucket ``` 4. Create a private object named `story.txt` in the bucket `funbucket`. ```shell $ gnfd-cmd -c config.toml -k keyA.json -p password.txt object put --contentType "text/xml" --visibility private ./story.txt gnfd://funbucket/story.txt ``` 5. Create a group named `fungroup`. ```shell $ gnfd-cmd -c config.toml -k keyA.json -p password.txt group create fungroup create group: fungroup succ, txn hash:17B6AE2C8D30B6D6EEABEE81DB8B37CF735655E9087CB02DC98EFF1DCA9FBE3A, group id: 136 ``` The console will return the id of the group, which is `136` in this case. 6. Bind the group `fungroup` to the object `story.txt`. ```shell ## Example, replace the ${GroupId} with the group id you get in the previous step $ export GroupId=136 $ gnfd-cmd -c config.toml -k keyA.json -p password.txt policy put --groupId ${GroupId} --actions get grn:o::funbucket/story.txt ``` 7. Mirror the group to BSC network. ```shell ## Example, replace the ${GroupId} with the group id you get in the previous step ## 97 is the chainId of BSC testnet ## 56 is the chainId of BSC mainnet $ export ChainId=56 $ gnfd-cmd -c config.toml -k keyA.json -p password.txt group mirror --destChainId ${GroupId} --id ${GroupId} ``` 8. Try to access the file through AccountB. ```shell ## Example $ gnfd-cmd -c config.toml -k keyA.json -p password.txt group head-member --groupOwner ${AccountA} ${AccountB} fungroup the user does not exist in the group $ gnfd-cmd -c config.toml -k keyB.json -p password.txt object get gnfd://funbucket/story.txt ./story-copy.txt run command error: statusCode 403 : code : AccessDenied (Message: Access Denied) ``` It turns out that AccountB is not permitted to access the file, which is expected. 9. Clone the [gnfd-contract](https://github.com/bnb-chain/greenfield-contracts) repository and install the dependencies. 10. Grant the access to Account B through the contract. === "Mainnet" ```sh export RPC_MAIN=https://bsc-dataseed.bnbchain.org $ forge script foundry-scripts/GroupHub.s.sol:GroupHubScript \ --sig "addMember(address operator, uint256 groupId, address member)" \ ${AccountA} ${GroupId} ${AccountB} \ -f $RPC_MAIN \ --private-key 148748590a8b83dxxxxxxxxxxxxxxxxx \ --legacy \ --broadcast ``` === "Testnet" ```sh export RPC_TEST=https://bsc-testnet-dataseed.bnbchain.org $ forge script foundry-scripts/GroupHub.s.sol:GroupHubScript \ --sig "addMember(address operator, uint256 groupId, address member)" \ ${AccountA} ${GroupId} ${AccountB} \ -f $RPC_TEST\ --private-key 148748590a8b83dxxxxxxxxxxxxxxxxx \ --legacy \ --broadcast ``` 10. Wait 30 seconds, and try to access the file through AccountB again. ```shell ## Example $ gnfd-cmd -c config.toml -k keyA.json -p password.txt group head-member --groupOwner ${AccountA} ${AccountB} fungroup the user is a member of the group $ gnfd-cmd -c config.toml -k keyB.json -p password.txt object get gnfd://funbucket/story.txt download object story.txt successfully, the file path is ./story-copy.txt, content length:20 ``` --- ## Native Access Control > Source: https://docs.bnbchain.org/bnb-greenfield/for-developers/tutorials/access-control/access-control/ # Native Access Control In this tutorial we’ll use the go-SDK library to manage your buckets and objects. ## Prerequisites Before getting started, you should be familiar with: * [Greenfield basics](../../../introduction.md) * Greenfield command line [examples](https://github.com/bnb-chain/greenfield-cmd#examples) ## Access Control Features | **Principal** | **Effect** | **Actions** | **Resources** | **Duration** | | --------------- | ---------- | ----------------------------------------------------------- | ------------- | ------------ | | Accounts/Groups | Allow/Deny | UpdateBucketInfo, DeleteBucket, etc | Bucket | | | Accounts/Groups | Allow/Deny | CreateObject,DeleteObject,CopyObject,GetObject,ExecuteObject, etc | Object | | | Accounts/Groups | Allow/Deny | UpdateGroupMember,DeleteGroup, etc | Group | | ## Setup ### Create a Go Project Let’s set up a Go project with the necessary dependencies. ### Init ```sh $ mkdir ~/hellogreenfield $ cd ~/hellogreenfield $ go mod init hellogreenfield ``` ### Add SDK Dependencies ```sh $ go get github.com/bnb-chain/greenfield-go-sdk ``` Edit go.mod to replace dependencies ```sh replace ( cosmossdk.io/api => github.com/bnb-chain/greenfield-cosmos-sdk/api v0.0.0-20230425074444-eb5869b05fe9 cosmossdk.io/math => github.com/bnb-chain/greenfield-cosmos-sdk/math v0.0.0-20230425074444-eb5869b05fe9 github.com/cometbft/cometbft => github.com/bnb-chain/greenfield-cometbft v0.0.2 github.com/cometbft/cometbft-db => github.com/bnb-chain/greenfield-cometbft-db v0.8.1-alpha.1 github.com/cosmos/cosmos-sdk => github.com/bnb-chain/greenfield-cosmos-sdk v0.2.3 github.com/cosmos/iavl => github.com/bnb-chain/greenfield-iavl v0.20.1-alpha.1 github.com/syndtr/goleveldb => github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 ) ``` ### Install dependensies ```sh go mod tidy ``` ### Test a simple function You can refer to the [overview](../../tutorials/app/file-management/basic-file-management.md) to learn about how to create a simple `main.go` If everything is set up correctly, your code will be able to connect to the Greenfield node and return the chain data as shown above. ## Account Setup You have to prepare two accounts, one is the `principal`, which acts like an admimistrator and a member, which will receive the access to view/update objects. ```go account, err := types.NewAccountFromPrivateKey("test", privateKey) if err != nil { log.Fatalf("New account from private key error, %v", err) } cli, err := client.New(chainId, rpcAddr, client.Option{DefaultAccount: account}) if err != nil { log.Fatalf("unable to new greenfield client, %v", err) } ``` ## Create Group The next step is to create a group, whose member will receive access from the principla account. ```go // create group groupTx, err := cli.CreateGroup(ctx, groupName, types.CreateGroupOptions{}) handleErr(err, "CreateGroup") _, err = cli.WaitForTx(ctx, groupTx) if err != nil { log.Fatalln("txn fail") } log.Printf("create group %s successfully \n", groupName) // head group info creator, err := cli.GetDefaultAccount() handleErr(err, "GetDefaultAccount") groupInfo, err := cli.HeadGroup(ctx, groupName, creator.GetAddress().String()) handleErr(err, "HeadGroup") log.Println("head group info:", groupInfo.String()) _, err = sdk.AccAddressFromHexUnsafe(memberAddress) if err != nil { log.Fatalln("the group member is invalid") } // add group member updateTx, err := cli.UpdateGroupMember(ctx, groupName, creator.GetAddress().String(), []string{memberAddress}, []string{}, types.UpdateGroupMemberOption{}) handleErr(err, "UpdateGroupMember") _, err = cli.WaitForTx(ctx, updateTx) if err != nil { log.Fatalln("txn fail") } log.Printf("add group member: %s to group: %s successfully \n", memberAddress, groupName) // head group member memIsExist := cli.HeadGroupMember(ctx, groupName, creator.GetAddress().String(), memberAddress) if !memIsExist { log.Fatalf("head group member %s fail \n", memberAddress) } log.Printf(" head member %s exist \n", memberAddress) ``` The result should look something similar to the following: ```shell 2023/10/31 09:34:54 create group sample-group successfully 2023/10/31 09:34:54 head group info: owner:"0x525482AB3922230e4D73079890dC905dCc3D37cd" group_name:"sample-group" id:"720" 2023/10/31 09:35:01 add group member: 0x843e77D639b6C382e91ef489881963209cB238E5 to group: sample-group successfully 2023/10/31 09:35:01 head member 0x843e77D639b6C382e91ef489881963209cB238E5 exist ``` ## Create Policy Now, you can let the principal grants the `delete bucket`, `update bucket`, `delete object`, `update object` access to this group ```go // put bucket policy bucketActions := []permTypes.ActionType{ permTypes.ACTION_UPDATE_BUCKET_INFO, permTypes.ACTION_DELETE_BUCKET, permTypes.ACTION_DELETE_OBJECT, permTypes.ACTION_GET_OBJECT, } ctx := context.Background() statements := utils.NewStatement(bucketActions, permTypes.EFFECT_ALLOW, nil, types.NewStatementOptions{}) policyTx, err := cli.PutBucketPolicy(ctx, bucketName, principalStr, []*permTypes.Statement{&statements}, types.PutPolicyOption{}) handleErr(err, "PutBucketPolicy") _, err = cli.WaitForTx(ctx, policyTx) if err != nil { log.Fatalln("txn fail") } log.Printf("put bucket %s policy sucessfully, principal is: %s.\n", bucketName, principal) ``` After you run the code, the result should look something similar to the following: ```shell 2023/10/31 10:46:55 put bucket sdkexamplebucket policy sucessfully, principal is: 2023/10/31 10:46:55 bucket: sdkexamplebucket policy info:id:"2358" principal: resource_type:RESOURCE_TYPE_BUCKET resource_id:"429" statements: ``` You can also inspect using the block scanner, e.g. [https://greenfieldscan.com](https://greenfieldscan.com/). #### Verify Policy Here is an example to verify the policy metadata onchain: ```go // get bucket policy policyInfo, err := cli.GetBucketPolicy(ctx, bucketName, memberAddress) handleErr(err, "GetBucketPolicy") log.Printf("bucket: %s policy info:%s\n", bucketName, policyInfo.String()) // verify permission effect, err := cli.IsBucketPermissionAllowed(ctx, memberAddress, bucketName, permTypes.ACTION_DELETE_BUCKET) handleErr(err, "IsBucketPermissionAllowed") if effect != permTypes.EFFECT_ALLOW { log.Fatalln("permission not allowed to:", principalStr) } ``` If the policy is recorded as expected, you will not see any error. ## Delete Policy Here is an example to delete your bucket policy. The `principalStr` can be generated by `NewPrincipalWithAccount` or `NewPrincipalWithGroupId` method. ```go // delete bucket policy policyTx, err = cli.DeleteBucketPolicy(ctx, bucketName, principalStr, types.DeletePolicyOption{}) handleErr(err, "DeleteBucketPolicy") _, err = cli.WaitForTx(ctx, policyTx) if err != nil { log.Fatalln("txn fail") } ``` ### Source Code * [Go-SDK](https://github.com/bnb-chain/greenfield-go-sdk/blob/master/examples/permission.go) * [JS-SDK](https://github.com/bnb-chain/greenfield-js-sdk/blob/main/examples/nodejs/cases/policy.js) --- ## Cross Chain Access Control by SDK > Source: https://docs.bnbchain.org/bnb-greenfield/for-developers/tutorials/access-control/cross-chain-access-control-by-sdk/ # Cross Chain Access Control by SDK In this tutorial we’ll use the go-SDK library to transfer control over objects to the smart contract on BSC and allowing on-chain management. Object mirroring enables greater flexibility and control over decentralized storage on BNB Greenfield to all dApps on BSC. It leverages the capabilities of the BSC and its smart contract functionality to provide enhanced functionality and interoperability between the two platforms. ## Prerequisites Before getting started, you should be familiar with: - [Greenfield basics](../../../introduction.md) - Greenfield command line [examples](https://github.com/bnb-chain/greenfield-cmd#examples) ## Cross Chain Mechanism Cross-chain communication serves as the foundation for enabling the exchange of assets, data, and functionalities across disparate blockchains, facilitating a more connected and efficient decentralised ecosystem. Cross-communication between BNB Greenfield and BSC stands apart from the approaches taken by Polkadot, Chainlink, and Cosmos in several significant aspects. | **Cross chain communication features** | **BNB Greenfield/BSC** | **Cosmos/IBC** | **Polkadot** | **Chainlink CCIP** | | -------------------------------------- | ------------------------------------------ | -------------------------- | ----------------------------------------- | -------------------------------------------- | | Bulk messaging | Custom and performant | General application | General application | General application | | Compatibility | Fully compatible with EVM and Ethereum L2s | Only Cosmos ecosystem | Only Polkadot ecosystem | Specific implementations for each blockchain | | Security Model | Own validators | Shared | Shared | Own validators | | Tokenomics | BNB | ATOM | DOT | LINK | | Address Scheme | Unified - same addresses | Can be different addresses | Can be different addresses | Can be different addresses | | Composability | Shared components with BNB Chain ecosystem | Implementation in progress | Shared components with Polkadot ecosystem | New implementation for each network | ## Account Setup ### Create a Go Project Let’s set up a Go project with the necessary dependencies. ### Init ```sh $ mkdir ~/hellogreenfield $ cd ~/hellogreenfield $ go mod init hellogreenfield ``` ### Add SDK Dependencies ```sh $ go get github.com/bnb-chain/greenfield-go-sdk ``` Edit go.mod to replace dependencies ```sh replace ( cosmossdk.io/api => github.com/bnb-chain/greenfield-cosmos-sdk/api v0.0.0-20230425074444-eb5869b05fe9 cosmossdk.io/math => github.com/bnb-chain/greenfield-cosmos-sdk/math v0.0.0-20230425074444-eb5869b05fe9 github.com/cometbft/cometbft => github.com/bnb-chain/greenfield-cometbft v0.0.2 github.com/cometbft/cometbft-db => github.com/bnb-chain/greenfield-cometbft-db v0.8.1-alpha.1 github.com/cosmos/cosmos-sdk => github.com/bnb-chain/greenfield-cosmos-sdk v0.2.3 github.com/cosmos/iavl => github.com/bnb-chain/greenfield-iavl v0.20.1-alpha.1 github.com/syndtr/goleveldb => github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 ) ``` ### Install dependensies ```sh go mod tidy ``` ### Test a simple function You can refer to the [overview](../../tutorials/app/file-management/basic-file-management.md) to learn about how to create a simple `main.go` If everything is set up correctly, your code will be able to connect to the Greenfield node and return the chain data as shown above. ### Account setup ```go account, err := types.NewAccountFromPrivateKey("test", privateKey) if err != nil { log.Fatalf("New account from private key error, %v", err) } cli, err := client.New(chainId, rpcAddr, client.Option{DefaultAccount: account}) if err != nil { log.Fatalf("unable to new greenfield client, %v", err) } ctx := context.Background() ``` ## Create Buckets Now, let's use the imported account to create a bucket. In this example, ```go // get storage providers list spLists, err := cli.ListStorageProviders(ctx, true) if err != nil { log.Fatalf("fail to list in service sps") } // choose the first sp to be the primary SP primarySP := spLists[0].GetOperatorAddress() bucketName := storageTestUtil.GenRandomBucketName() txHash, err := cli.CreateBucket(ctx, bucketName, primarySP, types.CreateBucketOptions{}) handleErr(err, "CreateBucket") log.Printf("create bucket %s on SP: %s successfully \n", bucketName, spLists[0].Endpoint) waitForTx, _ := cli.WaitForTx(ctx, txHash) log.Printf("Wait for tx: %s", waitForTx.TxResult.String()) ``` The example return message is like the following: ```shell 2023/10/31 13:14:54 create bucket ylatitsb on SP: https://gnfd-testnet-sp1.bnbchain.org successfully 2023/10/31 13:14:54 Wait for tx: data:"\0225\n+/greenfield.storage.MsgCreateBucketResponse\022\006\n\0043175\032\010\000\000\000\000\000\000\201\006" log:"[{\"msg_index\":0,\"events\":[{\"type\":\"message\",\"attributes\":[{\"key\":\"action\",\"value\":\"/greenfield.storage.MsgCreateBucket\"},{\"key\":\"sender\",\"value\":\"0x525482AB3922230e4D73079890dC905dCc3D37cd\"},{\"key\":\"module\",\"value\":\"storage\"}]},{\"type\":\"greenfield.storage.EventCreateBucket\",\"attributes\":[{\"key\":\"bucket_id\",\"value\":\"\\\"3175\\\"\"},{\"key\":\"bucket_name\",\"value\":\"\\\"ylatitsb\\\"\"},{\"key\":\"charged_read_quota\",\"value\":\"\\\"0\\\"\"},{\"key\":\"create_at\",\"value\":\"\\\"1698779691\\\"\"},{\"key\":\"global_virtual_group_family_id\",\"value\":\"40\"},{\"key\":\"owner\",\"value\":\"\\\"0x525482AB3922230e4D73079890dC905dCc3D37cd\\\"\"},{\"key\":\"payment_address\",\"value\":\"\\\"0x525482AB3922230e4D73079890dC905dCc3D37cd\\\"\"},{\"key\":\"primary_sp_id\",\"value\":\"1\"},{\"key\":\"source_type\",\"value\":\"\\\"SOURCE_TYPE_ORIGIN\\\"\"},{\"key\":\"status\",\"value\":\"\\\"BUCKET_STATUS_CREATED\\\"\"},{\"key\":\"visibility\",\"value\":\"\\\"VISIBILITY_TYPE_PRIVATE\\\"\"}]}]}]" gas_wanted:2400 gas_used:2400 events: attributes: > events: attributes: > events: attributes: attributes: > events: > events: attributes: > events: > events: attributes: attributes: > events: attributes: attributes: attributes: attributes: attributes: attributes: attributes: attributes: attributes: attributes: > ``` * Query the bucket with `HeadBucket` function ```go // head bucket bucketInfo, err := cli.HeadBucket(ctx, bucketName) handleErr(err, "HeadBucket") log.Println("bucket info:", bucketInfo.String()) ``` The example return message is like the following: ```shell 2023/10/31 13:14:54 bucket info: owner:"0x525482AB3922230e4D73079890dC905dCc3D37cd" bucket_name:"ylatitsb" visibility:VISIBILITY_TYPE_PRIVATE id:"3175" create_at:1698779691 payment_address:"0x525482AB3922230e4D73079890dC905dCc3D37cd" global_virtual_group_family_id:40 ``` ## Create Group The next step is to create a group, whose member will receive `get object` access from the principla account. ```go // create group groupTx, err := cli.CreateGroup(ctx, groupName, types.CreateGroupOptions{}) handleErr(err, "CreateGroup") _, err = cli.WaitForTx(ctx, groupTx) if err != nil { log.Fatalln("txn fail") } log.Printf("create group %s successfully \n", groupName) // head group info creator, err := cli.GetDefaultAccount() handleErr(err, "GetDefaultAccount") groupInfo, err := cli.HeadGroup(ctx, groupName, creator.GetAddress().String()) handleErr(err, "HeadGroup") log.Println("head group info:", groupInfo.String()) _, err = sdk.AccAddressFromHexUnsafe(memberAddress) if err != nil { log.Fatalln("the group member is invalid") } // add group member updateTx, err := cli.UpdateGroupMember(ctx, groupName, creator.GetAddress().String(), []string{memberAddress}, []string{}, types.UpdateGroupMemberOption{}) handleErr(err, "UpdateGroupMember") _, err = cli.WaitForTx(ctx, updateTx) if err != nil { log.Fatalln("txn fail") } log.Printf("add group member: %s to group: %s successfully \n", memberAddress, groupName) // head group member memIsExist := cli.HeadGroupMember(ctx, groupName, creator.GetAddress().String(), memberAddress) if !memIsExist { log.Fatalf("head group member %s fail \n", memberAddress) } log.Printf(" head member %s exist \n", memberAddress) ``` The result should look something similar to the following: ```shell 2023/10/31 09:34:54 create group sample-group successfully 2023/10/31 09:34:54 head group info: owner:"0x525482AB3922230e4D73079890dC905dCc3D37cd" group_name:"sample-group" id:"720" 2023/10/31 09:35:01 add group member: 0x843e77D639b6C382e91ef489881963209cB238E5 to group: sample-group successfully 2023/10/31 09:35:01 head member 0x843e77D639b6C382e91ef489881963209cB238E5 exist ``` ## Create Policy Now, you can let the principal grants the `get object` access to this group ```go // put bucket policy bucketActions := []permTypes.ActionType{ permTypes.ACTION_GET_OBJECT, } ctx := context.Background() statements := utils.NewStatement(bucketActions, permTypes.EFFECT_ALLOW, nil, types.NewStatementOptions{}) policyTx, err := cli.PutBucketPolicy(ctx, bucketName, principalStr, []*permTypes.Statement{&statements}, types.PutPolicyOption{}) handleErr(err, "PutBucketPolicy") _, err = cli.WaitForTx(ctx, policyTx) if err != nil { log.Fatalln("txn fail") } log.Printf("put bucket %s policy sucessfully, principal is: %s.\n", bucketName, principal) ``` After you run the code, the result should look something similar to the following: ```shell 2023/10/31 10:46:55 put bucket sdkexamplebucket policy sucessfully, principal is: 2023/10/31 10:46:55 bucket: sdkexamplebucket policy info:id:"2358" principal: resource_type:RESOURCE_TYPE_BUCKET resource_id:"429" statements: ``` You can also inspect using the block scanner, e.g. [https://greenfieldscan.com](https://greenfieldscan.com/). ## Mirror Group to BSC In Greenfield, object mirroring refers to the process of transferring control over objects stored on BNB Greenfield to a smart contract on BNB Smart Chain (BSC) This allows the object to be fully managed on-chain on BSC, meaning that users or other smart contracts can perform various operations and changes to the object through on-chain transactions. During the mirroring process from BNB Greenfield to BSC, the content of the file itself is not copied. This means that neither the data nor the file metadata, which is stored on the BNB Greenfield blockchain, is transferred to BSC. ```go //head group groupInfo, err := cli.HeadGroup(ctx, groupName, creator.GetAddress().String()) handleErr(err, "HeadGroup") log.Println("head group info:", groupInfo.String()) // mirror bucket txResp, err := cli.MirrorGroup(ctx, sdk.ChainID(crossChainDestBsChainId), groupInfo.Id, groupName, gnfdSdkTypes.TxOption{}) handleErr(err, "MirrorGroup") waitForTx, _ = cli.WaitForTx(ctx, txResp.TxHash) log.Printf("Wait for tx: %s", waitForTx.TxResult.String()) log.Printf("successfully mirrored group wiht id %s to BSC", groupInfo.Id) ``` ```shell 2023/10/31 21:43:57 group: sdkexamplegroup policy info:id:"712" principal: resource_type:RESOURCE_TYPE_BUCKET resource_id:"429" statements: 2023/10/31 21:43:57 bucket info: owner:"0x525482AB3922230e4D73079890dC905dCc3D37cd" bucket_name:"ylatitsb" visibility:VISIBILITY_TYPE_PRIVATE id:"3175" create_at:1698779691 payment_address:"0x525482AB3922230e4D73079890dC905dCc3D37cd" global_virtual_group_family_id:40 ``` You can also inspect using the block scanner, e.g. [https://greenfieldscan.com](https://greenfieldscan.com/). ## Access Control Management on BSC Now you have mirrored your group to BSC and there is an ERCC-721 token minted. At present, the NFTs are not transferable. The group membership can be directly managed by smart contracts on BSC. These operations will directly affect the storage format, access permissions, and other aspects of the data on greenfield with the help of [Greenfield Contract](https://github.com/bnb-chain/greenfield-contracts/tree/master). First, you have to install the dependencies and setup environment by following the [guides](https://github.com/bnb-chain/greenfield-contracts/tree/master#requirement). Once it's all set, you can run the following script to add member to your group: ``` # set your private-key, operator address, group id, and member address forge script foundry-scripts/GroupHub.s.sol:GroupHubScript \ --private-key ${your private key} \ --sig "addMember(address operator, uint256 groupId, address member)" \ ${the owner of the group} ${your group id} ${the member address to add} \ -f https://bsc-testnet-dataseed.bnbchain.org \ --legacy --ffi --broadcast ``` ## Conclusion The Greenfield Blockchain provides a comprehensive set of resources that can be mirrored on the BNB Smart Chain (BSC). This includes buckets, objects, and groups, which can be stored and managed on the BSC as non-fungible tokens (NFTs) conforming to the ERC-721 standard. This integration between Greenfield Blockchain and BNB Smart Chain allows for greater flexibility and accessibility when it comes to accessing and manipulating data, ultimately leading to a more streamlined and efficient data management process. ### Source Code * [Go-SDK](https://github.com/bnb-chain/greenfield-go-sdk/blob/master/examples/crosschain.go) * [JS-SDK](https://github.com/bnb-chain/greenfield-js-sdk/blob/main/examples/nextjs/src/components/mirror/index.tsx) * [Greenfield Contract Examples](https://github.com/bnb-chain/greenfield-contracts/tree/master/foundry-scripts/examples). --- ## Overview > Source: https://docs.bnbchain.org/bnb-greenfield/for-developers/tutorials/app/overview/ # Overview Native apps are applications developed only using the Greenfield SDK, without involving the development of smart contracts. In the following sections, we will delve deeper into each native application, providing step-by-step guides, code snippets, and best practices to empower you to create powerful and innovative dApps without the need for smart contract development. ## Data Marketplace Data marketplace is a data exchange platform where users can freely create, list, trade, and sell data assets, including digital publications, scientific experimental data, and specific domain data. ### Demo Link * Testnet: [https://testnet-marketplace.mindpress.io](https://testnet-marketplace.mindpress.io) ### Source Code MindPress consists of three engineering projects: * Frontend: [https://github.com/bnb-chain/mindpress-data-marketplace](https://github.com/bnb-chain/mindpress-data-marketplace) * Backend: [https://github.com/bnb-chain/mindpress-data-marketplace-backend](https://github.com/bnb-chain/mindpress-data-marketplace-backend) * Smart Contracts: [https://github.com/bnb-chain/mindpress-data-marketplace-smart-contract](https://github.com/bnb-chain/mindpress-data-marketplace-smart-contract) ## Developing with smart contracts on BSC One of the primary methods for building dApps with BNB Greenfield is by deploying smart contracts to the BSC. Smart contracts are self-executing programs that facilitate and enforce the execution of agreements without the need for intermediaries. * [How to develop BSC smart contract for Greenfield](../../tutorials/access-control/cross-chain-access-control-by-cmd.md) ## CLI * [Basic File Management](../file-management-overview.md) * [Hosting a Website](../hosting-websites-overview.md) ## SDK Demo * [Basic File Management](./file-management/basic-file-management.md) * [Resumable Upload & Download](./file-management/resumable-upload/overview.md) * [Batch operations](./file-management/batch-upload.md) --- ## Data Marketplace > Source: https://docs.bnbchain.org/bnb-greenfield/for-developers/tutorials/app/data-marketplace/ # MindPress Data Marketplace Introduction

1. Overview

[MindPress Data Marketplace](https://testnet-marketplace.mindpress.io) is a demo built on the BNB Smart Chain and BNB Greenfield storage chains. It uses the image trading scenario as an example to demonstrate the use of BNB Greenfield's latest release (V1.6&V1.7), such as cross-chain programmability, delegate upload, and sponsor-paid storage fees. With these features, developers can easily create a web3 decentralized trading platform based on the BNB Chain ecosystem with a great user experience and comprehensive functions such as storage, trading, and content permission management, thereby accelerating project development and marketing.

2. Features

As an image stock, sellers can upload and list photos for sale, while buyers can search for images they like, buy, and download the original files. _Seller_ * **Upload objects (e.g. images) to BNB Greenfield:** Sellers can upload multiple images to BNB Greenfield at once under the BSC network. * **List objects on the BNB Smart Chain:** Sellers can list their uploaded images for sale on the BSC network and begin selling download/view permissions to buyers to earn money. * **Delist objects**: Sellers can delist their images from the marketplace. _Buyer_ * **Search objects:** Buyers can search for objects by name and category ID to find what they want. * **Buy objects:** Buyers can purchase objects and obtain download/view permission. * **Download objects:** Buyers can download/view their purchased objects.

3. Benefits after Greenfield V1.6&1.7 updates

# Before After Code Related Greenfield Features Network Switch ❌Users have to switch between BNB Greenfield and BNB Smart Chain to upload objects and make the trading operation. ✅No network switch: Users can finish all the operations on BSC network. https://github.com/bnb-chain/greenfield-cosmos-sdk/pull/417 BEP-361: Streamline off-chain authentication on Greenfield BEP-363: Improve Greenfield cross-chain programming capability Payment Method ❌Users have to pay the storage fee and download quota fee by themselves. ✅Flexible payment method: Projects can choose to pay storage and download quota fees by themselves, allowing users to use this platform for free and lowering the user threshold, thereby expanding the number of users and facilitating promotion. https://github.com/bnb-chain/greenfield/pull/582 BEP-362: Greenfield Storage Fee Paymaster Upload Objects ❌Users must upload objects to DCellar before returning to MindPress to list them because the upload process is quite complex to embed in MindPress. ✅Easy to upload: Users can upload multiple large objects in MindPress at once without requiring a signature or incurring fees because the upload process is greatly simplified by the delegate upload feature. https://github.com/bnb-chain/greenfield/pull/581 BEP-364: Primary Storage Provider acts as the upload agent for object creation and update on Greenfield List Objects ❌Users have to execute 2-3 transactions to complete the list workflow, which also requires switching networks back and forth. ✅Easy to list: Users need only 2 transactions to complete the list operation to start selling. https://github.com/bnb-chain/greenfield-contracts/pull/140 BEP-363: Improve Greenfield cross-chain programming capability Multiple add multi-message support for Greenfield cross-chain app

4. Demo Video

4.1 Buyer workflow

| | | | -- | -- | | Search and filter | | | Buy Images | |

4.2 Seller Workflow

| | | | -- | -- | | Upload Images | | | List Images | | | Delist Images | |

5. Environment Support

* BNB Smart Chain Testnet: [https://mindpress.io](https://mindpress.io) (VPN required in some areas)

6. Technical Design

6.1 Overview

The BNB Greenfield offers resources such as buckets, objects, and groups that can be mirrored on the BNB Smart Chain (BSC) as non-fungible tokens (NFTs) following the ERC-721 standard. Buckets store objects, the basic units with data and metadata. Groups consist of accounts with similar permissions. These resources, including group members' permissions as ERC-1155 tokens, can be mirrored on the BSC. Smart contracts on BSC can directly control mirrored resources, affecting storage formats, access permissions, and other data aspects on Greenfield. This integration boosts flexibility and accessibility, streamlining data management on both platforms. For more on mirroring implementation, refer to [this document](https://docs.bnbchain.org/bnb-greenfield/core-concept/cross-chain/mirror/). In the context of the MindPress Data Marketplace, users have the ability to store images on the Greenfield network and sell them on the BSC. Let's take the example of Alice selling a picture of a carrot on MindPress. To sell carrot images, Alice needs to follow these steps: 1. Create a bucket, and upload the carrot image to this bucket on BNB Greenfield. 2. Create a group and grant this group permission to view the carrot image. 3. List the group on the MindPress Data Marketplace smart contract to sell access permissions on the BSC network. Since the carrot image is private, Bob will be denied access to it by default. Bob needs to buy permission to join the group. After becoming a member, he can view/download the carrot image.

6.2 Architecture

6.2.1 Greenfield Cross Chain Design
The true strength of the Greenfield ecosystem resides in its cutting-edge platform engineered not just for data storage, but also for fostering value creation from data assets and its associated economy. To empower data on Greenfield more effectively, a robust cross-chain mechanism has been introduced, enabling versatile cross-chain programming capabilities. The first layer is the Cross-Chain Communication Layer, which is responsible for handling and verifying the communication packages between BSC and BNB Greenfield. The second layer is the Resource Mirror Layer, which handles the resource assets defined on BNB Greenfield and mirrors them onto BSC. The top layer of the cross-chain system is the Application Layer. This layer consists of smart contracts that are developed by the community on BSC, enabling them to operate the mirrored resource entities on the Resource Mirror Layer.
6.2.2 MindPress Workflow
MindPress Data Marketplace is built on the cross-chain mechanism of BNB Greenfield and BSC, enabling users to flexibly manipulate data stored on Greenfield on the BSC side, facilitating data circulation and value creation. Below, we delve into the technical principles of the key processes involved in MindPress. * Create Space The MindPress contract will do the following operations: 1. help the user to create a bucket to store the uploaded images and the paymaster of the bucket is set to mindpress contract. 2. set the flow rate limit for the bucket to give the initial free charge. * List Object Users should go through the following 2 transactions to list an object: 1. Send a list request to the MindPress contract with the object ID, group name and price, MindPress will create a new group where all members of the group have access to the object. 2. Send a cross-chain put-policy transaction to bind the object and the created group. * Buy Object To purchase an object, the user simply sends a purchase request and pays the appropriate fee in BNB. The mindpress contract will send a cross-chain package to add the user into the access group.

6.3 Technical Considerations

* **CrossChain Design:** Application data is stored on the BSC chain. Objects/buckets and their access rights are recorded on the Greenfield chain. Relayers automatically relay cross-chain packages and acknowledgments between BSC and Greenfield. MindPress contracts can update the application state through Greenfield contract callbacks. * **Stateless Design:** The MindPress Data Marketplace is engineered to be stateless. The data query and object permission control involved in the application can only be interacted with through the BSC chain.

7. Getting Started

MindPress consists of three engineering projects: * Frontend: [https://github.com/bnb-chain/mindpress-data-marketplace](https://github.com/bnb-chain/mindpress-data-marketplace) * Backend: [https://github.com/bnb-chain/mindpress-data-marketplace-backend](https://github.com/bnb-chain/mindpress-data-marketplace-backend) * Smart Contracts: [https://github.com/bnb-chain/mindpress-data-marketplace-smart-contract](https://github.com/bnb-chain/mindpress-data-marketplace-smart-contract)

8. Contributing

Thank you for considering using and contributing to MindPress! We welcome developers to utilize our open-source codebase and encourage collaboration to improve and extend its functionality. If you have any questions, feel free to reach out to us for assistance. Happy coding!

9. License

The library is licensed under the [GNU Lesser General Public License v3.0](https://www.gnu.org/licenses/lgpl-3.0.en.html), also included in our repository in the [LICENSE](https://github.com/bnb-chain/mindpress-data-marketplace/blob/main/LICENSE) file.

10. Disclaimer

The software and related documentation are under active development, all subject to potential future change without notification and not ready for production use. The code and security audit have not been fully completed and are not ready for any bug bounty. We advise you to be careful and experiment on the network at your own risk. Stay safe out there. --- ## Simple Tool for File Management > Source: https://docs.bnbchain.org/bnb-greenfield/for-developers/tutorials/app/file-management/basic-file-management/ # Building File Management Tool with Greenfield SDK Several Chain API libraries are available. These libraries manage the low-level logic of connecting to Greenfield node, making requests, and handing the responses. * [go-sdk](https://github.com/bnb-chain/greenfield-go-sdk) * [js-sdk](https://github.com/bnb-chain/greenfield-js-sdk) In this tutorial we’ll use the go-SDK library to interact with testnet. ## Prerequisites Before getting started, you should be familiar with: * [Greenfield basics](../../../../introduction.md) * Greenfield command line [examples](https://github.com/bnb-chain/greenfield-cmd#examples) Also, make sure you have the following dependencies installed with the latest version: * Go version above 1.20 ## Go-SDK Features * **basic.go** includes the basic functions to fetch the blockchain info. * **storage.go** includes the most storage functions such as creating a bucket, uploading files, downloading files, heading, and deleting resources. * **group.go** includes group-related functions such as creating a group and updating group member. * **payment.go** includes the payment-related functions to a management payment account. * **crosschain.go** includes the cross-chain-related functions to transfer or mirror resources to BSC. ## Setup ### Create a Go Project Let’s set up a Go project with the necessary dependencies. Init ```sh $ mkdir ~/hellogreenfield $ cd ~/hellogreenfield $ go mod init hellogreenfield ``` Add SDK Dependencies ```sh $ go get github.com/bnb-chain/greenfield-go-sdk ``` Edit go.mod to replace dependencies ```sh replace ( cosmossdk.io/api => github.com/bnb-chain/greenfield-cosmos-sdk/api v0.0.0-20230425074444-eb5869b05fe9 cosmossdk.io/math => github.com/bnb-chain/greenfield-cosmos-sdk/math v0.0.0-20230425074444-eb5869b05fe9 github.com/cometbft/cometbft => github.com/bnb-chain/greenfield-cometbft v0.0.2 github.com/cometbft/cometbft-db => github.com/bnb-chain/greenfield-cometbft-db v0.8.1-alpha.1 github.com/cosmos/cosmos-sdk => github.com/bnb-chain/greenfield-cosmos-sdk v0.2.3 github.com/cosmos/iavl => github.com/bnb-chain/greenfield-iavl v0.20.1-alpha.1 github.com/syndtr/goleveldb => github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 ) ``` Install dependensies ```sh go mod tidy ``` ### Test a simple function Now we’re ready to connect to Greenfield testnet and interact with the storage provider APIs. Let’s write a simple script to query the Greenfield version to verify if everything works as expected. Create a ```main.go``` file in your project and add the following code. ```go package main import ( "context" "log" "github.com/bnb-chain/greenfield-go-sdk/client" "github.com/bnb-chain/greenfield-go-sdk/types" ) const ( rpcAddr = "https://greenfield-chain.bnbchain.org:443" chainId = "greenfield_1017-1" /*testnet rpcAddr = "https://gnfd-testnet-fullnode-tendermint-us.bnbchain.org:443" chainId = "greenfield_5600-1" */ privateKey = "" ) func main() { account, err := types.NewAccountFromPrivateKey("test", privateKey) if err != nil { log.Fatalf("New account from private key error, %v", err) } cli, err := client.New(chainId, rpcAddr, client.Option{DefaultAccount: account}) if err != nil { log.Fatalf("unable to new greenfield client, %v", err) } ctx := context.Background() nodeInfo, versionInfo, err := cli.GetNodeInfo(ctx) if err != nil { log.Fatalf("unable to get node info, %v", err) } log.Printf("nodeInfo moniker: %s, go version: %s", nodeInfo.Moniker, versionInfo.GoVersion) latestBlock, err := cli.GetLatestBlock(ctx) if err != nil { log.Fatalf("unable to get latest block, %v", err) } log.Printf("latestBlock header: %s", latestBlock.Header) heightBefore := latestBlock.Header.Height log.Printf("Wait for block height: %d", heightBefore) err = cli.WaitForBlockHeight(ctx, heightBefore+10) if err != nil { log.Fatalf("unable to wait for block height, %v", err) } height, err := cli.GetLatestBlockHeight(ctx) if err != nil { log.Fatalf("unable to get latest block height, %v", err) } log.Printf("Current block height: %d", height) } ``` Run the following command in your project directory: ``` go run main.go ``` This will output something like: ``` 2023/09/12 22:18:10 nodeInfo moniker: fullnode, go version: go version go1.20.7 linux/amd64 2023/09/12 22:18:10 latestBlock header: {{%!s(uint64=11) %!s(uint64=0)} greenfield_5600-1 %!s(int64=401149) 2023-09-13 04:18:05.661693468 +0000 UTC { "header": { "version": { "block": "11", "app": "0" }, "chain_id": "greenfield_5600-1", "height": "401149", "time": "2023-09-13T04:18:05.661693468Z", "last_block_id": { "hash": "KenBGYDrtA7Bnyy6j3R3d16GWuHnIl5gJW0J3kmM4r8=", "part_set_header": { "total": 1, "hash": "W6nmeVJEhHinvI4I6HBsU/A87Zma8DVVvddBATJdctE=" } }, "last_commit_hash": "/G92Jzr8fPpqKY89F3xa3dytOF8a2HLvqCrccm9scXM=", "data_hash": "47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=", "validators_hash": "FykCd/548F1J28ssZr71B1805hzxENaQvexsW/Dxo3E=", "next_validators_hash": "FykCd/548F1J28ssZr71B1805hzxENaQvexsW/Dxo3E=", "consensus_hash": "FgA8CM0pWCco2OYq8pA9tuklVX8bmHmMV2Ssdj31W4E=", "app_hash": "wv+XqXhJBQPYpat/Obaj00u86KfJ8le4LIIFFAgqVmA=", "last_results_hash": "f6XeDeH8QasoTSGpSJL0r2WGE4MlrXOVt0cE3bIQE8I=", "evidence_hash": "47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=", "proposer_address": "KhlQ9bz1O8iaWZnqKe36m3IpcP4=", "randao_mix": "/6zQmCJztTeqZIRHe/pXxhgSbfwDLE85awoa4c8sShUUwGGLqFyshMag63MTB7JC2fAsUqPg1ryALY+uQNZ3Bw==" } } 2023/09/12 22:18:10 Wait for block height: 401149 2023/09/12 22:18:34 Current block height: 401159 ``` If everything is set up correctly, your code will be able to connect to the Greenfield node and return the chain data as shown above. ## Get Chain Data In the previous step, we created a ```main.go``` file to demonstrate the basic steps to connect to the node and initialize a ```Client``` to query chain data. Next, let’s use some more functions. Get current chain head: We can add the following code in main.go to query current head of the chain. ```go blockByHeight, err := cli.GetBlockByHeight(ctx, height) if err != nil { log.Fatalf("unable to get block by height, %v", err) } log.Printf("Current block height: %d", blockByHeight.Header) ``` ## Get Address balance With a given greenfield wallet address, you can query its balance by calling ```GetAccountBalance``` function. ```go balance, err := cli.GetAccountBalance(ctx, account.GetAddress().String()) if err != nil { log.Fatalf("unable to get balance, %v", err) } log.Printf("%s Current balance: %s", account.GetAddress().String(), balance.String()) ``` Apart from the basic data queries shown above, there are many more features. Please see the [JSON-RPC API Reference](../../../network-endpoint/endpoints.md) for all Greenfield API definitions. ## Manage Wallet Greenfield wallets hold addresses that you can use to manage objects, sign transactions, and pay for gas fees. In this section, we will demonstrate different ways to manage your wallet. 1. First, let’s make sure your connected node is running and the wallet address contains some testnet BNB. 2. Create a new file called ```account.go``` in the same project as earlier. This is where we’ll write all out wallet-related code. 3. In ```account.go``` import modules and initialize your private key or mnemonic phrase. ```go //import mnemonic account, err := types.NewAccountFromMnemonic("test", mnemonic) //import private key account, err := types.NewAccountFromPrivateKey("test", privateKey) ``` Let’s create a second wallet address so we can test transfers. The new address will be created locally and start with 0 token balance: ```go account2, _, err := types.NewAccount("test2") ``` Now, let’s try to transfer tBNB to this new address. Under the hood, this will create a transaction to transfer tBNB from fromAddress to toAddress, sign the transaction using SDK, and send the signed transaction to the Greenfield node. ```go transferTxHash, err := cli.Transfer(ctx, account2.GetAddress().String(), math.NewIntFromUint64(10000000000), types2.TxOption{}) if err != nil { log.Fatalf("unable to send, %v", err) } log.Printf("Transfer response: %s", transferTxHash) waitForTx, err := cli.WaitForTx(ctx, transferTxHash) log.Printf("Wair for tx: %s", waitForTx.TxResult.String()) balance, err = cli.GetAccountBalance(ctx, account2.GetAddress().String()) ``` Run the code to test the transfer of tBNB: ```sh go run account.go ``` This will output something like: ``` 2023/09/07 11:18:51 Wair for tx: data:"\022&\n$/cosmos.bank.v1beta1.MsgSendResponse\032\010\000\000\000\000\000\000\372\235" log:"[{\"msg_index\":0,\"events\":[{\"type\":\"message\",\"attributes\":[{\"key\":\"action\",\"value\":\"/cosmos.bank.v1beta1.MsgSend\"},{\"key\":\"sender\",\"value\":\"0x525482AB3922230e4D73079890dC905dCc3D37cd\"},{\"key\":\"module\",\"value\":\"bank\"}]},{\"type\":\"coin_spent\",\"attributes\":[{\"key\":\"spender\",\"value\":\"0x525482AB3922230e4D73079890dC905dCc3D37cd\"},{\"key\":\"amount\",\"value\":\"10000000000BNB\"}]},{\"type\":\"coin_received\",\"attributes\":[{\"key\":\"receiver\",\"value\":\"0x525482AB3922230e4D73079890dC905dCc3D37cd\"},{\"key\":\"amount\",\"value\":\"10000000000BNB\"}]},{\"type\":\"transfer\",\"attributes\":[{\"key\":\"recipient\",\"value\":\"0x525482AB3922230e4D73079890dC905dCc3D37cd\"},{\"key\":\"sender\",\"value\":\"0x525482AB3922230e4D73079890dC905dCc3D37cd\"},{\"key\":\"amount\",\"value\":\"10000000000BNB\"}]},{\"type\":\"message\",\"attributes\":[{\"key\":\"sender\",\"value\":\"0x525482AB3922230e4D73079890dC905dCc3D37cd\"}]}]}]" gas_wanted:1200 gas_used:1200 events: attributes: > events: attributes: > events: attributes: attributes: > events: > events: attributes: > events: > events: attributes: attributes: > events: attributes: > events: attributes: > events: attributes: attributes: > events: > ``` ## Make a storage deal Storing data is one of the most important features of Greenfield. In this section, we’ll walk through the end-to-end process of storing your data on the Greenfield network. We’ll start by importing your data, then make a storage deal with a storage provider, and finally wait for the deal to complete. ### 1. Create a main file Create a ```storage.go``` file in your demo project and add the following boilerplate code: ```go func main() {​ // initialize account account, err := types.NewAccountFromPrivateKey("test", privateKey) log.Println("address info:", account)​ if err != nil { log.Fatalf("New account from private key error, %v", err) } //initialize client cli, err := client.New(chainId, rpcAddr, client.Option {DefaultAccount: account}) if err != nil { log.Fatalf("unable to new greenfield client, %v", err) } ctx := context.Background()​ // 1. choose storage provider // 2. Create a bucket // 3. Upload your data and set a quota ​ } ``` ### 2. Choose your own SP You can query the list of SP. ```go // get storage providers list spLists, err := cli.ListStorageProviders(ctx, true) if err != nil { log.Fatalf("fail to list in service sps") } //choose the first sp to be the primary SP primarySP := spLists[0].GetOperatorAddress() ``` ### 3. Create your bucket Bucket can be private or public. You can customize it with options. * VISIBILITY_TYPE_PUBLIC_READ * VISIBILITY_TYPE_PRIVATE ```go chargedQuota := uint64(10000000) visibility := storageTypes.VISIBILITY_TYPE_PUBLIC_READ opts := types.CreateBucketOptions{Visibility: visibility, ChargedQuota: chargedQuota} bucketTx, err := cli.CreateBucket(ctx, bucketName, primarySP, opts) if err != nil { log.Fatalf("unable to send, %v", err) } log.Printf("Create bucket response: %s", bucketTx) ``` To understand how does `quota` work, read [this doc](../../../../core-concept/billing-payment.md#storage-service-fee). ### 4. Upload your object Objects can also be private or public. Uploading objects is composed of two parts: create and put. * ```CreateObject``` gets an approval of creating an object and sends createObject txn to Greenfield network. * ```PutObject``` supports the second stage of uploading the object to bucket. ```go // create and put object var buffer bytes.Buffer line := `0123456789` for i := 0; i < objectSize/10; i++ { buffer.WriteString(fmt.Sprintf("%s", line)) } txnHash, err := cli.CreateObject(ctx, bucketName, objectName, bytes.NewReader(buffer.Bytes()), types.CreateObjectOptions{}) handleErr(err, "CreateObject") err = cli.PutObject(ctx, bucketName, objectName, int64(buffer.Len()), bytes.NewReader(buffer.Bytes()), types.PutObjectOptions{TxnHash: txnHash}) handleErr(err, "PutObject") log.Printf("object: %s has been uploaded to SP\n", objectName) waitObjectSeal(cli, bucketName, objectName) ``` ```go func waitObjectSeal(cli client.Client, bucketName, objectName string) { ctx := context.Background() // wait for the object to be sealed timeout := time.After(15 * time.Second) ticker := time.NewTicker(2 * time.Second) for { select { case <-timeout: err := errors.New("object not sealed after 15 seconds") handleErr(err, "HeadObject") case <-ticker.C: objectDetail, err := cli.HeadObject(ctx, bucketName, objectName) handleErr(err, "HeadObject") if objectDetail.ObjectInfo.GetObjectStatus().String() == "OBJECT_STATUS_SEALED" { ticker.Stop() fmt.Printf("put object %s successfully \n", objectName) return } } } } ``` The primary SP syncs with secondary SPs to set up the data redundancy, and then it signs a `Seal` transaction with the finalized metadata for storage. If the primary SP determines that it doesn't want to store the file due to whatever reason, it can also "SealReject" the request. ### 5. Object management #### 5.1 Read object You can call ```GetObject``` function to download data. ```go // get object reader, info, err := cli.GetObject(ctx, bucketName, objectName, types.GetObjectOptions{}) handleErr(err, "GetObject") log.Printf("get object %s successfully, size %d \n", info.ObjectName, info.Size) handleErr(err, "GetObject") objectBytes, err := io.ReadAll(reader) fmt.Printf("Read data: %s\n", string(objectBytes)) ``` #### 5.2 Update object visibility * You can call ```UpdateBucketVisibility``` to change bucket visibility * You can call ```UpdateObjectVisibility``` to change object visibility ```go //update bucket visibility updateBucketTx, err := cli.UpdateBucketVisibility(ctx, bucketName, storageTypes.VISIBILITY_TYPE_PRIVATE, types.UpdateVisibilityOption{}) resp, err := cli.WaitForTx(ctx, updateBucketTx) fmt.Printf("Update response: %s\n", resp) handleErr(err, "UpdateBucketVisibility") // Update object visibility updateObjectTx, err := cli.UpdateObjectVisibility(ctx, bucketName,objectName, storageTypes.VISIBILITY_TYPE_PRIVATE, types.UpdateObjectOption{}) resp, err := cli.WaitForTx(ctx, updateObjectTx) fmt.Printf("Update response: %s\n", resp) handleErr(err, "UpdateObjectVisibility") ``` #### 5.3 Delete object The function DeleteObject support deleting objects. ```go // delete object delTx, err := cli.DeleteObject(ctx, bucketName, objectName, types.DeleteObjectOption{}) handleErr(err, "DeleteObject") _, err = cli.WaitForTx(ctx, delTx) if err != nil { log.Fatalln("txn fail") } log.Printf("object: %s has been deleted\n", objectName) ``` ## Conclusion Congratulations on making it all the way through this tutorial! In this tutorial, we learned the basics of interacting with the Greenfield network using SDK library. ### Source Code * [Go-SDK](https://github.com/bnb-chain/greenfield-go-sdk/blob/master/examples/storage.go) * [JS-SDK](https://github.com/bnb-chain/greenfield-js-sdk/blob/main/examples/nodejs/storage.js) --- ## Simple Tool for File Management (JS) > Source: https://docs.bnbchain.org/bnb-greenfield/for-developers/tutorials/app/file-management/js-file-managemet/ # Building File Management Tool with Greenfield SDK (JS) Several Chain API libraries are available. These libraries manage the low-level logic of connecting to the Greenfield node, making requests, and handing the responses. * [go-sdk](https://github.com/bnb-chain/greenfield-go-sdk) * [js-sdk](https://github.com/bnb-chain/greenfield-js-sdk) In this tutorial, we’ll use the JS-SDK library to interact with testnet. ## Prerequisites Before getting started, you should be familiar with: * [Greenfield basics](../../../../introduction.md) * Follow the instructions provided in [Token Transfer](../../../../getting-started/token-transfer.md). Please be aware that if your account does not have any BNB, the transaction will not be executed. ## Setup ### Create Project === "Browser" Follow [Quick Start](https://docs.bnbchain.org/greenfield-js-sdk/getting-started/quick-start) to create the project. === "Nodejs" Create a new `index.js`: ```bash title="Nodejs create project" > mkdir gnfd-app > cd gnfd-app > touch index.js ``` Install SDK: ```bash title="npm install deps" > npm init -y > npm add @bnb-chain/greenfield-js-sdk ``` ### Create Greenfield Client === "Browser" ```js title="Create testnet Client" import { Client } from '@bnb-chain/greenfield-js-sdk'; const client = Client.create('https://gnfd-testnet-fullnode-tendermint-ap.bnbchain.org, '5600'); ``` === "Nodejs" ```js title="Create testnet client" const {Client} = require('@bnb-chain/greenfield-js-sdk'); // testnet const client = Client.create('https://gnfd-testnet-fullnode-tendermint-ap.bnbchain.org', '5600'); ``` ### Test a simple function === "Browser" ```jsx { const latestBlockHeight = await client.basic.getLatestBlockHeight(); alert(JSON.stringify(latestBlockHeight)); }} > getLatestBlockHeight ``` === "Nodejs" ```js title="index.js" ;(async () => { const latestBlockHeight = await client.basic.getLatestBlockHeight() console.log('latestBlockHeight', latestBlockHeight) })() ``` Run `index.js` to get the latest block height: ```bash > node index.js ``` This will output like: ```bash latestBlockHeight 3494585 ``` ## Get Address balance In the previous step, we verified that the client was OK. Now we try more features for an account. === "Browser" ```jsx { if (!address) return; const balance = await client.account.getAccountBalance({ address: address, denom: 'BNB', }); alert(JSON.stringify(balance)); }} > getAccountBalance ``` === "Nodejs" You can query an account's balance by calling `account.getAccountBalance` function. ```js title="get account's balance" ;(async () => { const balance = await client.account.getAccountBalance({ address: '0x1C893441AB6c1A75E01887087ea508bE8e07AAae', denom: 'BNB' }) console.log('balance: ', balance) })() ``` Run `node index.js` to get the account's balance: ```text balance: { balance: { denom: 'BNB', amount: '4804586044359520195' } } ``` Apart from the basic data queries shown above, there are many more features. Please see the [API Reference](https://docs.bnbchain.org/greenfield-js-sdk/category/api) for all Greenfield API definitions. ## Manage Wallet The wallet in Nodejs is generated by a private key, but the wallet plugin(MetaMask, CollectWallet, etc) can't get the user's private key in the browser, so another way is needed. === "Browser" ```jsx { if (!address) return; const transferTx = await client.account.transfer({ fromAddress: address, toAddress: '0x0000000000000000000000000000000000000000', amount: [ { denom: 'BNB', amount: '1000000000', }, ], }); const simulateInfo = await transferTx.simulate({ denom: 'BNB', }); const res = await transferTx.broadcast({ denom: 'BNB', gasLimit: Number(simulateInfo.gasLimit), gasPrice: simulateInfo.gasPrice, payer: address, granter: '', signTypedDataCallback: async (addr: string, message: string) => { const provider = await connector?.getProvider(); return await provider?.request({ method: 'eth_signTypedData_v4', params: [addr, message], }); }, }); if (res.code === 0) { alert('transfer success!!'); } }} > transfer ``` === "Nodejs" In general, we need to put the private key in the `.env` file and ignore this file in the `.gitignore` file (for account security). ```bash > touch .env ``` Add this information to `.env`: ```py # fill your account info ACCOUNT_PRIVATEKEY=0x... ACCOUNT_ADDRESS=0x... ``` Install `dotenv` dependencies(for loading variables from .env): ```bash > npm install dotenv ``` Everything is ready and we can transfer the transaction now. Create `transfer.js` file: ```js title="transfer.js" require('dotenv').config(); const {Client} = require('@bnb-chain/greenfield-js-sdk'); const client = Client.create('https://gnfd-testnet-fullnode-tendermint-ap.bnbchain.org', '5600'); ;(async () => { // construct tx const transferTx = await client.account.transfer({ fromAddress: process.env.ACCOUNT_ADDRESS, toAddress: '0x0000000000000000000000000000000000000000', amount: [ { denom: 'BNB', amount: '1000000000', }, ], }) // simulate transfer tx const simulateInfo = await transferTx.simulate({ denom: 'BNB', }); // broadcast transfer tx const res = await transferTx.broadcast({ denom: 'BNB', gasLimit: Number(simulateInfo.gasLimit), gasPrice: simulateInfo.gasPrice, payer: process.env.ACCOUNT_ADDRESS, granter: '', privateKey: process.env.ACCOUNT_PRIVATEKEY, }) console.log('res', res) })() ``` Running `node transfer.js`: More TxClient [References](https://docs.bnbchain.org/greenfield-js-sdk/client/tx-client). ## Make a storage deal Storing data is one of the most important features of Greenfield. In this section, we’ll walk through the end-to-end process of storing your data on the Greenfield network. We’ll start by importing your data, then make a storage deal with a storage provider, and finally wait for the deal to complete. ### 0. Create the main file === "Browser" The browser doesn't need the main file. === "Nodejs" ```bash > touch storage.js ``` ### 1. Choose your own SP You can query the list of SP: === "Browser" ```js title="utils/offchainAuth.ts" export const getSps = async () => { const sps = await client.sp.getStorageProviders(); const finalSps = (sps ?? []).filter((v: any) => v.endpoint.includes('nodereal')); return finalSps; }; export const getAllSps = async () => { const sps = await getSps(); return sps.map((sp) => { return { address: sp.operatorAddress, endpoint: sp.endpoint, name: sp.description?.moniker, }; }); }; export const selectSp = async () => { const finalSps = await getSps(); const selectIndex = Math.floor(Math.random() * finalSps.length); const secondarySpAddresses = [ ...finalSps.slice(0, selectIndex), ...finalSps.slice(selectIndex + 1), ].map((item) => item.operatorAddress); const selectSpInfo = { id: finalSps[selectIndex].id, endpoint: finalSps[selectIndex].endpoint, primarySpAddress: finalSps[selectIndex]?.operatorAddress, sealAddress: finalSps[selectIndex].sealAddress, secondarySpAddresses, }; return selectSpInfo; }; const getOffchainAuthKeys = async (address: string, provider: any) => { const storageResStr = localStorage.getItem(address); if (storageResStr) { const storageRes = JSON.parse(storageResStr) as IReturnOffChainAuthKeyPairAndUpload; if (storageRes.expirationTime < Date.now()) { alert('Your auth key has expired, please generate a new one'); localStorage.removeItem(address); return; } return storageRes; } const allSps = await getAllSps(); const offchainAuthRes = await client.offchainauth.genOffChainAuthKeyPairAndUpload( { sps: allSps, chainId: GREEN_CHAIN_ID, expirationMs: 5 * 24 * 60 * 60 * 1000, domain: window.location.origin, address, }, provider, ); const { code, body: offChainData } = offchainAuthRes; if (code !== 0 || !offChainData) { throw offchainAuthRes; } localStorage.setItem(address, JSON.stringify(offChainData)); return offChainData; }; ``` === "Nodejs" ```js title="storage.js" ;(async () => { // get storage providers list const sps = await client.sp.getStorageProviders() // choose the first up to be the primary SP const primarySP = sps[0].operatorAddress; })() ``` ### 2. Create your bucket Bucket can be private or public. You can customize it with options. `VisibilityType`: * `VISIBILITY_TYPE_PUBLIC_READ` * `VISIBILITY_TYPE_PRIVATE` ```jsx title="create bucket" import { Long, VisibilityType, RedundancyType, bytesFromBase64 } from '@bnb-chain/greenfield-js-sdk'; const createBucketTx = await client.bucket.createBucket( { bucketName: info.bucketName, creator: address, visibility: VisibilityType.VISIBILITY_TYPE_PUBLIC_READ, chargedReadQuota: Long.fromString('0'), primarySpAddress: spInfo.primarySpAddress, paymentAddress: address, }, ); const simulateInfo = await createBucketTx.simulate({ denom: 'BNB', }); console.log('simulateInfo', simulateInfo); const res = await createBucketTx.broadcast({ denom: 'BNB', gasLimit: Number(simulateInfo?.gasLimit), gasPrice: simulateInfo?.gasPrice || '5000000000', payer: address, granter: '', }); ``` ### 3. Create Object and Upload Object Objects can also be private or public. Getting the file's checksum needs [reed-solomon](https://github.com/bnb-chain/greenfield-js-sdk/tree/main/packages/reed-solomon): === "Browser" ```js import { ReedSolomon } from '@bnb-chain/reed-solomon'; const rs = new ReedSolomon(); // file is File type const fileBytes = await file.arrayBuffer(); const expectCheckSums = rs.encode(new Uint8Array(fileBytes)); ``` === "Nodejs" ```js const fs = require('node:fs'); const { NodeAdapterReedSolomon } = require('@bnb-chain/reed-solomon/node.adapter'); const filePath = './CHANGELOG.md'; const fileBuffer = fs.readFileSync(filePath); const rs = new NodeAdapterReedSolomon(); const expectCheckSums = await rs.encodeInWorker(__filename, Uint8Array.from(fileBuffer)); ``` Getting approval of creating an object and sending `createObject` txn to the Greenfield network: ```jsx const createObjectTx = await client.object.createObject( { bucketName: info.bucketName, objectName: info.objectName, creator: address, visibility: VisibilityType.VISIBILITY_TYPE_PRIVATE, contentType: fileType, redundancyType: RedundancyType.REDUNDANCY_EC_TYPE, payloadSize: Long.fromInt(fileBuffer.length), expectChecksums: expectCheckSums.map((x) => bytesFromBase64(x)), }, ); const simulateInfo = await createObjectTx.simulate({ denom: 'BNB', }); const res = await createObjectTx.broadcast({ denom: 'BNB', gasLimit: Number(simulateInfo?.gasLimit), gasPrice: simulateInfo?.gasPrice || '5000000000', payer: address, granter: '', }); ``` Upload Object: === "Browser" ```jsx await client.object.uploadObject( { bucketName: info.bucketName, objectName: info.objectName, body: info.file, txnHash: txnHash, }, { type: 'EDDSA', domain: window.location.origin, seed: offChainData.seedString, address, }, ); ``` === "Nodejs" ```js await client.object.uploadObject( { bucketName: bucketName, objectName: objectName, body: createFile(filePath), txnHash: createObjectTxRes.transactionHash, }, { type: 'ECDSA', privateKey: ACCOUNT_PRIVATEKEY, } ); // convert buffer to file function createFile(path) { const stats = fs.statSync(path); const fileSize = stats.size; return { name: path, type: '', size: fileSize, content: fs.readFileSync(path), } } ``` ### 4. Object management #### 4.1 Download object === "Browser" ```jsx await client.object.downloadFile( { bucketName: info.bucketName, objectName: info.objectName, }, { type: 'EDDSA', address, domain: window.location.origin, seed: offChainData.seedString, }, ); ``` === "Nodejs" ```js title="manage.js" ;(async () => { // download object const res = await client.object.getObject({ bucketName: 'extfkdcxxd', objectName: 'yhulwcfxye' }, { type: 'ECDSA', privateKey: ACCOUNT_PRIVATEKEY, }) // res.body is Blob console.log('res', res) const buffer = Buffer.from([res.body]); fs.writeFileSync('your_output_file', buffer) })() ``` #### 4.2 Update object visibility === "Browser" ```jsx const tx = await client.object.updateObjectInfo({ bucketName: info.bucketName, objectName: info.objectName, operator: address, visibility: 1, }); const simulateTx = await tx.simulate({ denom: 'BNB', }); const res = await tx.broadcast({ denom: 'BNB', gasLimit: Number(simulateTx?.gasLimit), gasPrice: simulateTx?.gasPrice || '5000000000', payer: address, granter: '', }); ``` === "Nodejs" ```js const tx = await client.object.updateObjectInfo({ bucketName: 'extfkdcxxd', objectName: 'yhulwcfxye', operator: ACCOUNT_ADDRESS, visibility: 1, }) const simulateTx = await tx.simulate({ denom: 'BNB', }) const createObjectTxRes = await tx.broadcast({ denom: 'BNB', gasLimit: Number(simulateTx?.gasLimit), gasPrice: simulateTx?.gasPrice || '5000000000', payer: ACCOUNT_ADDRESS, granter: '', privateKey: ACCOUNT_PRIVATEKEY, }); ``` #### 4.3 Delete Object === "Browser" ```jsx const tx = await client.object.deleteObject({ bucketName: info.bucketName, objectName: info.objectName, operator: address, }); const simulateTx = await tx.simulate({ denom: 'BNB', }); const res = await tx.broadcast({ denom: 'BNB', gasLimit: Number(simulateTx?.gasLimit), gasPrice: simulateTx?.gasPrice || '5000000000', payer: address, granter: '', }); ``` === "Nodejs" ```js ;(async () => { const tx = await client.object.deleteObject({ bucketName: 'extfkdcxxd', objectName: 'yhulwcfxye', operator: ACCOUNT_ADDRESS, }); const simulateTx = await tx.simulate({ denom: 'BNB', }) const createObjectTxRes = await tx.broadcast({ denom: 'BNB', gasLimit: Number(simulateTx?.gasLimit), gasPrice: simulateTx?.gasPrice || '5000000000', payer: ACCOUNT_ADDRESS, granter: '', privateKey: ACCOUNT_PRIVATEKEY, }); if (createObjectTxRes.code === 0) { console.log('delete object success') } })() ``` ## Conclusion Congratulations on making it through this tutorial! In this tutorial, we learned the basics of interacting with the Greenfield network using the SDK library. ### Tutorials Source Code * [Nodejs File Management](https://github.com/bnb-chain/greenfield-js-sdk/tree/main/examples/nodejs-file-management) * [Browser File Management](https://github.com/bnb-chain/greenfield-js-sdk/tree/main/examples/browser-file-management) --- ## Dataset Batch operations > Source: https://docs.bnbchain.org/bnb-greenfield/for-developers/tutorials/app/file-management/batch-upload/ # How does batch object uploading work in Greenfield? In `Greenfield`, uploading an object to a bucket is a two-stage process. First, a transaction including the object metadata needs to be broadcasted to the Greenfield Chain and confirmed. After confirmation, PUT the object to a Greenfield Storage Provider. In the first stage, every transaction needs to be signed by the primary key(also known as `account`, refer to [accounts](../../../../core-concept/accounts.md) for more details). And if you are accessing `Greenfield` via front-end app and connecting wallet like Metamask(or other compatible wallets), you will be asked for approval to sign the transaction. For people who may have encountered the need to upload large amounts of objets, while uploading objects to `Greenfield` individually can be a time-consuming and tedious process, because they have to repeatedly approve wallet's pop-up requests to send transactions, batch uploading can be a quick and efficient solution to this problem. ## Ways to Perform Batch Uploading We would introduce two ways to achive the purpose of batch uploading: ### Multi-Message. `Greenfield` supports supports embedding multiple messages in a single transaction. You can create a transaction with multiple `MsgCreateObject` messages and broadcast it to the Greenfield Chain. Once the object metadata is confirmed on-chain, you can start PUTting the objects to the Storage Provider. However, please note that this approach may not be suitable for very large batches due to transaction size limitations in Greenfield. ### Temporary Account. Create a temporary account at runtime and grant it full permissions to create objects on behalf of your primary account. In this approach, your primary account only needs to send a transaction to Greenfield to grant permissions to the temporary account. For each object to be uploaded, the temporary account will be used to broadcast the transaction to the Greenfield Chain. There is no further interaction required from the primary account. Please note, the temporary account does not need to be deposited. ### Bundle Service Storing small files in Greenfield is inefficient due to the metadata stored on the blockchain being larger than the files themselves. This leads to higher costs for users. Additionally, Greenfield Blockchain has a capacity limit for processing files simultaneously. To address this issue, we have proposed [BEP-323: Bundle Format For Greenfield](https://github.com/bnb-chain/BEPs/pull/323). This repository contains the Golang version of the bundle format, which guides users on aggregating objects into a bundle and parsing a bundled object into separate objects. ## Temporary Account Showcase To demonstrate the batch uploading process using the Temporary Account approach, an example is provided using the `Greenfield-go-sdk`. The example includes steps to create a bucket for object storage, generate a temporary account, grant permissions to the temporary account, and create and PUT objects. ### Create a bucket for object storage. Before we get started, we would need to create a bucket to hold objects using the primary account. This requires broadcasting a transaction to `Greenfield`. The code below shows how to fill in the `CreateBucket` request with the bucket name and selected Storage Provider that will serve our bucket, after the transaction is sent, you might want to check the bucket's existence to confirm its creation. ```go primaryAccount, _ := types.NewAccountFromPrivateKey("primaryAccount", privateKey) cli, _ := client.New(chainId, rpcAddr, client.Option{DefaultAccount: primaryAccount}) ctx := context.Background() // get storage providers list isInService := true spLists, _ := cli.ListStorageProviders(ctx, isInService) // choose the first sp to be the primary SP, you are free to choose any other one primarySP := spLists[0].GetOperatorAddress() // sends a request to Greenfield to create a bucket. cli.CreateBucket(ctx, "yourBucketName", primarySP, types.CreateBucketOptions{}) // wait for confirmation time.Sleep(3 * time.Second) // get bucket meta data from Greenfield bucketInfo, _ := cli.HeadBucket(ctx, "yourBucketName") ``` ### Temporary account generation Once the bucket is created, we can start generating the temporary account. A private key is 32 bytes represented as a 64 hexadecimal character string. We can create any random 64 hexadecimal character string to form a private key. However, in that case, we won't be able to recover it and reuse in the future. So, it is more preferred to use a designed payload to generate the private key. In the code snippet below, we concatenate a `signPayload` by string "payload" and the account sequence, We then use the signature signed by our primary account to form a newly created private key. The `signPayload` acts like a password. No matter what manipulation is applied to the `signPayload` to generate the signature, as long as we remember the `signPayload`, we can always retrieve the private key by applying the same manipulation again. The example shown here is just one way to get the signature and used for new temporary priavte key, but you are free to use any other algorithm. ```go // generate the temp account using user's primary account signing on payload decided by user, here we add the account nonce to be part of sign payload signPayload := fmt.Sprintf("payload%d", primaryAccount.GetSequence()) tempAcct, _ := genTemporaryAccount(primaryAccount, signPayload) tempAcctAddr, _ := tempAcct.GetAddress().Marshal() ``` ```go // genTemporaryAccount generates a temporary account, the signPayload is to be signed by user's own private key(Primary account), // and the signature is used to generate the temporary account's private key. // User can reconvert account with the signPayload at any time func genTemporaryAccount(acct *types.Account, signPayload string) (*types.Account, error) { signBz := []byte(signPayload) sig, err := acct.Sign(tmhash.Sum(signBz)) if err != nil { return nil, err } if len(sig) < privateKeyLength { return nil, fmt.Errorf("required signature lenght is no less than %d, cur lenght %d", privateKeyLength, len(sig)) } return types.NewAccountFromPrivateKey("temp", hex.EncodeToString(sig[:privateKeyLength])) } ``` ### Grant temporary account permissions To entitle the temporary account to create objects on behalf of the primary account, two types of permissions are required. Both need to be granted by the primary account: - Grant the creating object permission in the bucket. `Policy` defines that the operation that can be enforced on a resource by an account or a group. Refer to [permission](https://github.com/bnb-chain/greenfield/blob/master/docs/modules/permission.md) to get more details - Grant an allowance so that the gas fee will be deducted from the primary account, and the primary account will be the owner of objects. Again, we would need to broadcast transaction including these two types of granting messages to `Greenfield` using the primary account. ```go // Grant the temporary account creating objects permission in the primary account's bucket statement := &permTypes.Statement{ Actions: []permTypes.ActionType{permTypes.ACTION_CREATE_OBJECT}, Effect: permTypes.EFFECT_ALLOW, } msgPutPolicy := storageTypes.NewMsgPutPolicy(primaryAccount.GetAddress(), gnfdTypes.NewBucketGRN("yourBucketName").String(), permTypes.NewPrincipalWithAccount(tempAcct.GetAddress()), []*permTypes.Statement{statement}, nil) // Grant allowance to the temporary account to broadcast the expected transaction type allowedMsg := make([]string, 0) allowedMsg = append(allowedMsg, "/greenfield.storage.MsgCreateObject") allowance, _ := feegrant.NewAllowedMsgAllowance(&feegrant.BasicAllowance{}, allowedMsg) msgGrantAllowance, _ := feegrant.NewMsgGrantAllowance(allowance, primaryAccount.GetAddress(), tempAcct.GetAddress()) // Broadcast the transaction to Greenfield cli.BroadcastTx(ctx, []sdk.Msg{msgGrantAllowance, msgPutPolicy}, types.TxOption{}) // Wait for a block and confirm that permissions are granted ``` ### Create object meta and put object Finally, you can create the object metadata and put the object using the temporary account: ```go // Switch to use the temporary account cli.SetDefaultAccount(tempAcct) // Define the primary account as the granter txOpt := types.TxOption{FeeGranter: primaryAccount.GetAddress()} // create object content var buffer bytes.Buffer line := `0123456789` for i := 0; i < 100; i++ { buffer.WriteString(fmt.Sprintf("%s", line)) } // Create the object meta on Greenfield Chain cli.CreateObject(ctx, "yourBucketName", "yourObjectName", bytes.NewReader(buffer.Bytes()), types.CreateObjectOptions{TxOpts: &txOpt}) // Wait for a block, once the meta is created on the chain, upload the object to the Greenfield Storage Provider time.Sleep(3 * time.Second) // Upload the object to Greenfield Storage Provider cli.PutObject(ctx, "yourBucketName", "yourObjectName", int64(buffer.Len()), bytes.NewReader(buffer.Bytes()), types.PutObjectOptions{}) ``` ## Bundle Service Example Here is the guide for how to aggregate batch objects as a bundle, and how to parse a bundled object. As for how to interact with Greenfield, you should refer to 【Greenfield GO SDK](https://github.com/bnb-chain/greenfield-go-sdk). ### Aggregate various objects as bundle Follow the steps below to aggregate multiple objects into a single bundle. 1. Use the `NewBundle `function to create an empty bundle. ```go // Assemble above two objects into a bundle object bundle, err := bundle.NewBundle() handleErr(err, "NewBundle") ``` 2. Use the bundle's `AppendObject` method to add objects to the bundle individually. ```go _, err = bundle.AppendObject("object1", bytes.NewReader(buffer1.Bytes()), nil) handleErr(err, "AppendObject") _, err = bundle.AppendObject("object2", bytes.NewReader(buffer2.Bytes()), nil) handleErr(err, "AppendObject") ``` 3. Use the bundle's `FinalizeBundle` method to seal the bundle, preventing any further objects from being added. ```go bundledObject, totalSize, err := bundle.FinalizeBundle() handleErr(err, "FinalizeBundle") ``` 4. To release resources after use, utilize the Close method of the bundle. ```go defer bundle.Close() ``` Full example [here](https://github.com/bnb-chain/greenfield-bundle-sdk/blob/master/examples/upload_bundle.go) ### Extract objects from bundled object Follow the steps below to extract various objects from a bundle. 1. Open the bundled object as a bundle instance using `NewBundleFromFile`. ```go // Extract objects from bundled object bundle, err := bundle.NewBundleFromFile(bundleFile.Name()) handleErr(err, "NewBundleFromFile") ``` 2. Retrieve all the objects' meta within the bundle using the bundle's `GetBundleObjectsMeta` method. ```go // Extract objects from bundled object objMeta, err := bundle.GetBundleObjectsMeta(bundleFile.Name()) handleErr(err, "GetBundleObjectsMeta") ``` 3. Access various objects one by one using the bundle's `GetObject` method. ```go obj1, size, err := bundle.GetObject("object1") if err != nil || obj1 == nil || size != singleObjectSize { handleErr(fmt.Errorf("parse object1 in bundled object failed: %v", err), "GetObject") } obj2, size, err := bundle.GetObject("object2") if err != nil || obj2 == nil || size != singleObjectSize { handleErr(fmt.Errorf("parse object2 in bundled object failed: %v", err), "GetObject") } ``` 4. To release resources after use, utilize the Close method of the bundle. ```go defer bundle.Close() ``` Full example [here](https://github.com/bnb-chain/greenfield-bundle-sdk/blob/master/examples/download_bundle.go) --- ## Resumable Upload/Download Demo > Source: https://docs.bnbchain.org/bnb-greenfield/for-developers/tutorials/app/file-management/resumable-upload/overview/ # Resumable Upload & Resumable Download * Resumable Upload is a feature that allows files to be uploaded in multiple parts, enabling the upload process to be resumed from where it left off in case of interruptions or failures. This is particularly useful for large files or situations where network connectivity may be unreliable. * Resumable Download is a common download method in greenfield, which allows users to pause or interrupt the download process and resume it later. When a user requests to download a large file, it is often divided into multiple fixed-size chunks, and the download process uses the HTTP Range request header to specify the starting and ending positions for the download. If the user pauses or interrupts the download, the next request can resume the download from the last position by sending a request with an appropriate Range field, without having to re-download the entire file. ## Resumable Upload Resumable upload refers to the process of uploading a file in multiple parts, where each chunk is uploaded separately.This allows the upload to be resumed from where it left off in case of interruptions or failures, rather than starting the entire upload process from the beginning. During resumable upload, if an error occurs during the `PutObject` operation, the subsequent upload attempts will first query the server-side for the progress of the previous upload. It will then resume the upload from the last offset. ### Upload Process Overview 1. Start the initial `PutObject` operation to upload the object. 2. If an error occurs during the upload, such as a network interruption or server error, the upload process is interrupted. 3. When resuming the upload, the next `PutObject` operation will initiate a query to the server to retrieve the progress of the previous upload. 4. The server responds with the last offset from which the upload needs to resume. 5. The `PutObject` operation resumes the upload from offset received from the server. 6. The upload process continues from the point of interruption until completion. ### PutObject Options The `PutObject` operation in the Greenfield GO-SDK API allows you to upload an object to a bucket. It provides additional options for configuration through the `PutObjectOptions` struct. This document describes two new options introduced in the `PutObjectOptions` struct. - PartSize (Default: 16 MB) The `PartSize` option determines the size of each part when uploading large objects. If the size of the object is smaller than the `PartSize`, it will be uploaded as a single part. However, if the object size is larger and the `DisableResumable` option is set to `false`, resumable upload will be enabled. indicate the resumable upload 's part size, uploading a large file in multiple parts. The part size is an integer multiple of the segment size. - DisableResumable (Default: false) The `DisableResumable` option determines whether resumable upload is enabled. When set to `false`, resumable upload is enabled, allowing for the upload to be resumed if interrupted or failed. This is especially useful for large objects. If set to `true`, resumable upload is disabled. indicate whether need to enable resumeable upload. Resumable upload refers to the process of uploading a file in multiple parts, where each part is uploaded separately.This allows the upload to be resumed from where it left off in case of interruptions or failures, rather than starting the entire upload process from the beginning. ### Usage Example ```go var buffer bytes.Buffer err := s.Client.PutObject( ctx, bucketName, objectName, int64(buffer.Len()), bytes.NewReader(buffer.Bytes()), types.PutObjectOptions{ PartSize: 1024 * 1024 * 16, // 16 MB DisableResumable: false, }, ) ``` In the above example, we create a **`bytes.Buffer`** named **`buffer`** to hold the object data. We then use the **`PutObject`** operation to upload the object to the specified bucket and object name. The **`PutObjectOptions`** struct is passed with the desired options set. In this case, the **`PartSize`** is set to the default value of 16 MB, and the **`DisableResumable`** is set to false to enable resumable upload. Note: Make sure to replace the placeholder values (**`s.Client`**, **`s.ClientContext`**, **`bucketName`**, and **`objectName`**) with the actual variables or values relevant to your code. ## Resumable Download The `FGetObjectResumable` function in the S3 Client API allows you to perform resumable downloads for large files. This function downloads a file from the specified bucket and object name to a local file, with the ability to resume the download in case of errors or interruptions. ### Download Process Overview 1. Start the initial `FGetObjectResumable` function to download the file. 2. During the download process, the function retrieves segments of the file from the server-side and appends them to an `object_{operatoraddress}{getrange}.tmp` file. 3. If an error occurs during the download, such as a network interruption or server error, the download process is interrupted. 4. When resuming the download, the subsequent `FGetObjectResumable` function first checks if the `object_{operatoraddress}{getrange}.tmp` file exists. 5. If the `object_{operatoraddress}{getrange}.tmp` file exists, the function verifies the checksum to ensure the integrity of the partially downloaded file. 6. If the `object_{operatoraddress}{getrange}.tmp` file does not exist or the checksum is invalid, the function starts a fresh download of the object from the server. 7. The download process continues from the last offset, and appending the segments to the `object_{operatoraddress}{getrange}.tmp` file. 8. Once the download is complete, the `object_{operatoraddress}{getrange}.tmp` file can be renamed or processed as needed. ### Usage Example ``` err = s.Client.FGetObjectResumable( s.ClientContext, bucketName, objectName, newFile, types.GetObjectOptions{}, ) ``` In the above example, the **`FGetObjectResumable`** function is used to perform a resumable download of a file from the specified bucket and object name. If an error occurs during the download, the subsequent function calls will check the existence and validity of the **`object_{operatoraddress}{getrange}.tmp`** file, and resume the download from the last offset. ### Source code * [Go-SDK demo](https://github.com/bnb-chain/greenfield-go-sdk/blob/4940fb69df1258fcb232b92e1ed4894ead516583/e2e/e2e_storage_test.go#L452) --- ## Bundle Service > Source: https://docs.bnbchain.org/bnb-greenfield/for-developers/bundle-service/ With more and more developers joining BNB Greenfield ecosystem, many good practices utilizing decentralized storage continue to emerge. On the other hand, sending small files to Greenfield is not an economic way. When small files are sent, the information about the files (metadata) saved in the system can be bigger than the files themselves. This means it costs more for both the users and Greenfield. For instance, imagine a user's account wants to uploads a website to Greenfield. If the files of the website are tiny but there are a lot of them, it leads to the same problem: too much metadata and higher costs. BNB Chain has proposed the core protocol for the Greenfield bundle to solve this problem. You can find more details about [BEP-323](https://github.com/bnb-chain/BEPs/pull/323). NodeReal is the first infrastructure provider to implement the bundling service. Bundling service provides a solution to combine small files together into one big file before sending it to Greenfield. Thus, developers can can cut down unnecessary costs while still get to each file in the big file as if they were separate. NodeReal Bundling service is fully open sourced, developers can use NodeReal bundle service directly, while they can also deploy their own bundle service if needed. ## Bundle Format The bundle format specifies the structure and organization of the bundle that users create when packing files. This format is designed to pack flat files; hierarchical directory structures, or folders, are not supported. When dealing with a folder, we can simplify its structure by turning it into a series of individual files. As part of this process, we rename each file to include the folder path. For example, a file originally named file.txt inside the nested folders dira and dirb would be renamed to dira/dirb/file.txt. This approach allows us to maintain the organization of the folder while conforming to the requirement for flat files in the bundle. The bundle format is structured into several key components as follows: * Version: This indicates the version number of the bundle protocol being used. * Meta Size: This specifies the size of the bundle's metadata, allowing the construction of the bundle structure without the need to read the entire bundle. * Metadata: This section contains information about the files within the bundle. It facilitates the ability to access files randomly, which means you can jump directly to any file within the bundle without going through all the files. * Data: This portion represents the actual content and is comprised of all the files in bytes. For more details, you can refer to the [BEP-323](https://github.com/bnb-chain/BEPs/pull/323) and [Bundle-SDK](https://github.com/bnb-chain/greenfield-bundle-sdk). ## Bundle Service With the bundle format above, users now can pack their small objects into a bundle and upload the bundle file to Greenfield. But users can not visit the objects in the bundle file conveniently. The bundle service is designed to serve the users or dApps uploading a lot of small objects to Greenfield and provide an indexing service for the objects in the bundle. Users can upload small objects to the bundle service and the bundle service will pack the small files into a bundle and upload it to Greenfield, at the same time, the bundle service will also provide a URL to visit each object in the bundle file. The bundle service will upload the bundle file to the bucket that the user specified, so the user should grant the account of the bundle service permission to upload files to the bucket. Meanwhile, the user should also grant the transaction fee for the bundle service to upload objects to Greenfield. ### Architecture The bundle service contains two main components: API service and Bundler. #### API Service The API service will serve users' requests like uploading an object, querying an object, etc. #### Bundler The bundler will pack the objects that the user uploaded into a bundle file and upload it to a bucket in Greenfield. ### Main Workflows It is important to understand that the Bundler service uploads bundled files to the user's bucket, the user has absolute control over the bundle files. This level of control allows users to manage and manipulate their bundled files as needed effectively. The bundle service utilizes its own account to send transactions and submit bundled files to Greenfield. Users are responsible for covering the transaction fees, and they need to grant authorization to the bundler account to create new files under their bucket. Therefore, it is essential to complete the necessary authorization before using the bundler service. Greenfield can manage permissions for buckets and files. However, to keep the bundler service streamlined, complex permission management is currently not available. The bundler service only supports public buckets, allowing only the bucket owner to upload files. However, all users can access the files through the bundler service with no authorization. #### Grant Permission * Step 1: Before using the Bundle service, the user needs to create a bucket on Greenfield, and the visibility should be public. To create a bucket with the greenfield-go-sdk, use the following API. For a GUI option, you can use DCellar to create a new bucket. ```go func (c *Client) CreateBucket(ctx context.Context, bucketName string, primaryAddr string, opts types.CreateBucketOptions) (string, error) ``` * Step 2: To ensure optimal performance when uploading bundled files to Greenfield, the bundler service offers multiple operator addresses. The operator address is used to replace the user in uploading the bundled objects to Greenfield. Get the operator address for creating the bundled objects on Greenfield. * Step 3: Grant fee and permission to the operator address for creating bundled objects under the bucket. For the fee grant, you can only create a fee allowance for object creation. ```go func (c *Client) GrantAllowance(ctx context.Context, granteeAddr string, allowance feegrant.FeeAllowanceI, txOption gnfdsdktypes.TxOption) (string, error) // NewAllowedMsgAllowance creates new filtered fee allowance. func NewAllowedMsgAllowance(allowance FeeAllowanceI, allowedMsgs []string) (*AllowedMsgAllowance, error) ``` For the permission grant, you can use the following APIs to grant permission only for object creation. ```go func (c *Client) PutBucketPolicy(ctx context.Context, bucketName string, principalStr types.Principal, statements []*permTypes.Statement, opt types.PutPolicyOption, ) (string, error) func NewPrincipalWithAccount(principalAddr sdk.AccAddress) (types.Principal, error) func NewStatement(actions []permTypes.ActionType, effect permTypes.Effect, resource []string, opts types.NewStatementOptions, ) permTypes.Statement ``` #### Upload Object The bundle will be frozen if any of the following conditions are met: - The size of the bundle is equal to or greater than the MaxBundledSize, which has a default value of 1GB. - The number of objects in the current bundle is equal to or greater than the MaxBundledNumber, which has a default value of 1000. - The time interval since the creation of the bundle is equal to or greater than the MaxFinalizeTime, which has a default value of 24 hours. Users can also define their own rules for MaxBundledSize , MaxBundledNumber , and MaxFinalizeTime , but the values should not exceed the default ones. In this mode, when the previous bundle is frozen, if there are any new files uploaded, the bundler service will automatically create a new bundle for the user, eliminating the need for any additional user intervention. The bundles created by the bundler service follow the naming format of {bundle_prefix}_{bundle_nonce} . The bundle_prefix is bundle by default, and bundle_nonce is the number of bundles created in the bucket. In addition, users have the option to fully specify the lifecycle of a bundle by creating a new bundle using the "create bundle" API and then requesting to submit the bundle to Greenfield through the "seal bundle" API. It is important to note that the time from bundle creation to sealing should not exceed the DeaultMaxBundledTime of 24 hours. If this time limit is exceeded, the bundle service will automatically set the bundle as expired and the user can not finalize the bundle anymore. The bundler service is primarily designed to address the storage performance and efficiency issues associated with small files. Therefore, it is important to note that the file size uploaded to the bundle service should not exceed 16 MB. Any file exceeding this limit will be rejected by the bundle service. #### Upload Bundle Since users may want to upload files at the same time like uploading a website, the bundle service allows users to upload a valid bundle. You can use the [bundle commandline tool](https://github.com/bnb-chain/greenfield-bundle-sdk/tree/master?tab=readme-ov-file#command-line-tool) to easily combine small objects into a bundle. The bundle service will validate the uploaded bundle, if the bundle is invalid, the request will be rejected. For the valid bundle, it will index all the files in the bundle so the user can visit the files in the bundle like the objects uploaded via UploadObject API. Unlike the UploadObject API, the user must specify the bundle name when uploading a bundle and the user are not allowed to upload objects to this bundle any longer. The bundle will be marked as Finalized and it will be uploaded to Greenfield by the bundle service. #### Query Object The Bundle service stores index information for uploaded objects. It tracks the bundle and its metadata, making it easy to locate and index files bundled on Greenfield. The service also caches frequently accessed data to improve request performance. - When the bundler service has the file saved, the bundler service can respond to the request immediately. - If only the index information is available, the bundle service retrieves the file from Greenfield and returns it to the user. - If the index is missing, the service attempts to rebuild it from Greenfield and then retrieves and returns the file. ### APIs The Bundle Service Server API provides several endpoints for managing and interacting with bundles. Here's a brief overview: - **Upload a single object to a bundle (POST /uploadObject):** This endpoint allows users to upload a single object to a bundle, requiring details like bucket name, file name, and etc. - **Upload a bundle (POST /uploadBundle):** This endpoint allows users to upload a bundle of objects, requiring details like bucket name, bundle name, and etc. - **Retrieve an object as a file from a bundle (GET /view/{bucketName}/{bundleName}/{objectName}):** This endpoint fetches a specific object from a given bundle and returns it as a file. - **Download an object as a file from a bundle (GET /download/{bucketName}/{bundleName}/{objectName}):** This endpoint allows users to download a specific object from a given bundle and returns it as a file. - **Query bundle information (GET /queryBundle/{bucketName}/{bundleName}):** This endpoint queries a specific object from a given bundle and returns its related information. - **Query bundling bundle information of a bucket (GET /queryBundlingBundle/{bucketName}):** This endpoint queries the bundling bundle information of a given bucket. - **Start a New Bundle (POST /createBundle):** This endpoint initiates a new bundle, requiring details like bucket name and bundle name. - **Finalize an Existing Bundle (POST /finalizeBundle):** This endpoint completes the lifecycle of an existing bundle, requiring the bundle name for authorization. - **Delete an Existing Bundle (POST /deleteBundle):** This endpoint deletes an existing bundle after object deletion on Greenfield. - **Get Bundler Account for a User (POST /bundlerAccount/{userAddress}):** This endpoint returns the bundler account for a given user. - **Set New Bundling Rules (POST /setBundleRule):** This endpoint allows users to set new rules or replace old rules for bundling, including constraints like maximum size and number of files. For more detailed information about each endpoint, including required parameters and response formats, please refer to the swagger.yaml file in [https://github.com/node-real/greenfield-bundle-service](https://github.com/node-real/greenfield-bundle-service). For detailed usage cases, you can refer to the e2e test cases in [https://github.com/node-real/greenfield-bundle-service/tree/main/e2e](https://github.com/node-real/greenfield-bundle-service/tree/main/e2e). ### Endpoints Opensource implement from [NodeReal](https://docs.nodereal.io/docs/greenfield-bundle-service) #### Greenfield Testnet Using the testnet's bundle service, the bundle file will be uploaded to the Greenfield testnet. Endpoint: ``` https://gnfd-testnet-bundle.nodereal.io ``` #### Greenfield Mainnet Using the mainnet's bundle service, the bundle file will be uploaded to the Greenfield mainnet. Endpoint: ``` https://gnfd-mainnet-bundle.nodereal.io ``` --- ## Overview > Source: https://docs.bnbchain.org/bnb-greenfield/for-developers/apis-and-sdks/ # APIs & SDKs Below are the lists of Official APIs and SDKs for BNB Greenfield in different languages. ## Official APIs * [Greenfield Chain API Docs](https://greenfield.bnbchain.org/openapi) * [Greenfield SP API Docs](https://github.com/bnb-chain/greenfield-storage-provider/tree/master/docs/storage-provider-rest-api) ## Official SDKs * [Greenfield Go SDK](sdk-go.md), more details refer to [Go SDK Docs](https://pkg.go.dev/github.com/bnb-chain/greenfield-go-sdk). * [Greenfield Javascript SDK](sdk-js.md), more details refer to [JS SDK Docs](https://docs.bnbchain.org/greenfield-js-sdk/). --- ## Go SDK Example > Source: https://docs.bnbchain.org/bnb-greenfield/for-developers/apis-and-sdks/sdk-go/ # Quickstart The Greenfield SDK for Go provides APIs and utilities that developers can use to build Go applications that use Greenfield services, such as data storage and permission management. The SDK simplifies the process of programming directly with a web service interface. It takes care of many underlying details, including authentication, retrying requests, and managing errors. This guide provides configuration information, sample code, and an introduction to the SDK utilities. ## Install The Greenfield SDK for Go requires [Go 1.20 or later](https://go.dev/).You can view your current version of Go by running the go version command. For information about installing or upgrading your version of Go, see [https://golang.org/doc/install](https://golang.org/doc/install). To install the SDK and its dependencies, run the following Go command. ```sh $ go get github.com/bnb-chain/greenfield-go-sdk ``` Edit go.mod to replace dependencies ```sh replace ( cosmossdk.io/api => github.com/bnb-chain/greenfield-cosmos-sdk/api v0.0.0-20230425074444-eb5869b05fe9 cosmossdk.io/math => github.com/bnb-chain/greenfield-cosmos-sdk/math v0.0.0-20230425074444-eb5869b05fe9 github.com/cometbft/cometbft => github.com/bnb-chain/greenfield-cometbft v0.0.2 github.com/cometbft/cometbft-db => github.com/bnb-chain/greenfield-cometbft-db v0.8.1-alpha.1 github.com/cosmos/cosmos-sdk => github.com/bnb-chain/greenfield-cosmos-sdk v0.2.3 github.com/cosmos/iavl => github.com/bnb-chain/greenfield-iavl v0.20.1-alpha.1 github.com/syndtr/goleveldb => github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 ) ``` Install dependensies ```sh go mod tidy ``` ## Usage Now we’re ready to connect to Greenfield testnet and interact with the Greenfield APIs. Let’s write a simple script to query the Greenfield version to verify if everything works as expected. ### Create client Create a `main.go` file in your project and add the following code. ```go package main import ( "context" "log" "github.com/bnb-chain/greenfield-go-sdk/client" "github.com/bnb-chain/greenfield-go-sdk/types" ) const ( privateKey = "" // Mainnet Info rpcAddr = "https://greenfield-chain.bnbchain.org:443" chainId = "greenfield_1017-1" // Testnet Info // rpcAddr = "https://gnfd-testnet-fullnode-tendermint-us.bnbchain.org:443" // chainId = "greenfield_5600-1" ) func main() { // import acccount account, err := types.NewAccountFromPrivateKey("test", privateKey) if err != nil { log.Fatalf("New account from private key error, %v", err) } // create client cli, err := client.New(chainId, rpcAddr, client.Option{DefaultAccount: account}) if err != nil { log.Fatalf("unable to new greenfield client, %v", err) } ctx := context.Background() // get node info from RPC nodeInfo, versionInfo, err := cli.GetNodeInfo(ctx) if err != nil { log.Fatalf("unable to get node info, %v", err) } log.Printf("nodeInfo moniker: %s, go version: %s", nodeInfo.Moniker, versionInfo.GoVersion) // query latest block height height, err := cli.GetLatestBlockHeight(ctx) if err != nil { log.Fatalf("unable to get latest block height, %v", err) } log.Printf("Current block height: %d", height) } ``` Run the following command in your project directory: ```bash go run main.go ``` This will output something like: ``` 2023/06/22 10:44:16 nodeInfo moniker: validator-a, go version: go version go1.20.4 linux/amd64 2023/06/22 10:44:16 Current block height: 817082 ``` If everything is set up correctly, your code will be able to connect to the Greenfield node and return the chain data as shown above. ### Queries In the previous step, we created a `main.go` file to demonstrate the basic steps to connect to the node and initialize a `Client` to query chain data. Next, let’s use some more functions. #### 1. Get Current Chain Head We can add the following code in`main.go`to query current head of the chain. ```go // query latest block height blockByHeight, err := cli.GetBlockByHeight(ctx,height) if err != nil { log.Fatalf("unable to get block by height, %v", err) } log.Printf("Current block height: %d", blockByHeight.GetHeader()) ``` #### 2. Get Address Balance With a given greenfield wallet address, you can query its balance by calling `GetAccountBalance` function. ```go // query current balance balance, err := cli.GetAccountBalance(ctx, account.GetAddress().String()) if err != nil { log.Fatalf("unable to get balance, %v", err) } log.Printf("%s Current balance: %s", account.GetAddress().String(), balance.String()) ``` #### 3. Query Storage Providers In addition, the SDK provides support for querying the list of storage providers available and offers generic search capabilities for exploring metadata attributes. ```go cli, err := client.New(chainId, rpcAddr, client.Option{DefaultAccount: account}) if err != nil { log.Fatalf("unable to new greenfield client, %v", err) } ctx := context.Background() // get storage providers list spLists, err := cli.ListStorageProviders(ctx, true) if err != nil { log.Fatalf("fail to list in service sps") } ``` #### 4. Query Storage Price ```go // choose the first sp to be the primary SP primarySP := spLists[0].GetOperatorAddress() // query price for storing data price, err := cli.GetStoragePrice(ctx,primarySP) if err != nil { log.Fatalf("fail to list in service sps") } log.Printf("Read Price is %s and Store price is %s \n",price.ReadPrice,price.StorePrice) ``` #### 5. Query Buckets You can query the bucket info like this: ```go // head bucket bucketInfo, err := cli.HeadBucket(ctx, bucketName) handleErr(err, "HeadBucket") log.Println("bucket info:", bucketInfo.String()) ``` #### 5. Query Objects List all the objects under the same bucket ```go // list object objects, err := cli.ListObjects(ctx, bucketName, types.ListObjectsOptions{ ShowRemovedObject: false, Delimiter: "", MaxKeys: 100, EndPointOptions: &types.EndPointOptions{ Endpoint: httpsAddr, // sp endpoint SPAddress: "", }}) log.Println("list objects result:") for _, obj := range objects.Objects { i := obj.ObjectInfo log.Printf("object: %s, status: %s\n", i.ObjectName, i.ObjectStatus) } ``` Apart from the basic data queries shown above, there are many more features. Please see the[JSON-RPC API Reference](../network-endpoint/endpoints.md)for all Greenfield API definitions. ### Transactions #### 1. Manage Wallet Greenfield wallets hold addresses that you can use to manage objects, sign transactions, and pay for gas fees. In this section, we will demonstrate different ways to manage your wallet. * First, let’s make sure your connected node is running and the wallet address contains some testnet BNB. * Create a new file called `account.go` in the same project as earlier. This is where we’ll write all out wallet-related code. * In `account.go` import modules and initialize your private key or mnemonic phrase. ```go //import mnemonic account, err := types.NewAccountFromMnemonic("test", mnemonic) //import private key account, err := types.NewAccountFromPrivateKey("test", privateKey) ``` Let’s create a second wallet address so we can test transfers. The new address will be created locally and start with 0 token balance: ```go //create a differet account account2, _, err := types.NewAccount("test2") ``` Now, let’s try to transfer tBNB to this new address. Under the hood, this will create a transaction to transfer tBNB from`fromAddress`to`toAddress`, sign the transaction using SDK, and send the signed transaction to the Greenfield node. ```go // transfer token to acccount2 transferTxHash, err := cli.Transfer(ctx, account2.GetAddress().String(), math.NewIntFromUint64(1000000000000000000), types2.TxOption{}) if err != nil { log.Fatalf("unable to send, %v", err) } log.Printf("Transfer response: %s", transferTxHash) // wait for transaction hash waitForTx, err := cli.WaitForTx(ctx, transferTxHash) log.Printf("Wait for tx: %s", waitForTx.String()) //verify account2's balance balance, err = cli.GetAccountBalance(ctx, account2.GetAddress().String()) ``` Run the code to test the transfer of tBNB: ```go go run account.go ``` This will output something like: ```shell raw_log: '[{"msg_index":0,"events":[{"type":"message","attributes":[{"key":"action","value":"/cosmos.bank.v1beta1.MsgSend"},{"key":"sender","value":"0x525482AB3922230e4D73079890dC905dCc3D37cd"},{"key":"module","value":"bank"}]},{"type":"coin_spent","attributes":[{"key":"spender","value":"0x525482AB3922230e4D73079890dC905dCc3D37cd"},{"key":"amount","value":"1BNB"}]},{"type":"coin_received","attributes":[{"key":"receiver","value":"0x78C3A3d10B1032bB2810366361dCE84E2e92eFCB"},{"key":"amount","value":"1BNB"}]},{"type":"transfer","attributes":[{"key":"recipient","value":"0x78C3A3d10B1032bB2810366361dCE84E2e92eFCB"},{"key":"sender","value":"0x525482AB3922230e4D73079890dC905dCc3D37cd"},{"key":"amount","value":"1BNB"}]},{"type":"message","attributes":[{"key":"sender","value":"0x525482AB3922230e4D73079890dC905dCc3D37cd"}]}]}]' timestamp: "2023-06-22T20:02:19Z" tx: '@type': /cosmos.tx.v1beta1.Tx auth_info: fee: amount: - amount: "6000000000000" denom: BNB gas_limit: "1200" granter: "" payer: "" signer_infos: - mode_info: single: mode: SIGN_MODE_EIP_712 public_key: '@type': /cosmos.crypto.eth.ethsecp256k1.PubKey key: AirjhHwjRcZ34op5yCKHtDkn91RDgFOY8cJmbHH6Tmlu sequence: "12" tip: null body: extension_options: [] memo: "" messages: - '@type': /cosmos.bank.v1beta1.MsgSend amount: - amount: "1" denom: BNB from_address: 0x525482AB3922230e4D73079890dC905dCc3D37cd to_address: 0x78C3A3d10B1032bB2810366361dCE84E2e92eFCB non_critical_extension_options: [] timeout_height: "0" signatures: - FjUNT2dzpQZhCmVTLDGMEy1uR1NaNLeYjvqQiPr2xHM5xxeYP5Mic8CSxZtg3k4WHcAIEnQNcszqBi7fsgETagA= txhash: DFC2CE0514FE334B5BCB6BC3EBCCCD7A6E16B4CAEDC4FFDBE3F2FA3B6E548E61 ``` ### Make A Storage Deal Storing data is one of the most important features of Greenfield. In this section, we’ll walk through the end-to-end process of storing your data on the Greenfield network. We’ll start by importing your data, then make a storage deal with a storage provider, and finally wait for the deal to complete. #### 1. Create a `storage.go` file Create a `storage.go` file in yourdemoproject and add the following boilerplate code: ```go func main() { // initialize account account, err := types.NewAccountFromPrivateKey("test", privateKey) log.Println("address info:", account) if err != nil { log.Fatalf("New account from private key error, %v", err) } //initialize client cli, err := client.New(chainId, rpcAddr, client.Option{DefaultAccount: account}) if err != nil { log.Fatalf("unable to new greenfield client, %v", err) } ctx := context.Background() // 1. choose storage provider // 2. Create a bucket // 3. Upload your data and set a quota } ``` #### 2. Choose SP You can query the list of SP. ```go // get storage providers list spLists, err := cli.ListStorageProviders(ctx, true) if err != nil { log.Fatalf("fail to list in service sps") } //choose the first sp to be the primary SP primarySP := spLists[0].GetOperatorAddress() ``` #### 3. Create Buckets Bucket can be private or public. You can customize it with options. * VISIBILITY\_TYPE\_PUBLIC\_READ * VISIBILITY\_TYPE\_PRIVATE ```go chargedQuota := uint64(100) visibility := storageTypes.VISIBILITY_TYPE_PUBLIC_READ opts := types.CreateBucketOptions{Visibility: visibility, ChargedQuota: chargedQuota} ``` To understand how does `quota` work, read [this](../../core-concept/billing-payment.md#storage-service-fee). #### 4. Upload Objects Objects can also be private or public. Uploading objects is composed of two parts: `create` and `put`. * `CreateObject` gets an approval of creating an object and sends createObject txn to Greenfield network. * `PutObject` supports the second stage of uploading the object to bucket. ```go // create and put object txnHash, err := cli.CreateObject(ctx, bucketName, objectName, bytes.NewReader(buffer.Bytes()), types.CreateObjectOptions{}) handleErr(err, "CreateObject") // Put your object err = cli.PutObject(ctx, bucketName, objectName, int64(buffer.Len()), bytes.NewReader(buffer.Bytes()), types.PutObjectOptions{TxnHash: txnHash}) handleErr(err, "PutObject") log.Printf("object: %s has been uploaded to SP\n", objectName) //wait for SP to seal your object waitObjectSeal(cli, bucketName, objectName) ``` The primary SP syncs with secondary SPs to set up the data redundancy, and then it signs a "`Seal`" transaction with the finalized metadata for storage. If the primary SP determines that it doesn't want to store the file due to whatever reason, it can also "`SealReject`" the request. ### Object Management #### 1. Read Object You can call `GetObject` function to download data. ```go // get object reader, info, err := cli.GetObject(ctx, bucketName, objectName, types.GetObjectOption{}) handleErr(err, "GetObject") log.Printf("get object %s successfully, size %d \n", info.ObjectName, info.Size) handleErr(err, "GetObject") objectBytes, err := io.ReadAll(reader) if !bytes.Equal(objectBytes, buffer.Bytes()) { handleErr(errors.New("download content not same"), "GetObject") } ``` #### 2. Update Object Visibility You can call `UpdateObjectVisibility` to change object visibility ```go // update object visibility updateBucketTx, err := ccli.UpdateBucketVisibility(s.ClientContext, bucketName, storageTypes.VISIBILITY_TYPE_PRIVATE, types.UpdateVisibilityOption{}) ``` #### 3. Delete Object The function `DeleteObject` support deleting objects. ```go // delete object delTx, err := cli.DeleteObject(ctx, bucketName, objectName, types.DeleteObjectOption{}) handleErr(err, "DeleteObject") _, err = cli.WaitForTx(ctx, delTx) if err != nil { log.Fatalln("txn fail") } log.Printf("object: %s has been deleted\n", objectName) ``` ## Greenfield Client Documentation ### Usage Import Greenfield Go SDK client package, client package provides a client for interacting with Greenfield blockchain and SPs. ``` import "github.com/bnb-chain/greenfield-go-sdk/client" ``` Provide Greenfield blockchain RPC endpoint and chainID info, new a Greenfield Go SDK client instance to start the journey. ```go func New(chainID string, endpoint string, option Option) (Client, error) ``` ### API Documentation The Greenfield Go SDK client wraps lots of APIs for interacting with Greenfield, including account, bank, storage, and permission APIs, etc. For more details, you can refer to [Greenfield Go SDK Docs](https://pkg.go.dev/github.com/bnb-chain/greenfield-go-sdk). ## Code Repository - [Official Go implementation SDK](https://github.com/bnb-chain/greenfield-go-sdk) ## More info * [Storage Module on Greenfield](https://github.com/bnb-chain/greenfield/blob/master/docs/modules/storage-module.md): The storage module on Greenfield Chain. * [Storage Provider on Greenfield](https://github.com/bnb-chain/greenfield/blob/master/docs/modules/storage-provider.md): The storage provider on Greenfield Chain. * [Data Availability Challenge](https://github.com/bnb-chain/greenfield/blob/master/docs/modules/data-availability-challenge.md): The correctness of payload be stored in SP. * [Storage Provider Introduction](../../storage-provider/overview.md): The Greenfield Storage Provider documents. * [Storage Provider Compiling and Dependencies](../../storage-provider/run-book/compile-dependences.md): The detailed introduction to sp compiling and dependencies. * [Run Local Storage Provider Network](../../storage-provider/run-book/run-local-SP-network.md): The introduction to run local SP env for testing. * [Join SP Network](../../storage-provider/run-book/join-SP-network.md): The introduction to join SP network in testnet or mainnet --- ## Javascript SDK Example > Source: https://docs.bnbchain.org/bnb-greenfield/for-developers/apis-and-sdks/sdk-js/ # Quickstart The BNB Greenfield JavaScript SDK is designed for front-end environments and provides an API for interacting with BNB Greenfield decentralized storage. It offers a range of operations, including retrieving permission details, gas fees, etc. The SDK also includes a crypto component for signing transactions and sending them to BNB Greenfield. However, it should be noted that this SDK does not include methods for interacting with BNB Smart Chain (BSC). For a comprehensive understanding of available operations, refer to the [API Reference](https://github.com/bnb-chain/greenfield-js-sdk). ## Install ```bash npm install @bnb-chain/greenfield-js-sdk ``` ## Usage To utilize the SDK functionality, users need to instantiate a client object from the SDK. This client object serves as the interface to interact with BNB Greenfield and perform the desired operations. ### Create client ```js import { Client } from '@bnb-chain/greenfield-js-sdk' export const client = Client.create('https://gnfd-testnet-fullnode-tendermint-ap.bnbchain.org', '5600'); ``` The SDK offers two types of operations - sending transactions to BNB Greenfield, allowing users to modify the state of the blockchain; the second type enables users to send queries and retrieve metadata information about objects stored on the blockchain. The SDK consists of two parts: * Chain: [Greenfield Chain API](https://github.com/bnb-chain/greenfield/tree/master/docs/greenfield-api) * Storage Provider: [Greenfield Storage Provider API](https://github.com/bnb-chain/greenfield-storage-provider/tree/master/docs/storage-provider-rest-api) ### Transactions #### 1. Transaction construction The SDK offers functionality for transferring tokens between accounts, providing a straightforward and convenient way to perform token transfers. With the SDK, users can easily initiate and execute token transfers within the desired accounts, streamlining the process of managing and exchanging tokens. The SDK includes functionality for simulating and broadcasting transactions, allowing users to retrieve essential information related to gas fees, and sending the transaction over network. ```js const { simulate, broadcast } = await client.account.transfer({ fromAddress: address, toAddress: transferInfo.to, amount: [ { denom: 'BNB', amount: ethers.utils.parseEther(transferInfo.amount).toString(), }, ], }); ``` #### 2. Simulate Transactions This function returns the estimated gas limit, gas price, and overall gas fee. ```js // simulate tx const simulateInfo = await simulate({ denom: 'BNB', }); ``` Example output ```json { "gasLimit":2400, "gasPrice":"5000000000", "gasFee":"0.000012" } ``` #### 3. Broadcast Transactions Use the API endpoint to send the transaction data to the blockchain network. ```js // broadcast tx // This includes details such as gas limit, gas price, and overall gas fee. const broadcastRes = await broadcast({ denom: 'BNB', gasLimit: Number(simulateInfo.gasLimit), gasPrice: simulateInfo.gasPrice, payer: address, granter: '', }); ``` #### NOTICE: Signature mode for `Broadcast` `broadcast` use `window.ethereum` as signature provider by default. If you want to use others, you can set `signTypedDataCallback`: ```js // TrustWallet const broadcastRes = await broadcast({ //... signTypedDataCallback: async (addr: string, message: string) => { return await window.trustwallet.request({ method: 'eth_signTypedData_v4', params: [addr, message], }); } }); ``` If you broadcast in Nodejs, you can broadcast a tx by `privateKey`: ```js const broadcastRes = await broadcast({ //... privateKey: '0x.......' }); ``` Example output after broadcast your transaction: #### 4. Multi-Transactions The SDK also provides support for bundling multiple operations into a single transaction, thereby reducing gas fees. This feature allows users to optimize their transactions by combining several operations together, minimizing the overall gas cost associated with executing them individually. By leveraging this functionality, users can effectively manage their gas fees and enhance the efficiency of their transactions within the blockchain network using the SDK. ```js const createGroupTx = await client.group.createGroup(params); const mirrorGroupTx = await client.crosschain.mirrorGroup({ groupName, id, operator, }); const principal = { type: PermissionTypes.PrincipalType.PRINCIPAL_TYPE_GNFD_GROUP, value: GRNToString(newGroupGRN(address as string, groupName)), }; const statement: PermissionTypes.Statement = { effect: PermissionTypes.Effect.EFFECT_ALLOW, actions: [PermissionTypes.ActionType.ACTION_GET_OBJECT], resources: [ GRNToString( type === 'Data' ? newObjectGRN(bucketName, name) : newObjectGRN(bucketName, '*'), ), ], }; const policyTx = await client.object.putObjectPolicy(bucketName, name, { operator: address, statements: [statement], principal, }); const { simulate, broadcast } = await multiTx([ createGroupTx, mirrorGroupTx, policyTx, ]); ``` ### Querying Metadata * Account info ```js const { client, selectSp, generateString } = require('./client'); const { ACCOUNT_ADDRESS, ACCOUNT_PRIVATEKEY } = require('./env'); const Long = require('long'); (async () => { // get account info const addrInfo = await client.account.getAccount(ACCOUNT_ADDRESS); console.log('address is', addrInfo); }) ``` Example output ```json { "address":"0x525482AB3922230e4D73079890dC905dCc3D37cd", "pubKey":{ "typeUrl":"/cosmos.crypto.eth.ethsecp256k1.PubKey", "value":"CiECKuOEfCNFxnfiinnIIoe0OSf3VEOAU5jxwmZscfpOaW4=" }, "accountNumber":"5012", "sequence":"9" } ``` ### Storage Provider Client > [https://github.com/bnb-chain/greenfield-storage-provider/tree/master/docs/storage-provider-rest-api](https://github.com/bnb-chain/greenfield-storage-provider/tree/master/docs/storage-provider-rest-api) In addition, the SDK provides support for querying the list of storage providers available and offers generic search capabilities for exploring metadata attributes. SDK support two [authentication type](https://github.com/bnb-chain/greenfield-storage-provider/blob/master/docs/storage-provider-rest-api/README.md#authentication-type): * ECDSA: It is usually used on Node.js (Because it need to use a private key) * EDDSA: It is usually used in a browser `getBucketReadQuota` as example: ```js // generate seed: const allSps = await getAllSps(); const offchainAuthRes = await client.offchainauth.genOffChainAuthKeyPairAndUpload( { sps: allSps, chainId: GREEN_CHAIN_ID, expirationMs: 5 * 24 * 60 * 60 * 1000, domain: window.location.origin, address: 'your address', }, provider: 'wallet provider', ); // request sp api const bucketQuota = await client.bucket.getBucketReadQuota( { bucketName, }, { type: 'EDDSA', seed: offchainAuthRes.seedString, domain: window.location.origin, address: 'your address', }, ); ``` ```js // Node.js: // request sp api const bucketQuota = await client.bucket.getBucketReadQuota( { bucketName, }, { type: 'ECDSA', privateKey: '0x....' }, ); ``` Others functions: #### List Storage Providers ```js export const getSps = async () => { const sps = await client.sp.getStorageProviders(); const finalSps = (sps ?? []).filter( (v: any) => v?.description?.moniker !== 'QATest', ); return finalSps; }; ``` #### Search for objects It's important to note that even if an object is set to private, its metadata remains publicly accessible. This metadata includes information such as file size, file type, and file name. ```js export const searchKey = async (key: string) => { try { return await client.sp.listGroup(key, `${DAPP_NAME}_`, { sourceType: 'SOURCE_TYPE_ORIGIN', limit: 1000, offset: 0, }); } catch (e) { return []; } ``` ## Examples Now let's make a complete example, includes: 1. create bucket 2. create object and upload it to the bucket 3. download the object ### Prepare To begin, create an account and deposit tokens into it on Greenfield. Follow the instructions provided in [Token Transfer](../../getting-started/token-transfer.md). Please be aware that if your account does not have any BNB, the transaction will not be executed. #### Choose Storage Provider Storing data is one of the most important features of Greenfield. All storage-related apis require the [storage provider](../../storage-provider/overview.md) to be chose. ```js title="select sp" const spList = await client.sp.getStorageProviders(); const sp = { operatorAddress: spList[0].operatorAddress, endpoint: spList[0].endpoint, }; ``` #### ECDSA / OffChainAuth [ECDSA](https://github.com/bnb-chain/greenfield-storage-provider/blob/master/docs/storage-provider-rest-api/README.md#for-auth-type-gnfd1-ecdsa) require users to use private key for authentication. [OffChainAuth](https://github.com/bnb-chain/greenfield-storage-provider/blob/master/docs/modules/authenticator.md) is used to authenticate yourself to the provider. > Code can't access user's private key on browser, so we use `OffChainAuth` on browser and use `ECDSA` on Nodejs. === "Browser" ```js title="Browser" // MetaMask const provider = window.ethereum; const offchainAuthRes = await client.offchainauth.genOffChainAuthKeyPairAndUpload({ sps: { address: sp.operatorAddress, endpoint: sp.endpoint, }, chainId: '5600', expirationMs: 5 * 24 * 60 * 60 * 1000, domain: window.location.origin, // your wallet account address: '0x..', }, provider); ``` === "Nodejs" !!! info Nodejs don't need offchainauth. ```js title="Nodejs" // your account const ACCOUNT_ADDRESS = '0x....' // your account's private key const ACCOUNT_PRIVATEKEY = '0x....' ``` ### 1. Create Bucket #### 1.1 construct create bucket tx Bucket can be private or public, you can customize it with options (`visibility`): * `VISIBILITY_TYPE_PUBLIC_READ` * `VISIBILITY_TYPE_PRIVATE` ```js title="construct create bucket tx" const createBucketTx = await client.bucket.createBucket( { bucketName: 'bucket_name', creator: address, visibility: VisibilityType.VISIBILITY_TYPE_PUBLIC_READ, chargedReadQuota: Long.fromString('0'), primarySpAddress: sp.operatorAddress, paymentAddress: address, } ); ``` #### 1.2 simulate create bucket tx ```js title="simulate create bucket tx" const createBucketTxSimulateInfo = await createBucketTx.simulate({ denom: 'BNB', }); ``` #### 1.3 broadcast create bucket tx === "Browser" ```js title="broadcast create bucket tx" const res = await createBucketTx.broadcast({ denom: 'BNB', gasLimit: Number(simulateInfo?.gasLimit), gasPrice: simulateInfo?.gasPrice || '5000000000', payer: address, granter: '', }); ``` === "Nodejs" ```js title="broadcast create bucket tx" const res = await createBucketTx.broadcast({ denom: 'BNB', gasLimit: Number(createBucketTxSimulateInfo?.gasLimit), gasPrice: createBucketTxSimulateInfo?.gasPrice || '5000000000', payer: ACCOUNT_ADDRESS, granter: '', // highlight-start privateKey: ACCOUNT_PRIVATEKEY, // highlight-end }); ``` ### 2. Create Object #### 2.1 construct create object tx Like the [visibility of bucket](#11-construct-create-bucket-tx), object also has a visibility: * `VISIBILITY_TYPE_PUBLIC_READ` * `VISIBILITY_TYPE_PRIVATE` Getting file's checksum need [reed-solomon](https://github.com/bnb-chain/greenfield-js-sdk/tree/main/packages/reed-solomon): === "Browser" ```js import { ReedSolomon } from '@bnb-chain/reed-solomon'; const rs = new ReedSolomon(); // file is File type const fileBytes = await file.arrayBuffer(); const expectCheckSums = rs.encode(new Uint8Array(fileBytes)); ``` === "Nodejs" ```js const fs = require('node:fs'); const { NodeAdapterReedSolomon } = require('@bnb-chain/reed-solomon/node.adapter'); const filePath = './CHANGELOG.md'; const fileBuffer = fs.readFileSync(filePath); const rs = new NodeAdapterReedSolomon(); const expectCheckSums = await rs.encodeInWorker(__filename, Uint8Array.from(fileBuffer)); ``` ```js const createObjectTx = await client.object.createObject( { bucketName: 'bucket_name', objectName: 'object_name', // user's account address creator: '0x...', visibility: VisibilityType.VISIBILITY_TYPE_PRIVATE, contentType: 'json', redundancyType: RedundancyType.REDUNDANCY_EC_TYPE, payloadSize: Long.fromInt(13311), expectChecksums: expectCheckSums.map((x) => bytesFromBase64(x)), } ); ``` #### 2.2 simulate create object tx ```js const createObjectTxSimulateInfo = await createObjectTx.simulate({ denom: 'BNB', }); ``` #### 2.3 broadcast create object tx === "Browser" ```js const res = await createObjectTx.broadcast({ denom: 'BNB', gasLimit: Number(simulateInfo?.gasLimit), gasPrice: simulateInfo?.gasPrice || '5000000000', payer: address, granter: '', }); ``` === "Nodejs" ```js const createObjectTxRes = await createObjectTx.broadcast({ denom: 'BNB', gasLimit: Number(createObjectTxSimulateInfo?.gasLimit), gasPrice: createObjectTxSimulateInfo?.gasPrice || '5000000000', payer: ACCOUNT_ADDRESS, granter: '', // highlight-start privateKey: ACCOUNT_PRIVATEKEY, // highlight-end }); ``` #### 2.4 upload object === "Browser" ```js const uploadRes = await client.object.uploadObject( { bucketName: createObjectInfo.bucketName, objectName: createObjectInfo.objectName, body: file, txnHash: txHash, }, // highlight-start { type: 'EDDSA', domain: window.location.origin, seed: offChainData.seedString, address, }, // highlight-end ); ``` === "Nodejs" ```js const uploadRes = await client.object.uploadObject( { bucketName: bucketName, objectName: objectName, body: createFile(filePath), txnHash: createObjectTxRes.transactionHash, }, // highlight-start { type: 'ECDSA', privateKey: ACCOUNT_PRIVATEKEY, } // highlight-end ); // convert buffer to file function createFile(path) { const stats = fs.statSync(path); const fileSize = stats.size; return { name: path, type: '', size: fileSize, content: fs.readFileSync(path), } } ``` ### 3. Download Object === "Browser" ```js const res = await client.object.downloadFile( { bucketName: 'bucket_name', objectName: 'object_name', }, // highlight-start { type: 'EDDSA', address, domain: window.location.origin, seed: offChainData.seedString, }, // highlight-end ); ``` === "Nodejs" ```js const res = await client.object.getObject( { bucketName: 'bucket_name', objectName: 'object_name', }, // highlight-start { type: 'ECDSA', privateKey: ACCOUNT_PRIVATEKEY, } // highlight-end ); // res.body is Blob console.log('res', res) const buffer = Buffer.from([res.body]); fs.writeFileSync('your_output_file', buffer) ``` ## Code Repository - [Official JS implementation SDK](https://github.com/bnb-chain/greenfield-js-sdk) ## API Documentation - [Greenfield JS SDK Docs](https://docs.bnbchain.org/greenfield-js-sdk/) --- ## Overview > Source: https://docs.bnbchain.org/bnb-greenfield/for-validator/overview/ # Overview ## What is the Greenfield Blockchain The **Greenfield blockchain** plays a pivotal role in the [Greenfield ecosystem](../introduction.md#ecosystem). It forms the core of the platform and is constructed on the **Cosmos/Tendermint** infrastructure. Within the Greenfield blockchain, there are two categories of states that exist **on-chain**: - Accounts and their BNB balance ledger. - The metadata related to the object storage system, [Service Providers (SPs)](../storage-provider/overview.md), objects stored on this system, and permission and billing information associated with this storage. Transactions conducted on the Greenfield blockchain can alter the aforementioned states. These states and transactions make up the majority of the BNB Greenfield economic data. ## How Greenfield Blockchain Works The **Greenfield Blockchain** utilizes the [Tendermint consensus](https://tutorials.cosmos.network/) mechanism, implementing a [Proof-of-Stake](https://ethereum.org/en/developers/docs/consensus-mechanisms/pos/) approach to ensure network security. Validator election and governance are managed through a [proposal-vote mechanism](https://github.com/bnb-chain/greenfield/blob/doc-refactor/docs/modules/governance.md), following the governance module of Cosmos SDK. Greenfield's validators produce blocks every **2 seconds**. As for the blockchain's native token, **BNB** serves as both gas and governance token. The initial BNB is locked on BNB Smart Chain (BSC) and subsequently re-minted on Greenfield. Cross-chain communication enables smooth flow of BNB and data operation primitives between Greenfield and BSC. The total circulation of BNB remains unaffected and will continue moving along the BNB Beacon Chain, BSC, and Greenfield. !!! tip [Here is a good reading](https://docs.tendermint.com/v0.34/introduction/what-is-tendermint.html) about the working principles of an application chain built on Tendermint. ## Validator from Greenfield Blockchain The validators of the Greenfield Blockchain are integral to the network's security and reliability. However, their responsibilities extend well beyond that: 1. Validators are tasked with achieving consensus on cross-chain events and relaying cross-chain packets to both Greenfield and BNB Smart Chain. This ensures that cross-chain transactions are executed quickly, securely, and with minimal cost. 2. Validators play a key role in ensuring the integrity and availability of data provided by service providers (SPs). By challenging the data availability of SPs in a specific or random manner, validators can weed out malicious actors and those who provide subpar services. Punishing such actors through appropriate measures - such as slashing their stake, for example - helps to ensure the quality and reliability of services in the Greenfield ecosystem. 3. Validators also have a say in the governance of the network. They vote on issues related to the future development of Greenfield's ecosystem and adjust various network parameters as necessary. This ensures that the network remains healthy and sustainable over time, while accommodating the changing needs and demands of its users. --- ## Run Node > Source: https://docs.bnbchain.org/bnb-greenfield/for-validator/run-node/run-node/ # Run Node ## Minimum System Requirements The hardware must meet certain requirements to run a Full Node. * Desktop or laptop hardware running recent versions of Mac OS X, or Linux. * 1 TB of free disk space, accessible at a minimum read/write speed of 100 MB/s. * 4 cores of CPU and 12 gigabytes of memory (RAM). * A broadband Internet connection with upload/download speeds of at least 1 megabyte per second. ## Setting Up a New Node !!! info Please check the [greenfield repo](https://github.com/bnb-chain/greenfield/releases/latest) for information, including the correct version of the binaries to use and details about the config file 1. You need to choose a home folder `$NODE_HOME` (i.e. ~/.gnfd) for Greenfield Chain. You can setup this by: ``` mkdir ~/.gnfd mkdir ~/.gnfd/config ``` 2. Download `app.toml`, `config.toml` and `genesis.json` from `https://github.com/bnb-chain/greenfield/releases` and copy them into `$NODE_HOME/config` === "mainnet" ```bash wget $(curl -s https://api.github.com/repos/bnb-chain/greenfield/releases/latest |grep browser_ |grep mainnet_config |cut -d\" -f4) unzip mainnet_config.zip cp mainnet_config/* ~/.gnfd/config/ ``` === "testnet" ```bash wget $(curl -s https://api.github.com/repos/bnb-chain/greenfield/releases/latest |grep browser_ |grep testnet_config |cut -d\" -f4) unzip testnet_config.zip cp testnet_config/* ~/.gnfd/config/ ``` You can edit this moniker later, in the `$NODE_HOME/config/config.toml` file: ```toml # A custom human readable name for this node moniker = "" ``` !!! note Monikers can contain only ASCII characters. Using Unicode characters will render your node unreachable. Now your Full Node has been initialized. 4. Start your Full Node. ```shell gnfd start ``` !!! note Alternatively, if you choose a different $NODE_HOME location and you are not using the suggested default `~/.gnfd`, you may start the full node by using below script, where $NODE_HOME is your selected directory. Example: If you set `/usr/local/gnfd` as your home directory. Run the Full Node with below command. ```shell gnfd start --home /usr/local/gnfd ``` ### Additional Configuration - Seed node: Your Full Node needs to know how to find peers in the blockchain network. You'll need to add healthy seed nodes to $NODE_HOME/config/config.toml. The recommended `config.toml` already contains links to some seed nodes. - Service Port: RPC service listens on port `26657` and P2P service listens on port `26656` by default. Make sure these two ports are open before starting a full node, unless the full node has to listen on other ports. - Store: All the state and block data will store under `$NODE_HOME/data`, do not delete or edit any of these files. ## Get Extra Information From Your Fullnode If you have a Full Node running, then you can publish extra messages to local files. ##### Monitor Syncing Process You can verify if state sync is done by `curl localhost:26657/status` several times and see whether `latest_block_height` is increasing in response. ``` "sync_info": { ... "latest_block_height": "280072", "latest_block_time": "2023-04-07T01:58:13.572249854Z", ... } ``` ## Prometheus Metrics Prometheus is enabled on port `26660` by default, and the endpoint is `/metrics`. ## Tools * [Explorer](https://greenfieldscan.com/) --- ## Run Relayer > Source: https://docs.bnbchain.org/bnb-greenfield/for-validator/run-node/run-relayer/ # Run Relayer This tutorial is for running relayers for Greenfield to BSC and opBNB. Please note that they are using the same binary, but two individual processes which require different databases connected. Most configs for these two relayers are the same, with a few differences which will be illustrated below. ## Prerequisites ### Recommended Hardware The following lists the recommended hardware requirements: - Hardware Requirements: Desktop or laptop hardware running recent versions of Mac OS X, or Linux. - CPU: 4 cores - RAM: 4 GB - Relational database: Mysql ### Key Preparation - Relayer private key: This is the account which is used to relay transaction between Greenfield and the BSC/opBNB. Ensures it has balance on both Blockchain networks. - Bls private key: Used to create bls signature for cross-chain package. These two keys refer to `validator_relayer` and `validator_bls` created in [become-validator](become-validator.md) step 2. You can retrieve them with the following commands. ```bash gnfd keys export validator_relayer --unarmored-hex --unsafe --keyring-backend test gnfd keys export validator_bls --unarmored-hex --unsafe --keyring-backend test ``` ## Prepare binary Get the greenfield-relayer app by running the following command in your terminal: ```bash git clone --branch "$(curl -s https://api.github.com/repos/bnb-chain/greenfield-relayer/releases/latest | jq -r '.tag_name')" https://github.com/bnb-chain/greenfield-relayer.git cd greenfield-relayer ``` ## Config Modify `config/config.json`. Or, you can create a new one and specify the config path by `--config-path` flag when start the relayer. !!! info For Testnet config, refer to [Testnet configure](https://github.com/bnb-chain/bnb-chain-charts/blob/master/gnfd-relayer-testnet-values/values.yaml#L4). You can use it as a template for your Mainnet config by adapting a few changes as illustrated below. 1. Set relayer private key and bls private key import method (via file or aws secret) and keys, the block monitoring start heights. ```json "greenfield_config": { "key_type": "local_private_key", // or "aws_private_key" if you are using aws secret manager. ... "aws_bls_secret_name": "", "private_key": "your_private_key", // this is the relayer private key for relaying transaction. "bls_private_key": "your_private_key", // this is the bls key for signing crosschain package. "rpc_addrs": [ "https://greenfield-chain.bnbchain.org:443" ] "chain_id": 1017, ... "start_height": 1, // please change to the current block height of Greenfield network. "chain_id_string": "greenfield_1017-1" }, "bsc_config": { "key_type": "local_private_key", // or "aws_private_key" if you are using aws secret manager. ... "rpc_addrs": [ "BSC_RPC" ], "private_key": "your_private_key", // same as the above one in greenfield_congfig. "gas_limit": 20000000, ... "start_height": 0, // please change to the current block height of BSC network. "chain_id": 56 // 56 is BSC Mainnet chain id. } ``` For setting up the relayer that crosschain to `opBNB`, modify the `bsc_config` as below. ```json "bsc_config": { "op_bnb": true, // this specifies that conifg is for opBNB crosschain. "key_type": "local_private_key", // or "aws_private_key" if you are using aws secret manager. ... "rpc_addrs": [ "opBNB_RPC" ], "private_key": "your_private_key", // same as the above one in greenfield_congfig. "gas_limit": 20000000, ... "start_height": 0, // please change to the current block height of opBNB network. "chain_id": 204 // opBNB mainnet chain id } ``` Note: Refer to [Greenfield Endpoints](../../for-developers/network-endpoint/endpoints.md) for Greenfield RPC address, [BSC Endpoints](https://docs.bscscan.com/misc-tools-and-utilities/public-rpc-nodes) for BSC RPC address, and use the appropriate ones based on your location, [opBNB Endpoints](../../../bnb-opbnb/get-started/network-info.md) for opBNB RPC address, and use the appropriate ones based on your location. You might encounter `Rate limit` issue for using official BSC/opBNB endpoints, we would highly recommend using 3rd Party RPCs, like the [NodeReal MegaNode](https://nodereal.io/meganode) 2. Config crossChain, greenfield light client and relayer hub smart contracts addresses, others can keep the default value, refer to this [contract-list](../../for-developers/cross-chain-integration/contract-list.md) to get addresses for Mainnet/Testnet. === "BSC-Mainnet" ``` json "relay_config": { ... "cross_chain_contract_addr": "0x77e719b714be09F70D484AB81F70D02B0E182f7d", "greenfield_light_client_contract_addr": "0x433bB48Bd86c089375e53b2E2873A9C4bC0e986B", "relayer_hub_contract_addr": "0x31C477F05CE58bB81A9FB4b8c00560f1cBe185d1" } ``` === "BSC-Testnet" ``` json "relay_config": { ... "cross_chain_contract_addr": "0xa5B2c9194131A4E0BFaCbF9E5D6722c873159cb7", "greenfield_light_client_contract_addr": "0xa9249cefF9cBc9BAC0D9167b79123b6C7413F50a", "relayer_hub_contract_addr": "0x91cA83d95c8454277d1C297F78082B589e6E4Ea3" } ``` === "opBNB-Mainnet" ``` json "relay_config": { ... "cross_chain_contract_addr": "0x7E376AEFAF05E20e3eB5Ee5c08fE1B9832b175cE", "greenfield_light_client_contract_addr": "0xf51ba131716776685A805E8E4Ecc95be2f923B93", "relayer_hub_contract_addr": "0xEd873b460C53D22f0FF3fc511854d9b8b16C4aE2" } ``` === "opBNB-Testnet" ``` json "relay_config": { ... "cross_chain_contract_addr": "0xF0Bcf6E4F72bCB33b944275dd5c9d4540a259eB9", "greenfield_light_client_contract_addr": "0xc50791892F6528E42A58DD07869726079C71F3f2", "relayer_hub_contract_addr": "0x59ACcF658CC4589C3C41720fd48e869B97A748a1" } ``` 3. Config the database settings. ```json "db_config": { "dialect": "mysql", "key_type": "local_private_key", "aws_region": "", "aws_secret_name": "", "password": "${pass}", "username": "${user}", "url": "tcp(${host})/greenfield-relayer?charset=utf8&parseTime=True&loc=Local", "max_idle_conns": 10, "max_open_conns": 100 } ``` Note: Please replace `${pass}`, `${user}`, `${host}` with your Mysql instance credential and host. And use a distinct database other than `greenfield-relayer`, e.g. `greenfield-op-relayer` when running the Greenfield Relayer for crosschain to opBNB on the same DB instance. ## Build Build the binary: ```shell make build ``` Or Build docker image: ```shell make build_docker ``` ## Run ### Create DB Schema Make sure the database instance is running. Create schema by MySQL client: ```shell CREATE SCHEMA IF NOT EXISTS `greenfield-relayer` DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci; ``` ### Start Relayer ```shell ./build/greenfield-relayer --config-type [local or aws] --config-path config_file_path --aws-region [aws region or omit] --aws-secret-key [aws secret key for config or omit] ``` Example: ```shell ./build/greenfield-relayer --config-type local --config-path config/config.json ``` Run docker: ```shell docker run -it -v /your/data/path:/greenfield-relayer -e CONFIG_TYPE="local" -e CONFIG_FILE_PATH=/your/config/file/path/in/container -d greenfield-relayer ``` Or you can deploy the greenfield relayer application using Helm Chart V3. Please refer to [relayer-readme](https://github.com/bnb-chain/greenfield/blob/master/deployment/helm/relayer-readme.md). --- ## Run Challenger > Source: https://docs.bnbchain.org/bnb-greenfield/for-validator/run-node/run-challenger/ ## Prerequisites ### Recommended Hardware The following lists the recommended hardware requirements: - Hardware Requirements: Desktop or laptop hardware running recent versions of Mac OS X, or Linux. - CPU: 4 cores - RAM: 4 GB - Relational database: Mysql ### Key Preparation - Challenger private key: Used to sign and approve transactions. - Bls private key: Used to aggregate votes. These two keys refer to `validator_challenger` and `validator_bls` created in [become-validator](become-validator.md) step 2. You can retrieve them with the following commands. ```bash gnfd keys export validator_challenger --unarmored-hex --unsafe --keyring-backend test gnfd keys export validator_bls --unarmored-hex --unsafe --keyring-backend test ``` ## Prepare Binary Get the greenfield-challenger app by running the following command in your terminal: ```bash git clone --branch "$(curl -s https://api.github.com/repos/bnb-chain/greenfield-challenger/releases/latest | jq -r '.tag_name')" https://github.com/bnb-chain/greenfield-challenger.git cd greenfield-challenger ``` ## Config Modify `config/config.json`. Or, you can create a new one and specify the config path by `--config-path` flag when start the challenger. !!! info Reference for a complete [config file](https://github.com/bnb-chain/bnb-chain-charts/blob/master/gnfd-challenger-testnet-values/values.yaml#L4) 1. Set your private key and bls key (via file or aws secret). ``` "greenfield_config": { "key_type": "local_private_key" or "aws_private_key" depending on whether you are storing the keys on aws or locally in this json file "aws_region": set this if you chose "aws_private_key" "aws_secret_name": set this if you chose "aws_private_key" "aws_bls_secret_name": set this if you chose "aws_private_key" "private_key": set this if you chose "local_private_key" "bls_private_key": set this if you chose "local_private_key" ... } ``` !!! note The term `private_key` refers to the private key of the `validator_challenger` account, while `bls_private_key` refers to the private key of the `validator_bls` account. To obtain these private keys, you can follow the instructions provided in the [key preparation](#key-preparation) section. 2. Set your RPC Address and Chain ID === "Mainnet" ```bash "greenfield_config": { rpcAddr = "https://greenfield-chain.bnbchain.org:443" chainId = "greenfield_1017-1" } ``` === "Testnet" ```bash "greenfield_config": { rpcAddr = "https://gnfd-testnet-fullnode-tendermint-us.bnbchain.org:443" chainId = "greenfield_5600-1" } ``` 3. Config your database settings. ``` "db_config": { "dialect": "mysql", "db_path": "your_db_path" "key_type": "local_private_key" or "aws_private_key" depending on whether you are storing the keys on aws or locally in this json file "aws_region": set this if you chose "aws_private_key", else leave as "" "aws_secret_name": set this if you chose "aws_private_key", else leave as "" "username": set db username if you chose "local_private_key", else leave as "" "password": set db password if you chose "local_private_key", else leave as "" ... } ``` 4. Config your internal sp config (for metrics purpose). ``` "sp_config": { "internal_sp_endpoints": [] // list of internal sps' endpoints } ``` ## Build Build binary: ```shell make build ``` Build docker image: ```shell make build_docker ``` ## Run ### Run MySQL in Docker(this can be skipped if you are using sqlite) ```shell docker run --name gnfd-mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=root -d mysql:5.7 ``` ### Create DB Schema Create schema in MySQL client: ```sql CREATE SCHEMA IF NOT EXISTS `challenger` DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci; ``` ### Start Challenger ```shell ./build/greenfield-challenger --config-type [local or aws] --config-path config_file_path --aws-region [aws region or omit] --aws-secret-key [aws secret key for config or omit] ``` Example: ```shell ./build/greenfield-challenger --config-type local --config-path config/config.json ``` Run docker: ```shell docker run -it -v /your/data/path:/greenfield-challenger -e CONFIG_TYPE="local" -e CONFIG_FILE_PATH=/your/config/file/path/in/container -d greenfield-challenger ``` Or you can deploy the greenfield challenger application using Helm Chart V3. Please refer to [challenger-readme](https://github.com/bnb-chain/greenfield/blob/master/deployment/helm/challenger-readme.md). --- ## Become Validator > Source: https://docs.bnbchain.org/bnb-greenfield/for-validator/run-node/become-validator/ --- title: Become Validator - BNB Greenfield Node order: 6 --- # Become Validator ## Minimum Requirements - Number of BNB to be staked: `1000BNB` - Hardware Requirements: Desktop or laptop hardware running recent versions of Mac OS X, or Linux. - CPU: 4 cores - RAM: 12 GB - HDD/SDD: 1 TB - Bandwidth: 1 MB/s - Slashing details: No slashing will occur for validator so far. ## Setting up Validator Node ### 1. Install Fullnode Follow the instructions [here to set up a full node](run-node.md). ### 2. Prepare validator, delegator, validator BLS, relayer, and challenger accounts !!! warning The current key generation and storage procedures are not very secure. It is highly recommended to implement a more robust method, particularly when dealing with keys like the `delegator` and `operator` keys. For enhanced security and best practices, the usage of the `Cold Wallet` and `MPC Wallet` is strongly encouraged. !!! note The `keyring-backend` supports multiple storage backends, some of which may not be available on all operating systems. See more details [here](../../core-concept/accounts.md#key-management). ```bash gnfd keys add validator --keyring-backend test gnfd keys add delegator --keyring-backend test gnfd keys add validator_bls --keyring-backend test --algo eth_bls gnfd keys add validator_relayer --keyring-backend test gnfd keys add validator_challenger --keyring-backend test ``` !!! tip Alternatively, if you choose a different $KEY_HOME location and you are not using the suggested default `~/.gnfd`, you may start the full node by using below script, where $KEY_HOME is your selected directory. ```bash gnfd keys add validator --keyring-backend test --home ${KEY_HOME} gnfd keys add delegator --keyring-backend test --home ${KEY_HOME} gnfd keys add validator_bls --keyring-backend test --algo eth_bls --home ${KEY_HOME} gnfd keys add validator_relayer --keyring-backend test --home ${KEY_HOME} gnfd keys add validator_challenger --keyring-backend test --home ${KEY_HOME} ``` ### 3. Obtain validator, delegator, validator BLS, relayer, and challenger account addresses !!! note Ensure you choose the correct --keyring-backend and that --home is set correctly if you saved the files in a custom folder in `step 2`. ```bash VALIDATOR_ADDR=$(gnfd keys show validator -a --keyring-backend test) DELEGATOR_ADDR=$(gnfd keys show delegator -a --keyring-backend test) RELAYER_ADDR=$(gnfd keys show validator_relayer -a --keyring-backend test) CHALLENGER_ADDR=$(gnfd keys show validator_challenger -a --keyring-backend test) VALIDATOR_BLS=$(gnfd keys show validator_bls --keyring-backend test --output json | jq -r '.pubkey_hex') VALIDATOR_BLS_PROOF=$(gnfd keys sign ${VALIDATOR_BLS} --keyring-backend test --from validator_bls) VALIDATOR_NODE_PUB_KEY=$(cat ${CONFIG_PATH}/config/priv_validator_key.json | jq -r '.pub_key.value') ``` ### 4. Submit a Create Validator Proposal Replace the values in the following JSON and save it as create_validator_proposal.json: - `${NODE_NAME}`: A custom human-readable name for this node. - `${VALIDATOR_NODE_PUB_KEY}`: The consensus key generated in step 1 (stored in ${HOME}/.gnfd/config/priv_validator_key.json by default). - `${VALIDATOR_ADDR}`: The operator address created in step 2. - `${DELEGATOR_ADDR}`: The delegator address created in step 2. - `${VALIDATOR_BLS}`: The BLS key created in step 2. - `${VALIDATOR_BLS_PROOF}`: The BLS proof created in step2. - `${RELAYER_ADDR}`: The relayer address created in step 2. - `${CHALLENGER_ADDR}`: The challenger address created in step 2. ```json { "messages": [ { "@type": "/cosmos.staking.v1beta1.MsgCreateValidator", "description": { "moniker": "${NODE_NAME}", "identity": "", "website": "", "security_contact": "", "details": "" }, "commission": { "rate": "0.070000000000000000", "max_rate": "1.000000000000000000", "max_change_rate": "0.010000000000000000" }, "min_self_delegation": "1000000000000000000000", "delegator_address": "${DELEGATOR_ADDR}", "validator_address": "${VALIDATOR_ADDR}", "pubkey": { "@type": "/cosmos.crypto.ed25519.PubKey", "key": "${VALIDATOR_NODE_PUB_KEY}" }, "value": { "denom": "BNB", "amount": "1000000000000000000000" }, "from": "0x7b5Fe22B5446f7C62Ea27B8BD71CeF94e03f3dF2", "relayer_address": "${RELAYER_ADDR}", "challenger_address": "${CHALLENGER_ADDR}", "bls_key": "${VALIDATOR_BLS}", "bls_proof": "${VALIDATOR_BLS_PROOF}" } ], "metadata": "", "title": "Create ${NODE_NAME} Validator", "summary": "create ${NODE_NAME} validator", "deposit": "1000000000000000000BNB" } ``` #### 4.1 Run create validator command to submit the proposal by local keys. Ensure the delegator account has enough BNB tokens. !!! info If you are utilizing the `Cold Wallet` or `MPC wallet`, please proceed to step [#4.2](#42-submit-the-proposal-by-gnfd-tx-sender-ensure-the-delegator-account-has-enough-bnb-tokens). ```bash gnfd tx staking create-validator ./create_validator_proposal.json --keyring-backend test --chain-id "greenfield_1017-1" --from ${DELEGATOR_ADDR} --node "https://greenfield-chain.bnbchain.org:443" -b sync --gas "200000000" --fees "1000000000000000000BNB" --yes ``` ```bash gnfd tx staking create-validator ./create_validator_proposal.json --keyring-backend test --chain-id "greenfield_5600-1" --from ${DELEGATOR_ADDR} --node "https://gnfd-testnet-fullnode-tendermint-us.bnbchain.org:443" -b sync --gas "200000000" --fees "1000000000000000000BNB" --yes ``` #### 4.2 Submit the proposal by `gnfd-tx-sender`. Ensure the delegator account has enough BNB tokens. Run command to generate the transaction details. ```bash gnfd tx staking create-validator ./create_validator_proposal.json --from ${DELEGATOR_ADDR} --print-eip712-msg-type ``` Submit the transaction using [gnfd-tx-sender](https://gnfd-tx-sender.nodereal.io/). ### 5. Wait for the voting until the Proposal is passed. After submitting the proposal successfully, you must wait for the voting to be completed and the proposal to be approved. It will last 7days on mainnet while 1 day on testnet. Once it has passed and is executed successfully, you can verify that the node has become a validator. !!! warning Please ensure that the validator node is running before it is selected. And the validator is responsible for [running relayer](run-relayer.md) and [runing challenger](run-challenger.md), please ensure all these services are running as expected. ### 6. Query all validators === "Mainnet" ```bash gnfd query staking validators --node "https://greenfield-chain.bnbchain.org:443" ``` === "Testnet" ```bash gnfd query staking validators --node "https://gnfd-testnet-fullnode-tendermint-us.bnbchain.org:443" ``` --- ## Overview > Source: https://docs.bnbchain.org/bnb-greenfield/storage-provider/overview/ # Overview ## What is the Greenfield Storage Provider Storage Provider (SP) is an infrastructure provider for storage services. They work in synergy with Greenfield validators to provide a complete storage service. Validators store metadata and financial ledgers with consensus, while SPs store the actual data (payload data) of objects using the Greenfield chain as the ledger and single source of truth. SPs provide a range of convenient services for users and dApps to manage data on Greenfield. ## How the Greenfield Storage Providers works SPs need to register themselves firstly by depositing on the Greenfield blockchain as their `Service Stake`. The Greenfield validators will then conduct a governance procedure to vote to elect the SPs. When joining and leaving the network, SPs must follow specific actions to ensure data redundancy for users, or they will face fines on their `Service Stake`. SPs provide publicly accessible APIs that allow users to upload, download and manage data. These APIs are designed to be similar to Amazon S3 APIs, making it easier for existing developers to write code for them. SPs are responsible for responding to user requests to write (upload) and read (download) data, as well as managing user permissions and authentications. Each SP maintains its own local full node, allowing for a strong connection with the Greenfield network. This enables the SP to directly monitor state changes, properly index data, send transaction requests in a timely manner and manage local data accurately. To encourage SPs to showcase their capabilities and provide a professional storage system with high-quality SLA, it is recommended that they advertise their information and prove to the community. ## Architecture SP contains fifteen core modules as shown below: - **Gater**: It serves as the gateway for SP, providing HTTP services and adhering to the S3 protocol. It generates corresponding tasks to user requests and forwards them to other modules within SP. Since Gater does not allow customization, no interface is defined in the modular file. - **Authenticator**: It is responsible for verifying authentication. - **Approver**: It is responsible for handling approval requests, specifically `MigrateBucketApproval`, etc. - **Uploader**: It handles the `PutObject` requests from user accounts and stores payload data into piece store of the primary SP. - **Downloader**: It is responsible for handling `GetObject` requests from user accounts and `GetChallengeInfo` requests from other components in the Greenfield system. - **Executor**: It is responsible for handling background tasks. This module can ask tasks from the `Manager` module, execute them and report the results or status back to the `Manager`. - **Manager**: It is responsible for managing task scheduling of SP and other management functions, such as bucket migration and sp exit procedure. - **P2P**: It is responsible for handling the interaction of control information between SPs. - **Receiver**: It receives data from the primary SP, calculates the integrity hash of the payload data, signs it, and returns it to the primary SP for sealing on Greenfield blockchain. - **Signer**: It handles the signing of the SP data on the Greenfield blockchain operator and holds all the SP's private keys. Due to the sequence number of the SP account, it must be a singleton. - **Metadata**: It is used to provide efficient query interfaces for meta info in SP. This module achieves low latency and high-performance SP requirements. - **BlockSyncer**: It records block info in Greenfield blockchain. - **PieceStore**: It interacts with underlying storage vendors, eg. AWS S3, MinIO, OSS, etc. - **SPDB**: It stores all the contexts of the background jobs and the metadata of SP. - **BSDB**: It stores all the events' data from the Greenfield blockchain and provides them to the `Metadata` service of SP. ## How to implement customized requirements in Greenfield SP From the code level, SP is not only an implementation layer, it has been expanded into a framework called `GfSp`, which allows users to implement their own logics according to their own needs. If users want to implement some specific functions, you can override these methods that are declared in the abstract interfaces. If users don't need to implement customized requirements, `GfSp` will use default implementations. There are nine important layers of abstraction: - [lifecycle](https://github.com/bnb-chain/greenfield-storage-provider/tree/master/core/lifecycle): It provides two abstract interfaces to manage services: `Service` and `Lifecycle` to control and manage services in SP. - [module](https://github.com/bnb-chain/greenfield-storage-provider/tree/master/core/module): It provides multiple abstract interfaces to interact with different modules in GfSp. Therefore, users can implement replated methods to meet your own requirements. - [consensus](https://github.com/bnb-chain/greenfield-storage-provider/tree/master/core/consensus): It is provides abstract interfaces about how to query data on Greenfield blockchain. - [piecestore](https://github.com/bnb-chain/greenfield-storage-provider/tree/master/core/piecestore): It is used to interact with underlying storage systems. - [spdb](https://github.com/bnb-chain/greenfield-storage-provider/tree/master/core/spdb): It provides abstract interfaces about how to store background tasks and metadata of SP. - [bsdb](https://github.com/bnb-chain/greenfield-storage-provider/blob/master/core/bsdb): It provides abstract interfaces about how to query metadata in SP. - [rcmgr](https://github.com/bnb-chain/greenfield-storage-provider/tree/master/core/rcmgr): It provides abstract interfaces about managing cpu and memory resources in SP. - [task](https://github.com/bnb-chain/greenfield-storage-provider/tree/master/core/task): It provides abstract interfaces about the smallest uint for interacting with SP background services. - [taskqueue](https://github.com/bnb-chain/greenfield-storage-provider/tree/master/core/taskqueue): It provides abstract interfaces about task scheduling and executing. --- ## Storage Provider Lifecycle > Source: https://docs.bnbchain.org/bnb-greenfield/storage-provider/storage-provider-lifecycle/ # Storage Provider Lifecycle This document describes the entire lifecycle of a storage provider from joining the Greenfield Storage Network to exiting. ## Preparation First, the storage provider needs to learn how to run and create a storage provider node, which requires several different user accounts and a unified external EndPoint. - Follow Recommended Prerequisites to get ready - Create the required accounts, E.g operator/fundig/seal/approval/gv/bls - Run all services of Storage Provider !!! note For more information, please see [Run Storage Provider](./run-book/run-SP-node.md) ## Proposal The Storage Provider (SP) must initiate an on-chain proposal that outlines the Msg information to be automatically executed after receiving approval through the voting process. Specifically, the Msg in this case is `MsgCreateStorageProvider`. It's essential to ensure that the deposit tokens exceed the minimum deposit tokens specified on the chain. Below are the required fields that need to be modified in the proposal: - Addresses: - sp_address: The address of the storage provider that will be added to the network. - seal_address: The address used for sealing object - approval_address: The address responsible for approving bucket/object creation. - gc_address: The address for garbage collection. - maintenance_address: The address is used for testing while in maintenance mode. - EndPoint: Details of the endpoint where the SP will serve data requests. - Quota & Price: - read_price: The cost in Gwei per byte per second for read operations. - stora_price: The cost in Gwei per byte per second for data storage - free_read_quota: The default free read quota allocated to users (e.g., 10GB). - Deposit for SP Staking: - The SP must stake at least 1000 BNB (Binance Coin) in the testnet as a commitment to providing storage services. - Deposit for Proposal: - The proposal itself must have a deposit of at least 1 BNB in the testnet. !!! note For more information, please see [Add Storage Provider to Greenfield Network](./run-book/join-SP-network.md) Initiating this on-chain proposal with the necessary modifications and deposits is a crucial step for the SP to become an active participant in the Greenfield network, offering reliable and secure storage services to users. By complying with the proposal requirements, the SP can enhance its reputation and attract more users, contributing to the growth and success of the decentralized storage ecosystem. ## In Service During the in-service status, Storage Providers (SPs) actively engage in the network's daily operations. They handle a variety of user requests, including data storage, retrieval, and other storage-related operations. SPs assume a critical role in maintaining the availability, integrity, and confidentiality of the data they store. As gatekeepers of user access, they enforce proper authentication and authorization procedures to safeguard data from unauthorized access or tampering. At this stage, SPs must create virtual groups within the Greenfield network to efficiently serve buckets and objects. These virtual groups, resembling disk sectors, allow SPs to manage data storage in a more organized and optimized manner. By associating objects with virtual groups, SPs can limit the range of secondary storage providers responsible for storing object replica data, which enhances data redundancy and resilience. !!! note For more information, please see [Virtual Group](https://github.com/bnb-chain/greenfield/blob/doc-refactor/docs/modules/virtual-group.md#abstract) Additionally, SPs are required to provide corresponding stakes for the amount of data they store. This staking mechanism further incentivizes SPs to offer reliable and high-quality services to users. By staking tokens or digital assets, SPs demonstrate their commitment to maintaining a robust and trustworthy network, aligning their interests with the overall security and success of the storage ecosystem. Moreover, the creation of virtual groups and staking helps to disentangle the interdependency between buckets/objects and SPs. By doing so, SPs mitigate the need for an extensive volume of transactions when modifying on-chain BucketInfo and ObjectInfo during SP exits and bucket migrations. This leads to more efficient network management and smoother transitions during changes in the network's composition. As SPs continue to serve user needs and actively participate in network operations, their reputation and service quality become paramount. A positive reputation score is crucial for attracting more users to store their data with a particular SP. Through continuous improvement and adaptation, SPs can enhance their services, increase storage capacity, and maintain a competitive edge in the dynamic decentralized storage market. ## In Maintenance The maintenance mode for service providers (SPs) is a status in which SPs do not serve any create/upload requests from users. There are two circumstances in which an SP can be in maintenance mode: 1. When an SP joins the network after a proposal has passed, it will stay in `STATUS_IN_MAINTENANCE` until it sends a transaction including msg `MsgUpdateStorageProviderStatus` to Greenfield to change its status to `STATUS_IN_SERVICE`. 2. If an SP is already in service, it can send a transaction with msg `MsgUpdateStorageProviderStatus` to Greenfield and request a maintenance duration, if there are no restrictions violated, the SP is allowed to enter maintenance mode immediately. !!! note Note: The SP needs to send a transaction to Greenfield to update its status back `STATUS_IN_SERVICE` before its request duration ends, or Greenfield would do it mandatorily. There are two restrictions that apply when an SP requests to be in maintenance. These restrictions work with the parameters `num_of_historical_blocks_for_maintenance_records`, `maintenance_duration_quota` and `num_of_lockup_blocks_for_maintenance`. Refer to [Params](https://github.com/bnb-chain/greenfield/blob/doc-refactor/docs/modules/storage-provider.md#params) * The total maintenance duration for each SP, within the number of blocks defined by `num_of_historical_blocks_for_maintenance_records`, should not exceed the `maintenance_duration_quota`. * An SP is not allowed to make two consecutive requests to `STATUS_IN_MAINTENANCE` within `num_of_lockup_blocks_for_maintenance`, even if there are enough quotas for it. To ensure the quality of service provided, we strongly recommend that SPs conduct a self-test via the maintenance account before turning back to `STATUS_IN_SERVICE`. This includes creating buckets/objects to verify that all functionalities work as expected. For a detailed illustration on how to use SDK to create bucket/object, please refer to the [APIs and SDKs](../for-developers/apis-and-sdks/index.md). ## Exit There are two types of exit based on the behavior and choices of the SP: Graceful Exit and Forced Exit. ### Graceful Exit At some point, the SP may choose to voluntarily exit the Greenfield storage network for various reasons. Ensuring a graceful exit process is crucial to ensure a seamless transition of responsibilities and data to other SPs. During the exit process, the SP must continue to fulfill user serve user querying requests, Once the exit process is successfully completed, the SP can retrieve all the staked BNB. To execute a graceful exit, all its stored data need to be migrated to other successor SPs that are willing to take over. This data migration process involves recovering data from the exiting SP by successor SPs in a secure and efficient manner. After the exit SP sending a `StorageProviderExit` transaction to the Greenfield Blockchain, its status will turn to `STATUS_GRACEFUL_EXITING`. A successor SP can initiate the recovery process by first sending a `ReserveSwapIn` transaction to the Greenfield Blockchain, reserving the exit SP's position in the respective Global Virtual Group (GVG) or GVG Family so that it will be allowed to recover data from other SPs. Once the successor SP successfully takes over all data in a GVG or GVG Family, it will send a `CompleteSwapIn` transaction to the Greenfield Blockchain, confirming the completion of the data transfer process. Greenfield Blockchain incorporates an effective consensus mechanism to facilitate and validate the graceful exit process. This mechanism ensures that the exit is carried out transparently, maintaining the network's integrity and preventing any disruptions or data loss during the transition. To ensure the safe and reliable migration of data, frequent data challenges are applied to the SPs that take over the data. These challenges are designed to verify the integrity and consistency of the migrated data, reassuring users that their data remains secure and accessible. ### Forced Exit An uncooperative SP no longer wishes to provide service and refuses to go through the standard graceful exit process. In such a case, Greenfield governance will force the SP to exit, make it enter `STATUS_FORCED_EXITING`. The data recovery process for successor SP is the same as graceful exit mentioned above. However, a forced exit SP will face penalties, and its staked BNB will be locked into the Payment module governance account, this payment account is used to receive forced settlement fee, and pay for potential debt from late forced settlement. !!! note For more information, please see [SP exit](https://github.com/bnb-chain/greenfield/blob/doc-refactor/docs/modules/virtual-group.md#sp-exit-workflow) --- ## Data Service Quality Standard > Source: https://docs.bnbchain.org/bnb-greenfield/storage-provider/standard/ # Data Service Quality Standard ## Abstract BNB Greenfield is a decentralized storage network comprising two layers: blockchain and storage providers(SPs). The BNB Greenfield blockchain maintains ledgers for users and records storage metadata as common blockchain state data. SPs refer to storage service infrastructures provided by organizations or individuals. This standard aims to ensure SPs on Greenfield can provide enterprise-level, secure, reliable, and high-quality storage infrastructure and services to users. SPs that fail to meet the standards may have their eligibility and access revoked from the network. The standards consist of two parts: * Minimum service quality standards. The minimum service quality for SPs on various metrics on the mainnet, as well as the preferred requirements. * Storage provider protocols. The API and P2P protocol interfaces that SPs must implement. In addition to these standards, this document will introduce an official implementation of the SP protocols. Community developers are welcome to: * directly use the official implementation, which currently supports Kubernetes deployment and AWS S3, OSS, MinIO, B2, Ali Lindorm as the underlying storage. * extend the official implementation. The official solution has initially achieved modularity. SP developers can replace modules as needed. * refer to the SP protocol documentation to customize their own solutions. ## Minimum Service Quality Standards ### Capacity * `2M/s uplink bandwidth`: This is the minimum bandwidth requirement for SP nodes in uploading files. SP nodes must be able to stably upload files at a rate of at least 2 megabits per second. * `20M/s downlink bandwidth`: This is the minimum bandwidth requirement for SP nodes in querying files. SP nodes must be able to provide 20M/s of download bandwidth. * 2 files/s. This is the minimum requirement for SP nodes in file upload capability. SP nodes must be able to stably upload at least 2 files per second, the size of each test file can be 1M. * `1PB storage capacity`: Because the SP needs to run several microservices, these computing resources will generate inevitable fixed costs. If the SP only provides a very small amount of storage capacity, it is difficult for the corresponding profits to cover these fixed costs. We hope that SP's storage capacity is unlimited. ### Availability * `99.9% SLA`: The SLA here means the uptime of the SP API. * `99.99% data durability`: Data durability refers to the ability to preserve and maintain data over time. It is a measure of how permanent and invulnerable the data is to loss or change. If the data durability of each SP can meet this standard, then the data stored using erasure coding and distributed across different SPs will have higher data durability guarantees. Greenfield will punish unavailable or poor quality SPs through challenge mechanisms. SPs with SLA below 99.9% or data durability below 99.99% are likely to be phased out. In the early stages of Greenfield, to encourage more inexperienced SPs to participate, Greenfield will apply a relatively relaxed slash mechanism to protect SPs from slashing more than 1 BNB within one hour. ### Scalability(better to have) We encourage SPs to dynamically scale up capacity on the basis of providing minimum capacity to avoid being unable to provide services due to sudden traffic and being slashed. The scaling strategy is related to the computing resource platform chosen by the SP. We do not make specific requirements in this regard. ## Storage Provider Protocols ### HTTP RESTful API Specification Supporting the Greenfield Network API is essential for storage providers. It allows users and developers to interact and integrate with each SP node through a unified interface without having to adapt to custom interfaces from different SP nodes, greatly simplifying the user experience and development difficulty. The API includes functions to retrieve storage space information, upload and download files, and manage permissions. SP nodes can implement compatibility with the network API based on their own technology. Developers can refer to the Greenfield Network's open API documentation for interfacing development. ### Universal Endpoint All storage objects in the Greenfield Network can be identified and accessed through a universal resource identifier (URI). When creating a storage object, the SP node needs to assign it a unique URI according to the network rules and support using that URI to retrieve the object. The detailed spec is defined [here](https://github.com/bnb-chain/greenfield-whitepaper/blob/main/part3.md#231-universal-endpoint). ### Auth Methods Permission management and authentication mechanisms are essential for a decentralized storage network, ensuring that only authorized users can access specific storage objects. The Greenfield Network defines standard permission divisions and authorization processes, requiring SP nodes to implement detailed permission control and user authentication accordingly. SP should achieve following three authentication at least: * `GNFD1-ECDSA` It requires users to use a private key to sign for authentication. * `GNFD2-EDDSA` It is used for web-based applications and users to store the “off chain auth” EdDSA account key in SPs. Users can communicate with the SP without explicit signature for most interactions. * `GNFD1-ETH-PERSONAL_SIGN` It is only used to verify wallet personal signature when registering EdDSA account key in SP from a web application (e.g. [https://dcellar.io](https://dcellar.io)). ## Open source Implementation The open source storage provider framework implements the Greenfield storage provider API and protocol specifications. It provides standardized interfaces and abstractions for SP node developers, greatly reducing the difficulty of setting up a storage provider. Developers can quickly build SP based on this framework and conduct secondary development according to their business needs. This helps cultivate the developer ecosystem of the Greenfield Network and encourages more technical teams to join the construction of the Greenfield Network. Refer to the [GitHub repo](https://github.com/bnb-chain/greenfield-storage-provider) for more details. ### Interfaces * [Consensus](https://github.com/bnb-chain/greenfield-storage-provider/blob/master/core/consensus/consensus.go): is an interface to query greenfield consensus data. the consensus data can come from validator, fullnode, or other off-chain data service * [ResourManager](https://github.com/bnb-chain/greenfield-storage-provider/blob/master/core/rcmgr/README.md): ResourceManager is an interface to the resource management subsystem. The ResourceManager tracks and accounts for resource usage in the stack, from the internals to the application, and provides a mechanism to limit resource usage according to a user configurable policy. * [PieceStore](https://github.com/bnb-chain/greenfield-storage-provider/blob/master/core/piecestore/piecestore.go): PieceStore defines the interfaces to the piece store that store the object payload data. * [PieceOp](https://github.com/bnb-chain/greenfield-storage-provider/blob/master/core/piecestore/piecestore.go): PieceOp is a helper interface for piece key operator and piece size calculation. * [SPDB](https://github.com/bnb-chain/greenfield-storage-provider/blob/master/core/spdb/spdb.go): SPDB is an interface to record the SP metadata. * [BSDB](https://github.com/bnb-chain/greenfield-storage-provider/blob/master/store/bsdb/database.go): BSDB is an interface to record the greenfield chain metadata. * [TaskQueue](https://github.com/bnb-chain/greenfield-storage-provider/blob/master/core/taskqueue/README.md): Task is an interface to the smallest unit of SP background service interaction. Task scheduling and execution are directly related to the order of task arrival, so task queue is a relatively important basic interface used by all modules inside SP. ### Modules * [Approver](https://github.com/bnb-chain/greenfield-storage-provider/blob/master/core/module/README.md) : Approver is a module to handle approval requests, such as MigrateBucketApproval. * [Authorizer](https://github.com/bnb-chain/greenfield-storage-provider/blob/master/core/module/README.md): Authorizer is a module to authority verification. * [Downloader](https://github.com/bnb-chain/greenfield-storage-provider/blob/master/core/module/README.md): Downloader is a module to handle download requests from users, and get challenge info requests from other components in the system. * [TaskExecutor](https://github.com/bnb-chain/greenfield-storage-provider/blob/master/core/module/README.md): TaskExecutor is a module to handle background task, it will ask task from Manager modular, handle the tasks and report the results or status to the manager module includes: `ReplicatePieceTask`, `SealObjectTask`, `ReceivePieceTask`, `GCObjectTask`, `GCZombiePieceTask`, `GCMetaTask`. * [Manager](https://github.com/bnb-chain/greenfield-storage-provider/blob/master/core/module/README.md): Manager is a module responsible for task scheduling and other management of SP. * [P2P](https://github.com/bnb-chain/greenfield-storage-provider/blob/master/core/module/README.md): P2P is a module to the interaction of control information between Sps, handles the replicate piece approval, it will broadcast the approval to other SPs, wait the responses, if up to min approved number or max approved number before timeout, will return the approvals. * [Receiver](https://github.com/bnb-chain/greenfield-storage-provider/blob/master/core/module/README.md): Receiver is a module to receive the piece data from primary SP, calculates the integrity hash of the piece data and sign it, returns to the primary SP for sealing objects on greenfield. * [Signer](https://github.com/bnb-chain/greenfield-storage-provider/blob/master/core/module/README.md): Signer is a module to handle the SP's sign and on greenfield chain operators. It holds SP all private keys. Considering the sp account's sequence number, it must be a singleton. * [Uploader](https://github.com/bnb-chain/greenfield-storage-provider/blob/master/core/module/README.md): Uploader is a module to handle upload requests from users, and store it in primary SP's piece store. ### Minimal Hardware Requirement * Recommend kubernetes or kubernetes compatible platforms. * More than 10 virtual machines, 4 core 8G spec. * 50GB+ SQL database. * 1 GBbps network connection. ### Secondary Development Examples Customize interface ```go // new your own CustomizedPieceStore instance that implement the PieceStore interface pieceStore := NewCustomizedPieceStore(...) // new GfSp framework app gfsp, err := NewGfSpBaseApp(GfSpConfig, CustomizePieceStore(pieceStore)) if err != nil { return err } gfsp.Start(ctx) // the GfSp framework will replace the default PieceStore with CustomizedPieceStore ``` Customize module ```go // new your own CustomizedApprover instance that implement the Approver interface // NewCustomizedApprover must be func type: // func(app *GfSpBaseApp, cfg *gfspconfig.GfSpConfig) (coremodule.Modular, error) approver := NewCustomizedApprover(GfSpBaseApp, GfSpConfig) // the Special Modular name is Predefined gfspapp.RegisterModularInfo(model.ApprovalModularName, model.ApprovalModularDescription, approver) // new GfSp framework app gfsp, err := NewGfSpBaseApp(GfSpConfig, CustomizeApprover(approver)) if err != nil { return err } gfsp.Start(ctx) // the GfSp framework will replace the default Approver with Customized Approver ``` ## Documents * [Greenfield Whitepaper](https://github.com/bnb-chain/greenfield-whitepaper): The official Greenfield Whitepaper. * [Greenfield](../index.md): The Greenfield documents. * [Storage Module on Greenfield](https://github.com/bnb-chain/greenfield/blob/master/docs/modules/storage-module.md): The storage module on Greenfield Chain. * [Storage Provider on Greenfield](https://github.com/bnb-chain/greenfield/blob/master/docs/modules/storage-provider.md): The storage provider on Greenfield Chain. * [Data Availability Challenge](https://github.com/bnb-chain/greenfield/blob/master/docs/modules/data-availability-challenge.md): The correctness of payload be stored in SP. * [Storage Provider Introduction](./overview.md): The Greenfield Storage Provider documents. * [Storage Provider Compiling and Dependencies](./run-book/compile-dependences.md): The detailed introduction to sp compiling and dependencies. * [Run Local Storage Provider Network](./run-book/run-local-SP-network.md): The introduction to run local SP env for testing. * [Join SP Network](./run-book/join-SP-network.md): The introduction to join SP network in testnet or mainnet --- ## SP Compiling and Dependencies > Source: https://docs.bnbchain.org/bnb-greenfield/storage-provider/run-book/compile-dependences/ ## Compile SP Compilation dependencies: - [Golang](https://go.dev): SP is written in Golang, you need to install it. Golang version requires `1.20+`. - [Buf](https://buf.build): A new way of working with Protocol Buffers. SP uses Buf to manage proto files. - [protoc-gen-gocosmos](https://github.com/cosmos/gogoproto): Protocol Buffers for Go with Gadgets. SP uses this protobuf compiler to generate pb.go files. - [mockgen](https://github.com/uber-go/mock): A mocking framework for the Go programming language that is used in unit test. - [jq](https://stedolan.github.io/jq/): Command-line JSON processor. Users should install jq according to your operating system. ```shell # clone source code git clone https://github.com/bnb-chain/greenfield-storage-provider.git cd greenfield-storage-provider/ # install dependent tools: buf, protoc-gen-gocosmos and mockgen make install-tools # compile sp make build # move to build directory cd build # execute gnfd-sp binary file ./gnfd-sp version # show the gnfd-sp version information Greenfield Storage Provider __ _ __ _____/ /_____ _________ _____ ____ ____ _________ _ __(_)___/ /__ _____ / ___/ __/ __ \/ ___/ __ / __ / _ \ / __ \/ ___/ __ \ | / / / __ / _ \/ ___/ (__ ) /_/ /_/ / / / /_/ / /_/ / __/ / /_/ / / / /_/ / |/ / / /_/ / __/ / /____/\__/\____/_/ \__,_/\__, /\___/ / .___/_/ \____/|___/_/\__,_/\___/_/ /____/ /_/ Version : v1.0.0 Branch : master Commit : 7e1f56809c5385bf1ea6f41d318ab1419dcb0f86 Build : go1.20.3 darwin arm64 2023-10-08 10:31 # show the gnfd-sp help info ./gnfd-sp -h ``` ### Note If you've already executed `make install-tools` command in your shell, but you failed to make build and encountered one of the following error messages: ```shell # error message 1 buf: command not found # you can execute the following command, assumed that you installed golang in /usr/local/go/bin. Other OS are similar. GO111MODULE=on GOBIN=/usr/local/go/bin go install github.com/bufbuild/buf/cmd/buf@v1.25.0 # error message 2 Failure: plugin gocosmos: could not find protoc plugin for name gocosmos - please make sure protoc-gen-gocosmos is installed and present on your $PATH # you can execute the fowllowing command, assumed that you installed golang in /usr/local/go/bin. Other OS are similar. GO111MODULE=on GOBIN=/usr/local/go/bin go install github.com/cosmos/gogoproto/protoc-gen-gocosmos@latest # if you want to execute unit test of sp, you should execute the following command, assumed that you installed golang in /usr/local/go/bin. Other OS are similar. GO111MODULE=on GOBIN=/usr/local/go/bin go install go.uber.org/mock/mockgen@latest ``` Above error messages are due to users don't set go env correctly. More info users can search `GOROOT`, `GOPATH` and `GOBIN`. ## SP Dependencies If a user wants to start SP in local mode or testnet mode, you must prepare `SPDB`, `BSDB` and `PieceStore` dependencies. ### SPDB and BSDB SP uses [SPDB](https://github.com/bnb-chain/greenfield-storage-provider/blob/master/docs/modules/spdb.md) and [BSDB](https://github.com/bnb-chain/greenfield-storage-provider/blob/master/docs/modules/bsdb.md) to store some metadata such as object info, object integrity hash, etc. These two DBs now use `RDBMS` to complete corresponding function. Users now can use `MySQL` or `MariaDB` to store metadata.The following lists the supported RDBMS: 1. [MySQL](https://www.mysql.com/) 2. [MariaDB](https://mariadb.org/) More types of database such as `PostgreSQL` or NewSQL will be supported in the future. ### PieceStore Greenfield is a decentralized data storage system which uses object storage as the main data storage system. SP encapsulates data storage as [PieceStore](https://github.com/bnb-chain/greenfield-storage-provider/blob/master/docs/modules/piece-store.md) which provides common interfaces to be compatible with multiple data storage systems. Therefore, if a user wants to join SP or test the function of SP, you must use a data storage system. The following lists the supported data storage systems: 1. [AWS S3](https://aws.amazon.com/s3/): An object storage can be used in production environment. 2. [Aliyun OSS](https://www.alibabacloud.com/en/product/object-storage-service): Fully managed object storage service to store and access any amount of data from anywhere. 3. [B2](https://www.backblaze.com/cloud-storage): Backblaze B2 provides unlimited data storage in the cloud at 1/5th the cost of Amazon S3. 4. [MinIO](https://min.io/): An object storage can be used in production environment which is compatible with AWS S3. 5. [POSIX Filesystem](https://en.wikipedia.org/wiki/POSIX): Local filesystem is used for experiencing the basic features of SP and understanding how SP works. The piece data created by SP cannot be got within the network and can only be used on a single machine. Detailed info about `PieceStore`, you can refer this [doc](piece-store.md). ### Install Dependencies #### Install MySQL in CentOS 1. Install MySQL yum package ```shell # 1. Download MySQL yum package wget http://repo.mysql.com/mysql57-community-release-el7-10.noarch.rpm # 2. Install MySQL source rpm -Uvh mysql57-community-release-el7-10.noarch.rpm # 3. Install public key rpm --import https://repo.mysql.com/RPM-GPG-KEY-mysql-2022 # 4. Install MySQL server yum install -y mysql-community-server # 5. Start MySQL systemctl start mysqld.service # 6. Check whether the startup is successful systemctl status mysqld.service # 7. Get temporary password grep 'temporary password' /var/log/mysqld.log # 8. Login MySQL through temporary password # After you log in with the temporary password, do not perform any other operations. Otherwise, an error will occur. In this case, you need to change the password mysql -uroot -p # 9. change MySQL password rules mysql> set global validate_password_policy=0; mysql> set global validate_password_length=1; mysql> ALTER USER 'root'@'localhost' IDENTIFIED BY 'yourpassword'; ``` --- ## Run Local SP Network > Source: https://docs.bnbchain.org/bnb-greenfield/storage-provider/run-book/run-local-SP-network/ This guide helps you to set up a local Greenfield Storage Provider network for testing and other development related purposes. - [Recommended Prerequisites](#recommended-prerequisites) - [Quickly setup local Greenfield blockchain network](#quickly-setup-local-greenfield-blockchain-network) - [Setup local SP network](#setup-local-sp-network) - [Operate With SP](#operate-with-sp) - [1. Generate your test account](#1-generate-your-test-account) - [2. Transefer some BNB tokens to test account](#2-transefer-some-bnb-tokens-to-test-account) - [3. Use cmd to send requests](#3-use-cmd-to-send-requests) ## Recommended Prerequisites The following lists the recommended hardware requirements: - VPS running recent versions of Mac OS X, Linux, or Windows; - 16 cores of CPU, 64 GB of memory(RAM); - At least 100GB disk space for backend storage; - 10GB+ SQL Database. ## Quickly setup local Greenfield blockchain network 1. Build Greenfield Blockchain **Note** Greenfield blockchain uses a lib which uses `cgo`, so you should set cgo env var; in addition, you should install `gcc` compiler in your OS. ```shell git clone https://github.com/bnb-chain/greenfield.git cd greenfield/ export CGO_ENABLED=1 make build ``` If you encountered the following error messages while compiling greenfield blockchain, you should install `glibc-static` and `libstdc++-static`. ```shell # command-line-arguments /usr/local/go/pkg/tool/linux_amd64/link: running gcc failed: exit status 1 /bin/ld: cannot find -lstdc++ collect2: error: ld returned 1 exit status make: *** [build] Error 1 ``` 2. Start Greenfield Blockchain ```shell # 1 validator and 8 storage providers bash ./deployment/localup/localup.sh all 1 8 ``` 3. Export the keys of SPs ```shell bash ./deployment/localup/localup.sh export_sps 1 8 # result example # { # "sp0": { # "OperatorAddress": "0x14539343413EB47899B0935287ab1111Df891d04", # "FundingAddress": "0x21c6ff21DD7012DE1CCf9055f2eB234A44a1d3fB", # "SealAddress": "0x8e424c6Db42Ad9A5d91b24e20b5f603eC70abbA3", # "ApprovalAddress": "0x7Aa5C8B50696f1D15B3A60d6629f7318c605bb4C", # "GcAddress": "0xfa238a4B262e1dc35c4970A2296A2444B956c9Ca", # "MaintenanceAddress": "0xbE03316B1D7c3FCB69136e47e02442d6Fb3396dB", # "OperatorPrivateKey": "ba6e97958d9c43d1ad54923eba99f8d59f54a0c66c78a5dcbc004c5c3ec72f8c", # "FundingPrivateKey": "bd9d9e7823cd2dc7bc20f1b6676c3025cdda6cf5a8df9b04597fdff42c29af01", # "SealPrivateKey": "aacd6b834627fdbc5de2bfdb1db31be0ea810a941854787653814c8040a9dd39", # "ApprovalPrivateKey": "32108ed1a47c0af965824f84ac2162c029f347eec6d0988e642330b0ac264c85", # "GcPrivateKey": "2fad16031b4fd9facb7dacda3da4ca4dd5f005f4166891bf9f7be13e02abb12d", # "MaintenancePrivateKey": "cc38f4c004f73a810223776376a37a8ab3ed8204214f5a3a0a2f77f7bb5e2dc1", # "BlsPrivateKey": "6f349866f18413abb1a78cab947933459042044649686f354e941a646b9ed6e7" # } # ... # } ``` These JSON data will be used for setup local SP network, so you'd better save it as a json file: ```shell bash ./deployment/localup/localup.sh export_sps 1 8 > sp.json ``` ## Setup local SP network 1. Compile SP Users who want to compile SP can refer this [doc](compile-dependences.md#compile-sp). 2. Generate localup env Use the following instruction to generate template config file, sp.info and db.info in seven different directories. This command is used for generating sp env the first time or regenerating sp env. ```shell # This command accepts four args, the first arg is json file path that only supports absolute path, the second arg is db user name, # the third arg is db password and the fourth arg is db address. cd greenfield-storage-provider/ bash ./deployment/localup/localup.sh --generate json_file_path db_username db_password db_address ``` The json file path accepted for the first arg is generated by [quickly setup local greenfield blockchain network step3](#quickly-setup-local-greenfield-blockchain-network). View directory structure: ```shell ls deployment/localup/local_env/sp0 ├── sp0 │   ├── config.toml # generated template config file │   ├── db.info # generated db.info is used for config.toml │   ├── gnfd-sp0 # gnfd-sp binary │   └── sp.info # generated sp.info is used for config.toml ├── sp1 ├── ... ``` ```shell # An example for generating local sp env cd greenfield-storage-provider/ bash ./deployment/localup/localup.sh --generate /root/sp.json root greenfield localhost:3306 [root@yourmachine sp0]# cat db.info #!/usr/bin/env bash USER="root" # database username PWD="greenfield" # database password ADDRESS="localhost:3306" # db endpoint, e.g. "localhost:3306" DATABASE="sp_0" # database name [root@yourmachine sp0]# cat sp.info #!/usr/bin/env bash SP_ENDPOINT="127.0.0.1:9033" # gateway endpoint, e.g. "127.0.0.1:9033" OPERATOR_ADDRESS="0x14539343413EB47899B0935287ab1111Df891d04" # OperatorAddr is generated in setup local Greenfield blockchain step 3. OPERATOR_PRIVATE_KEY="ba6e97958d9c43d1ad54923eba99f8d59f54a0c66c78a5dcbc004c5c3ec72f8c" # OperatorPrivKey is generated in setup local Greenfield blockchain step 3. FUNDING_PRIVATE_KEY="bd9d9e7823cd2dc7bc20f1b6676c3025cdda6cf5a8df9b04597fdff42c29af01" # FundingPrivKey is generated in setup local Greenfield blockchain step 3. SEAL_PRIVATE_KEY="aacd6b834627fdbc5de2bfdb1db31be0ea810a941854787653814c8040a9dd39" # SealPrivKey is generated in setup local Greenfield blockchain step 3. APPROVAL_PRIVATE_KEY="32108ed1a47c0af965824f84ac2162c029f347eec6d0988e642330b0ac264c85" # ApprovalPrivKey is generated in setup local Greenfield blockchain step 3. GC_PRIVATE_KEY="2fad16031b4fd9facb7dacda3da4ca4dd5f005f4166891bf9f7be13e02abb12d" # GcPrivateKey is generated in setup local Greenfield blockchain step 3. BLS_PRIVATE_KEY="6f349866f18413abb1a78cab947933459042044649686f354e941a646b9ed6e7" # BlsPrivateKey is generated in setup local Greenfield blockchain step 3. ``` 4. Start Eight SPs Make config.toml according to db.info, sp.info and start eight SPs. ```shell cd greenfield-storage-provider/ bash ./deployment/localup/localup.sh --reset bash ./deployment/localup/localup.sh --start ``` The environment directory is as follows: ```shell deployment/localup/local_env/ ├── sp0 │   ├── config.toml # real config │   ├── data/ # piecestore data directory │   ├── db.info │   ├── gnfd-sp0 │   ├── gnfd-sp.log # gnfd-sp log file │   ├── log.txt │   └── sp.info ├── sp1 ├── ... ``` !!! note "Recompile SP" If you want to modify config.toml in different sp directories or recompile gnfd-sp binary file, you can use the following commands to reset and start local sp: ```shell cd greenfield-storage-provider/ bash ./deployment/localup/localup.sh --reset bash ./deployment/localup/localup.sh --start ``` 5. Supported commands ```shell # this command should be executed in greenfield-storage-provider/ directory. bash ./deployment/localup/localup.sh --help Usage: deployment/localup/localup.sh [option...] {help|generate|reset|start|stop|print} --help display help info --generate generate sp.info and db.info that accepts four args: the first arg is json file path, the second arg is db username, the third arg is db password and the fourth arg is db address --reset reset env --start start storage providers --stop stop storage providers --clean clean local sp env --print print sp local env work directory ``` ## Operate With SP If you have already started Greenfield blockchain and Greenfield SP successfully in local, you can use Greenfield Cmd to operate with SP such as CreateBucket, PutObject and GetObject. Detailed info about Greenfield Cmd can be found [here](../../getting-started/greenfield-command.md). !!! tip We strongly recommend you reading [Greenfield Cmd](https://github.com/bnb-chain/greenfield-cmd). It will help you explore the functions of Greenfield blockchain and SP. Next, We provide you a hand by hand tutorial to operate with chain and SP. ### 1. Generate your test account We firstly need to generate a test account and private key: ```shell cd greenfield/ # this command will generate a test account whose name is testkey, you can change its name ./build/bin/gnfd keys add testkey --keyring-backend os # export the private key of test account ./build/bin/gnfd keys export testkey --unarmored-hex --unsafe --keyring-backend os ``` ### 2. Transefer some BNB tokens to test account After generating test account, there are no any tokens in this account. We should transefer some BNB tokens: ```shell cd greenfield/ # transefer 5000 BNB tokens ./gnfd tx bank send validator0 {generated_test_account_address} 500000000000000000000BNB --home /{your_greenfield_path}/greenfield/deployment/localup/.local/validator0 --keyring-backend test --node http://localhost:26750 -y # query your account balances ./gnfd q bank balances {generated_test_account_address} --node http://localhost:26750 ``` ### 3. Use cmd to send requests If you come in this step, congratulations, you can operate with your own private chain and SP. First, we need to configure cmd: ```shell cd greenfield-cmd/ make build cd build/ # generate a keystore file to manage private key information touch key.txt & echo ${TEST_ACCOUNT_PRIVATE_KEY} > key.txt touch password.txt & echo "test_sp_function" > password.txt ./gnfd-cmd --home ./ --passwordfile password.txt account import key.txt # construct config.toml touch config.toml { echo rpcAddr = \"http://localhost:26750\" echo chainId = \"greenfield_9000-121\" } > config.toml ``` Second, you can do some operations with SP: 1. Create bucket ```shell # list current available SPs ./gnfd-cmd -c ./config.toml --home ./ sp ls # random choose one SP to create bucket ./gnfd-cmd -c ./config.toml --home ./ bucket create gnfd://${BUCKET_NAME} # head bucket info ./gnfd-cmd -c ./config.toml --home ./ bucket head gnfd://${BUCKET_NAME} # choose one sp to create bucket, operator_address is shown in sp ls result ./gnfd-cmd -c ./config.toml --home ./ bucket create --primarySP ${operator_address} gnfd://${BUCKET_NAME} ``` 2. PutObject & GetObject ```shell # generate a 17MB random file dd if=/dev/urandom of=./random_file bs=17M count=1 # put object ./gnfd-cmd -c ./config.toml --home ./ object put --contentType "application/octet-stream" ./random_file gnfd://${BUCKET_NAME}/random_file # get object ./gnfd-cmd -c ./config.toml --home ./ object get gnfd://${BUCKET_NAME}/random_file ./new_random_file ``` Users can use md5 to compare your generated file and downloaded file whether is the same. You can explore other functions of Greenfield Cmd. --- ## Run SP Node > Source: https://docs.bnbchain.org/bnb-greenfield/storage-provider/run-book/run-SP-node/ This guide helps you set up an SP Node. Once you set up the SP Node successfully, you can follow the [Join SP Network guide](join-SP-network.md) to make it online. - [Prerequisites](#prerequisites) - [Recommended Hardware](#recommended-hardware) - [Wallet Preparation](#wallet-preparation) - [Database Configuration](#database-configuration) - [PieceStore Configuration](#piecestore-configuration) - [Gateway Configuration](#gateway-configuration) - [1. Support both path-style and virtual-style routers in https certificates](#1-support-both-path-style-and-virtual-style-routers-in-https-certificates) - [2. CORS Configuration](#2-cors-configuration) - [3. Sample CORS Configuration for Nginx](#3-sample-cors-configuration-for-nginx) - [4. Other Q&A on Nginx config](#4-other-qa-on-nginx-config) - [Create Storage Provider](#create-storage-provider) - [1. Compile SP](#1-compile-sp) - [2. SP Config](#2-sp-config) - [Generate config template](#generate-config-template) - [Write config](#write-config) - [3. Run SP](#3-run-sp) ## Prerequisites ### Recommended Hardware The following lists the recommended hardware requirements: - VPS running recent versions of Mac OS X, Linux, or Windows; - 16 cores of CPU, 64 GB of memory(RAM); - 1 Gbps network connection with upload/download speeds of 10MB/s+; - At least 1 TB disk space for backend storage; - 50GB+ SQL database; - Piece Store: AWS S3, MinIO(Beta); - 6 Greenfield accounts with enough BNB tokens. !!! danger "IMPORTANT" Each storage provider will hold 7 different accounts serving different purposes ### Wallet Preparation - `Operator Account`: Used to edit the information of the StorageProvider. Please make sure it has enough BNB to pay the gas fee of `EditStorageProvider` and `UpdateStorageProviderStatus` transactions. - `Funding Account`: Used to deposit staking tokens and receive earnings. It is important to ensure that there is enough money in this account, and the SP must submit a deposit as a guarantee. At least `500+` BNB are required for staking. You should use this address to send `CreateStorageProvider` proposal on-chain. Besides the `500BNB` for staking, the funding address should have enough tokens for creating VGF to store more data, so we suggest depositing at least `510BNB` into this account. - `Seal Account`: Used to seal the user's object. Please make sure it has enough BNB to pay the gas fee of `SealObject` transaction. We suggest depositing `10BNB` into this account. - `Approval Account`: Used to approve user's requests. This account does not require holding BNB tokens. - `GC Account`: It is a special address for sp and is used by sp to clean up local expired or unwanted storage. Please make sure it has enough BNB tokens because it's going to keep sending transactions up the chain. - `Maintenance Account`: It is used for SP self-testing while in maintenance mode. This account for creating bucket and object will be allowed-listed by Chain while other users' create request will fail. - `Bls Account`: Used to create bls signature when sealing objects to ensure integrity, it does not need to be deposited. There are six accounts below, you can use the below command to generate these accounts: ```shell ./build/bin/gnfd keys add operator --keyring-backend os ./build/bin/gnfd keys add seal --keyring-backend os ./build/bin/gnfd keys add approval --keyring-backend os ./build/bin/gnfd keys add gc --keyring-backend os ./build/bin/gnfd keys add maintenance --keyring-backend os ./build/bin/gnfd keys add bls --keyring-backend os --algo eth_bls ``` and then export these private keys to prepare for SP deployment: ```shell ./build/bin/gnfd keys export operator --unarmored-hex --unsafe --keyring-backend os ./build/bin/gnfd keys export seal --unarmored-hex --unsafe --keyring-backend os ./build/bin/gnfd keys export approval --unarmored-hex --unsafe --keyring-backend os ./build/bin/gnfd keys export gc --unarmored-hex --unsafe --keyring-backend os ./build/bin/gnfd keys export bls --unarmored-hex --unsafe --keyring-backend os ``` !!! danger "IMPORTANT" `FundingAddress` is used to deposit staking tokens and receive earnings. Therefore, users should prepare your own `FundingAddress` public key and private key. And keep private key of `FundingAddress` in cold wallet for safety! The private keys of `OperatorAddress`, `SealAddress`, `ApprovalAddress`, `GCAddress` and `BlsAddress` can be kept in hot wallet, because they are often used to send transactions. If you want to generate public key and private key of `FundingAddress` in `gnfd` binary file, you can execute the following commands: ```shell ./build/bin/gnfd keys add funding --keyring-backend os ./build/bin/gnfd keys export funding --unarmored-hex --unsafe --keyring-backend os ``` maintenance account is not needed for SP deployment, but you should export it to conduct self-test: ```shell ./build/bin/gnfd keys export maintenance --unarmored-hex --unsafe --keyring-backend os ``` Please keep these seven private keys safe! Moreover, obtain bls public key and generate bls proof to fill in the proposal of creating Storage Provider `bls_pub_key`: ```shell ./build/bin/gnfd keys show bls --keyring-backend os --output json | jq -r '.pubkey_hex' ``` `bls_proof`: ```shell # Replace the ${bls_pub_key} with the above bls_pub_key to ensure sign the correct bls pub key!!! ./build/bin/gnfd keys sign "${bls_pub_key}" --from bls --keyring-backend os ``` ### Database Configuration You should create two databases: `${SpDB.Database}` and `${BsDB.Database}`. Both values can be found in [configuration file](config.md). !!! danger "IMPORTANT" `${BsDB.Database}` requires the **utf8mb4_unicode_ci** as the character set and collation. The following example assumes `${SpDB.Database}` as `storage_provider_db` and `${BsDB.Database}` as `block_syncer`. ```shell # login in mysql and create database # the default encoding for the database should be utf8mb4_unicode_ci mysql> CREATE DATABASE storage_provider_db; mysql> CREATE DATABASE block_syncer CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; # check the database encoding format mysql> show create database block_syncer; ``` This is the encoding we expect to see | Database | Create Database | | ------------ | ----------------------------------------------------------------------------------------------------- | | block_syncer | CREATE DATABASE `block_syncer` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_0900_ai_ci` */ | ### PieceStore Configuration Please follow this [doc](piece-store.md) to config your PieceStore. ### Gateway Configuration #### 1. Support both path-style and virtual-style routers in https certificates You need certificates for SP's exposed gateway service domain name and wildcard subdomain name of it, say you exposed your SP's gateway service on `https://my-sp1.mainnet.dummy-sp.io`, then you need SSL certificates for both `my-sp1.mainnet.dummy-sp.io` and `*.my-sp1.mainnet.dummy-sp.io`. For instance, if you reqeust AWS ACM certificate, you could request with this: Also, route all traffic from both `my-sp1.mainnet.dummy-sp.io` and `*.my-sp1.mainnet.dummy-sp.io` to gateway service, for instance, if you use nginx for ingress control, then you'll need to configure rules look like the following: ```yaml rules: - host: my-sp1.mainnet.dummy-sp.io http: paths: - backend: service: name: gateway # where your SP gateway service is internally, such a k8s service. port: number: 9033 path: / pathType: ImplementationSpecific - host: '*.my-sp1.mainnet.dummy-sp.io' http: paths: - backend: service: name: gateway # the same with the above one. port: number: 9033 path: / pathType: ImplementationSpecific ``` #### 2. CORS Configuration When working with web applications (e.g. DCellar), SPs need to allow CORS (Cross-Origin Resource Sharing) requests. See: [CORS Errors](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS/Errors) If CORS is not configured properly, you may find the DCellar (or any other web applications which mean to interact with your SP) will report CORS errors, similar to below: Most people run their SP services behind the nginx or other similar reverse proxies. Usually the CORS settings should be configured in those reverse proxies. We recommend SP with reverse proxy can return the following headers: ```shell access-control-allow-headers: * access-control-allow-methods: * access-control-allow-origin: * access-control-expose-headers: * ``` After you finish the configuration, you can verify if it works in DCellar. 1. Go to [https://dcellar.io](https://dcellar.io) 2. Press F12 to launch web developer tools and go to "Network" tab. 3. Connect your wallet 4. Find the "OPTIONS" request to your SP and check its status and response headers. If you see a similar result to the following screenshot, it means your CORS configuration is correct. #### 3. Sample CORS Configuration for Nginx Many storage providers (SPs) prefer to use nginx as their SP's reverse proxy server. It can also help handle CORS requests. Below is a sample nginx config, which can return those expected http response headers about CORS, mentioned in [above section](#2-cors-configuration). Please note that the nginx servers should explicitly return 204 as response code for http **OPTIONS** requests. ```config server { listen 443; server_name example.com; # Cors Preflight methods needs additional options and different Return Code location / { if ($request_method = 'OPTIONS') { add_header 'Access-Control-Allow-Origin' '*'; add_header 'Access-Control-Allow-Methods' '*'; add_header 'Access-Control-Allow-Headers' '*'; add_header 'Access-Control-Max-Age' 1728000; add_header 'Access-Control-Expose-Headers' '*'; add_header 'Content-Type' 'text/plain; charset=utf-8'; add_header 'Content-Length' 0; return 204; } add_header 'Access-Control-Allow-Origin' '*'; add_header 'Access-Control-Allow-Methods' '*'; add_header 'Access-Control-Allow-Headers' '*'; add_header 'Access-Control-Expose-Headers' '*'; # Rest of your server configuration... } } ``` #### 4. Other Q&A on Nginx config We observed that some SPs use nginx as their reverse-proxy layer. In this section , we will list some known best practises on nginx config. - proxy_pass and proxy_set_header If your nginx uses proxy_pass directive to pass a request to a proxied server (e.g. the SP gateway microservice), you need also use proxy_set_header to set the HOST header. Otherwise, the head of request passed to the SP gateway, will be parsed as 127.0.0.1. In this case, the SP gateway could not verify the signature of the user requests. ```config location / { proxy_pass http://127.0.0.1:9033 proxy_set_header Host $host; } ``` ## Create Storage Provider ### 1. Compile SP Follow the [Compile SP](compile-dependences.md#compile-sp) doc to compile the SP binary or you can download the binary from the [Greenfield Storage Provider Release](https://github.com/bnb-chain/greenfield-storage-provider/releases). ### 2. SP Config #### Generate config template ```shell cd greenfield-storage-provider/build # dump default configuration ./gnfd-sp config.dump ``` #### Write config You can learn about how to write your `config.toml` file [here](config.md) It's recommended to deploy Kubernetes cluster following this [guide](https://github.com/bnb-chain/greenfield-sp-deployment/blob/main/docs/README.md). The corresonding config file is [here](https://github.com/bnb-chain/greenfield-sp-deployment/blob/main/docs/k8s/aws/config.toml). ### 3. Run SP ```shell # start sp ./gnfd-sp --config ${config_file_path} ``` --- ## Join SP Network > Source: https://docs.bnbchain.org/bnb-greenfield/storage-provider/run-book/join-SP-network/ This guide will help you join SP Network: Mainnet and Testnet. - [Prerequisite for Becoming a Mainnet SP](#prerequisite-for-becoming-a-mainnet-sp) - [How to Join SP Network?](#how-to-join-sp-network) - [1. Submit Proposal](#1-submit-proposal) - [Hot Wallet Manual](#hot-wallet-manual) - [Hardware Wallet Manual](#hardware-wallet-manual) - [Understanding the Parameters](#understanding-the-parameters) - [2. Deposit BNB to Proposal](#2-deposit-bnb-to-proposal) - [3. Wait Voting and Check Voting Result](#3-wait-voting-and-check-voting-result) - [4. Activate SP](#4-activate-sp) - [Storage Provider Standard Test](#storage-provider-standard-test) - [Update SP status](#update-sp-status) - [5. SP address deposit](#5-sp-address-deposit) - [Funding Address](#funding-address) - [Operator Address](#operator-address) - [Storage Provider Operations](#storage-provider-operations) - [EditStorageProvider](#editstorageprovider) - [Update SP Price](#update-sp-price) - [Update SP Quota](#update-sp-quota) - [Recover SP Objects](#recover-sp-objects) - [Claim SP Income](#claim-sp-income) - [To query the income of a primary sp](#to-query-the-income-of-a-primary-sp) - [To query the income of a secondary sp](#to-query-the-income-of-a-secondary-sp) - [Tools](#tools) - [Trouble Shooting](#trouble-shooting) ## Prerequisite for Becoming a Mainnet SP To ensure the stable provision of data services, Storage Providers must meet specific criteria to join the mainnet. - The SP must join the testnet for a minimum of one month. - The SP must store over 1K files across more than 100 buckets on the testnet. - There were no slash event on the SP in the past week. ## How to Join SP Network? Greenfield Blockchain validators are responsible for selecting storage providers. For each on-chain proposal to add new storage provider, there are deposit period for depositing BNB and voting period for validators to make votes. Once the proposal passes, new SP can join the network afterwards. You can query the governance parameters [here](https://greenfield-chain.bnbchain.org/openapi#/Query/GovV1Params). ### 1. Submit Proposal The SP needs to initiate an on-chain proposal that specifies the Msg information to be automatically executed after the vote is approved. In this case, the Msg is `MsgCreateStorageProvider`. It's worth noting that the deposit tokens needs to be greater than the minimum deposit tokens specified on the chain. === "Mainnet" ``` rpcAddr = "https://greenfield-chain.bnbchain.org:443" chainId = "greenfield_1017-1" ``` === "Testnet" ``` rpcAddr = "https://gnfd-testnet-fullnode-tendermint-us.bnbchain.org:443" chainId = "greenfield_5600-1" ``` #### Hot Wallet Manual You can use the `gnfd` command to directly send the transaction for creating a storage provider. To do this, please import the private key of the funding account into the Keystore. However, it is not safe to use a hot wallet for Mainnet. Instead, you should refer to the [Hardware Wallet Manual](#hardware-wallet-manual) for instructions on using a hardware wallet. Command for creating storage provider: ```shell ./build/bin/gnfd tx sp create-storage-provider ./create_storage_provider.json --from {funding_address} --node ${rpcAddr} --chain-id ${chainId} --keyring-backend os ``` The content for create_storage_provider.json, modify it with the correct values as you need: ```shell cat ./create_storage_provider.json { "messages":[ { "@type":"/greenfield.sp.MsgCreateStorageProvider", "description":{ "moniker":"{moniker}", "identity":"{identity}", "website":"{website}", "security_contact":"{security_contract}", "details":"{details}" }, "sp_address":"{operator_address}", "funding_address":"{funding_address}", "seal_address":"{seal_address}", "approval_address":"{approval_address}", "gc_address":"{gc_address}", "maintenance_address":"{maintenance__address}", "endpoint":"https://{your_endpoint}", "deposit":{ "denom":"BNB", # Mainnet: 500000000000000000000, Testnet: 1000000000000000000000 "amount":"500000000000000000000" }, "read_price":"0.1469890427", "store_price":"0.02183945725", "free_read_quota": 1073741824, "creator":"0x7b5Fe22B5446f7C62Ea27B8BD71CeF94e03f3dF2", "bls_key":"{bls_pub_key}", "bls_proof":"{bls_proof}" } ], "metadata":"4pIMOgIGx1vZGU=", "title":"Create Storage Provider", "summary":"create Storage Provider", "deposit":"1000000000000000000BNB" } ``` #### Hardware Wallet Manual The gnfd command is not available for connecting with the hardware wallet, so you should use the [gnfd-tx-sender](https://gnfd-tx-sender.nodereal.io/) to send transactions. Here are the steps: 1. Generate the transaction data. ```shell ./build/bin/gnfd tx sp create-storage-provider ./create_storage_provider.json --from {funding_address} --print-eip712-msg-type ``` 2. Visit the [gnfd-tx-sender](https://gnfd-tx-sender.nodereal.io/) website. 3. Add your hardware wallet into Metamask, and connect the wallet. 4. Navigate to the `Custom Tx` page and fill in the generated transaction data in step1. 5. Click the `Submit` button to send the transaction. #### Understanding the Parameters !!! note You can get the gov module address by this command ```shell curl -X GET "https://greenfield-chain-us.bnbchain.org/cosmos/auth/v1beta1/module_accounts/gov" -H "accept: application/json" ``` - `endpoint` is URL of your gateway - `read_price` and `store_price` unit is `wei/bytes/s` - `free_read_quota` unit is *Bytes* - `creator` is the address of `gov module` - `metadata` is optional ### 2. Deposit BNB to Proposal !!! note You can get the mininum deposit for proposal by the above command. Please make sure that the initial deposit is greater than `min_deposit` when submitting the proposal. ```shell curl -X GET "https://greenfield-chain-us.bnbchain.org/cosmos/gov/v1/params/deposit" -H "accept: application/json" ``` You can skip this step if the initial deposit amount is greater than the min deposit required by the proposal. Each proposal needs to deposit enough tokens to enter the voting phase. ```shell ./build/bin/gnfd tx gov deposit ${proposal_id} 1BNB --from ${funding_address} --keyring-backend os --node ${rpcAddr} --chain-id ${chainId} ``` ### 3. Wait Voting and Check Voting Result After submitting the proposal successfully, you must wait for the voting to be completed and the proposal to be approved. It will last **7 days** on Mainnet while **1 day** on Testnet. Once it has passed and is executed successfully, you can verify that the storage provider has been joined. !!! warning Please ensure that the storage provider service is running before it has been joined. You can check the on-chain SP information to confirm whether the SP has been successfully created. ```shell ./build/bin/gnfd query sp storage-providers --node ${rpcAddr} ``` Alternatively, you can check the proposal to know about its execution status. ```shell ./build/bin/gnfd query gov proposal ${proposal_id} --node ${rpcAddr} ``` ### 4. Activate SP #### Storage Provider Standard Test After the proposal has passed, the status of SP is `STATUS_IN_MAINTENANCE`. To prevent being slashed due to functional abnormalities, you should first perform a full functional test using the maintenance account. You can refer to the [SP standard test](https://github.com/bnb-chain/greenfield-sp-standard-test). #### Update SP status Once the testing is completed, you need to send a tx to activate the SP to `STATUS_IN_SERVICE`. ```shell gnfd tx sp update-status [sp-address] STATUS_IN_SERVICE [flags] ``` Refer to [Maintenance Mode](../storage-provider-lifecycle.md#in-maintenance) for more details. ### 5. SP address deposit #### Funding Address As a new SP, you need deposit a minimum amount of BNB into the funding address. Please note the initial deposit requirement varies on different environments. You can check the `sp.params.min_deposit` value (in wei BNB) from genesis endpoint response of Greenfield testnet/mainnet. By the time when this doc is written, - According to [https://gnfd-testnet-fullnode-tendermint-us.bnbchain.org/genesis](https://gnfd-testnet-fullnode-tendermint-us.bnbchain.org/genesis), SP in testnet requires minimum **1000BNB** deposited in funding address. - According to [https://greenfield-chain.bnbchain.org/genesis](https://greenfield-chain.bnbchain.org/genesis), SP in mainnet requires minimum **500BNB** deposited in funding address. In addition, to join the network in [Step 2](#2-deposit-bnb-to-proposal), an SP must initiate a proposal using a funding address and stake 1 BNB to enter the voting phase. After the voting concludes, the 1 BNB will be refunded to the original account. Therefore, it is advisable for the Funding Address to reserve an additional >1 BNB to cover these costs. #### Operator Address SP operator address will be used to send "Create Global Virtual Group", "Edit Storage Provider", "Update Storage Provider Status" and other txs to greenfield chain. So it requires some BNB deposited for transaction fee as well. We recommend SP operator address can hold at least **0.1** BNB but not necessarily as much as possible. ## Storage Provider Operations ### EditStorageProvider This command is used to edit the information of the SP, including endpoint, description, etc. Usage: ```shell gnfd tx sp edit-storage-provider [sp-address] [flags] ``` For example, edit the endpoint: ```shell ./build/bin/gnfd tx sp edit-storage-provider ${operator_address} --endpoint ${new_endpoint} --from ${operator_address} --keyring-backend os --node ${rpcAddr} --chain-id ${chainId} ``` ### Update SP Price Update the storage provider read, store price and free read quota, if there is no change to a specific value, the current value should also be provided. The unit of price is a decimal, which indicates wei BNB per byte per second. E.g. the price is 0.02183945725, means approximately $0.018 / GB / Month. `(0.02183945725 * (30 * 86400) * (1024 * 1024 * 1024) * 300 / 10 ** 18 ≈ 0.018, assume the BNB price is 300 USD)` The free-read-quota unit is bytes, for 1GB free quota, it should be 1073741824. Usage: ```shell gnfd tx sp update-price [sp-address] [read-price] [store-price] [free-read-quota] [flags] ``` Example: ```shell ./build/bin/gnfd tx sp update-price ${operator_address} 0.1469890427 0.02183945725 1073741824 --from ${operator_address} --keyring-backend os ---node ${rpcAddr} --chain-id ${chainId} ``` ### Update SP Quota Besides the above `update-price` command, you can also use the `gnfd-sp` command to update the free read quota for SP. The update.quota command is used to update the free quota of the SP, it will send a transaction to the blockchain to update the free read quota, but keep the storage price and read price unchanged. Usage: ```shell gnfd-sp update.quota [command options] [arguments...] ``` Example: ```shell ./build/bin/gnfd-sp update.quota --quota 1073741824 --config ./config.toml ``` ### Recover SP Objects Besides the above commands, you can also use the `gnfd-sp` command to recover objects for SP, whether it is the primary or secondary sp of the object. The recover.object command is used to recover an object or objects of the SP, it will send a request to other SPs to get replicate of the object(s) you want to recover. Usage: ```shell gnfd-sp recover.object [command options] [arguments...] ``` Example: ```shell ./build/bin/gnfd-sp recover.object --config ./config.toml -b bucket_name -o single_object_name ./build/bin/gnfd-sp recover.object --config ./config.toml -b bucket_name -l object_name1//_object_name2//object_name3 ``` ### Claim SP Income To claim income, a storage provider can use `settle` cmd to settle income in global virtual group families or global virtual groups. To find the global virtual group families or global virtual groups to settle, a storage provider can use `query.primary.sp.income` or `query.secondary.sp.income` of `gnfd-sp` commands. #### To query the income of a primary sp Usage: ```shell # query sp's income in global virtual group families gnfd-sp query.primary.sp.income --config config.toml --sp.id ${sp_id} ``` An example of response will look like: ```js querying primary sp income details for sp 1 query timestamp 1698830787 2023-11-01 17:26:27 +0800 CST query results: [{"vgf_id":2,"stream_record":{"account":"primary_sp_virtual_payment_account_address_1","crud_timestamp":1698631653,"netflow_rate":"4643666191","static_balance":"1093710972008743","buffer_balance":"0","lock_balance":"0","frozen_netflow_rate":"0"},"income":"2018422795287337"},{"vgf_id":13,"stream_record":{"account":"primary_sp_virtual_payment_account_address_2","crud_timestamp":1698745565,"netflow_rate":"5452639431","static_balance":"38607334626064242","buffer_balance":"0","lock_balance":"0","frozen_netflow_rate":"0"},"income":"39072019463652924"},{"vgf_id":15,"stream_record":{"account":"primary_sp_virtual_payment_account_address_3","crud_timestamp":1698573876,"netflow_rate":"1925652979","static_balance":"55285141693450020","buffer_balance":"0","lock_balance":"0","frozen_netflow_rate":"0"},"income":"55779863125937889"},{"vgf_id":23,"stream_record":{"account":"primary_sp_virtual_payment_account_address_4","crud_timestamp":1698745588,"netflow_rate":"5063874897","static_balance":"2339430126330703","buffer_balance":"0","lock_balance":"0","frozen_netflow_rate":"0"},"income":"2770867203680206"},{"vgf_id":246,"stream_record":{"account":"primary_sp_virtual_payment_account_address_5","crud_timestamp":1698667216,"netflow_rate":"59568181","static_balance":"19326420423320","buffer_balance":"0","lock_balance":"0","frozen_netflow_rate":"0"},"income":"29070047357671"}] ``` The unit of the unsettled income is **wei BNB**. The first element in above query result array means the sp 1 gets **2018422795287337** **wei BNB** in vgf_id 2. #### To query the income of a secondary sp ```shell # query sp's income in global virtual groups gnfd-sp query.secondary.sp.income --config config.toml --sp.id ${sp_id} ``` An exmaple of response will look like: ```js querying secondary sp income details for sp 1 query timestamp 1698830440 2023-11-01 17:20:40 +0800 CST query results: [{"gvg_id":2531,"stream_record":{"account":"secondary_sp_virtual_payment_account_address_1","crud_timestamp":1695347375,"netflow_rate":"22256589564","static_balance":"917684637479280","buffer_balance":"0","lock_balance":"0","frozen_netflow_rate":"0"},"income":"13073138794535490"},{"gvg_id":8,"stream_record":{"account":"secondary_sp_virtual_payment_account_address_2","crud_timestamp":1696735440,"netflow_rate":"6698761332","static_balance":"24312367733445348","buffer_balance":"0","lock_balance":"0","frozen_netflow_rate":"0"},"income":"6391045453997558"},{"gvg_id":11,"stream_record":{"account":"secondary_sp_virtual_payment_account_address_3","crud_timestamp":1696072153,"netflow_rate":"6832159830","static_balance":"15803326565544654","buffer_balance":"0","lock_balance":"0","frozen_netflow_rate":"0"},"income":"5774730701092644"} ... ] ``` The unit of the unsettled income is **wei BNB**. The first element in above query result array means the sp 1 gets **13073138794535490** **wei BNB** in gvg_id 2531. ```shell # settle income in global virtual group family or global virtual groups gnfd tx virtualgroup settle [global-virtual-group-family-id] [global-virtual-group-ids] [flags] ``` Example: ```shell # query sp's income in global virtual group families gnfd-sp query.primary.sp.income --config config.toml --sp.id 1 ``` ```shell # query sp's income in global virtual groups gnfd-sp query.secondary.sp.income --config config.toml --sp.id 2 ``` ```shell # settle income in global virtual group family with id 100 gnfd tx virtualgroup settle 100 0 [flags] # settle income in global virtual groups with id 2 or 3 or 4 gnfd tx virtualgroup settle 0 2,3,4 [flags] ``` ## Tools SP can use Greenfield Cmd or DCellar to verify its functions: - Greenfield Cmd: Get more details from the [repo](https://github.com/bnb-chain/greenfield-cmd). - DCellar: [Mainnet](https://dcellar.io/), [Testnet](https://testnet.dcellar.io). ## Trouble Shooting If you meet issues, please refer to [SP common issues](common-issues.md). --- ## Exit SP Network > Source: https://docs.bnbchain.org/bnb-greenfield/storage-provider/run-book/exit-SP-network/ This guide provides step-by-step instructions for SPs to exit the Greenfield NextWork on the Mainnet or Testnet, along with the necessary actions to be performed by both the exiting SP and the successor SP(s). - [How to exit Greenfield network](#how-to-exit-greenfield-network) - [1. Declare the exit](#1-declare-the-exit) - [2. Data recovery](#2-data-recovery) - [2.1 ReserveSwapIn](#21-reserveswapin) - [2.2 Data Recovery](#22-data-recovery) - [2.3 CompleteSwapIn](#23-completeswapin) - [3. Finalize the Exit](#3-finalize-the-exit) ## How to exit Greenfield network When an SP decides to exit the Greenfield network, there are three main steps to go through, involving both the exiting SP and other SPs in the network: 1. Declare the exit 2. Data recovery by successor SP(s) 3. Finalize the exit ### 1. Declare the exit The exiting SP needs to initiate an `StorageProviderExit` transaction to Greenfield blockchain, which will turn its status to `STATUS_GRACEFUL_EXITING`. To exit the network, you can use the following commands based on the desired network: === "Mainnet" ``` rpcAddr = "https://greenfield-chain.bnbchain.org:443" chainId = "greenfield_1017-1" ``` === "Testnet" ``` rpcAddr = "https://gnfd-testnet-fullnode-tendermint-us.bnbchain.org:443" chainId = "greenfield_5600-1" ``` Command for storage provider to exit: ```shell gnfd-sp spExit [command options] [arguments...] ``` Example: ```shell ./build/bin/gnfd-sp spExit --config ./config.toml ``` ### 2. Data recovery For SPs interested in becoming successors, you need to perform the following data recovery steps: #### 2.1 ReserveSwapIn The perspective successor SP needs to determine Global Virtual group(GVG) and Global Virtual Group Family(VGF) that exiting SP has, This information can be obtained from [GreenfieldScan](https://greenfieldscan.com/account/0x2901fddef924f077ec6811a4a6a1cb0f13858e8f?tab=gvg) or by using the provided CLI. Usage: ```shell # List the GVG that the exit SP act as secondary SP ./gnfd-sp query-gvg-by-sp [command options] [arguments...] # List the GVG Family that the exit SP act as primary SP ./gnfd-sp query-vgf-by-sp [command options] [arguments...] ``` Example: ```shell # List the GVG that the exit SP(id=1) act as secondary SP ./gnfd-sp query-gvg-by-sp --config ./config.toml -sp 1 # List the GVG Family that the exit SPP(id=1) act as primary SP ./gnfd-sp query-vgf-by-sp --config ./config.toml -sp 1 ``` Once the successor SP has obtained the necessary information, it needs to reserve the position in the exit SP's GVG Family or GVG. Usage: ```shell # Reserve the exit SP's position in GVG family or GVG ./gnfd-sp swapIn [command options] [arguments...] ``` Example: ```shell # Reserve the exit SP's(id=1) position in GVG family(id=1) ./gnfd-sp swapIn --config ./config.toml -f 1 -sp 1 # Reserve the exit SP's(id=1) position in GVG(id=1) ./gnfd-sp swapIn --config ./config.toml --gid 1 -sp 1 ``` #### 2.2 Data Recovery The data recovery process is triggered by the successor SP using the following commands: Usage: ```shell ./gnfd-sp recover-vgf [command options] [arguments...] ./gnfd-sp recover-gvg [command options] [arguments...] ``` Example: ```shell # To recover the exit SP's data in the VGF(id=1) as a primary SP: ./gnfd-sp recover-vgf --config /config/config.toml -f 1 # To recover the exit SP's data in the GVG(id=1) as a secondary SP: ./gnfd-sp swapIn --config ./config.toml --gid 1 ``` Once the recovery job is triggered, it will run in the background in the SP Manager module. The progress can be queried using the following command: Usage: ```shell ./gnfd-sp query-recover-p [command options] [arguments...] ``` Example: ```shell # Query the GVG family(id=1) recover progress ./gnfd-sp recover-vgf --config /config/config.toml -f 1 # Query the GVG(id=1) recover progress ./gnfd-sp recover-vgf --config /config/config.toml --gid 1 ``` #### 2.3 CompleteSwapIn Upon completion of the data recovery process and successful verification, the successor SP needs to send a `CompleteSwapIn` transaction to the Greenfield blockchain, it will be automatically conducted before the recover process concludes, This will finalize the recovery process and allow the successor SP to take over the position in the GVG Family or GVG. !!! note It is crucial to note that under no circumstances should the `CompleteSwapIn` be triggered manually if the successor SP has not completed the data recovery process but acknowledges it. Doing so may result in data availability challenges and potential loss of funds. ### 3. Finalize the Exit Once the successor SP has completed the data recovery process and taken over the position in the GVG Family or GVG, by checking the GVG statistic of exitting SP, confirm that there are no more GVGs associated with it. Anyone in Greenfield network can send a `CompleteStorageProviderExit` transaction to the Greenfield blockchain to finalize its exit from the network. Below shows the CLI triggered by exiting SP itself. Usage: ```shell ./gnfd-sp completeSpExit [command options] [arguments...] ``` Example: ```shell ./gnfd-sp completeSpExit --config /config/config.toml ``` --- ## Deploy Piece Store > Source: https://docs.bnbchain.org/bnb-greenfield/storage-provider/run-book/piece-store/ Greenfield SP is a storage infrastructure for Greenfield decentralized storgage platform. Greenfield SP uses `PieceStore` to store users' payload data. ## PieceStore Config When creating a PieceStore, there are the following options to configure underlying storage: ```toml [PieceStore] # required Shards = 0 [PieceStore.Store] # required Storage = '' # optional BucketURL = '' # optional MaxRetries = 0 # optional MinRetryDelay = 0 # optional TLSInsecureSkipVerify = false # required IAMType = '' ``` - `Storage`: Specify the underlying storage to be used by PieceStore, e.g. `Storage = 's3'`. - `BucketURL`: Specify the underlying storage access address, e.g. `BucketURL = 'https://mybucket.s3.us-ease-1.amazonaws.com'`. Safer way sets bucket url via environment variable, e.g. `export BUCKET_URL=https://mybucket.s3.us-ease-1.amazonaws.com`. - `MaxRetries`: Specify the max retry count when there are something worong doing an operation on the underlying storage, e.g. `MaxRetries = 3`. - `MinRetryDelay`: Specify the min retry delay when there are something worong doing an operation on the underlying storage, e.g. `MinRetryDelay = 10`. - `TLSInsecureSkipVerify`: Specify whether you disable `HTTPS` when sending `HTTP` requests, e.g. `TLSInsecureSkipVerify = false`. - `IAMType`: Specify which authentication you will use to access the uderlying storage, e.g. `IAMType = 'AKSK'`. ## Shards When creating a PieceStore, multiple buckets can be defined as the underlying storgae through the `Shards` option. Based on the sharding, SP can distribute the files to multiple buckets according to the hashed value of the file name. Data sharding technology can distribute the load of concurrent writing of large-scale data to multiple buckets, thereby improving the writing performance. The following are points to note when using the data sharding function: - The `Shards` option accepts an integer between 0 and 256, indicating how many Buckets the files will be scattered into. The default value is 0, indicating that the data sharding function is not enabled. - Only multiple buckets under the same object storage can be used. - The integer wildcard `%d` needs to be used to specify the buckets, for example, `http://10.180.42.161:9000%d`. Buckets can be created automatically by SP when creating PieceStore. - The data sharding is set at the time of creation and cannot be modified after creation. You cannot increase or decrease the number of buckets, nor cancel the shards function. For example, the following config creates PieceStore with 5 shards. ```toml [PieceStore] Shards = 5 [PieceStore.Store] Storage = 'minio' BucketURL = 'http://10.180.42.161:9000/mybucket%d' IAMType = 'AKSK' ``` After SP initialized through the above command, PieceStore will create 5 buckets named `mybucket0`, `mybucket1`, `mybucket2`, `mybucket3` and `mybucket4`. ## IAMType PieceStore supports two authentication modes: `AKSK` and `SA`. ### AKSK In `AKSK` mode, PieceStore will access object storage by using `AccessKeyID` and `AccessKeySecret`. If users use s3 as object storage, you can set `AWSAccessKey` and `AWS_SECRET_KEY` into environment variables which are more secure. Permanent access credentials generally have two parts, Access Key, Secret Key, while temporary access credentials generally include three parts, Access Key, Secret Key and token, and temporary access credentials have an expiration time, usually between a few minutes and a few hours. ### SA Service Account (abbreviated as SA) is a more secure way for object storage system to authenticate users. In this mode, you needn't to provide `AccessKeyID` and `AccessKeySecret`. If you deploy your SP in Kubernetes, we recommend you using SA to access object storage. AWS S3 can read this [documentation](https://docs.aws.amazon.com/eks/latest/userguide/service-accounts.html) to learn how to use SA. Alibaba Cloud OSS uses `OIDC` to visit OSS safely which users don't need to provide `AccessKeyID` and `AccessKeySecret`. #### How to get temporary credentials Different cloud vendors have different acquisition methods. Generally, the Access Key, Secret Key and ARN representing the permission boundary of the temporary access credential are required as parameters to request access to the STS server of the cloud service vendor to obtain the temporary access credential. This process can generally be simplified by the SDK provided by the cloud vendor. For example, Amazon S3 can refer to this [link](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html) to obtain temporary credentials, and Alibaba Cloud OSS can refer to this [link](https://www.alibabacloud.com/help/en/object-storage-service/latest/use-a-temporary-credential-provided-by-sts-to-access-oss). Temporary credentials are also set into environment variables such as s3 by `AWS_SESSION_TOKEN`, minio by `MINIO_SESSION_TOKEN` and so on. Due to there is an expiration time in temporary credentials, this is used in test mode. ## Supported Storage Type PieceStore now supports the following storage system. If the listed storage systems don't conatin that you want to use, feel free to submit a requirement [issue](https://github.com/bnb-chain/greenfield-storage-provider/issues). | Name | value | | --------------------------------------- | -------- | | [Amazon S3](#amazon-s3) | `s3` | | [Alibaba Cloud OSS](#alibaba-cloud-oss) | `oss` | | [Backblaze B2](#backblaze-b2) | `b2` | | [MinIO](#minio) | `minio` | | [File](#file) | `file` | | [Memory](#memory) | `memory` | ### Amazon S3 S3 supports [two styles of endpoint URI](https://docs.aws.amazon.com/AmazonS3/latest/userguide/VirtualHosting.html): virtual hosted-style and path-style. The differences are: - Virtual-hosted-style: `https://.s3..amazonaws.com` - Path-style: `https://s3..amazonaws.com/` The `` should be replaced with specific region code, e.g. the region code of US East (N. Virginia) is `us-east-1`. All the available region codes can be found [here](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-regions-availability-zones.html#concepts-available-regions). If you use s3 as the underlying storage, you can set `Storage = s3` in config.toml. AWS S3 `AKSK` environment variables as follows: ```shell // AWS_ACCESS_KEY defines env variable name for aws access key export AWS_ACCESS_KEY="your_access_key" // AWS_SECRET_KEY defines env variable name for aws secret key export AWS_SECRET_KEY="your_secret_key" // AWS_SESSION_TOKEN defines env variable name for aws session token, this is optional export AWS_SESSION_TOKEN="your_session_token" ``` AWS S3 `SA` environment variables as follows: ```shell // AWS_ROLE_ARN defines env variable for aws role arnv export AWS_ROLE_ARN="your_role_arn" // AWSSecretKey defines env variable name for aws web identity token file export AWS_WEB_IDENTITY_TOKEN_FILE="your_web_identity_token_file" ``` !!! note If the S3 bucket has public access (anonymous access is supported), please set `export AWS_ACCESS_KEY="NoSignRequest"`. ### Alibaba Cloud OSS Please follow this [document](https://www.alibabacloud.com/help/en/basics-for-beginners/latest/obtain-an-accesskey-pair) to learn how to get access key and secret key. Alibaba Cloud also supports using Security Token Service (STS) to authorize temporary access to OSS. If you use OSS as the underlying storage, you can set `Storage = oss` in config.toml. Alibaba Cloud OSS `AKSK` environment variables as follows: ```shell // ALIBABA_CLOUD_ACCESS_KEY defines env variable name for OSS access key export ALIBABA_CLOUD_ACCESS_KEY="your_access_key" // ALIBABA_CLOUD_SECRET_KEY defines env variable name for OSS secret key export ALIBABA_CLOUD_SECRET_KEY="your_secret_key" // ALIBABA_CLOUD_SESSION_TOKEN defines env variable name for OSS session token, this is optional export ALIBABA_CLOUD_SESSION_TOKEN="your_session_token" // ALIBABA_CLOUD_OSS_REGION defines env variable name for OSS region export ALIBABA_CLOUD_OSS_REGION="oss_region" ``` Alibaba Cloud OSS `SA` environment variables as follows: ```shell // ALIBABA_CLOUD_ROLE_ARN defines env variable for OSS role arnv export ALIBABA_CLOUD_ROLE_ARN="your_role_arn" // ALIBABA_CLOUD_OIDC_TOKEN_FILE defines env variable name for OSS oidc token file export ALIBABA_CLOUD_OIDC_TOKEN_FILE="your_oidc_token_file" // ALIBABA_CLOUD_OIDC_PROVIDER_ARN defines env variable for OSS oidc provider arn export ALIBABA_CLOUD_OIDC_PROVIDER_ARN="your_oidc_provider_arn" ``` ### Backblaze B2 To use Backblaze B2 as a storage system for Greenfield SP, you need to create [application key](https://www.backblaze.com/docs/cloud-storage-application-keys) firstly. Application Key ID and Application Key respectively corresponds to Access Key and Secret Key. If you use Backblaze B2 as the underlying storage, you can set `Storage = b2` in config.toml. Backblaze B2 `AKSK` environment variables as follows: ```shell // B2_ACCESS_KEY defines env variable name for b2 access key export B2_ACCESS_KEY="your_access_key" // B2_SECRET_KEY defines env variable name for b2 secret key export B2_SECRET_KEY="your_secret_key" // B2_SESSION_TOKEN defines env variable name for b2 session token export B2_SESSION_TOKEN="your_session_token" ``` ### MinIO [MinIO](https://min.io/) is a high-performance, S3 compatible object store. You can visit the official website to learn how to deploy and maintain a MinIO cluster or you can purchase minio service. If you use MinIO as the underlying storage, you can set `Storage = minio` in config.toml. MinIO `AKSK` environment variables as follows: ```shell // MINIO_REGION defines env variable name for minio region export MINIO_REGION="minio_region" // MINIO_ACCESS_KEY defines env variable name for minio access key export MINIO_ACCESS_KEY="your_access_key" // MINIO_SECRET_KEY defines env variable name for minio secret key export MINIO_SECRET_KEY="your_secret_key" // MINIO_SESSION_TOKEN defines env variable name for minio session token, this is optional export MINIO_SESSION_TOKEN="your_session_token" ``` ### File When running Greenfield SP in your local machine, you can use local disk to test SP basic functions. The default storage path for root user is `/var/piecestore` and `~/.piecestore/local` for ordinary users in Linux and macOS. In Windows system, the default path is `C:/piecestore/local`. Local storage is usually only used to help users understand how Greenfield SP works and to give users an experience on the basic features of Greenfield SP. The created PieceStore storage can only be used on a single machine. This is not recommended in production environment. ### Memory Memory type can be used to test all PieceStore interfaces in memory. It's convenient for unit test or e2e test. --- ## SP Config > Source: https://docs.bnbchain.org/bnb-greenfield/storage-provider/run-book/config/ ## SP Config This section gives you a complete config of SP. `./gnfd-sp config.dump` will generate a template config.toml. ```toml # optional Env = '' # optional AppID = '' # optional Server = [] # optional GRPCAddress = '' [SpDB] # required User = '' # required Passwd = '' # required Address = '' # required Database = '' # optional ConnMaxLifetime = 0 # optional ConnMaxIdleTime = 0 # optional MaxIdleConns = 0 # optional MaxOpenConns = 0 # optional EnableTracePutEvent = false [BsDB] # required User = '' # required Passwd = '' # required Address = '' # required Database = '' # optional ConnMaxLifetime = 0 # optional ConnMaxIdleTime = 0 # optional MaxIdleConns = 0 # optional MaxOpenConns = 0 # optional EnableTracePutEvent = false [PieceStore] # required Shards = 0 [PieceStore.Store] # required Storage = '' # optional BucketURL = '' # optional MaxRetries = 0 # optional MinRetryDelay = 0 # optional TLSInsecureSkipVerify = false # required IAMType = '' [Chain] # required ChainID = '' # required ChainAddress = [] # optional SealGasLimit = 0 # optional SealFeeAmount = 0 # optional RejectSealGasLimit = 0 # optional RejectSealFeeAmount = 0 # optional DiscontinueBucketGasLimit = 0 # optional DiscontinueBucketFeeAmount = 0 # optional CreateGlobalVirtualGroupGasLimit = 0 # optional CreateGlobalVirtualGroupFeeAmount = 0 # optional CompleteMigrateBucketGasLimit = 0 # optional CompleteMigrateBucketFeeAmount = 0 [SpAccount] # required SpOperatorAddress = '' # required OperatorPrivateKey = '' # optional FundingPrivateKey = '' # required SealPrivateKey = '' # required ApprovalPrivateKey = '' # required GcPrivateKey = '' # required BlsPrivateKey = '' [Endpoint] # required ApproverEndpoint = '' # required ManagerEndpoint = '' # required DownloaderEndpoint = '' # required ReceiverEndpoint = '' # required MetadataEndpoint = '' # required UploaderEndpoint = '' # required P2PEndpoint = '' # required SignerEndpoint = '' # required AuthenticatorEndpoint = '' [Approval] # optional BucketApprovalTimeoutHeight = 0 # optional ObjectApprovalTimeoutHeight = 0 # optional ReplicatePieceTimeoutHeight = 0 [Bucket] # optional AccountBucketNumber = 0 # optional MaxListReadQuotaNumber = 0 # optional MaxPayloadSize = 0 [Gateway] # required DomainName = '' # required HTTPAddress = '' [Executor] # optional MaxExecuteNumber = 0 # optional AskTaskInterval = 0 # optional AskReplicateApprovalTimeout = 0 # optional AskReplicateApprovalExFactor = 0.0 # optional ListenSealTimeoutHeight = 0 # optional ListenSealRetryTimeout = 0 # optional MaxListenSealRetry = 0 # optional MaxObjectMigrationRetry = 0 # optional ObjectMigrationRetryTimeout = 0 # optional EnableSkipFailedToMigrateObject = false # optional BucketTrafficKeepTimeDay = 0 # optional ReadRecordKeepTimeDay = 0 # optional ReadRecordDeleteLimit = 0 [P2P] # optional P2PPrivateKey = '' # optional P2PAddress = '' # optional P2PAntAddress = '' # optional P2PBootstrap = [] # optional P2PPingPeriod = 0 [Parallel] # optional GlobalCreateBucketApprovalParallel = 0 # optional GlobalCreateObjectApprovalParallel = 0 # optional GlobalMaxUploadingParallel = 0 # optional GlobalUploadObjectParallel = 0 # optional GlobalReplicatePieceParallel = 0 # optional GlobalSealObjectParallel = 0 # optional GlobalReceiveObjectParallel = 0 # optional GlobalRecoveryPieceParallel = 0 # optional GlobalMigrateGVGParallel = 0 # optional GlobalBackupTaskParallel = 0 # optional GlobalDownloadObjectTaskCacheSize = 0 # optional GlobalChallengePieceTaskCacheSize = 0 # optional GlobalSyncConsensusInfoInterval = 0 # optional GlobalGCObjectParallel = 0 # optional GlobalGCBucketMigrationParallel = 0 # optional GlobalGCZombieParallel = 0 # optional GlobalGCMetaParallel = 0 # optional UploadObjectParallelPerNode = 0 # optional ReceivePieceParallelPerNode = 0 # optional DownloadObjectParallelPerNode = 0 # optional ChallengePieceParallelPerNode = 0 # optional AskReplicateApprovalParallelPerNode = 0 # optional QuerySPParallelPerNode = 0 # required DiscontinueBucketEnabled = false # optional DiscontinueBucketTimeInterval = 0 # required DiscontinueBucketKeepAliveDays = 0 # optional LoadReplicateTimeout = 0 # optional LoadSealTimeout = 0 [Task] # optional UploadTaskSpeed = 0 # optional DownloadTaskSpeed = 0 # optional ReplicateTaskSpeed = 0 # optional ReceiveTaskSpeed = 0 # optional SealObjectTaskTimeout = 0 # optional SealObjectTaskRetry = 0 # optional ReplicateTaskRetry = 0 # optional ReceiveConfirmTaskRetry = 0 # optional GcObjectTaskTimeout = 0 # optional GcZombieTaskTimeout = 0 # optional GcMetaTaskTimeout = 0 # optional GcObjectTaskRetry = 0 # optional GcZombieTaskRetry = 0 # optional GcMetaTaskRetry = 0 [Monitor] # required DisableMetrics = false # required DisablePProf = false # required DisableProbe = false # required MetricsHTTPAddress = '' # required PProfHTTPAddress = '' # required ProbeHTTPAddress = '' # optional [Rcmgr] # optional DisableRcmgr = false [Log] # optional Level = '' # optional Path = '' [BlockSyncer] # required Modules = ['epoch','bucket','object','payment','group','permission','storage_provider','prefix_tree','virtual_group','sp_exit_events','object_id_map','general'] # required Workers = 0 # optional BsDBWriteAddress = '' [APIRateLimiter] # every line should represent one entry of gateway route. The comment after each line must contain which route name it represents. # Most of APIs has a qps number, offered by QA team. That usually means the max qps for the whole 4 gateway cluster. # How to setup the RateLimit value, it is a sophistcated question and need take a lot of factors into account. # 1. For most query-APIs, we can setup a rate limit up to the 1/4 of max qps, as the config is for only one gateway instance. # 2. Also we avoid to setup a too large or too small rate limit value. # 3. For upload/download APIs, it is diffiult to use a rate limit as a protect mechanism for the servers. Because the performance of upload/download interactions usually dependens on how large the file is processed. # 4. We tetatively setup 50~75 as the rate limit for the download/upload APIs and we can ajdust them once we have a better experience. # 5. Currently, please only put one name inside the name list of PathPatttern # optional PathPattern = [ {Key = "/auth/request_nonce", Method = "GET", Names = ["GetRequestNonce"]}, {Key = "/auth/update_key", Method = "POST", Names = ["UpdateUserPublicKey"]}, {Key = "/permission/.+/[^/]*/.+", Method = "GET", Names = ["VerifyPermission"]}, {Key = "/greenfield/admin/v1/get-approval", Method = "GET", Names = ["GetApproval"]}, {Key = "/greenfield/admin/v1/challenge", Method = "GET", Names = ["GetChallengeInfo"]}, {Key = "/greenfield/admin/v2/challenge", Method = "GET", Names = ["GetChallengeInfo"]}, {Key = "/greenfield/receiver/v1/replicate-piece", Method = "PUT", Names = ["ReplicateObjectPiece"]}, {Key = "/greenfield/recovery/v1/get-piece", Method = "GET", Names = ["RecoveryPiece"]}, {Key = "/greenfield/migrate/v1/notify-migrate-swap-out-task", Method = "POST", Names = ["NotifyMigrateSwapOut"]}, {Key = "/greenfield/migrate/v1/migrate-piece", Method = "GET", Names = ["MigratePiece"]}, {Key = "/greenfield/migrate/v1/migration-bucket-approval", Method = "GET", Names = ["MigrationBucketApproval"]}, {Key = "/greenfield/migrate/v1/get-swap-out-approval", Method = "GET", Names = ["SwapOutApproval"]}, {Key = "/download/[^/]*/.+", Method = "GET", Names = ["DownloadObjectByUniversalEndpoint"]},{Key = "/download", Method = "GET", Names = ["DownloadObjectByUniversalEndpoint"]}, {Key = "/view/[^/]*/.+", Method = "GET", Names = ["ViewObjectByUniversalEndpoint"]},{Key = "/view", Method = "GET", Names = ["ViewObjectByUniversalEndpoint"]}, {Key = "/status", Method = "GET", Names = ["GetStatus"]}, {Key = "/.+/.+[?]offset.*", Method = "POST", Names = ["ResumablePutObject"]}, {Key = "/.+/.+[?]upload-context.*", Method = "GET", Names = ["QueryResumeOffset"]}, {Key = "/.+/.+[?]upload-progress.*", Method = "GET", Names = ["QueryUploadProgress"]}, {Key = "/.+/.+[?]bucket-meta.*", Method = "GET", Names = ["GetBucketMeta"]}, {Key = "/.+/.+[?]object-meta.*", Method = "GET", Names = ["GetObjectMeta"]}, {Key = "/.+/.+[?]object-policies.*", Method = "GET", Names = ["ListObjectPolicies"]}, {Key = "/.+[?]read-quota.*", Method = "GET", Names = ["GetBucketReadQuota"]}, {Key = "/.+[?]list-read-quota.*", Method = "GET", Names = ["ListBucketReadRecord"]}, {Key = "/[?].*group-query.*", Method = "GET", Names = ["GetGroupList"]}, {Key = "/[?].*objects-query.*", Method = "GET", Names = ["ListObjectsByIDs"]}, {Key = "/[?].*buckets-query.*", Method = "GET", Names = ["ListBucketsByIDs"]}, {Key = "/[?].*verify-id.*", Method = "GET", Names = ["VerifyPermissionByID"]}, {Key = "/[?].*user-groups.*", Method = "GET", Names = ["GetUserGroups"]}, {Key = "/[?].*group-members.*", Method = "GET", Names = ["GetGroupMembers"]}, {Key = "/[?].*owned-groups.*", Method = "GET", Names = ["GetUserOwnedGroups"]}, {Key = "/.+/$", Method = "GET", Names = ["ListObjectsByBucket"]}, {Key = "/.+/[?].*", Method = "GET", Names = ["ListObjectsByBucket"]}, {Key = "/.+/.+", Method = "GET", Names = ["GetObject"]}, {Key = "/.+/.+", Method = "PUT", Names = ["PutObject"]}, {Key = "/$", Method = "GET", Names = ["GetUserBuckets"]}, {Key = "/[?].*", Method = "GET", Names = ["GetUserBuckets"]}, ] NameToLimit = [ {Name = "GetRequestNonce", RateLimit = 100, RatePeriod = 'S'}, # requestNonceRouterName 3000qps {Name = "UpdateUserPublicKey", RateLimit = 100, RatePeriod = 'S'}, # updateUserPublicKeyRouterName 4000qps {Name = "VerifyPermission", RateLimit = 100, RatePeriod = 'S'}, # verifyPermissionRouterName 1200qps {Name = "GetApproval", RateLimit = 35, RatePeriod = 'S'}, # approvalRouterName 150qps {Name = "GetChallengeInfo", RateLimit = 20, RatePeriod = 'S'}, # getChallengeInfoRouterName, no test data {Name = "ReplicateObjectPiece", RateLimit = 1000, RatePeriod = 'S'}, # replicateObjectPieceRouterName, no test data. Internal API among sps, no rate limit is needed. {Name = "RecoveryPiece", RateLimit = 1000, RatePeriod = 'S'}, # recoveryPieceRouterName, no test data. Internal API among sps, no rate limit is needed. {Name = "NotifyMigrateSwapOut", RateLimit = 10, RatePeriod = 'S'}, # notifyMigrateSwapOutRouterName, no test data. Internal API among sps, no rate limit is needed. {Name = "MigratePiece", RateLimit = 10, RatePeriod = 'S'}, # migratePieceRouterName, no test data {Name = "MigrationBucketApproval", RateLimit = 10, RatePeriod = 'S'}, # migrationBucketApprovalName, no test data {Name = "SwapOutApproval", RateLimit = 10, RatePeriod = 'S'}, # swapOutApprovalName, no test data {Name = "DownloadObjectByUniversalEndpoint", RateLimit = 50, RatePeriod = 'S'}, # downloadObjectByUniversalEndpointName, 50qps {Name = "ViewObjectByUniversalEndpoint", RateLimit = 50, RatePeriod = 'S'}, # viewObjectByUniversalEndpointName, 50qps {Name = "GetStatus", RateLimit = 200, RatePeriod = 'S'},# getStatusRouterName, 2000qps {Name = "ResumablePutObject", RateLimit = 30, RatePeriod = 'S'}, # resumablePutObjectRouterName , test data is same as putObject object 10qps {Name = "QueryResumeOffset", RateLimit = 30, RatePeriod = 'S'}, # queryResumeOffsetName, test data is same as putObject object 10qps {Name = "QueryUploadProgress", RateLimit = 50, RatePeriod = 'S'}, # queryUploadProgressRouterName, test data is same as putObject object 10qps {Name = "GetBucketMeta", RateLimit = 100, RatePeriod = 'S'}, # getBucketMetaRouterName, 400qps {Name = "GetObjectMeta", RateLimit = 100, RatePeriod = 'S'}, # getObjectMetaRouterName, 400qps {Name = "ListObjectPolicies", RateLimit = 200, RatePeriod = 'S'}, # listObjectPoliciesRouterName, 2000qps {Name = "GetBucketReadQuota", RateLimit = 200, RatePeriod = 'S'}, # getBucketReadQuotaRouterName {Name = "ListBucketReadRecord", RateLimit = 100, RatePeriod = 'S'}, # listBucketReadRecordRouterName {Name = "GetGroupList", RateLimit = 200, RatePeriod = 'S'}, # getGroupListRouterName, similar to getUserGroupsRouterName, 2000qps {Name = "ListObjectsByIDs", RateLimit = 200, RatePeriod = 'S'}, # listObjectsByIDsRouterName, 1200qps {Name = "ListBucketsByIDs", RateLimit = 200, RatePeriod = 'S'}, # listBucketsByIDsRouterName, 2000qps {Name = "VerifyPermissionByID", RateLimit = 200, RatePeriod = 'S'}, # verifyPermissionByIDRouterName, 1200qps {Name = "GetUserGroups", RateLimit = 200, RatePeriod = 'S'}, # getUserGroupsRouterName, 2000qps {Name = "GetGroupMembers", RateLimit = 200, RatePeriod = 'S'}, # getGroupMembersRouterName, 2000qps {Name = "GetUserOwnedGroups", RateLimit = 200, RatePeriod = 'S'}, # getUserOwnedGroupsRouterName, 2000qps {Name = "ListObjectsByBucket", RateLimit = 75, RatePeriod = 'S'}, # listObjectsByBucketRouterName, 300qps {Name = "GetObject", RateLimit = 75, RatePeriod = 'S'}, # getObjectRouterName, 100 qps {Name = "PutObject", RateLimit = 75, RatePeriod = 'S'}, # putObjectRouterName, 100 qps {Name = "GetUserBuckets", RateLimit = 75, RatePeriod = 'S'}] # getUserBucketsRouterName, 1000 qps HostPattern = [] [Manager] # optional EnableLoadTask = false # optional EnableHealthyChecker = false # optional SubscribeSPExitEventIntervalMillisecond = 0 # optional SubscribeSwapOutExitEventIntervalMillisecond = 0 # optional SubscribeBucketMigrateEventIntervalMillisecond = 0 # optional GVGPreferSPList = [] # optional SPBlackList = [] # optional EnableTaskRetryScheduler = false # optional RejectUnsealThresholdSecond = 0 [GC] # optional GCObjectTimeInterval = 0 # optional GCObjectBlockInterval = 0 # optional GCObjectSafeBlockDistance = 0 # optional EnableGCZombie = false # optional GCZombieSafeObjectIDDistance = 0 # optional GCZombiePieceTimeInterval = 0 # optional GCZombiePieceObjectIDInterval = 0 # optional EnableGCMeta = false # optional GCMetaTimeInterval = 0 [Quota] # optional MonthlyFreeQuota = 0 ``` ### App info These fields are optional. ```shell # optional Env = '' # optional AppID = '' # optional Server = [] # optional GRPCAddress = '' ``` ### Database To config `[SpDB]`, `[BsDB]`, you have to input the `user name`, `db password`,`db address` and `db name` in these fields. ### PieceStore To config `[PieceStore]` and `[PieceStore.Store]`, you can read the details in this [doc](piece-store.md) ### Chain info * `ChainID` of mainnet is `greenfield_1017-1` and testnet is `greenfield_5600-1`. * `ChainAddress` is RPC endpoint of mainnet, you can find RPC info [here](../../for-developers/network-endpoint/endpoints.md) ### SpAccount These private keys are generated during wallet setup. ### Endpoint `[Endpoint]` specified the URL of different services. For single-machine host (not recommended): ```toml [Endpoint] ApproverEndpoint = '' ManagerEndpoint = '' DownloaderEndpoint = '' ReceiverEndpoint = '' MetadataEndpoint = '' UploaderEndpoint = '' P2PEndpoint = '' SignerEndpoint = '' AuthenticatorEndpoint = '' ``` For K8S cluster: ```toml [Endpoint] ApproverEndpoint = 'manager:9333' ManagerEndpoint = 'manager:9333' DownloaderEndpoint = 'downloader:9333' ReceiverEndpoint = 'receiver:9333' MetadataEndpoint = 'metadata:9333' UploaderEndpoint = 'uploader:9333' P2PEndpoint = 'p2p:9333' SignerEndpoint = 'signer:9333' AuthenticatorEndpoint = 'localhost:9333' ``` ### P2P !!! note We don't use P2P service in mainnet and testnet, so users can ignore P2P items. * `P2PPrivateKey` and `node_id` is generated by `./gnfd-sp p2p.create.key -n 1` * `P2PAntAddress` is your load balance address. If you don't have a load balance address, you should have a public IP and use it in `P2PAddress`. It consists of `ip:port`. * `P2PBootstrap` can be left empty. ### Gateway ```toml [Gateway] DomainName = 'region.sp-name.com' ``` The correct configuration should not include the protocol prefix `https://`. ### BlockSyncer Here is block_syncer config. The configuration of BsDBWriteAddress can be the same as the BSDB.Address module here. To enhance performance, you can set up the write database address here and the corresponding read database address in BSDB. ```toml Modules = ['epoch','bucket','object','payment','group','permission','storage_provider','prefix_tree', 'virtual_group','sp_exit_events','object_id_map','general'] Workers = 50 BsDBWriteAddress = 'localhost:3306' ``` ### FundingPrivateKey There is no need to write `FundingPrivateKey` in config.toml. It should be kept in cold wallet for safety. ### Rcmgr ResourceManager manages resources within SP system, tracking and accounting for usage across the stack, from internal components to applications. It also allows for resource usage to be limited based on user-configurable policies. Config schema shows as below: ```proto message GfSpLimit { int64 memory = 1; int32 tasks = 2; int32 tasks_high_priority = 3; int32 tasks_medium_priority = 4; int32 tasks_low_priority = 5; int32 fd = 6; int32 conns = 7; int32 conns_inbound = 8; int32 conns_outbound = 9; } message GfSpLimiter { GfSpLimit system = 1; GfSpLimit transient = 2; map service_limit = 3; } ``` ### Quota Here is quota config. The configuration of MonthlyFreeQuota define the free quota in each month.It will be reduced when the charge quota is exhausted. ```toml [Quota] MonthlyFreeQuota = 0 ``` ### SP Probe It contains two probes: liveness and readiness probe. If users want to check SP whether is healthy and ready. Users can refer [Kubernetes docs](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/) to learn related concepts. About detailed SP probe info, users can refer [SP probe](https://github.com/bnb-chain/greenfield-storage-provider/blob/master/core/prober/prober.go). ## SP Mainnet Recommended Config This section shows the config of official in Greenfield, so users can add use similar config: ```toml # optional Env = "mainnet" # optional Server = [] # optional GRPCAddress = '0.0.0.0:9333' [SpDB] # required User = '' # required Passwd = '' # required Address = '{your_db_address}' # required Database = 'storage_provider_db' [BsDB] # required User = '' # required Passwd = '' # required Address = '{your_db_address}' # required Database = 'block_syncer' [PieceStore] # required Shards = 0 [PieceStore.Store] # required Storage = 's3' # optional BucketURL = '{your_bucker_url}' # optional MaxRetries = 5 # optional MinRetryDelay = 0 # optional TLSInsecureSkipVerify = false # required IAMType = 'SA' [Chain] # required ChainID = 'greenfield_1017-1' # required ChainAddress = ['{your_fullnode_address}'] [SpAccount] # required SpOperatorAddress = '{your_operator_address}' # required # OperatorPrivateKey = '' # required # SealPrivateKey = '' # required # ApprovalPrivateKey = '' # required # GcPrivateKey = '' [Endpoint] # required ApproverEndpoint = 'approver:9333' # required ManagerEndpoint = 'manager:9333' # required DownloaderEndpoint = 'downloader:9333' # required ReceiverEndpoint = 'receiver:9333' # required MetadataEndpoint = 'metadata:9333' # required UploaderEndpoint = 'uploader:9333' # required P2PEndpoint = 'p2p-service:9333' # required SignerEndpoint = 'signer:9333' # required AuthenticatorEndpoint = 'localhost:9333' [Gateway] # required DomainName = '{your_domain_name}' # required HTTPAddress = '0.0.0.0:9033' [P2P] # optional #P2PPrivateKey = '' # optional P2PAddress = '0.0.0.0:9933' # optional P2PAntAddress = '' # optional P2PBootstrap = [] # optional # P2PPingPeriod = 0 [Parallel] # optional DiscontinueBucketEnabled = false # optional DiscontinueBucketKeepAliveDays = 365 # optional GlobalMaxUploadingParallel = 3072 # optional UploadObjectParallelPerNode = 100 # optional ReceivePieceParallelPerNode = 1024 # optional DownloadObjectParallelPerNode = 200 # optional ChallengePieceParallelPerNode = 200 # optional AskReplicateApprovalParallelPerNode = 10240 # optional GlobalCreateBucketApprovalParallel = 1024 # optional GlobalCreateObjectApprovalParallel = 1024 # optional GlobalUploadObjectParallel = 1024 # optional GlobalReplicatePieceParallel = 1024 # optional GlobalSealObjectParallel = 1024 # optional GlobalReceiveObjectParallel = 10240 # optional GlobalBackupTaskParallel = 1024 # optional GlobalRecoveryPieceParallel = 1024 # optional GlobalGcObjectSafeBlockDistance = 64 # optional GlobalMigrateGVGParallel = 10 [Monitor] # required DisableMetrics = false # required DisablePProf = false # required DisableProbe = false # required MetricsHTTPAddress = '0.0.0.0:24367' # required PProfHTTPAddress = '0.0.0.0:24368' # required ProbeHTTPAddress = '0.0.0.0:24369' # optional [Rcmgr] # optional DisableRcmgr = false # optional [Rcmgr.GfSpLimiter] # optional [Rcmgr.GfSpLimiter.System] # optional Memory = 4294967296 # optional Tasks = 10240 # optional TasksHighPriority = 128 # optional TasksMediumPriority = 1024 # optional TasksLowPriority = 16 # optional Fd = 2147483647 # optional Conns = 2147483647 # optional ConnsInbound = 2147483647 # optional ConnsOutbound = 2147483647 [BlockSyncer] # required Modules = ['epoch','bucket','object','payment','group','permission','storage_provider','prefix_tree','virtual_group','sp_exit_events','object_id_map','general'] # required Workers = 50 # optional BsDBWriteAddress = "{your_db_address}" [APIRateLimiter] # every line should represent one entry of gateway route. The comment after each line must contain which route name it represents. # Most of APIs has a qps number, offered by QA team. That usually means the max qps for the whole 4 gateway cluster. # How to setup the RateLimit value, it is a sophistcated question and need take a lot of factors into account. # 1. For most query-APIs, we can setup a rate limit up to the 1/4 of max qps, as the config is for only one gateway instance. # 2. Also we avoid to setup a too large or too small rate limit value. # 3. For upload/download APIs, it is diffiult to use a rate limit as a protect mechanism for the servers. Because the performance of upload/download interactions usually dependens on how large the file is processed. # 4. We tetatively setup 50~75 as the rate limit for the download/upload APIs and we can ajdust them once we have a better experience. # 5. Currently, please only put one name inside the name list of PathPatttern # optional PathPattern = [ {Key = "/auth/request_nonce", Method = "GET", Names = ["GetRequestNonce"]}, {Key = "/auth/update_key", Method = "POST", Names = ["UpdateUserPublicKey"]}, {Key = "/permission/.+/[^/]*/.+", Method = "GET", Names = ["VerifyPermission"]}, {Key = "/greenfield/admin/v1/get-approval", Method = "GET", Names = ["GetApproval"]}, {Key = "/greenfield/admin/v1/challenge", Method = "GET", Names = ["GetChallengeInfo"]}, {Key = "/greenfield/admin/v2/challenge", Method = "GET", Names = ["GetChallengeInfo"]}, {Key = "/greenfield/receiver/v1/replicate-piece", Method = "PUT", Names = ["ReplicateObjectPiece"]}, {Key = "/greenfield/recovery/v1/get-piece", Method = "GET", Names = ["RecoveryPiece"]}, {Key = "/greenfield/migrate/v1/notify-migrate-swap-out-task", Method = "POST", Names = ["NotifyMigrateSwapOut"]}, {Key = "/greenfield/migrate/v1/migrate-piece", Method = "GET", Names = ["MigratePiece"]}, {Key = "/greenfield/migrate/v1/migration-bucket-approval", Method = "GET", Names = ["MigrationBucketApproval"]}, {Key = "/greenfield/migrate/v1/get-swap-out-approval", Method = "GET", Names = ["SwapOutApproval"]}, {Key = "/download/[^/]*/.+", Method = "GET", Names = ["DownloadObjectByUniversalEndpoint"]},{Key = "/download", Method = "GET", Names = ["DownloadObjectByUniversalEndpoint"]}, {Key = "/view/[^/]*/.+", Method = "GET", Names = ["ViewObjectByUniversalEndpoint"]},{Key = "/view", Method = "GET", Names = ["ViewObjectByUniversalEndpoint"]}, {Key = "/status", Method = "GET", Names = ["GetStatus"]}, {Key = "/.+/.+[?]offset.*", Method = "POST", Names = ["ResumablePutObject"]}, {Key = "/.+/.+[?]upload-context.*", Method = "GET", Names = ["QueryResumeOffset"]}, {Key = "/.+/.+[?]upload-progress.*", Method = "GET", Names = ["QueryUploadProgress"]}, {Key = "/.+/.+[?]bucket-meta.*", Method = "GET", Names = ["GetBucketMeta"]}, {Key = "/.+/.+[?]object-meta.*", Method = "GET", Names = ["GetObjectMeta"]}, {Key = "/.+/.+[?]object-policies.*", Method = "GET", Names = ["ListObjectPolicies"]}, {Key = "/.+[?]read-quota.*", Method = "GET", Names = ["GetBucketReadQuota"]}, {Key = "/.+[?]list-read-quota.*", Method = "GET", Names = ["ListBucketReadRecord"]}, {Key = "/[?].*group-query.*", Method = "GET", Names = ["GetGroupList"]}, {Key = "/[?].*objects-query.*", Method = "GET", Names = ["ListObjectsByIDs"]}, {Key = "/[?].*buckets-query.*", Method = "GET", Names = ["ListBucketsByIDs"]}, {Key = "/[?].*verify-id.*", Method = "GET", Names = ["VerifyPermissionByID"]}, {Key = "/[?].*user-groups.*", Method = "GET", Names = ["GetUserGroups"]}, {Key = "/[?].*group-members.*", Method = "GET", Names = ["GetGroupMembers"]}, {Key = "/[?].*owned-groups.*", Method = "GET", Names = ["GetUserOwnedGroups"]}, {Key = "/.+/$", Method = "GET", Names = ["ListObjectsByBucket"]}, {Key = "/.+/.+", Method = "GET", Names = ["GetObject"]}, {Key = "/.+/.+", Method = "PUT", Names = ["PutObject"]}, {Key = "/$", Method = "GET", Names = ["GetUserBuckets"]}, ] NameToLimit = [ {Name = "GetRequestNonce", RateLimit = 100, RatePeriod = 'S'}, # requestNonceRouterName 3000qps {Name = "UpdateUserPublicKey", RateLimit = 100, RatePeriod = 'S'}, # updateUserPublicKeyRouterName 4000qps {Name = "VerifyPermission", RateLimit = 100, RatePeriod = 'S'}, # verifyPermissionRouterName 1200qps {Name = "GetApproval", RateLimit = 35, RatePeriod = 'S'}, # approvalRouterName 150qps {Name = "GetChallengeInfo", RateLimit = 20, RatePeriod = 'S'}, # getChallengeInfoRouterName, no test data {Name = "ReplicateObjectPiece", RateLimit = 1000, RatePeriod = 'S'}, # replicateObjectPieceRouterName, no test data. Internal API among sps, no rate limit is needed. {Name = "RecoveryPiece", RateLimit = 1000, RatePeriod = 'S'}, # recoveryPieceRouterName, no test data. Internal API among sps, no rate limit is needed. {Name = "NotifyMigrateSwapOut", RateLimit = 10, RatePeriod = 'S'}, # notifyMigrateSwapOutRouterName, no test data. Internal API among sps, no rate limit is needed. {Name = "MigratePiece", RateLimit = 10, RatePeriod = 'S'}, # migratePieceRouterName, no test data {Name = "MigrationBucketApproval", RateLimit = 10, RatePeriod = 'S'}, # migrationBucketApprovalName, no test data {Name = "SwapOutApproval", RateLimit = 10, RatePeriod = 'S'}, # swapOutApprovalName, no test data {Name = "DownloadObjectByUniversalEndpoint", RateLimit = 50, RatePeriod = 'S'}, # downloadObjectByUniversalEndpointName, 50qps {Name = "ViewObjectByUniversalEndpoint", RateLimit = 50, RatePeriod = 'S'}, # viewObjectByUniversalEndpointName, 50qps {Name = "GetStatus", RateLimit = 200, RatePeriod = 'S'},# getStatusRouterName, 2000qps {Name = "ResumablePutObject", RateLimit = 30, RatePeriod = 'S'}, # resumablePutObjectRouterName , test data is same as putObject object 10qps {Name = "QueryResumeOffset", RateLimit = 30, RatePeriod = 'S'}, # queryResumeOffsetName, test data is same as putObject object 10qps {Name = "QueryUploadProgress", RateLimit = 50, RatePeriod = 'S'}, # queryUploadProgressRouterName, test data is same as putObject object 10qps {Name = "GetBucketMeta", RateLimit = 100, RatePeriod = 'S'}, # getBucketMetaRouterName, 400qps {Name = "GetObjectMeta", RateLimit = 100, RatePeriod = 'S'}, # getObjectMetaRouterName, 400qps {Name = "ListObjectPolicies", RateLimit = 200, RatePeriod = 'S'}, # listObjectPoliciesRouterName, 2000qps {Name = "GetBucketReadQuota", RateLimit = 200, RatePeriod = 'S'}, # getBucketReadQuotaRouterName {Name = "ListBucketReadRecord", RateLimit = 100, RatePeriod = 'S'}, # listBucketReadRecordRouterName {Name = "GetGroupList", RateLimit = 200, RatePeriod = 'S'}, # getGroupListRouterName, similar to getUserGroupsRouterName, 2000qps {Name = "ListObjectsByIDs", RateLimit = 200, RatePeriod = 'S'}, # listObjectsByIDsRouterName, 1200qps {Name = "ListBucketsByIDs", RateLimit = 200, RatePeriod = 'S'}, # listBucketsByIDsRouterName, 2000qps {Name = "VerifyPermissionByID", RateLimit = 200, RatePeriod = 'S'}, # verifyPermissionByIDRouterName, 1200qps {Name = "GetUserGroups", RateLimit = 200, RatePeriod = 'S'}, # getUserGroupsRouterName, 2000qps {Name = "GetGroupMembers", RateLimit = 200, RatePeriod = 'S'}, # getGroupMembersRouterName, 2000qps {Name = "GetUserOwnedGroups", RateLimit = 200, RatePeriod = 'S'}, # getUserOwnedGroupsRouterName, 2000qps {Name = "ListObjectsByBucket", RateLimit = 75, RatePeriod = 'S'}, # listObjectsByBucketRouterName, 300qps {Name = "GetObject", RateLimit = 75, RatePeriod = 'S'}, # getObjectRouterName, 100 qps {Name = "PutObject", RateLimit = 75, RatePeriod = 'S'}, # putObjectRouterName, 100 qps {Name = "GetUserBuckets", RateLimit = 75, RatePeriod = 'S'}] # getUserBucketsRouterName, 1000 qps HostPattern = [] [Manager] # optional EnableLoadTask = true # optional GVGPreferSPList = [1,2,3,4,5,6,7] # optional EnableTaskRetryScheduler = true [Executor] # optional ListenSealRetryTimeout = 30 [Quota] MonthlyFreeQuota = 0 ``` --- ## SP Common Issues > Source: https://docs.bnbchain.org/bnb-greenfield/storage-provider/run-book/common-issues/ This is a list of solutions to common SP deployment issues ## On-chain Proposal ### 1. Why send tx failed? * Reason 1: The gnfd binary doesn't match, you should use the [latest version](https://github.com/bnb-chain/greenfield/releases/latest) * Reason 2: The chain ID doesn't match, you should specify the chain ID correctly. For Greenfield `mainnet` you should add `--chain-id "greenfield_1017-1"`; for Greenfield `testnet`, you should add `--chain-id "greenfield_5600-1"`. ### 2. Why is Proposal Rejected? If your proposal received less than 2/3 of `yes` votes from validators, your propoosal will be rejected. ### 3. Why is Proposal Failed To query the failed reason, run the following command: ```shell # Greenfield Mainnet ./gnfd query gov proposal --node https://greenfield-chain-us.bnbchain.org:443 # Greenfield Testnet ./gnfd q gov proposal --node https://gnfd-testnet-fullnode-tendermint-ap.bnbchain.org:443 ``` If you see the following message: ```shell failed_reason: 'spendable balance 999009992000000000000BNB is smaller than 1000000000000000000000BNB: ``` It means the proposal initiator should be the funding address, and it should have balance of **1k BNB** as deposit, according to above error msg. Please note the initial deposit requirement varies on different environments. see [funding-address](join-SP-network.md#funding-address) ## SP Node Issues ### 1. Address Not Found Issue #### Description After starting SP binary, see the following error: ```shell rpc error: code = NotFound desc = rpc error: code = NotFound desc = account 0x12334567890 not found: key not found" ``` #### Root Cause It's not possiible to find information about a newly created address on chain. #### Solution Before starting your SP, transfer BNB to all of your 5 addresses. ### 2. Database Configuration Issue #### Description After starting SP binary, see the following error: ```shell Table "block_syncer.master_db" does not exist Failed to get db config from config file ``` #### Root Cause Data source name(dsn) is not set in `config.toml`. #### Solution ```shell [BlockSyncer] Modules = ['epoch','bucket','object','payment','group','permission','storage_provider','prefix_tree', 'virtual_group','sp_exit_events','object_id_map','general'] Dsn = [BsDB_User]:[BsDB_Passwd]@tcp([BsDB_Address])/[BsDB_Database?parseTime=true&multiStatements=true&loc=Local&interpolateParams=true ``` ### 3. Object Sealed State Issue #### Description After uploading a file, you see an error message: ```shell Message: object has not been sealed state ``` From SP log, you see the following: ```shell {"t":"2023-07-10T11:34:50.856+0800","l":"error","caller":"gfspapp/sign_server.go:42","msg":"failed to seal object","error":"code_space:\"signer\" http_status_code:400 inner_code:120002 description:\"failed to broadcast seal object tx, error: failed to broadcast tx, resp code: 13\" "} ``` #### Root Cause `SealAddress` does not have enough BNB to sign seal transactions #### Solution Transfer BNB to `SealAddress`. ### 4. P2P Issue #### Description After starging SP binary, you see an error message: ```shell failed to parse address 'k8s-gftestne-p2pexter-bc25ac70bc-a31e9596d87054c3.elb.us-east-1.amazonaws.com:9933' domain ``` #### Root Cause SP is trying to get connected with invalid SP URL in P2P network #### Solution Update [P2P] setting in `config.toml`: ```shell [P2P] # p2p node msg Secp256k1 encryption key, it is different from other SP's addresses P2PPrivateKey = '${p2p_private_key}' P2PAddress = '0.0.0.0:9933' P2PAntAddress = '${load_balance_doamin:port}' P2PBootstrap = [] P2PPingPeriod = 0 ``` `P2PAntAddress` is your load balance address. If you don't have a load balance address, you should have a public IP and use it in `P2PAddress`. `P2PBootstrap` is not used anymore, you can leave this field empty. ### 5.MinIO Authentication Issue #### Description Cannot config Minio as storage ```shell {"t":"2023-07-17T18:05:40.245+0800","l":"debug","caller":"storage/object_storage.go:15","msg":"created minio storage at endpoint http://172.17.0.2:9000/hashquark"} Jul 17 18:05:41 10-7-46-85 gnfd-sp[18585]: {"t":"2023-07-17T18:05:40.245+0800","l":"info","caller":"storage/minio.go:37","msg":"new minio store succeeds","bucket":"hashquark"} Jul 17 18:07:01 10-7-46-85 gnfd-sp[18585]: {"t":"2023-07-17T18:07:00.893+0800","l":"error","caller":"storage/s3.go:147","msg":"S3 failed to head bucket","error":"NoCredentialProviders: no valid providers in chain. Deprecated.\n\tFor verbose messaging see aws.Config.CredentialsChainVerboseErrors"} Jul 17 18:07:01 10-7-46-85 gnfd-sp[18585]: {"t":"2023-07-17T18:07:00.893+0800","l":"error","caller":"piece/piece_store.go:88","msg":"failed to head bucket","error":"NoCredentialProviders: no valid providers in chain. Deprecated.\n\tFor verbose messaging see aws.Config.CredentialsChainVerboseErrors"} Jul 17 18:07:01 10-7-46-85 gnfd-sp[18585]: {"t":"2023-07-17T18:07:00.893+0800","l":"error","caller":"piece/piece_store.go:77","msg":"failed to check bucket due to storage is not configured rightly ","error":"deny access bucket","object":"minio://hashquark/"} Jul 17 18:07:01 10-7-46-85 gnfd-sp[18585]: {"t":"2023-07-17T18:07:00.893+0800","l":"error","caller":"piece/piece_store.go:21","msg":"failed to create storage","error":"deny access bucket"} ``` #### Root Cause This is a MinIO authentication #### Solution You can refer [here](piece-store.md#minio). ### 6. SP Standard Test Issue #### Description ```html 2023/07/26 19:06:03.543395 [INFO] GID 41, Uploading file - object: 2q4l5v4v3z, bucket: sc1bw default error msg : 413 Request Entity Too Large

413 Request Entity Too Large

nginx/1.18.0 (Ubuntu) {"level":"error","time":"2023-07-26T13:06:03-06:00","message":"do API error, url: https://sc1bw.gnfd-testnet-sp.epotter-qa.io/2q4l5v4v3z, err: statusCode 413 : code : unknown error request-id (Message: \r\n413 Request Entity Too Large\r\n\r\n

413 Request Entity Too Large

\r\nnginx/1.18.0 (Ubuntu)\r\n\r\n)"} 2023/07/26 19:06:03.543395 [INFO] GID 41, Uploading file - object: 2q4l5v4v3z, bucket: sc1bw default error msg : 413 Request Entity Too Large

413 Request Entity Too Large

nginx/1.18.0 (Ubuntu) {"level":"error","time":"2023-07-26T13:06:03-06:00","message":"do API error, url: https://sc1bw.gnfd-testnet-sp.epotter-qa.io/2q4l5v4v3z, err: statusCode 413 : code : unknown error request-id (Message: \r\n413 Request Entity Too Large\r\n\r\n

413 Request Entity Too Large

\r\nnginx/1.18.0 (Ubuntu)\r\n\r\n)"} ``` #### Root Cause Nginx does not support large file #### Solution Enlarge `proxy-boody-size` ## DCellar Integration Issues ### 1. No 'Access-Control-Allow-Origin' header is present on the requested resource Error: ```shell Access to XMLHttpRequest at 'https://fbgtest.gnfd-testnet-sp.fbgx.ai/?read-quota&year-month=2023-07' from origin 'https://dcellar.io' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. ``` #### Solution Add these headers ```http Access-Control-Allow-Credentials: true Access-Control-Allow-Headers: Access-Control-Allow-Headers: DNT,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-MD5,Range,Authorization,X-Gnfd-Content-Sha256,X-Gnfd-Unsigned-Msg,X-Gnfd-Txn-Hash,Date,X-Gnfd-Object-ID,X-Gnfd-Resource,X-Gnfd-Piece-Index,X-Gnfd-Redundancy-Index,Address,X-Gnfd-User-Address,X-Gnfd-App-Domain,X-Gnfd-App-Reg-Nonce,X-Gnfd-Date,X-Gnfd-App-Reg-Public-Key,X-Gnfd-App-Reg-Expiry-Date,X-Gnfd-Expiry-Timestamp Access-Control-Allow-Methods: GET, PUT, POST, DELETE, PATCH, OPTIONS Access-Control-Allow-Origin: * Access-Control-Expose-Headers: *, X-Gnfd-Request-ID,X-Gnfd-Signed-Msg,X-Gnfd-Object-ID,X-Gnfd-Integrity-Hash,X-Gnfd-Piece-Hash Access-Control-Max-Age: 1728000 ``` ### 2. when an OPTION request is made, I get OPTIONS 405 (Method Not Allowed) error #### Root cause The 405 Method Not Allowed error occurs when the web server is configured in a way that does not allow you to perform a specific action for a particular URL. It’s an HTTP response status code that indicates that the request method is known by the server but is not supported by the target resource.The 405 Method Not Allowed error occurs when the web server is configured in a way that does not allow you to perform a specific action for a particular URL. It’s an HTTP response status code that indicates that the request method is known by the server but is not supported by the target resource. #### Solution Your application is likely running on a server using one of these three popular webserver software: Apache, nginx, or Cloudflare. Check your configuration files for your web server software for unintentional redirect or request handling instructions. --- ## SP FAQ > Source: https://docs.bnbchain.org/bnb-greenfield/storage-provider/run-book/sp-faqs/ ### What are requirements for Greenfield Storage Provider? Storage Providers(SP) should meet the following requirements: * Collateral: * Each SP candidate has to deposit **500 BNB** as collateral * SP needs to pledge additional funds to store more data at 200% of the storage fees of the data stored as Primary SP, which is 0.023 * 1024 * 2 = $47.104/TB. * [Hardware requirements](./run-SP-node.md#recommended-hardware) ### How does SP receive their rewards? SP will receive their rewards in `funding address` after sending `Settlement Transaction`. ### When to update store price and read price? Every SP can set their own suggested store price and read price via on-chain transactions. Read how to send commands [here](./join-SP-network.md#update-sp-price) There are some [constrains](https://github.com/bnb-chain/greenfield/blob/master/docs/modules/billing-and-payment.md#storage-fee-price-and-adjustment ): * When to Update : The global rates will be calculated and updated in each month's first block (UTC time) by default. * When not Update: By default, SPs cannot update their price in the last two days of the current month. ### How much BNB is required by SP to stake in relation to how much space they want to provide? SP needs to stake additional funds to store user's data. It's based on formula: storage_staking_price * stored_size, and the price is now 160000 wei/byte, which could be fetched from [this API](https://greenfield-chain.bnbchain.org/openapi#/Query/VirtualGroupParams) . ### What's the limit of Storage Provider capacity? Each VGF serves a limited number of buckets. Once the store size exceeds a specified threshold, the family will no longer allow to serve more buckets. No limit on number of VGF but max size per VGF is 64T ### How to become a reliable SP? 1. Make sure your SP passed this [standard test](https://github.com/bnb-chain/greenfield-sp-standard-test) 2. If your infra is not working, switch your SP back to `maintenance mode`. Then, back up lost data from secondary SPs. --- ## Roadmap > Source: https://docs.bnbchain.org/bnb-greenfield/roadmap/roadmap/ # Roadmap ## March 2023, Testnet Congo - Support Ethereum compatible address and EIP-712 transactions - Support cross-chain token transfer between BSC and Greenfield - Support storage management, including bucket, object, and group operations - Support stream payment billing system ## May 2023, Testnet Mekong - Support mirror storage resources from Greenfield to BSC, and cross-chain programming paradigm on BSC - Support permission management on buckets, objects, and groups - Support data challenge ## September 2023, Launch Mainnet Lena - Support SP standard framework - Support SP join by governance - Support data recovery - Support large object and breakpoint resume transfer ## December 2023, Mainnet - Enrich the ecosystem by building abundant toolchains and programming paradigms, such as data marketplace, NFT toolset, data migration toolset and so on - Link Greenfield with opBNB - Greenfield bundle service - Resource tagging and indexing ## March 2024, Mainnet - Cross-chain permission control - Support the free exit of SP - Simple data migration - Object atomic update ## June 2024, Mainnet - Enhance user experience of using greenfield and cross-chain programming - Paymaster - Data availability layer for BSC and L2 blockchains ## December 2024, Mainnet - Support off-chain generic computing - Support permanent storage - Higher performance For additional information, please refer to the [BNB Greenfield Roadmap Proposal](https://forum.bnbchain.org/t/bnb-greenfield-roadmap-proposal/2273). --- ## Feature Lists > Source: https://docs.bnbchain.org/bnb-greenfield/roadmap/features/ # Feature Lists As a decentralized storage network, Greenfield provides a rich set of features and playability. This article documents the key features and their development status on Greenfield. Please stay tuned. | Feature Name | Description | Status | |:----------------------------------:|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:-------:| | Ethereum compatible address | Greenfield supports Ethereum compatible address format, which means users can continue to use Ethereum compatible wallets and accounts | Mainnet | | EIP-712 transaction | Support structured signature method of EIP-712, making the signed message user-readable | Mainnet | | Governance | Validators can vote on proposals through governance, including modification of various module parameters, validator joining and exiting, new SP joining, cross-chain contract parameters, etc. | Mainnet | | Permission staking | Support validator joining and exiting through governance, validator delegate/undelegate operations | Mainnet | | Greenfield <-> BSC token transfer | Support bidirectional cross-chain token transfer between BSC and Greenfield | Mainnet | | SP basic operations | Support new SP joining, viewing current SP, modifying SP information, and updating SP storage prices, etc. | Mainnet | | Bucket operations | Support creating/updating/deleting buckets | Mainnet | | Object operations | Support creating/uploading/downloading/deleting objects | Mainnet | | Group operations | Support creating/updating/deleting groups | Mainnet | | Billing system | Users need to pay storage and reading fees for objects stored on Greenfield. SPs earn corresponding income through corresponding storage services. Greenfield uses a stream payment method to calculate fees | Mainnet | | Permission management | Greenfield provides rich permission management functions, which can assetize data stored on it and open it to certain users. Greenfield supports adding or deleting permissions for individual users or groups at the bucket and object level | Mainnet | | Resource mirror | Greenfield supports mapping buckets, objects, and groups to BSC. There is a unique NFT on BSC corresponding to the data and resources, and developers can build various smart contract cross-chain management of resources on BSC, providing rich playability | Mainnet | | Universal endpoint | Users can access files stored on Greenfield through any SP in the SP network | Mainnet | | Folder | Greenfield supports prefix queries and delimiter queries for files within buckets, allowing dApps to organize folders on top of Greenfield | Mainnet | | Data challenge | Greenfield uses the data challenge scheme as a guarantee of data existence. Greenfield will randomly challenge the data segments stored on SPs. Users can also challenge any data segments stored on SPs to ensure that SPs correctly store their data | Mainnet | | Data recovery | Data recovery is used to ensure that the original data can be recovered when certain data is lost on SPs, ensuring the reliability of user data on Greenfield. Greenfield supports various forms of data recovery: 1. Data will be automatically recovered after data challenge succeeds. 2. Data will be automatically recovered when users find that the data is unreadable. 3. SPs can selectively recover some lost data through tools | Mainnet | | Large object and breakpoint resume | Greenfield supports breakpoint resume, which improves the efficiency and user experience of object transfer | Mainnet | | SP graceful exit | When SPs want to exit voluntarily for some reason, Greenfield can support SPs to migrate the previously stored data to other SPs and then exit, so that the freedom of SPs is ensured without affecting the availability of data on Greenfield | Mainnet | | Migrate bucket | Greenfield supports users to migrate their bucket from one SP to another | Mainnet | | Expiration time for group member | Greenfield supports setting expired time for group members | Mainnet | | Link with opBNB | Build native cross-chain bridge between Greenfield and opBNB | Mainnet | | Resource tags | Support setting tags for bucket, object, and group | Mainnet | | Cross-chain permission module | Enable add/delete permission from BSC/opBNB smart contracts | Mainnet | | Atomic update | Support update object other than delete and create again | Testnet | | Greenfield as DA layer | Make Greenfield as the DA layer of the other Blockchains such as opBNB and BSC | Design | | Permanent Storage | Support for permanent object storage | Design | | Off Chain Auth | Streamline off-chain authentication on Greenfield | Mainnet | | SP as the upload agent | Primary Storage Provider acts as the upload agent for object creation on Greenfield | Mainnet | | Greenfield Storage Fee Paymaster | A storage fee paymaster solution for sponsors to cover storage costs on Greenfield | Mainnet | | Cross-Chain Programming | Improve Greenfield cross-chain programming capability | Mainnet | --- ## Overview > Source: https://docs.bnbchain.org/showcase/mcp/ # Model Context Protocol (MCP) The **Model Context Protocol** is an open interface that lets AI agents and developer tools share a rich execution context. In practice, that means you can: * Ask natural‑language questions about on‑chain data or documentation. * Invoke blockchain‑aware tools (read‑only or state‑changing) without manual RPC calls. * Plug the same back‑end into multiple IDEs, CLIs or chat front‑ends. > **Why use it?** > *Unified access* – instantly switch between chat, code, and terminal workflows. > *Extensibility* – add your own prompts & tools. > *Open source* – fork, self‑host, or just `npx` it. --- ## 1 Available MCP servers | Name | Endpoint / Install | Scope | Typical usage | | ------------------------------------------------------------- | ------------------------------------------------------- | ----------------------------------------------------------------- | ------------------------------------------------------------------- | | [**bnbchain‑mcp**](https://github.com/bnb-chain/bnbchain-mcp) | `npx @bnb-chain/mcp@latest`or self-host via Docker | Full toolkit: blocks, txs, wallets, Greenfield ops & more | Build, test, or automate on-chain actions from your IDE or scripts. | | [**ask‑ai‑mcp**](./docs/showcase/mcp/ask-ai-to-ide.md) | `https://api.superintern.ai/agent/async/mcp/mcp` | Read-only semantic search over BNB Chain docs, BEPs, blogs & FAQs | Quick answers in chat panes or command palettes. | Both servers speak the *same* MCP schema, so you can swap them in your settings with a single JSON change. --- ## 2 What can MCP do? ### Conversational queries ```text What is BEP‑20 and how does it differ from ERC‑20? ``` Answer arrives instantly with source links. ### Tool execution (bnbchain‑mcp only) ```text get_block_by_number number=37000000 chain=bsc ``` Returns structured JSON for the requested block. Supply a `PRIVATE_KEY` to unlock write‑capable tools such as `transfer_erc20` or `write_contract`. ### IDE‑agnostic integration * VS Code, Cursor, JetBrains: add a **servers.mcp** entry in settings → choose the agent in your chat panel. * Terminal lovers: `curl` or your favourite HTTP client. * Custom apps: import `@bnb-chain/mcp` as a library. --- ## 3 Quick links & next steps * **Official Skills for AI** – [Skills for AI Agents](../mcp/skills.md): official instructions and agent commands (`npx @bnb-chain/mcp@latest`). Use this page so your agent can connect to BNB Chain. * **GitHub – bnbchain‑mcp** – source, issues, self‑hosting guide: [https://github.com/bnb-chain/bnbchain-mcp](https://github.com/bnb-chain/bnbchain-mcp) * **Ask AI Tutorial** – connect your IDE to the read‑only doc search endpoint: `ai/askai-tutorial.md` * **AI Agent solution page** – see how MCP fits into BNB Chain’s broader AI strategy: [https://www.bnbchain.org/en/solutions/ai-agent](https://www.bnbchain.org/en/solutions/ai-agent) Have questions? Join **#ai‑tooling** on Discord or open a GitHub issue. PRs welcome! --- ## Skills > Source: https://docs.bnbchain.org/showcase/mcp/skills/ # BNB Chain Skills This page is for **AI agents** that integrate with BNB Chain. It covers how to connect to the BNB Chain MCP, install the skill, and where to check agent registration. **Skills repository:** [github.com/bnb-chain/bnbchain-skills](https://github.com/bnb-chain/bnbchain-skills) --- ## 1. Connect to BNB Chain MCP - **Run the MCP server:** `npx @bnb-chain/mcp@latest` - **Fetch this skill page (optional):** `curl -s https://raw.githubusercontent.com/bnb-chain/bnb-chain.github.io/main/docs/showcase/mcp/skills.md` --- ## 2. Agent registration - **Mainnet:** Check agent registration and status at **[https://www.8004scan.io/](https://www.8004scan.io/)** - **Testnet:** Check registration at **[https://testnet.8004scan.io/](https://testnet.8004scan.io/)** --- ## 3. Learn the skill Install the BNB Chain MCP skill so your agent can use it (e.g. in Cursor or Claude): ```bash npx skills add bnb-chain/bnbchain-skills ``` Install globally (available across all projects): ```bash npx skills add bnb-chain/bnbchain-skills -g ``` --- ## References - **BNB Chain Skills (GitHub):** [https://github.com/bnb-chain/bnbchain-skills](https://github.com/bnb-chain/bnbchain-skills) --- ## Integrating AskAI > Source: https://docs.bnbchain.org/showcase/mcp/ask-ai-to-ide/ # Quick‑Start Tutorial Follow these steps to wire any IDE that supports the **Model Context Protocol (MCP)** to BNB Chain’s Ask AI knowledge base **and start querying documentation right away**. > **Time required:** ≈ 2 minutes > **Prerequisites:** > • IDE with an MCP client (e.g. VS Code MCP extension, Cursor ≥ 0.23.0, JetBrains plugin) --- ## 1 Add the Ask AI MCP server 1. Open your IDE’s **Settings / Preferences** and find the **MCP** section. 2. Choose **Add MCP server** (wording may vary). 3. Paste the JSON block below and save. ```jsonc { "mcpServers": { "bnbchain-askai-mcp": { "url": "https://api.superintern.ai/agent/async/mcp/mcp" } } } ``` 4. Reload the IDE window if the MCP client does not restart automatically. A **Connected** status should now appear next to *bnbchain‑askai‑mcp*. --- ## 2 What the MCP can do The Ask AI MCP lets you **query** BNB Chain’s public documentation corpus in natural language and receive the most relevant passages, with source links, inside your editor. It is *read‑only* – no blockchain transactions are executed. --- ## 3 Run queries inside your IDE Below are three common ways to interact with the Ask AI MCP once it is connected. ### 3.1 Chat Panels (Copilot, Cursor Chat, etc.) 1. Open your IDE’s AI/Chat pane (Copilot Chat, Cursor side‑chat, JetBrains AI Assistant…). 2. Locate the **agent / provider selector** at the top of the chat window. 3. Choose **bnbchain‑askai‑mcp**. 4. Ask questions in plain English – e.g. *“Summarise BEP‑20.”* > **Want a detailed step-by-step walkthrough for VS Code?** Check out the companion guide: [Ask AI in VS Code](ask-ai-vs-code-guide.md) – complete with annotated screenshots. ### 3.2 Command Palette / Command Menu | IDE | How to open | Steps | | ------------- | ----------------------------------------------------------- | ------------------------------------------------------------------------------ | | **VS Code** | Ctrl/Cmd + Shift + P | Type **“MCP: Run Query”** → pick **bnbchain‑askai‑mcp** → enter your question. | | **Cursor** | Cmd + K (mac) or Ctrl + K (win/linux) | Select **Ask MCP…** → choose **bnbchain‑askai‑mcp** → ask away. | | **JetBrains** | Shift + Shift then “MCP Query” | Pick **bnbchain‑askai‑mcp** and type a question. | ### 3.3 Terminal / cURL (optional) For quick tests outside the IDE you can hit the endpoint directly: ```bash curl -s -X POST \ -H "Content-Type: application/json" \ -d '{"query":"What is BEP‑20?"}' \ https://api.superintern.ai/agent/async/mcp/mcp ``` You’ll receive a JSON response containing an `answer` field and `sources` array. --- ## 4 Example queries ```text What is the gas limit on BSC blocks? Summarise BEP‑336 in two sentences. List all fee tiers supported by opBNB. Explain the purpose of Greenfield buckets. ``` --- ## 5 Troubleshooting | Symptom | Fix | | -------------------------- | ---------------------------------------------------------------- | | **400/401 response codes** | Verify the JSON snippet (no trailing commas). | | **Long latency (> 10 s)** | Disable any *Throttle Streaming* or similar setting in your IDE. | | **No answer returned** | Make sure you chose **bnbchain‑askai‑mcp** and asked a question. | Need more help? Ping us in **#ai‑tooling** on the BNB Chain Discord. Open an issue in the [docs repo](https://github.com/bnb-chain/docs-site/issues) if your favourite editor is missing. --- ## Decentralized Identity > Source: https://docs.bnbchain.org/showcase/identity/did/ # Decentralized Identity ## What is Decentralized Identity? Identity, in both the digital and physical worlds, serves as a means of distinguishing and authenticating individuals and entities. **Digital Identity**: * Includes online personas, accounts, and digital certificates. * Verified using usernames, passwords, and other authentication methods. * Relies on electronic data and cryptographic methods for authenticity and security. **Decentralized Identifier (DID)**: * A semi-anonymous identifier for individuals, companies, objects, etc. * Protected by a private key, with only the key owner able to verify ownership. * Allows for multiple DIDs to prevent tracking across different activities. * Example: One DID for gaming, another for credit reporting. ### How are decentralized identities secured? A crucial aspect of securing decentralized identities is cryptography. In cryptography, private keys are known only to their owners, while public keys are widely distributed. This pairing serves two main purposes. First, it enables authentication, allowing the public key to verify that a message was sent by the holder of the corresponding private key. Second, it facilitates encryption, ensuring that only the holder of the paired private key can decrypt a message encrypted with the public key. ## Benefits of decentralized identity * **Increased Individual Control**: Users have more control over their identifying information without relying on centralized authorities or third-party services. * **Trustless Verification**: Facilitates a trustless, seamless, and privacy-protecting method for verifying and managing user identity. * **Blockchain Technology**: Uses blockchain to create trust between parties and provides cryptographic guarantees for the validity of attestations. * **Portability of Identity Data**: Identity data is portable; users can store attestations and identifiers in a mobile wallet and share them with any party of their choice, independent of the issuing organization's database. * **Compatibility with Zero-Knowledge Technologies**: Supports zero-knowledge proofs, allowing individuals to prove ownership or actions without revealing specifics, enhancing trust and privacy for applications like voting. ## Decentralized Identity Use Cases | Industry | Traditional Process | Problems/Risks | Verifiable Credentials Solution | | ------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | | Supply chain | Utilizes physical IDs and documents to prove compliance, leading to inefficiencies. | Documents can be easily falsified and are challenging to authenticate. The manual verification process is slow and error-prone. Unapproved and non-compliant medical supplies can enter the market, endangering public health. | Verifiable Credentials are tamper-proof and can be verified instantly without needing to contact the issuer, greatly reducing time and costs. | | Finance | To access financial services, individuals must undergo compliance screening by submitting personal details in physical form, which are stored in large databases and shared with multiple third parties for KYC and credit checks. | Individuals have no control over the security, sharing, and access of their data by third parties. | Credentials are cryptographically secured, tamper-proof, and can be verified, ensuring data integrity and security. | | Healthcare | Employers manually verify paper-based licenses and certificates for healthcare providers. | Traditional verification processes take weeks or months, delaying the filling of essential healthcare positions. | Medical licenses can be issued as digital credentials by regulatory organizations, allowing healthcare providers to easily share them for immediate verification by hospitals, clinics, or medical departments where they seek employment. | --- ## SpaceID > Source: https://docs.bnbchain.org/showcase/identity/dns/ # Decentralized Naming Service ## Traditional DNS vs Decentralized Naming Service Traditional Domain Name System (DNS) and decentralized naming services like [Ethereum Name Service (ENS)](https://docs.ens.domains/) serve similar purposes but differ significantly in their underlying structures and control mechanisms. Traditional DNS translates human-readable domain names into IP addresses, enabling users to access websites easily. It is managed by centralized authorities, such as ICANN, which oversee the domain registration and resolution process. This centralization can lead to vulnerabilities, such as censorship, single points of failure, and control by a few entities. In contrast, decentralized naming services like ENS operate on blockchain technology, distributing control among network participants. ENS maps human-readable names to Ethereum addresses and other resources using smart contracts, ensuring that no single entity has overarching control. This decentralized approach enhances security, reduces the risk of censorship, and provides greater resilience against failures, aligning with the principles of trustlessness and user sovereignty inherent in blockchain ecosystems. ## SpaceID ### Overview [Space ID](https://space.id/) offers a universal namespace for blockchain, enabling users to register and manage domain names across different blockchains. It enhances cross-chain interoperability and simplifies user identification across the Web3 ecosystem. This project supports a broad range of applications, from crypto trading to token lending and NFT minting, showcasing a versatile approach to decentralized digital identities. ### How SpaceID works SPACE ID aims to create a universal name service network that connects decentralized identities with the physical and digital worlds. It is progressing toward becoming a comprehensive digital identity solution for Web3. Read the details [here](https://docs.space.id/) ### Key features of SpaceID **Multi-Chain Name Service** Among the top priorities of SPACE ID is supporting more blockchains and top-level domains (TLDs). Unlike SPACE ID 1.0, whose main emphasis was on .bnb Name Service, SPACE ID 2.0 instead focuses on multi-chain name service. SPACE ID has reached out to various blockchains for partnership discussions, and expects its ecosystem to flourish with time. **Web3 Name SDK & API** SPACE ID aims to streamline web3 services through the use of a single SDK to assist in the building of DApps. This saves developers time, since they don't have to work with multiple protocols and be encumbered with issues of blockchain incompatibility. This vision is being realized by adding an all-in-one API over the SDK, allowing current and future partners to seamlessly integrate their web3 services with their unified Web3 Name SDK. ### Benefits of DNS * **Simplified Address Management**: Users can use easy-to-remember names instead of long hexadecimal addresses, reducing the risk of errors in transactions. * **Interoperability**: SpaceID names can point to various types of addresses and resources, supporting multiple blockchain networks and off-chain data. * **Decentralization**: SpaceID is built on blockchain, ensuring that no single entity controls the naming system, which enhances security and censorship resistance. * **Flexibility**: Domain owners have full control over their domains, including the ability to create subdomains, update addresses, and manage metadata. ### Use Case of SpaceID * **Cryptocurrency Wallets**: Users can receive payments using simple names instead of complex addresses. * **Decentralized Websites**: SpaceID names can point to Greenfield content, enabling decentralized websites. * **Identity Management**: SpaceID can be used as part of a decentralized identity system, linking a user’s SpaceID to their decentralized identifiers and attestations. * **DApps and Smart Contracts**: Developers can use SpaceID to provide human-readable names for their smart contracts and decentralized applications, improving user experience. --- ## Build with SpaceID > Source: https://docs.bnbchain.org/showcase/identity/dns-dev/ # Get Started - SpaceID ## How to Resolve a Name Using the Space ID SDK ### Step 1: Setup Your Project 1. Install Node.js and npm Ensure you have Node.js and npm installed. You can download them from Node.js official website. 2. Create a New Project Open your terminal and create a new project directory: ```bash mkdir spaceid-tutorial cd spaceid-tutorial npm init -y ``` 3. Install the Space ID SDK Install the Space ID SDK package using npm: ```bash Copy code npm install @spaceid/sdk ``` ### Step 2: Write the Code to Resolve a Name 1. Create a JavaScript File Create a file named `resolveName.js` in your project directory. 2. Import the Space ID SDK At the top of `resolveName.js`, import the Space ID SDK: ```javascript const { SpaceID } = require('@spaceid/sdk'); ``` 3. Initialize the Space ID SDK Initialize the SDK with the necessary parameters: ```javascript const spaceId = new SpaceID({ endpoint: 'https://api.spaceid.io', // API endpoint apiKey: 'your_api_key' // Replace with your actual API key }); ``` 4. Resolve a Name Write a function to resolve a name using the SDK: ```javascript async function resolveName(name) { try { const result = await spaceId.resolveName(name); console.log(`Address for ${name}: ${result.address}`); } catch (error) { console.error('Error resolving name:', error); } } ``` 5. Call the Function Call the `resolveName` function with a sample name: ```javascript resolveName('example.eth'); ``` ### Step 3: Run the Code 1. Run the Script In your terminal, run the script: ```bash node resolveName.js ``` 2. View the Result If everything is set up correctly, you should see the resolved address for the provided name in the terminal output. ## Example Code Here’s the complete code for resolveName.js: ```javascript const { SpaceID } = require('@spaceid/sdk'); const spaceId = new SpaceID({ endpoint: 'https://api.spaceid.io', apiKey: 'your_api_key' }); async function resolveName(name) { try { const result = await spaceId.resolveName(name); console.log(`Address for ${name}: ${result.address}`); } catch (error) { console.error('Error resolving name:', error); } } resolveName('example.eth'); ``` Replace 'your_api_key' with your actual API key and 'example.eth' with the name you want to resolve. You can read more in this [blog](https://nodereal.io/blog/en/how-to-resolve-a-name-through-spaceid-sdk/). --- ## BNB Attestation Service > Source: https://docs.bnbchain.org/showcase/identity/attestation/ # BNB Attestation Service ## What is attestation? Attestations are digital signatures on structured data used to build more trust on-chain. ## BNB Attestation Service(BAS) The [BNB Attestation Service (BAS)](https://bascan.io/attestation) is an infrastructure built on the BNB ecosystem for generating attestation to verify information. BAS assists users in on-chain or off-chain verification, allowing them to assert ownership of attestation by storing them in Greenfield. This approach ensures data privacy and access control. BAS serves as a standard and infrastructure for generating arbitrary attestations. Anyone can define any attestation in BAS along with its resolver. BAS supports the generation of on-chain/off-chain attestations, and by storing off-chain attestations in Greenfield, users gain ownership, ensure attestation privacy, and implement access control. ### Core Components of BAS * [Schema](https://doc.bascan.io/core_concept/schema): A schema is a structured framework that defining the data format and resolver with attest function. Schema dictate what kind of data can be attested and how that data should be presented. * [Attestation](https://doc.bascan.io/core_concept/attestation): Attestation provide a standard for user to import any data into web3. With in BAS, attestations can be created on-chain and off-chain. * [Resolver](https://doc.bascan.io/core_concept/resolver): User can use resolver to introduce any logic to their attestations. Checkout the smart contracts [here](https://github.com/bnb-attestation-service/bas-contract). ## Types of attestations Attestations can be made either onchain or offchain. While onchain attestations are stored directly on the BNBChain, offchain attestations reside outside of it, often in decentralized storage solutions like Greenfield. Both methods have their unique advantages, and the choice largely depends on the specific requirements of the use case. Learn about the idfference between on-chain and off-chain difference [here](https://doc.bascan.io/core_concept/onchain_vs_offchain). ### On-Chain Attestation Record Users can clearly view the structure of an on-chain attestation on [BASCAN](https://bascan.io/attestation). ### OffChain Attestation Record Here's an off-chain attestation record. Unlike the on-chain record, this attestation is public, and the server is unaware of it. Users can share the attestation URL with others to decode the data or publish it to GreenField. Once published or pinned to GreenField, the status icon will switch to "public.” ## Use Cases of Attestation ### KYC Combined BAS with zero-knowledge proofs, [zkPass](https://bas.zkpass.org/) uses three-party TLS and zero-knowledge (ZK) technology to create zero-knowledge proofs of user’s real-world assets or actions directly in your browser. This ensures privacy by not oversharing your data and not requiring API authorizations. ZKPass is a private data protocol using affordable zero-knowledge technology. You can learn more about the use case in this [blog](https://medium.com/zkpass/zkpass-commits-4-million-zkp-tokens-for-bnb-chain-airdrop-alliance-rewards-87e5f32a9ee4). ### Developer on-chain reputation [Aspecta ID](https://aspecta.id/) integrates with the BAS to create and verify on-chain attestations of developers' achievements and activities, ensuring transparency, security, and trust in digital identity management. This partnership allows Aspecta to offer a tamper-proof and verifiable record of developers' skills and contributions, enhancing interoperability and trust within the AI and blockchain ecosystems. By leveraging BAS, Aspecta provides developers with a robust platform to authenticate their credentials, making their professional profiles more credible and secure. You can learn more about the use case in this [blog](https://medium.com/@aspecta_id/bnb-chain-builder-economy-a-builder-community-consensus-to-boost-innovation-with-productivity-ba4d71af6021). --- ## Build your Attestation > Source: https://docs.bnbchain.org/showcase/identity/attestation-dev/ # Get Started - Attestation ## Creating On-chain Attestations The `attest` function enables you to confidently create an on-chain attestation for a specific schema. This powerful function accepts an object with the following properties: * `schema`: The unique identifier (UID) of the schema for which the attestation is being created. * `data`: An object that contains the following properties: * `recipient`: The BNB address of the attestation recipient. * `expirationTime`: A Unix timestamp that represents the expiration time of the attestation. You can set it to 0 for no expiration. * `revocable`: A boolean value that indicates whether the attestation can be revoked or not. * `refUID`: (Optional) The UID of a referenced attestation. If there is no reference, use ZERO_BYTES32. * `data`: The encoded data for the attestation, which should be generated using the SchemaEncoder class. This function gracefully returns a Promise that resolves to the UID of the newly created attestation. ```javascript import { BAS, SchemaEncoder } from "@bnb-attestation-service/bas-sdk"; const bas = new BAS(BASContractAddress); bas.connect(signer); // Initialize SchemaEncoder with the schema string const schemaEncoder = new SchemaEncoder("uint256 eventId, uint8 voteIndex"); const encodedData = schemaEncoder.encodeData([ { name: "eventId", value: 1, type: "uint256" }, { name: "voteIndex", value: 1, type: "uint8" }, ]); const schemaUID = "0xb16fa048b0d597f5a821747eba64efa4762ee5143e9a80600d0005386edfc995"; const tx = await bas.attest({ schema: schemaUID, data: { recipient: "0xFD50b031E778fAb33DfD2Fc3Ca66a1EeF0652165", expirationTime: 0, revocable: true,// Be aware that if your schema is not revocable, this MUST be false data: encodedData, }, }); const newAttestationUID = await tx.wait(); console.log("New attestation UID:", newAttestationUID); ``` ## Creating Off-chain Attestations without Saving to GreenField To generate an off-chain attestation, you can confidently utilize the signOffchainAttestation function offered by the Off-chain class in the BAS SDK. Here’s an example: ```javascript import { SchemaEncoder } from "@bnb-attestation-service/bas-sdk"; const offchain = await bas.getOffchain(); // Initialize SchemaEncoder with the schema string const schemaEncoder = new SchemaEncoder("uint256 eventId, uint8 voteIndex"); const encodedData = schemaEncoder.encodeData([ { name: "eventId", value: 1, type: "uint256" }, { name: "voteIndex", value: 1, type: "uint8" }, ]); // Signer is an ethers.js Signer instance const signer = new ethers.Wallet(privateKey, provider); const offchainAttestation = await offchain.signOffchainAttestation({ recipient: '0xFD50b031E778fAb33DfD2Fc3Ca66a1EeF0652165', // Unix timestamp of when attestation expires. (0 for no expiration) expirationTime: 0, // Unix timestamp of current time time: 1671219636, revocable: true,// Be aware that if your schema is not revocable, this MUST be false version: 1, nonce: 0, schema: "0xb16fa048b0d597f5a821747eba64efa4762ee5143e9a80600d0005386edfc995", refUID: '0x0000000000000000000000000000000000000000000000000000000000000000', data: encodedData, }, signer); This function will confidently generate an attestation object off-chain, which will be signed and contain the UID, signature, and attestation data. You can confidently share this object with the intended recipient or confidently store it for future use. ``` ## Creating Off-chain Attestation and Saving to GreenField To generate an off-chain attestation and save the result to GreenField Storage, you can confidently utilize the attestOffChain function offered by the BAS SDK. Here’s an example: ```javascript const offchain = await bas.getOffchain(); // Use wallet or client to ensure the chain is BNB // [WARN]: should call an async function await shouldSwitchNetwork(chains[1].id); // BNB chainId // Attest offchain const attestation = await attestOffChain({ schemaStr: attestParams.schemaStr, schemaUID: attestParams.schemaUID, data: attestParams.data, recipient: attestParams.recipient, revocable: attestParams.revocable, }); const attestationUID = attestation.uid; // Use wallet or client to ensure the chain is Greenfield Chain await shouldSwitchNetwork(chains[0].id); const provider = await connector?.getProvider({ chainId: chains[0].id }); BigInt.prototype.toJSON = function () { return this.toString(); }; // Encode the attestation object into blob to store on the Greenfield Storage const str = JSON.stringify(attestation); const bytes = new TextEncoder().encode(str); const blob = new Blob([bytes], { type: "application/json;charset=utf-8", }); let res; try { // Use GreenField SDK to store the attestation res = await gfClient.createObject( provider, new File([blob], `${attestParams.schemaUID}.${attestationUID}`), attestParams.isPrivate || true ); } catch (err: any) { console.log(err); alert(err.message); } ``` This function will generate an attestation object off-chain. The attestation object will be signed and will contain the UID, signature, and attestation data. Similar to the previous function, you can also save it to greenfield storage and set the access according to your preferences. ## More Use Cases On-chain attestations will enable a powerful new range of web3 applications, including: * Identity * Trust Scores * KYC Services * Social Networks * Voting * Oracles (who can be atomically paid for making attestations inside the protocol) * Likes/Dislikes * Portable Trust Layers * Credit Scores * Clout * Land Registries And many more! ## Resources * [BAS JS-SDK](https://doc.bascan.io/sdk/js) --- ## Telegram Mini Game on BNB Chain > Source: https://docs.bnbchain.org/showcase/telegram/minigame/ # Creating Telegram BNB Mini Apps: A How-to Guide for Developers Launching decentralized applications on Telegram has become increasingly popular due to it giving users access to mini apps and games without requiring them to install additional software, providing an easy way for users to interact with blockchain-based services. This lowers the barriers to entry for users and makes it simple for developers to distribute their apps to a large Telegram audience. This guide will walk you through the steps for building a basic Telegram mini app on BNB in just a few hours. By the end, you will have the skills to launch your own BNB project on Telegram’s open platform. Whether you are a blockchain expert or just starting out, this tutorial aims to demystify decentralized app creation. So let’s get started building on BSC! The possibilities are endless when you master Telegram mini apps. **Note: This guide only provides a high level overview of the steps that may be involved in creating telegram BNB miniapp. For a detailed guide, visit the [youtube demo](https://www.youtube.com/watch?v=6dMDhPOpPjI) or the [github repo](https://github.com/kang5647/bnb-telegram-demo).** # Introduction to Telegram BNB Mini Apps ## What are Telegram Mini Apps? **Telegram Mini Apps** are lightweight web apps that run inside Telegram chats. They allow developers to create social experiences, games, marketplaces, and other services that tap into Telegram's features and large audience. Catizen’s play-to-earn and Hamster Kombat’s tap-to-earn, what's the next big thing for Telegram mini games? Mini Apps load instantly, work offline, and don't need to be installed. They can use Telegram login, payments, storage and more. Developers can build Mini Apps using HTML, CSS and JavaScript. How to Create a Mini App To create a Mini App, you need: - A Telegram bot - Create a bot using @BotFather and obtain an API token. - A web app - Build an app using web technologies (HTML, CSS, JS) that communicates with your bot. - Mini App manifest - Provide info about your app like name, description, icon, and your web app's URL. Register the manifest using the @BotFather. Your web app will run in an iframe and communicate with the user's Telegram app using the Telegram Bridge. The Bridge exposes the Telegram API and passes messages between your web app and the user's Telegram app. ## Mini App Types There are two main types of Mini Apps: ### Inline Apps Inline Apps show up as results when a user types the bot's username followed by a query. The user taps an app result to launch the Mini App. Inline Apps are great for: - Search experiences - Quick interactions - Discovering new content ### Direct Link Apps Users can open a Direct Link App just by tapping a link. Direct Link Apps are aware of the current chat context and support shared, collaborative experiences. Direct Link Apps are ideal for: - Social experiences - Games - Productivity tools - And more The mini app can also be launched from a keyboard button, from an inline button, and from the bot menu button. Refer to the [official Telegram mini app documentation](https://core.telegram.org/bots/webapps#implementing-mini-apps). ## Step-by-Step Guide to Creating a BNB Mini App With the power of Telegram behind them, Mini Apps open up countless new opportunities for creativity and building engaging experiences on the platform. The potential for Mini Apps is huge, and this is just the beginning. ### Create a Telegram Bot To get started, you will need to create a Telegram bot. Visit the **@BotFather** bot and enter **/newbot** to create a new bot. You will receive an API token for your bot. Keep this token private as it will allow you to control your bot. ### Connect the Webapp to Your Bot Next, you need to connect your webapp to the Telegram bot. Use the **/newapp** command in the **@BotFather** bot by selecting your bot. Provide details such as the app name, description, photo, etc. Finally, enter the URL of your webapp. Your mini app will now appear in the Telegram app and can be launched by users. ### Additional Capabilities Mini apps opened from a direct link have limited capabilities. They cannot read or send messages on behalf of the user. However, they support cooperative and multiplayer features within the current chat context. Users must redirect to inline mode to actively pick a result in order to send messages. Mini apps are powerful tools for creating fully-fledged web services, team collaborations, multiplayer games, and more. The possibilities are endless. ## Turning Your Mini App Into a Game To transform your Mini App into an engaging game on Telegram, you must first register a bot with **@BotFather** and create a Mini App as outlined in the previous section. Once you have a functioning Mini App, you can then convert it into a game by using Telegram’s Game API. ### Difference Between Mini Apps and Mini Games Mini games build upon mini apps by providing additional information like: - leaderboards, - game descriptions, - and a button to launch the game. - They help package your mini app to make sharing with friends and community easier. To create a mini game, use the /newgame command and configure callback functions to return your game's URL. ### Register a Game with @GameBot The first step is to register your game with @BotFather. Send the /newgame command to @BotFather, and provide the required details including: - The title and description of your game - A cover photo - The message text a user will see when starting a game - The URL of your Mini App Implement Callbacks You must implement callback functions in your code to handle interactions with the Telegram Game API. Specifically, you need a callback_query() callback which will receive updates from Telegram when a user clicks an inline button in your game. Within this callback, you should check the callback ID to determine which button was clicked. You may implement multiple inline keyboard buttons for the game, but note that the first button must always launch the game. ### Share Your Game Once registered, your game will receive a shareable game URL and a game code which players can enter to launch the game. You can share this URL and code on your website, social media, and within Telegram chats to spread your game to new players. ### Consider a Leaderboard (Optional) To increase engagement and competition, you can implement an in-game leaderboard where players can see the top scores. You will need to store player scores in a database, and return the leaderboard data within your callbacks. Leaderboards are an optional feature, but can greatly enhance the popularity and longevity of Telegram games. By following these steps, you can build fully-featured games within Telegram using JavaScript and the Telegram Game API. Games are an exciting way to engage users, and the possibilities for multiplayer, social, and interactive gaming experiences on Telegram are endless. Let your creativity run wild, and build the next hit game on Telegram! ## FAQs About Telegram BNB Mini Apps ### What are the main features of Telegram BNB Mini Apps? Telegram BNB Mini Apps allow developers to build decentralized applications on BSC or opBNB that can be accessed directly within Telegram. Some of the key features include: - Access to Telegram username, chat ID and message ID to provide chat context - Ability to send messages on behalf of users (with their permission) - Option to accept payments via crypto wallet - Access to BSC/opBNB for decentralized functionality - Option to build multiplayer games and other interactive experiences ### What are the differences between Mini Apps and Bots? Telegram Mini Apps are web apps that run within the Telegram app, while Telegram Bots are automated accounts controlled via API. Some key differences include: - Mini Apps have a visual interface, while Bots primarily communicate via text messages. - Mini Apps can access features like payments, games and location sharing, while Bots have more limited functionality. - Mini Apps require user consent to access data and send messages, while Bots have implicit access to user data and messaging abilities. - Mini Apps provide a more robust experience for users while still protecting their data and privacy. Bots continue to be useful for simpler use cases like news updates, reminders and customer support. ### What languages and frameworks can I use to build a Mini App? You can build Telegram Mini Apps using: - HTML, CSS and JavaScript - Mini Apps are web apps that run within the Telegram app. - React, Vue.js or Angular - Popular JavaScript frameworks can be used to build the frontend. - Solidity - To write smart contracts on BSC for decentralized functionality. - Web3.js - To interact with BSC from your Mini App's frontend. ## Summary Telegram mini apps and mini games provide developers with exciting new ways to engage users. By following the step-by-step guide outlined here, you can leverage Telegram's massive user base to share your own interactive web apps and games. Consider the possibilities - multiplayer experiences, chatbots, productivity tools and more are now just a few lines of code away. As Telegram continues expanding its platform, developers have an opportunity to be on the cutting edge and reach an audience of millions. So don't wait, get started building your own mini app today! With the right idea and a bit of effort, you could create the next viral sensation on Telegram. --- ## Telegram Wallets > Source: https://docs.bnbchain.org/showcase/telegram/wallets/ ## **BNB Chain on Telegram: Your Gateway to Web3 Convenience** Telegram isn't just for chatting anymore. It's evolving into a powerful hub for Web3 interactions, and BNB Chain is leading the way. If you've been curious about managing your BNB, interacting with dApps, or exploring the decentralized world all within your favorite messaging app, you're in the right place. Let's dive into the exciting possibilities! ### **Telegram Wallets: Your BNB Chain Companion** Forget switching between apps. With Telegram bot wallets, you can seamlessly manage your BNB and interact with the BNB Chain ecosystem directly within your chats. | Name | Telegram Link | SDK Doc | | ----------------- | -------------------------- | ------------------------------------------------------------ | | CodexField Wallet | https://t.me/codexfieldbot | https://www.npmjs.com/package/codexfield-wallet-connector?activeTab=readme | | UXUY Wallet | https://t.me/UXUYbot | https://docs.uxuy.com/uxuy-connect/quickstart/ | ### **Telegram Authentication: A Developer's Dream** If you're a developer building on BNB Chain, streamlining user onboarding is key. [Privy's SDK](https://docs.privy.io/guide/dashboard/telegram) and [Particle wallet](https://developers.particle.network/guides/wallet-as-a-service/waas/auth/tg-quickstart) let you integrate secure Telegram logins into your app, making it frictionless for users to connect their Telegram identity with your platform. ### **Telegram MiniApp EVM Wallet Connection: A Developer's SDK** In your telegram mini app, you can also use the wallet connection SDK to allow your users to connect with their EVM wallets | Name | SDK Doc | | -------------------------- | ------------------------------------------------------------ | | OKX Wallet Connection | https://www.okx.com/web3/build/docs/sdks/okx-wallet-integration-introduction | | Bitget Omni Wallet Connect | https://web3.bitget.com/en/docs/dapp/telegram-webapps-wc.html | ### **Embrace the Future of Web3 on Telegram** The convergence of BNB Chain and Telegram opens up a world of possibilities. Whether you're a user looking for convenience or a developer building the next big dApp, these Telegram integrations offer a powerful way to engage with the decentralized world. **Remember:** Always do your own research and stay informed about the latest developments in the Web3 space! --- ## In-app Wallet and Account Abstraction > Source: https://docs.bnbchain.org/showcase/wallet/in-app-wallet/ references: https://thirdweb.com/account-abstraction ## Service plan Developers can choose between two service plans tailored to their needs: 1. **Free Plan:** Offers basic functionalities and limited access to Thirdweb services. 2. **Pro Plan:** Provides advanced features, priority support, and expanded usage limits. ## SDK Key Creation To utilize Thirdweb services, developers need to create an SDK key. This key allows integration of the Thirdweb SDK into their applications, enabling various blockchain functionalities. **** ## Services of Thirdweb **1. Storage Service** - **IPFS Support:** The current storage service supports the InterPlanetary File System (IPFS), allowing decentralized file storage and sharing. - **Future Integration:** There is potential to expand storage options to include Greenfield. This is subject to discussions with Thirdweb. **2. In-App Wallet (Wallet as a Service)** - **Seamless Integration:** Thirdweb provides an in-app wallet solution, simplifying the process of integrating cryptocurrency wallets into applications. - **User-Friendly:** This service enhances user experience by offering a seamless and secure method for managing digital assets within the app. **** **3. Account Abstraction** - **Paymaster Configuration:** Thirdweb includes a configuration setup for account abstraction, allowing for advanced transaction management and cost optimization. - **Customizable:** Developers can tailor the paymaster settings to suit their application's needs. **** **4. Third-Party Bundler and Paymaster Integration** - **Biconomy and Stackup Support:** Thirdweb supports integration with third-party bundler and paymaster services such as Biconomy and Stackup, offering enhanced functionality and flexibility. ## Supported Chains | **Chain** | **mainnet** | **testnet** | | --------- | ----------- | ----------- | | **BSC** | **Y** | **Y** | | **opBNB** | **Y** | **N** | ## Typical example in React app https://portal.thirdweb.com/connect/account-abstraction/guides/react --- ## Introduction > Source: https://docs.bnbchain.org/showcase/tokenization/introduction/ --- title: BNB Chain Tokenization Tutorial description: BNB Greenfield is a decentralized storage and blockchain storage solution that simplifies data management and access while connecting data ownership with the DeFi context of BNB Chain. keywords: [Tokenization, create token, nft, loyalty program, real world asset, RWA, BNB Chain] sidebar_label: Tokenization Tutorial --- # BNB Chain Tokenization Tutorial Overview Welcome to the BNB Chain Tokenization Tutorial. Tokenization is a process by which you create a digital token that can be traded on a blockchain. Tokenization has opened up a new way for businesses to create new revenue streams and help small and medium-sized businesses (SMEs) to access funding and grow their businesses. BNB Chain's multi-chain framework, including BSC, opBNB, and Greenfield, offers scalability, low costs, and secure data storage, making it ideal for SMEs to start their tokenization journey. ## Account Preparation There are different sceneraios of tokenization, but in general, you need to prepare a wallet account and buy some crypto before you start create token. The [Account Preparation Tutorial](./account-preparation.md) will help you get prepared before starting your tokenization journey. ## Company Tokenization Business Owners can create token to help get their business grow and reward their customers back. The [Company Tokenization Tutorial](./company-tokenization.md) will help you start with the simplest tokenization in a few minutes with no coding. ## Real World Asset(RWAs) Real World Assets(RWAs) in crypto involve tokenizing physical assets like real estate, receivables, and loans on blockchain. Tokenizing real-world assets (RWAs) involves converting ownership rights of physical assets into digital tokens on a blockchain. It provides liquidity for your tangible assets and creates better cash flow for you. The [Real World Assets(RWAs) Tokenization Tutorial](./rwa-tokenization.md) will help you tokenize your real world assets at ease. ## NFT Loyalty Programs NFT Loyalty Programs based on NFTs can replace traditional paper-based systems and physical membership cards by enhancing user experience and user loyalty. The [NFT Loyalty Programs Tokenization Tutorial](./nft-loyalty-programs.md) will empower your businesses with NFTs. --- ## Account Preparation > Source: https://docs.bnbchain.org/showcase/tokenization/account-preparation/ Welcome to the BNB Chain Tokenization Tutorial. Tokenization is a process by which you create a digital token that can be traded on a blockchain. Tokenization has opened up a new way for businesses to create new revenue streams and help small and medium-sized businesses (SMEs) to access funding and grow their businesses. BNB Chain's multi-chain framework, including BSC, opBNB, and Greenfield, offers scalability, low costs, and secure data storage, making it ideal for SMEs to start their tokenization journey. There are different sceneraios of tokenization, but in general, you need to prepare a wallet account and buy some crypto before you start create token. In this toturial we will focus on the account preparation steps, help you set up your wallet and buy crypto to pay fees. ## 1 Preparation ### 1.1 Set Up Wallet A Web3 wallet is essential to start your tokenization. You need to confirm the operations as well as pay service fees using the web3 wallet. Also, a web3 wallet account is your identity during the whole process. In this guide, we suggest you use Trust Wallet or Metamask to create your first Web3 wallet account: - Trust Wallet () - MetaMask ( ) #### 1.1.1 Trust Wallet ##### Step 1: Install the Wallet Extension We suggest you use the Chrome extension to create your wallet, since most of the tokenization tools provide only a desktop version, they cannot be used very well on your mobile phone. Follow these steps to get started: 1) **Download and install Chrome browser** Here is the download link: - Google Chorme windows 64: - Google Chorme windows 32: - Google Chorme mac: 2) **Visit the Trust Wallet Official Website** * Go to the [Trust Wallet](https://trustwallet.com/) website. * Click on the “Download” button and choose the extension compatible with Chrome. 3) **Add the Extension**: * Click the “Add to Chrome” button and confirm the installation. ##### Step 2: Create a New Wallet Account Once the extension is installed, you need to create a new Trust Wallet account: 1) **Open the Extension**: Click on the Trust Wallet icon in your browser’s toolbar to open the extension. 2) **Start Setup**: Click the ‘Get Started’ button to begin, and click on “Create a New Wallet” to set up your wallet. 3) **Set Password**: Pick a password and confirm it to create your account. ##### Step 3: Backup your Wallet Account Backing up your wallet is vital to protect your assets. Click the action bar on the trust wallet interface. 1)**Show Seed Phrase**: Trust Wallet will generate a seed phrase (12 or 24 words) for you. This phrase is crucial for wallet recovery, so click the “Show” button, write it down, and store it securely offline. Do not share this phrase with anyone. 2)**Confirm Seed Phrase**: To ensure you have recorded the seed phrase correctly, Trust Wallet will ask you to confirm it by selecting the words in the correct order. Once your wallet is set up, you can start using token-issuing tools to create tokens. #### 1.1.2 MetaMask ##### Step 1: Install the Wallet Extension 1)**Download and install Chrome browser** Here is the download link: - Google Chorme windows 64: - Google Chorme windows 32: - Google Chorme mac: 2)**Add Metamask extension**: Visit the Chrome Web store Click the “Add to Chrome” button and confirm the installation. ##### Step 2: Create a New Wallet Account Once the extension is installed, you need to create a new MetaMask account: 1) **Open the Extension**: Click on the MetaMask Wallet icon in your browser’s toolbar to open the extension. 2) **Start Setup**: Agree on the terms of use, and click on “Create a New Wallet” to set up your wallet. 3) **Set Password**: Pick a password and confirm it to create your account. ##### Step 3: Backup your Wallet Account Backing up your wallet is vital to protect your assets. Click on “Secure my wallet” to get your recovery phrase. 1) **Show Seed Phrase**: MetaMask Wallet will generate a seed phrase (12 or 24 words) for you. This phrase is crucial for wallet recovery, so click the “Reveal Secret Recovery Phase” button, write it down, and store it securely offline. Do not share this phrase with anyone. 2) **Confirm Seed Phrase**: To ensure you have recorded the seed phrase correctly, MetaMask Wallet will ask you to confirm it by selecting the words in the correct order. Once your wallet is set up, you can start buy cryptos. ### 1.2 Buy Crypto Tokenization requires service fees, which need to be paid by crypto.You can discover numerous service providers within your wallet. We will instruct you on how to commence purchasing crypto from your Wallet. In this guide, we suggest you use Trust Wallet or Metamask to start buying crypto: - Trust Wallet () - MetaMask ( ) #### 1.2.1 Trust Wallet ##### Step 1: Login to your wallet The Trust Wallet extension allows you to buy crypto using fiat. Follow these steps to get started: 1) **Open Trust Wallet Extension** Click the Trust Wallet Icon in your chrome, and usually, it will open directly. 2) **Enter Password** If you did not login for a while, Trust Wallet might ask you to enter your password to login ##### Step 2: Choose network and crypto Trust Wallet provides different vendors for you to choose from, you can use them to buy crypto with fiat. 1) **Click Buy&Sell button** 2) **Choose network and crypto** Choose BNB on BNB Smart Chain ##### Step 3: Choose vender Select your vendor. Here we can see Trust Wallet provides several different vendors, we suggest using MoonPay to continue ##### Step 4: Enter Credit Card Information 1) **Select Payment Method**: - Choose “Credit Card” as your payment method. 2) **Enter Credit Card Details**: - Fill in your credit card details, including the credit card number, expiration date, CVV code, and billing address. Ensure all information is accurate to avoid payment issues. 3) **Complete Identity Verification**: - Depending on MoonPay’s requirements, you may need to complete identity verification, such as uploading identification documents or confirming your identity via SMS verification. ##### Step 5: Confirm and Complete Purchase 1) **Review Transaction Details**: - Carefully review the transaction details, including the purchase amount, wallet address, and payment method. 2) **Confirm Transaction**: - Click the “Confirm” or “Complete Purchase” button to finalize the transaction. 3) **Wait for Transaction Processing**: - After completing the transaction, you will receive a confirmation email or notification. The purchased BNB will be sent to the wallet address you provided. Processing times may vary depending on network congestion. 4) **View your BNB in your wallet** You can now see your transaction is complete. The BNB should be received by your Trust Wallet. #### 1.2.2 MetaMask ##### Step 1: Login to your wallet and Add BNB network The MetaMask Wallet did not set BNB Chain Network as default, so to start, you need to add BNB network. 1) **Login to your Metamask Wallet** Click the MetaMask Icon in your chrome, and usually, it will open directly. If you did not login for a while, MetaMask might ask you to enter your password to login Once Login, you need to add BNB Chain Network to your wallet 2) **Click Add Network** Usually you will see you are under Etherum network, click on the Etherum icon and it will guide you to a select network page, if you did not see BNB Chain underneath, click Add network button. 3) **Add BNB Chain network** 4) **Approve to add BNB Chain to your wallet** 5) **Switch to BNB chain network** ##### Step 2: Choose network and crypto Metamask provides different vendors for you to choose from, you can use them to buy crypto with fiat. 1) **Click buy button** 2) **Choose network and crypto**, choose BNB chain first, and then select BNB token ##### Step 3: Choose country and fiat ##### Step 4: Choose vender 1) Select your payment method - We suggest using “Debit or Credit” which has a relatively lower service fee. 2) Select your vendor. - Here we can see MetaMask provides several different vendors, we suggest using MoonPay to continue ##### Step 5: Enter Credit Card Information 1) **Select Payment Method**: Choose “Credit Card” as your payment method. 2) **Enter Credit Card Details**: Fill in your credit card details, including the credit card number, expiration date, CVV code, and billing address. Ensure all information is accurate to avoid payment issues. 3) **Complete Identity Verification**: Depending on MoonPay’s requirements, you may need to complete identity verification, such as uploading identification documents or confirming your identity via SMS verification. ##### Step 6: Confirm and Complete Purchase 1) **Review Transaction Details**: Carefully review the transaction details, including the purchase amount, wallet address, and payment method. 2) **Confirm Transaction**: Click the “Confirm” or “Complete Purchase” button to finalize the transaction. 3) **Wait for Transaction Processing**: After completing the transaction, you will receive a confirmation email or notification. The purchased BNB will be sent to the wallet address you provided. Processing times may vary depending on network congestion. --- ## Company Tokenization Tutorial > Source: https://docs.bnbchain.org/showcase/tokenization/company-tokenization/ Welcome to the BNB Chain Tokenization Tutorial. Tokenization is a process by which you create a digital token that can be traded on a blockchain. Tokenization has opened up a new way for businesses to create new revenue streams and help small and medium-sized businesses (SMEs) to access funding and grow their businesses. BNB Chain's multi-chain framework, including BSC, opBNB, and Greenfield, offers scalability, low costs, and secure data storage, making it ideal for SMEs to start their tokenization journey. It generally takes 4 steps to tokenize your company: 1) Preparation 1. Setup Wallet 2. Buy Crypto 2) Token Launch 1. Create Token 2. Presale 3) Withdrawal 4) Reward Distribution ## 1 Preparation Go to [Account Preparation Tutorial](./account-preparation.md) to get prepared before starting your tokenization journey. ## 2 Token Launch After all the preparation work, you are now ready to create your token. ### 2.1 Create Token To create a token, you only need to configure a few basic parameters. We suggest these two service providers since they provide one-stop service with rich features: - PinkSale ( ) - TokenFi ( ) #### 2.1.1 PinkSale PinkSale allows you to create a token and manage your token all in one platform, which provides convenience to token issuers. ##### Step 1: Login with your wallet 1) **Connect your Wallet** Enter , choose “MetaMask” or “Trust Wallet”, use the wallet you just created in chapter 1.1 setup wallet ##### Step 2: Create Token 1) **Select Create Token** Click Create token on the left navigation bar, you should be able to see the landing page as follow 2) **Enter Token information** Here is how to set each parameter: **Chain**: It means the blockchain infrastructure where your token will be created and running all the time. Here we suggest you choose **BNB Chain.** **Type**: It means token design mechanism, which contains several parameters, are typically employed to establish the mechanism by which the investors of the token will obtain the financial reward.Here we suggest you choose **Standard.** **Name:** This is ideally a human readable name such as "ACE Coffee Coin". **Symbol**: The token symbol is comparable to its ticker symbol, typically four or more characters are used such as "ACE". **Total supply**: The amount of tokens that get minted at token creation. Usually you will not increase the supply after token creation, so it will be the total supply of your token at all times. The supply is usually determined by the desired token denomination (i.e. the nominal value per token). For example, for a bond offering with a nominal amount of USD 10 million and a denomination of USD 100,000 the supply would have to be 100 tokens. **Decimals**: Values can be 0-18, when 0 is used, the token is not divisible. We suggest you set it as “**18**”. 3) **Confirm Transaction** Click the create token button then your wallet will be invoked. Confirm with your wallet, please notice you need to pay service fee using BNB, you should follow chapter 1.2 buy crypto to charge your wallet account in advance. ##### Step 3: Check Your Token You can see your token address and other basic information as follow #### 2.1.2 TokenFi ##### Step 1: Login with your wallet Enter , choose “MetaMask” or “Trust Wallet” ##### Step 2: Create Token **1. Select Token Type**: Click the ERC-20 token, you should be able to see the landing page as follow: **2. Enter Token information** Enter token information recording to your demand Here is how to set each parameter: **Type**: It means token standard, we suggest you choose **ERC-20**. ERC-20 is a token standard which is most commonly used in company tokenization scenario, you do not need to understand the standard to continue your process, nevertheless, if you want to know more about the token standard, you can visit for more information. **Logo**: The image icon of your token, it will show up on all your token promotion pages, we suggest you use images that are highly related to your company’s business so that investors can get more information from your logo image. You should prepare the image beforehand, and make sure that you have the copyright of your image. **Name:** This is ideally a human readable name such as "ACE Coffee Coin". **Symbol**: The token symbol is comparable to its ticker symbol, typically four or more characters are used such as "ACE". **Initial supply**: The amount of tokens that get minted at token creation. It should be no bigger than Max Supply. **Max Supply**: The sum up amount of tokens that you will mint all time. We suggest you do not increase the supply after token creation, so the max supply will be set as the same as the initial supply. The supply is usually determined by the desired token denomination (i.e. the nominal value per token). For example, for a bond offering with a nominal amount of USD 10 million and a denomination of USD 100,000 the supply would have to be 100 tokens. **Decimals**: Values can be 0-18, when 0 is used, the token is not divisible.We suggest you set it as **18**. **Treasury Wallet:** where the token will be sent to after the tokens are created. It is default set as the wallet address you used to login. Which means all the created tokens will be sent to your current wallet address. **Features and tokenomics:** This part is optional advanced features**,** which contains several parameters, are typically employed to establish the mechanism by which the investors of the token will obtain the financial reward.Here we suggest you **skip** this part. If you want to know more about this part, you can visit for more guidance. **3. Confirm Transaction** Click the create token button then your wallet will be invoked. Confirm with your wallet, please notice you need to pay service fee using BNB, you should follow chapter 1.2 buy crypto to charge your wallet account in advance. ##### Step 3: Check Your Token You can see your token address and other basic information as follow ### 2.2 Presale Now that your token has been created, you can invite your early investors to join your presale activities. Investors can buy your token through the presale link you created, you can quickly raise early-stage funding through pre-sales to develop your business. It’s suggested that you use the same service providers to manage your presale. Here we suggest two service providers: - PinkSale ( ) - TokenFi ( ) #### 2.2.1 PinkSale ##### Step 1: Login with your wallet Visit and choose “MetaMask” or “Trust Wallet” to login. ##### Step 2: Create Presale 1) After login, choose launchpad>create presale in left navigation bar. Here are the parameters you need to input: **Address**: Input your token address,if you created your token using PinkSale, it should be filled in automatically. Or you can find it at your token creation page. **Currency**:The token you will receive for your presale. Here we suggest you choose **BNB**. **Fee Option**: Pinksale will charge your some fees for presale, Here we suggest you to choose **5% BNB**, which means PinkSale will charge 5% of all your BNB sold as Presale service fees **Listing Option**:Usually, you need to create a secondary marketplace for your tokens, so that your investors who have bought your tokens during the presale phase can sell the token to others in the secondary market if they do not want to hold the tokens anymore. You will need to add liquidity to the secondary market so that your investors can trade. By adding liquidity, part of your token pair with BNB will be automatically locked so as to be used to add liquidity in the future. Auto listing means liquidity will be added automatically after Finalize, manual listing means you have to add liquidity manually. By selecting auto listing, your token will be listed at PinkSwap automatically.We suggest you choose **Manual listing** to keep it simple. If you want to choose auto listing, you can visit for more guidance. **Pool Type:** It means the type of this round of token sale. Here we suggest you to choose **presale** **Affiliate**: It indicates that you want to promote your project together with some KOLs Pinksale suggested. We suggest you **disable the Affiliate** program option.If you want to know more about affiliate, you can visit for more guidance. 2) Review again and click on “Next”. ##### Step 3: Add Launchpad Info After verifying your token, you need to input the Presale information that you want to raise. Here are some following important parameters: **Presale Rate**: This is similar to token price, it means how many of your tokens an investor can receive if he gives 1 BNB. You must use positive numbers. **Whitelist:** Choose "Enable" if you have a whitelist of presale contributors. You can enable/disable the whitelist anytime.We suggest you **disable** the whitelist to keep it simple. If you want to know more about affiliate, you can visit for more guidance. **Soft cap:** Soft cap means the least amount of tokens you need to sell for this presale to launch successfully. SoftCap must be greater than or equal to 25% of the hard cap. **Hard cap**: It means the amount of tokens for your presale. Once you sell the amount of tokens, your presale will automatically stop **Refund types:** you can choose refund or burn from the dropdown list. Here we suggest you choose **Refund** **Minimum buy BNB:** how many bnb one investor need to pay at least in order to participate **Maximum buy BNB:**how many bnb can one investor buy at most **Start Time**: the start time of your presale, you can select now or later. **End Time**: the end time of your presale. Please make sure the start time is before the end time. **Vesting Contributor**: Vesting For Contributors is a feature on PinkSale that helps projects to ensure long term price stability by locking away the tokens of presale investors for a period of time. It prevents presale investors from selling all their tokens at once at listing time, which causes too much sell pressure and crashes the price. To make it simple, we suggest you **disable** it. ##### Step 4: Add Additional Info Now that you have almost setup all the information you need for your presale, we suggest you add some additional info about your project so that your investors can know more about your company, your business, and be more willing to participate in your presale. There are some notes for this step: - Logo URL and website are required fields, cannot be blank. You can’t complete this step without those. - Logo URL must end with a supported image extension: png, jpg, jpeg or gif. For example:[ ](https://www.pinkswap.finance/pinkswap.png) ##### Step 5: Confirm with your wallet This is the final step. You can review all the information one last time before submitting, after you have made sure that everything is perfect, or you can go back to the previous step to make any changes. Click “Approve Spending Token” and "Confirm" on Metamask. After that, click "Submit". After clicking on “Submit”, MetaMask/TrustWallet will now ask you to confirm the deal. It will also show you the fee that you are required to pay for the presale service. If you agree, then click on the “Confirm” button to finish the process. ##### Step 6: Check Your Presale Status You can view your presale status as follow: ##### Step 7: Invite your community to buy Guide your community members to [https://www.pinksale.finance/launchpads](https://www.pinksale.finance/#/launchpads) Your community members can find your project through searching by token name, they can find the detail page of your presale as follows. Enter the amount of token they want to buy, and confirm with their wallets. Now that you need to wait for enough community members to buy your token until your soft cap has been reached. Then you can finalized the presale pool. If the hard cap has been reached, your presale will be finalized automatically. After you have finalized the presale pool, your community member can claim the token. After claiming a token, your community member should be able to see the token they bought in their wallet. #### 2.2.2 TokenFi TokenFi also provides a launchpad for you to create a presale for your tokens. ##### Step 1: Login to TokenFi Launchpad with your wallet Open , Click Connect Wallet to Login Sign the message ##### Step 2: Input token information 1) Select BNB network **2)** Choose “I will provide my own token” and click 'Next' to proceed with your launchpad setup. 3) Input your token address, you can find it at previous steps. ##### Step 3: Input Presale Information 1) Define your project’s funding targets by entering the details below: **Token Price**: Specify the price per token, e.g. 1 BNB per token. **Soft Cap**: Enter the minimum token amount you aim to raise. This is the lowest funding goal required to consider the fundraising a success. **Hard Cap**: Set the maximum token amount you wish to raise. This should not exceed the total available supply minus any tokens reserved for the treasury. **Available Supply**: Note that the hard cap cannot surpass the available supply of 2500 tokens. Click the 'Next' button once all fields are filled to continue setting up your project. 2) Configure your fundraising parameters by following these steps: **Maximum Tokens per Wallet**: Input the maximum number of tokens that can be purchased by a single wallet. Ensure this aligns with your fundraising goals and token distribution strategy. **Fundraise Start Date**: Choose the date and time when your fundraising will begin. This is the moment from which participants can start purchasing tokens. **Fundraise End Date**: Set the date and time when your fundraising will conclude. After this time, no more tokens can be purchased. Then click “Next”. 3) Set up your token release schedule efficiently: **TGE (Token Generation Event)**: Set the percentage of tokens allocated and the specific date and time for release during the TGE. This initial allocation is crucial for the market introduction of your token. **Allocation Percentage**: Input the percentage of total tokens you want to allocate during the TGE. **TGE Date**: Select the date and time when these tokens will become available. **Allocation Tracker**: Observe the progress bar to ensure your allocations do not exceed the total supply. **Add New Release Date**: Click this button to schedule additional token releases, specifying new dates and allocation percentages. Click the 'Next' button once all fields are filled to continue setting up your project. ##### Step 4: Review and Confirm with your wallet Review each section carefully before proceeding: **General Information**: - **Blockchain**: The blockchain network selected for the project. **Token Information**: - **Name**: The official name of your token. - **Symbol**: The designated ticker symbol. - **Decimals**: The decimal precision for transactions. - **Max Supply**: Total number of tokens created. - **Reserved for Treasury**: Tokens allocated for future project needs. **Goals**: - **Price Currency**: The currency used for pricing tokens. - **Token Price**: Price per token. - **Soft Cap**: Minimum funds targeted. - **Hard Cap**: Maximum funds targeted. **Fundraising Setup**: - **Max Vesting per Wallet**: The maximum token amount a single wallet can hold. - **Fundraise Period**: The duration of the fundraising campaign. **Release Schedule**: Details of token distribution, including percentages and specific dates for each type of vesting. **Payment Setup**: **Accepted Tokens**: List of cryptocurrencies accepted for payment. **Additional Settings**: **Blocked Countries**: Countries restricted from participating in the project. Once you have confirmed that all details are correct and finalized, press 'Confirm' to launch your project. This is the final step. You can review all the information one last time before submitting, after you have made sure that everything is perfect, or you can go back to the previous step to make any changes. Click “Approve” and "Confirm". After that, click "Submit". ##### Step 5: Check Your Presale Status On the 'My Projects' screen, find your project and click “View Details” to update and refine your project details. On the 'Edit Project' screen, follow these steps to update and refine your project details: Click “Edit Details”: Begin by accessing the editing mode for your project. **Add Launchpad Summary**: Summarize your project to provide a quick overview for potential investors. **Link Social Media**: Connect your social media accounts to broaden your reach and engage more effectively with your audience. **Input Website and Whitepaper Links**: Provide links to your project's website and Whitepaper, offering deeper insight into your project's objectives and developments. **Provide a Detailed Description**: Expand on the details of your project, highlighting key information and unique selling points to attract interest. **Save Your Changes**: After updating the information, click 'Save' to apply the changes. Your project is now optimized and ready to attract funding on the TokenFi Launchpad. ##### Step 6: Invite your community to buy Guide your community members to Your community members can find your project through searching by token name, they can find the detail page of your presale as follows. Your community member can then click “Invest” to go to the Invest page,enter the amount they want to invest on the Invest page and review the transaction details. Now that you need to wait for enough community members to buy your token until your soft cap has been reached. Then you can finalized the presale pool. If the hard cap has been reached, your presale will be finalized automatically. After you have finalized the presale pool, your community member can claim the token. After claiming a token, your community member should be able to see the token they bought in their wallet. ## 3 Withdrawal When enough investors purchase your token and your presale succeeded, you will receive an amount of BNB in return. You can exchange your BNB for Fiat, withdraw fiat to your bank account to expand your actual operation or production. Service providers you may choose: - TrustWallet () - MetaMask ( ) ### 3.1 TrustWallet ##### Step 1: Login The Trust Wallet extension allows you to sell BNB to fiat. Follow these steps to get started: 1) **Open Trust Wallet Extension** Click the Trust Wallet Icon in your chrome, and usually, it will open directly. 2) **Enter Password** If you did not login for a while, Trust Wallet might ask you to enter your password to login ##### Step 2: Choose Vendor Trust Wallet provides different vendors for you to choose from, you can use them to sell crypto to fiat. 1) **Click Buy & Sell button** 2) **Choose network and crypto** 3) **Select your vendor** Here we can see Trust Wallet provides several different vendors.we suggest you use moonpay to continue ##### Step 3: Login to vender and add your bank account 1) **Enter your email address** 2) **Add your bank details** 3) **Review your order** * MoonPay shows you the estimated price for your crypto and a summary of the fees. * Accept [Terms of Use](https://www.moonpay.com/legal/terms_of_use). * Click “Sell Now” to confirm your order. 4) **Ready to Pay** * Next, MoonPay will generate a wallet for you to send your cryptocurrency to. MoonPay will also email you instructions on how to pay for your order. * To see the wallet for your order, tap View deposit details. * You can directly copy the deposit wallet address by selecting the "Copy" icon. ##### **Step 4: Send Your Crypto to Vendor** 1) Open Trust Wallet Extension 2) Click “Send” 3) Choose the cryptocurrency (BNB) 4) Enter the Mercuryo’s Address and the amount you want to sell 5) Complete the transaction in your wallet. ##### Step 5: Check your bank account Mercuryo takes your cryptocurrency from there When you send it to the given address. You’ll receive a bank transfer shortly after your cryptocurrency is received. Read the [Processing Time](https://support.moonpay.com/customers/docs/when-will-i-receive-my-cryptocurrency) article to learn how long bank transfers take in different regions. Once your transaction is complete, Mercuryo will send you a confirmation email. Click on See complete deposit instructions to access our tracker. ### 3.2 MetaMask ##### Step 1: Login The MetaMask Wallet extension allows you to sell crypto to fiat. Follow these steps to get started: 1) **Open Metamask Extension** Click the MetaMask Icon in your chrome, and usually, it will open directly. 2) **Enter Password** If you did not login for a while, MetaMask might ask you to enter your password to login ##### Step 2: Choose network and crypto Metamask provides different vendors for you to choose from, you can use them to sell crypto to fiat. 1) **Click buy & sell button,** make sure you are under BNB chain network 2) **Choose network and crypto**, choose BNB chain first, and then select BNB token ##### Step 3: Choose your country and fiat ##### Step 4: Choose Vender Select your vendor. Here we can see MetaMask provides several different vendors, we suggest using MoonPay to continue ##### Step 5: Log in to vender and add your bank account 1) **Enter your email address** 2) **Add your bank details** 3) **Review your order** * MoonPay shows you the estimated price for your crypto and a summary of the fees. * Accept [Terms of Use](https://www.moonpay.com/legal/terms_of_use). * Click “Sell Now” to confirm your order. 4) **Ready to Pay** * Next, MoonPay will generate a wallet for you to send your cryptocurrency to. MoonPay will also email you instructions on how to pay for your order. * To see the wallet for your order, tap View deposit details. * You can directly copy the deposit wallet address by selecting the "Copy" icon. ##### Step 6:Send Your Crypto to Vendor 1) Open Trust Wallet Extension 2) Click “Send” 3) Choose the cryptocurrency (BNB) 4) Enter the MoonPay’s Address and the amount you want to sell 5)Complete the transaction in your wallet. ##### Step 7: check your bank account 1) MoonPay takes your cryptocurrency from there When you send it to the given address. You’ll receive a bank transfer shortly after your cryptocurrency is received. Read the [Processing Time](https://support.moonpay.com/customers/docs/when-will-i-receive-my-cryptocurrency) article to learn how long bank transfers take in different regions. 2) Once your transaction is complete, MoonPay will send you a confirmation email. Click on See complete deposit instructions to access our tracker. ## 4 Reward Distribution When your business earns profits, it is crucial to reward your early investors. This creates a sustainable tokenization cycle, enabling you to utilize tokenization again in the future for the growth of your business. You can give your investors dividends when your business gets profit through Airdrop tokens. Service providers you may choose: - Pink Sale ( ) #### 4.1 PinkSale PinkSale allows you to create airdrop, so that your investors can claim airdrop to get their reward ##### Step 1: Login with your wallet Choose “MetaMask” or “Trust Wallet” ##### Step 2: Create New Airdrop 1) Go to[ ](https://www.pinksale.finance/#/airdrop/create)[https://www.pinksale.finance/airdrop/create](https://www.pinksale.finance/#/airdrop/create) 2) Paste your token address into the “Token address” section. After that, your token name, symbol and decimals will be shown. Make sure everything is correct and then click on “Next”. 3) After selecting your token, you will need to input the Airdrop information. Here are some following important parameters: **Airdrop Title**:Create a meaningful name for your reward distribution. **Logo URL**:Logo URL must end with a supported image extension: png, jpg, jpeg or gif. You can upload your image using[ ](https://upload.pinksale.finance/) to get the link to your logo. **Website:** Paste your company’s website url here. These three parameters cannot be blank. While others like social links and descriptions can be empty. Finish all the information, and then click “Create New Airdrop”. After clicking on the “Create New Airdrop” button, MetaMask/TrustWallet will now ask you to confirm the transaction. It will also show you the fee that you are required to pay for that transaction. If you agree, then click on the “Confirm” button to finish the process. 4) You will be redirected to this page: ##### Step 3: Set Allocation Prepare a list of airdrop addresses then click on “Set Allocations” After clicking on “Set Allocations”, you will see a pop-up box. Here, you can add addresses and amounts to your “Users allocation” list. Addresses are separated by a new line. The amount of each user is separated by comma (,) You should ask your community members to give you their wallet address beforehand. The below list can be used as an example: Click on “Add Allocations” when you are done inputting the addresses. The wallet will now ask you to confirm the transaction. It will also show you the fee that you are required to pay for that transaction. If you agree, then click on the “Confirm” button to finish the process. After successfully adding airdrop allocations, those allocations will be shown on the airdrop page. ##### Step 4. Set Vesting After clicking on “Set Vesting”, you will see a pop-up box. Below are some important parameters: **TGE release percent (%)**: The percentage of the first batch of airdrop tokens to be released. Please note that this is expressed in percentage, not number of tokens. **Cycle release percent (%)**: How many % of airdrop tokens will be released each cycle following the first TGE release percent batch. Please note this is expressed in percentage, not in number of tokens. **Cycle (days)**: How long, in days, between each batch of vested tokens is released. Click on “Set Vesting” when you are done inputting the numbers, then wallet will now ask you to confirm the transaction. It will also show you the fee that you are required to pay for that transaction. If you agree, then click on the “Confirm” button to finish the process. ##### Step 5: Start Airdrop 1) Before starting the airdrop, you must[ ](https://docs.pinksale.finance/exclude-fees-dividends-max-tx-on-bscscan)[exclude fees, dividends, max tx](https://docs.pinksale.finance/exclude-fees-dividends-max-tx-on-bscscan) for airdrop address. You can find your airdrop address on your airdrop page. Before you finalize your presale, you need to access your contract address from BSCScan or you can click on the token address on your launchpad page. 2) Go to Contract -> Write contract -> Connect to Web3 to connect your wallet, you need to use owner address. 3) Ctrl + F, Search “exclude”, then input your presale address, then click on "Write", to exclude all fee/tax, max TX, rewards for presale address. 4) After clicking on the “Write” button, MetaMask will now ask you to confirm the transaction. It will also show you the fee that you are required to pay for that transaction. If you agree, then click on the “Confirm” button to finish the process. If you see exclude (bool), please input “true” 5) Sometimes contract doesn’t have “exclude” but "exempt" instead, Search “exempt”, then input your presale address, then click on "Write" to exclude all fee/tax, max TX, rewards for presale address. 6) After you have successfully exclude fees for airdrop address, you can go back to your airdrop page by this link[ ](https://www.pinksale.finance/#/airdrops/own) - Created By You - View Airdrop 7) Then click on “Start Airdrop” 8) You will see how many tokens will be used for airdrop here (total airdrop tokens + 1% fee). Now you can choose to start now: Or start with a specific time like this: 10) Click on "Approve", MetaMask will now ask you to confirm the transaction. It will also show you the fee that you are required to pay for that transaction. If you agree, then click on the “Confirm” button to finish the process. ##### Step 6: Guide your investors to claim airdrop You need to guide your community members to claim airdrop so that they can get their reward. 1) guide your community members to this link[ ](https://www.pinksale.finance/#/airdrops/my) - My Airdrops - View Airdrop. they can see airdrops which they joined here.Please remind them to login with the same wallet address they have shared to you previously. 2) Check claimable tokens then click on “Claim” 3) MetaMask/Trust Wallet will now ask you to confirm the transaction. It will also show you the fee that you are required to pay for that transaction. If you agree, then click on the “Confirm” button to finish the process. --- ## RWA Tokenization Tutorial > Source: https://docs.bnbchain.org/showcase/tokenization/rwa-tokenization/ Welcome to the BNB Chain Real World Asset Tokenization Tutorial. Real World Assets (RWA) in crypto involve tokenizing physical assets like real estate, receivables, and loans on blockchain.Tokenizing real-world assets (RWAs) involves converting ownership rights of physical assets into digital tokens on a blockchain. It provides liquidity for your tangible assets and creates better cash flow for you. BNB Chain's multi-chain framework, including BSC, opBNB, and Greenfield, offers scalability, low costs, and secure data storage, making it ideal for Enterprises to start their Real World Asset tokenization journey. It generally takes 4 steps to tokenize your real world asset: 1) Asset Preparation 1. Legal structuring 2. Asset custody 2) Account Preparation 1. Setup Wallet 2. Buy Crypto 3) Issue Token 4) Launch Token There are plenty of tools and service providers in the BNB Chain ecosystem that can help you with the tokenization journey, we carefully select some of the best in our tutorial to guide you through the Web3 way. You can create your token in a few minutes with no coding or any blockchain knowledge. ## 1 Asset Preparation ### 1.1 Legal Structuring The asset tokenization journey begins with identifying an asset with strong tokenization potential, such as real estate, fine arts, commodities, and precious metals. Ensure that the asset is eligible for tokenization and complies with relevant regulations. The value of the asset is then carefully assessed and documented, following standard financial practices. At this step, a legal framework is established to ensure that digital tokens represent valid claims to the underlying real world assets. This involves defining the specific rights associated with the tokens and choosing an appropriate tokenization structure. ‍ Two common tokenization structures for real world assets The two common tokenization structures include Tokenized Special Purpose Vehicle (“SPV”) and Direct Asset Tokenization: - **Tokenized SPV**: Tokenized SPV approach also known as indirect tokenization is a common approach where the asset is held by an entity, either a private limited company or a trust. This entity is then tokenized, and tokens are issued through a pooling of funds from multiple investors, giving investors indirect interests in the underlying RWA. This is often a better approach as it fits within the securities regulations. - **Direct Asset Tokenization**: The asset itself is directly tokenized and the tokens represent a direct claim on the underlying asset This approach is typically less common due to regulatory challenges and issues such as non-fungibility, lack of regulatory clarity, and limited use cases. Each tokenization structure often comes with different licensing requirements. Suggested Service Provider: [InvestaX](https://www.investax.io/) ### 1.2 Asset Custody Before digitalization, the underlying asset (RWA) will be custodized to ensure the asset is immobilized and safe kept before its digital representation is created on the blockchain. Most times if it's a tangible movable RWA like whiskey barrels the RWA is securely stored and managed by qualified custodians, trustees, or licensed managers. On the other hand, the digital representation i.e. RWA tokens can be either held in i) Self Custodized or ii) 3rd Party licensed custodian. **Self-custody** Self-custody wallets are wallets used to store digital assets providing users full control over their private keys and, consequently, their assets. It is the practice of individuals taking full control and responsibility for storing and managing their own digital assets without relying on third-party intermediaries. With self-custody, users hold their own private keys, which are essential for accessing and transacting with their digital assets. Self-custody wallets, which can be software-based (like mobile or desktop applications) or hardware-based (physical devices), allow users to interact directly with blockchain networks, giving them complete ownership and control over their assets. While self-custody offers enhanced security and privacy, it also requires users to be vigilant about safeguarding their private keys and recovery phrases, as there is no central authority to recover lost or stolen assets. **Custodizing RWA Tokens with a Licensed 3rd Party Custodian** Licensed Custodians are regulated and authorized to provide custody services. These custodians are typically subject to stringent regulatory requirements and oversight, ensuring they adhere to high standards of security, operational integrity, and compliance. By leveraging the services of a licensed digital asset custodian, organizations can mitigate the risks associated with holding and managing digital assets, ensuring they are stored securely and in compliance with relevant regulations. Some of the security measures adopted are decentralized security protocols and multi-party computation (MPC) to eliminate single points of failure, thereby enhancing the protection against both external and internal threats. Additionally, custodians often implement multi-signature wallets, hardware security modules (HSMs), and key sharding to further safeguard private keys. These technologies are complemented by rigorous compliance with regulatory standards, such as Know Your Customer (KYC) and anti-money laundering (AML) rules, ensuring that custodians meet stringent reporting, auditing, and fraud detection requirements There are many different types of assets in the world and how the custodian is handled and regulated is widely different. The issuers should evaluate the custodian's services, such as asset management, trade processing, and asset servicing, to ensure they meet the needs of the RWA. Suggested Service Provider: [InvestaX](https://www.investax.io/) ## 2 Account Preparation Go to [Account Preparation Tutorial](./account-preparation.md) to get prepared before starting your tokenization journey. ## 3 Issue Token After you have successfully completed the asset preparation and account preparation process, you can finally start creating your RWA token now. Here we recommend these two service providers as they possess a simplistic WebUI and explicit documentation, being friendly for beginners to get acquainted with. Service providers you may choose: - Bitbond ( ) - Brickken ( ) ### 3.1 Brickken 1) Go to the Token Suite sign up page and sigh up using your email account. 2) Select the type of financial instrument that the digital asset will represent, Equity, Debt, Invoice Factoring or a Revenue Digitization. 3) Select a Network, here we suggest you choose Binance Smart Chain(BSC). Once you have selected the BNB Chain, please click continue. 4) Connect your wallet you have just created in Step 2: Account Preparation. 5) Complete your KYC steps 6) Enter your digital asset information. Here are the parameters you need to input: **Digital Asset Name**: enter the full name of your digital asset **Digital Asset Symbol:** enter the abbreviation of your digital asset **Import your Digital Asset Logotype**: Upload the logo of your digital asset **Address of the company’s wallet**: To make it simple, you can use the wallet address you just created if you are the business owner. Press the Green Icon to confirm the wallet that will manage the digital asset 7) Input your digital asset details * If applicable, establish a maximum supply for your digital asset. This will ensure that no additional assets can be created in the future, so as to bring trust to your investors. * Upload your digital asset legal documents * If you have collected the wallet address of existing shareholders, you can allocate the digital assets to existing shareholders by filling in their wallet address in this step. 8) Confirm the transaction with your wallet Use your wallet to confirm the transaction, you will need to pay gas fee and service fee in this step. After your confirm the transaction, you can see the contract address on BNB Chain. 9) Mange your token on dashboard You can login to Briccken dashboard to manage your token after the creation. ### 3.2 Bitbond 1) Visit and connect your wallet to login 2) Select BNB Chain network 3) Choose Defi Token, enter basic setting information Here is how to set each parameter: **Name:** This is ideally a human readable name such as "Real World Asset No. 001". **Symbol**: The token symbol is comparable to its ticker symbol, typically four or more characters are used such as "RWA1". **Initial supply**: The amount of tokens that get minted at token creation. Usually you will not increase the supply after token creation, so it will be the total supply of your token at all times. The supply is usually determined by the desired token denomination (i.e. the nominal value per token). For example, for a bond offering with a nominal amount of USD 10 million and a denomination of USD 100,000 the supply would have to be 100 tokens. **Decimals**: Values can be 0-18, when 0 is used, the token is not divisible. We suggest you set it as “**18**”. 4) Set advanced token setting To make it simply, here we suggest you use the default setting and do not make any changes. 5) Confirm the transaction with your wallet You might need the pay the gas fee and service fee for the creation. ## 4 Launch Token In order to distribute your token toward your investors, you need to launch your token towards open or private market. Here we will guide you how to launch your token. Service providers you may choose: - Bitbond ( ) - Brickken ( ) ### 4.1 Brickken 1) Login to Brickken dashboard and click my digital asset offering on the left navigation bar 2) Setup whitelist Approve your preferred investor for your digital asset and whitelist your potential investors on BNB chain by 3) Setup token offering informations Here are the parameters you need to input: **Token Offering Name**: enter token offering name, such as “RWA No. 001 token offering round A” **Amount of Tokens to issue:** enter the amount of token you want to offer in this round. **Offering Start & End Date:** set up the time schedule of your token offering **Min & Max amount to raise in USD:** setup the min the max amount to raise for this round of token offering **ERC-20 token accepted:** setup the token type you want to raise, i.e. what token can investors use to purchase your RWA token. Here we suggest you choose USDT. **Token Price in USD**: set the token price of your token. **Min & Max Investment in USD**: setup the min and max investment for one investor to purchase your token. 4) Confirm with your wallet ### 4.2 Bitbond 1) Login to Bitbond Dashboard and click create token sale on the left navigation bar. Enter your token address. If you create your token using Bitbond, you can find it on Bitbond dashboard. 2) Setup token sale information Here are the parameters you need to input: **Payment token:** setup the token type you want to raise, i.e. what token can investors use to purchase your RWA token. Here we suggest you choose BNB. **Token Price**: set the token price of your token. **Soft & Hard Cap:** only when rich soft cap can the token sale be created. If the hard cap was reached, the token sale will automatically finish. **Min & Max Investment amount:** setup the min the max amount for per investor to invest in this round of token offering **Offering Start & End Date:** set up the time schedule of your token offering ; **Lock duration in days:** setup the lock date which means investors need to wait several days for the token to be accepted after their investment. **Token Sale Owner:** please enter the account of your wallet if you are the business owner 3) Confirm with your wallet 4) Setup white list After your token sale have been created, you can mange your whitelist of your investors in the dashboard Enter the address of your investors and confirm with your wallet Your whitelist has been successfully set up. --- ## NFT Loyalty Program Tutorial > Source: https://docs.bnbchain.org/showcase/tokenization/nft-loyalty-programs/ NFT Loyalty Programs based on NFTs can replace traditional paper-based systems and physical membership cards by enhancing user experience and user loyalty. It generally takes 3 steps to create your NFT loyalty program: 1) Preparation 1. Setup Wallet 2. Buy Crypto 2) Create NFT 3) Distribute NFT There are plenty of tools and service providers in the BNB Chain ecosystem that can help you with the tokenization journey, we carefully select some of the best in our tutorial to guide you through the Web3 way. You can create your token in a few minutes with no coding or any blockchain knowledge. ## 1 Preparation Go to [Account Preparation Tutorial](./account-preparation.md) to get prepared before starting your tokenization journey. ## 2 Create NFT After all the preparation work, you are now ready to create your NFT. To create a token, you only need to configure a few basic parameters. We suggest these two service providers since they provide one-stop service with rich features: - NFTs2Me ( ) - Bitbond ( ) ### 2.1 NFTs2Me 1) **Connect your Wallet** Open NFTs2Me and select the “Connect Wallet” option. Choose your wallet (e.g.,Turstwallet/MetaMask). The system will ask you to sign a message to verify account ownership. 2) **Choose BNB Chain** Once your wallet is connected, select the BNB Chain as the network to work on. Make sure your wallet is on the same network to avoid errors. 3) **Create NFT Project(Edition)** Create an edition NFT collection in which only customers selected by the company owner will be able to mint NFTs. 4) **Upload Media and Complete the form** Business owners then can create an NFT, and decide the name, and media of the NFT. Customers can mint the NFT for free to receive a brand-new virtual VIP card in the form of a unique NFT, which they can use to access membership benefits. Enter the name of the collection (e.g., “ACE Milk Tea VIP Card”), a unique symbol to identify it and enter the descripcion. Upload an image or multimedia file to represent the NFT, whether it's an image, GIF, or even a short video. Select the initial phase to be Presale so that only customers on the Whitelist can claim their NFT. In addition, you have the option to: Open the collection to everyone with the Public phase, allowing anyone who knows about the NFT to claim it. Set different prices for WhiteList users and the general public, rewarding early or loyal supporters with discounts. Click “Deploy to BNB Smart Chain” to deploy the collection to the blockchain, then confirm the transaction in your wallet when prompted. 4) **Sign with your wallet** This confirmation will create a smart contract on BNB Chain containing the entire collection. Once the process is complete, a modal window will display all the information about the NFT project, including a link to the minting page and a link to the dashboard for managing the project. In the next step, we will use this dashboard to manage the customer whitelist. ### 2.2 Bitbond 1) **Connect your Wallet** Open Bitbond Token Tool and select the “Connect Wallet” option. Choose your wallet (e.g., TrustWallet/MetaMask). The system will ask you to sign a message to verify account ownership. 2) **Choose BNB Chain** Once your wallet is connected, select the BNB Chain as the network to work on. Make sure your wallet is on the same network to avoid errors. 3) **Create NFT Project** Business owners then can create an NFT, and decide the name, and media of the NFT. Customers can mint the NFT for free to receive a brand-new virtual VIP card in the form of a unique NFT, which they can use to access membership benefits. Enter the name of the collection (e.g., “ACE Milk Tea VIP Card”), a unique symbol to identify it and enter the descripcion. Enable Public Minting Enter Start and End Time, Enable Whitelist Click “Confirm” then confirm the transaction in your wallet when prompted. 4) **Success** This confirmation will create a smart contract on BNB Chain containing the entire collection. You will see the pop up if success. You can then go to dashboard to manage your NFTs Add Metadata to your NFTs Upload media or small video Enter description Cofirm to complete ## 3 Distribute NFT Business owners can invite customers to their NFT airdrop activities by sharing the links. When their customers open the link, they can mint the NFT. ### 3.1 NFTs2Me 1) **Whitelist** Collect the wallet addresses of customers interested in the airdrop. 2) **Setup whitelist** Add these addresses to the NFTs2Me platform to create a whitelist, ensuring that only those on this list can claim the NFTs. 3) **Mint NFT for free** Customers can mint NFT when they see the minting page link for free. Customers will open the minting page and connect their wallet. Once connected, customers will see the “Mint” button. By clicking "Mint," a wallet window will appear, prompting the account to confirm the transaction. Once the transaction is successfully completed, the NFT will be transferred to the customer. ### 3.2 Bitbond 1) **Whitelist** Go to dashboard to manage your NFT 2) **Setup whitelist** Add these addresses to the platform to create a whitelist, ensuring that only those on this list can claim the NFTs. 3) **Confirm with wallet** You can see the white list if success 4) **Mint NFT for free** Copy the minting page link here and send it to your NFT buyers so they can mint it in their wallet Connect Wallet to login, and if the customer address is in the whitelist, they are able to mint for free Click Mint NFT to Continue By clicking "Mint," a wallet window will appear, prompting the account to confirm the transaction. Once the transaction is successfully completed, the NFT will be transferred to the customer. By following these steps, you’ll complete the tokenization process for your business and offer a unique loyalty experience through NFTs. --- ## BNB Chain Fusion > Source: https://docs.bnbchain.org/bc-fusion/ The detailed roadmap of BNB Chain fusion. Migrate staking from the Beacon Chain to BSC for higher APY. Transfer token from Beacon Chain to BSC with single click. Bind the token between BC and BSC to enable bridge, and token recover even after the sunset of Beacon Chain. Stake on BSC directly to secure the network and earn BNB! Participate in governance on the BSC through Tally --- ## Overview > Source: https://docs.bnbchain.org/bc-fusion/overview/ # Overview **BNB Beacon Chain has been shut down at block height 385,251,927 since December 3, 2024.** BNB Beacon Chain is a blockchain developed by the BNB Chain community that implements a vision of a decentralized exchange (DEX) for digital assets. Besides this, Beacon Chain and BSC is a dual-chain structure: Beacon Chain helps to enhance the security of BSC as a staking and governance layer. With the rise of various other forms of Dex, order-book based decentralized exchange was decommissioned in [BEP151](https://github.com/bnb-chain/BEPs/blob/master/BEPs/BEP151.md). With the quick evolution of BSC, the Beacon Chain has become a burden. The cross-chain bridge that connects the two chains slows down the development iteration and always exposes BNB to a certain level of security vulnerabilities. It's time to take a step further and migrate the functionality of Beacon Chain to BSC, **allowing Beacon Chain to retire**. There will be several pahses to retrie Beacon Chain: - **First Sunset Fork** - Some types of Beacon chain transactions will be disabled, for example, TimeLockMsg, TimeRelockMsg, FreezeMsg, IssueMsg, MintMsg, IssueMiniMsg, HTLTMsg, DepositHTLTMsg, MsgCreateValidatorOpen, MsgCreateSideChainValidator, MsgCreateSideChainValidatorWithVoteAddr, MsgEditSideChainValidatorWithVoteAddr, MsgSideChainDelegate, MsgSideChainReDelegate. - **BSC Feynman Hardfork** - Native validators and staking, native goverenance will be enabled on BNB Smart Chain. The BSC validators/delegators can start migrations after the Feynman upgrade. - **Second Sunset Fork** - More Beacon chain transactions will be disabled, for example,MsgSideChainSubmitProposal. All TimeLock and AtomicSwap will automatically be refunded to the user's wallet. All the BSC delegation will be undelegated automatically. - **Final Sunset Fork** - Cross-chain communication between the Beacon Chain and BSC will be completely stopped. - **Post BC Fusion** - Beacon Chain will be dumped and and a merkle tree will be generated for recover the assets, which are binded to BSC however not transffered to BSC yet. All stakholders (e.g., token holders/owners, validators, project owners) should pay attention BNB Chain blog for releated annonuncements and take actions proactively. For more information about BNB Chain fusion, please refer to [BEP-333](https://github.com/bnb-chain/BEPs/pull/333?ref=bnbchain.ghost.io). For the roadmap and milestons of BNB Chain fusion, please refer to [the blog](https://www.bnbchain.org/en/blog/bnb-chain-fusion-roadmap). --- ## Merkle Proof Verification > Source: https://docs.bnbchain.org/bc-fusion/post-fusion/merkle-tree-verify/ # Verify Merkle Tree Proofs The [BEP299](https://github.com/bnb-chain/BEPs/blob/master/BEPs/BEP-299.md) describes how to recover the bound BEP2/BEP8 on the BSC afer the fusion. One of the most important steps is to generate and verify the Beacon Chain merkle tree proofs. If a wrong merkle tree root is generated, the bound BEP2/BEP8 cannot be recovered and there will a huge financial loss. Therefore, the communities are encouraged to use the following tools to verify the proofs and report any issues. To do the verification, please follow the detailed steps in the following links: * https://github.com/bnb-chain/node-dump/blob/master/Readme.md * https://github.com/bnb-chain/node-dump/blob/master/docs/verification.md --- ## Token Recovery > Source: https://docs.bnbchain.org/bc-fusion/post-fusion/token-recovery/ # Token Recovery dApp To facilitate the token migration after the Beacon Chain shutdown, the [BEP299](https://github.com/bnb-chain/BEPs/blob/master/BEPs/BEP-299.md) is proposed to recover the BEP2/BEP8 assets on the Beacon Chain to the BSC chain. This document will guide you through the process of token recovery. Be noted: * Only [the crosschain bound/mirrored assets](../users/assets.md) can be recovered. URL: - **Mainnet**: [https://www.bnbchain.org/en/token-recovery](https://www.bnbchain.org/en/token-recovery) ## Steps ### Step 1: Connect to your BC wallet. When opening the token recovery dApp, you will be prompted to connect to your wallet. [BNB Chain Wallet](https://chromewebstore.google.com/detail/bnb-chain-wallet/fhbohimaelbohpjbbldcngcnapndodjp) and [Trust Wallet Extension](https://trustwallet.com/) are supported. For Trust users, you can refer to [this](https://trustwallet.com/blog/trust-wallet-to-deprecate-bnb-beacon-chain-bep2-bep8-support) for more information. ### Step 2: Select the BEP2/BEP8 assets to be recovered. Click the "Recover Now" button to start the recovery process. ### Step 3: Input the receiver address. The receiver address on BSC is the address where the BEP2/BEP8 assets will be recovered to. The token recovery dApp will try to get the BSC address from your wallet automatically. If the address is not populated or you want to use a different address, you can also input the address you want to use. Be noted: * The address will receive the BEP2/BEP8 assets on BSC. Please input it correctly to avoid any fund loss. * The account will be used in the later steps for sending a transaction to BSC. So it should have some BNB on BSC for the gas fee. * If this BSC address has already been used as the receiver for a token recovery from a BC address, and it is used again for the recovery of the same token from a different BC address, the unlock time will be recalculated, starting from the most recent recovery and extending 7 days forward. ### Step 4: Confirm the receiver address and signing. By confirming the token recovery request, you will be promoted to sign a message via your wallet. ### Step 5: Send the token recovery transaction to BSC. You will be asked to switch to the BSC network in your wallet. The connected address should be the receiver address inputted in the previous step. If it is not, the token recovery dApp will detect it and ask you to switch to the correct account in your wallet. Then click the "Confirm" button to send the token recovery transaction to BSC. You will be prompted to sign and confirm the transaction, which will be sent to the BSC. ### Step 6: Wait for the recovery. After the transaction is sent, the token recovery dApp will populate a window to indicate that the token recovery request is sent successfully. Finally, you need to wait for 7 days for the BEP2/BEP8 assets to be recovered on BSC and received in your wallet. !!! info "Having Trouble with Token Recovery?" If you encounter any issues during the recovery process, please first double-check that you have followed all the steps correctly. If the problem persists, you can submit a support ticket through our official channels: - **Discord**: [https://discord.gg/bnbchain](https://discord.gg/bnbchain) - **Telegram**: [@bnbchain_official_bot](https://t.me/bnbchain_official_bot) Please describe your issue in detail and provide the following information: - Your wallet address - Wallet name (e.g., Trust Wallet) - Wallet version - If using a hardware wallet, please provide the brand and model (e.g., Ledger Nano X, Trezor Model T) - Screenshots of the error - Steps you followed before the error occurred --- ## FAQ > Source: https://docs.bnbchain.org/bc-fusion/post-fusion/faq/ # FAQ ## 1. What will happen during and after the final sunset hardfork? Before executing Final Sunset, users still have the opportunity to transfer funds across chains. However, after Final Sunset, cross-chain communication between the Beacon Chain and BSC will be completely stopped. After Sunset Fork (i.e., post fusion), the validators in the Beacon Chain community will gradually shut down, and the entire chain will no longer accept new transactions or propose new blocks. Some of the funds will be permanently locked: * On the Beacon Chain, the BEP2/BEP8 tokens that are not mirrored or bound to BSC. * The BEP153 staking reward that is less than 0.1BNB or staked value which is less than 0.01BNB will be locked forever. All these funds are not recoverable after the Final Sunset Fork. After BC shutdown, the core dev team will dump the ledger of Beacon Chain and generate a merkle tree. A governance proposal will be submitted to set the merkel root and approver account of the token migration contract. A dapp (token recovery dApp) will be provided for token migration from Beacon Chain to BSC. All the blockchain data of Beacon Chain will be uploaded to Greenfield, Filecoin and Arweave for archive. ## 2.What users should do to manage their BEP2/BEP8 assets before and after the fusion? Before the final sunset hardfork: * Users should cross-chain transfer the BNB and bound BEP2/BEP8 to the BSC network. After the final sunset hadfork (i.e., post fusion): * Users should wait for the release of [the token recovery dApp](token-recovery.md), and use the token recovery dApp to get the assets back on the BSC network. Important: to use the token recovery dApp, the private key/mnemonic for your BC account will be used to prove that you are the owner of the assets. Please take care of your key/mnemonic. ## 3. How do users access the balance snapshot post fusion? * Several BC nodes (not validators) will be kept for users to query the blockchain data, including the user balances. - Testnet RPC Node: https://data-seed-pre-0-s1.bnbchain.org/ - Mainnet RPC Node: https://dataseed1.bnbchain.org/ * An API endpoint will be kept for querying the snapshot balance. - Testnet API Endpoint: https://testnet-dex.bnbchain.org/api/v1/account/{tbnb_address} - Mainnet API Endpoint: https://dex.bnbchain.org/api/v1/account/{bnb_address} * The snapshot file can be downloaded from Greenfield, R2, and so on. The users can download the snapshot file and set up a local BC node for retrieving any data on the blockchain. - Testnet/Mainnet snpashot file: https://github.com/bnb-chain/node-dump/blob/master/Readme.md ## 4. Can I still acccess the BC releated services or products after the fusion? Most of the BC related services and products will be shut down after the final sunset hardfork, inluding and not limited to: * Staking service (including UI/API) - Testnet staking service: https://testnet-staking.bnbchain.org/en/staking - Mainnet staking service: https://www.bnbchain.org/en/staking * Block service (including API) - Testnet block service: https://testnet-api.bnbchain.org/bc - Mainnet block service: https://api.bnbchain.org/bc/ Be noted: No snapshot will be provided for any of the BC related services and products. The Beacon Chain Explorer will keep running for users to query the blockchain data, however, the explorer for BC testnet will be shut down if there is no query traffic for a long time. * Explorer service (including UI) - Testnet explorer service: https://testnet-explorer.bnbchain.org/ - Mainnet explorer service: https://explorer.bnbchain.org/ # Other Commonly Asked Questions - [Recovering EOS Tokens from SafePal Wallet After BEP2 Shutdown](../faq/recovering-eos-token-from-safepal.md) If your issue is not listed here, please explore our other documentation or open an issue. ---