diff --git a/.github/workflows/rainix-manual-sol-artifacts.yaml b/.github/workflows/rainix-manual-sol-artifacts.yaml index c337488..b4993ff 100644 --- a/.github/workflows/rainix-manual-sol-artifacts.yaml +++ b/.github/workflows/rainix-manual-sol-artifacts.yaml @@ -70,6 +70,8 @@ on: required: false RPC_URL_ROBINHOOD_FORK: required: false + RPC_URL_BSC_FORK: + required: false RPC_URL_SEPOLIA_FORK: required: false CI_DEPLOY_ARBITRUM_ETHERSCAN_API_KEY: @@ -86,6 +88,8 @@ on: required: false CI_DEPLOY_ROBINHOOD_ETHERSCAN_API_KEY: required: false + CI_DEPLOY_BSC_ETHERSCAN_API_KEY: + required: false CI_DEPLOY_FLARE_ETHERSCAN_API_KEY: required: false env: @@ -141,6 +145,8 @@ jobs: RAINIX_RPC_VARS_POLYGON: ${{ vars.RPC_URL_POLYGON_FORK }} RAINIX_RPC_SECRET_ROBINHOOD: ${{ secrets.RPC_URL_ROBINHOOD_FORK }} RAINIX_RPC_VARS_ROBINHOOD: ${{ vars.RPC_URL_ROBINHOOD_FORK }} + RAINIX_RPC_SECRET_BSC: ${{ secrets.RPC_URL_BSC_FORK }} + RAINIX_RPC_VARS_BSC: ${{ vars.RPC_URL_BSC_FORK }} RAINIX_RPC_SECRET_SEPOLIA: ${{ secrets.RPC_URL_SEPOLIA_FORK }} RAINIX_RPC_VARS_SEPOLIA: ${{ vars.RPC_URL_SEPOLIA_FORK }} # 41 submission attempts over 10 minutes, against foundry's default 6 over @@ -168,4 +174,5 @@ jobs: # Etherscan API but ignores the key; exported so a consumer's `[etherscan]` # entry for it never resolves to an unset variable. CI_DEPLOY_ROBINHOOD_ETHERSCAN_API_KEY: ${{ secrets.EXPLORER_VERIFICATION_KEY || secrets.CI_DEPLOY_ROBINHOOD_ETHERSCAN_API_KEY || vars.CI_DEPLOY_ROBINHOOD_ETHERSCAN_API_KEY || '' }} + CI_DEPLOY_BSC_ETHERSCAN_API_KEY: ${{ secrets.EXPLORER_VERIFICATION_KEY || secrets.CI_DEPLOY_BSC_ETHERSCAN_API_KEY || vars.CI_DEPLOY_BSC_ETHERSCAN_API_KEY || '' }} CI_DEPLOY_FLARE_ETHERSCAN_API_KEY: ${{ secrets.CI_DEPLOY_FLARE_ETHERSCAN_API_KEY || vars.CI_DEPLOY_FLARE_ETHERSCAN_API_KEY || '' }} diff --git a/.github/workflows/rainix-manual-sol-verify.yaml b/.github/workflows/rainix-manual-sol-verify.yaml index fa484af..43a7244 100644 --- a/.github/workflows/rainix-manual-sol-verify.yaml +++ b/.github/workflows/rainix-manual-sol-verify.yaml @@ -64,6 +64,8 @@ on: required: false CI_DEPLOY_ROBINHOOD_ETHERSCAN_API_KEY: required: false + CI_DEPLOY_BSC_ETHERSCAN_API_KEY: + required: false CI_DEPLOY_FLARE_ETHERSCAN_API_KEY: required: false env: @@ -163,4 +165,5 @@ jobs: # Etherscan API but ignores the key; exported so a consumer's `[etherscan]` # entry for it never resolves to an unset variable. CI_DEPLOY_ROBINHOOD_ETHERSCAN_API_KEY: ${{ secrets.EXPLORER_VERIFICATION_KEY || secrets.CI_DEPLOY_ROBINHOOD_ETHERSCAN_API_KEY || vars.CI_DEPLOY_ROBINHOOD_ETHERSCAN_API_KEY || '' }} + CI_DEPLOY_BSC_ETHERSCAN_API_KEY: ${{ secrets.EXPLORER_VERIFICATION_KEY || secrets.CI_DEPLOY_BSC_ETHERSCAN_API_KEY || vars.CI_DEPLOY_BSC_ETHERSCAN_API_KEY || '' }} CI_DEPLOY_FLARE_ETHERSCAN_API_KEY: ${{ secrets.CI_DEPLOY_FLARE_ETHERSCAN_API_KEY || vars.CI_DEPLOY_FLARE_ETHERSCAN_API_KEY || '' }} diff --git a/.github/workflows/rainix-sol-test.yaml b/.github/workflows/rainix-sol-test.yaml index cfcfacd..bac5832 100644 --- a/.github/workflows/rainix-sol-test.yaml +++ b/.github/workflows/rainix-sol-test.yaml @@ -24,6 +24,8 @@ on: required: false RPC_URL_ROBINHOOD_FORK: required: false + RPC_URL_BSC_FORK: + required: false RPC_URL_SEPOLIA_FORK: required: false env: @@ -87,6 +89,8 @@ jobs: RAINIX_RPC_VARS_POLYGON: ${{ vars.RPC_URL_POLYGON_FORK }} RAINIX_RPC_SECRET_ROBINHOOD: ${{ secrets.RPC_URL_ROBINHOOD_FORK }} RAINIX_RPC_VARS_ROBINHOOD: ${{ vars.RPC_URL_ROBINHOOD_FORK }} + RAINIX_RPC_SECRET_BSC: ${{ secrets.RPC_URL_BSC_FORK }} + RAINIX_RPC_VARS_BSC: ${{ vars.RPC_URL_BSC_FORK }} RAINIX_RPC_SECRET_SEPOLIA: ${{ secrets.RPC_URL_SEPOLIA_FORK }} RAINIX_RPC_VARS_SEPOLIA: ${{ vars.RPC_URL_SEPOLIA_FORK }} - run: nix develop github:rainlanguage/rainix/${{ env.RAINIX_SHA }}#sol-shell -c forge test -vvv diff --git a/.github/workflows/rainix-sol.yaml b/.github/workflows/rainix-sol.yaml index e9c1b0b..e3c17a0 100644 --- a/.github/workflows/rainix-sol.yaml +++ b/.github/workflows/rainix-sol.yaml @@ -24,6 +24,8 @@ on: required: false RPC_URL_ROBINHOOD_FORK: required: false + RPC_URL_BSC_FORK: + required: false RPC_URL_SEPOLIA_FORK: required: false jobs: @@ -45,4 +47,5 @@ jobs: RPC_URL_HYPEREVM_FORK: ${{ secrets.RPC_URL_HYPEREVM_FORK }} RPC_URL_POLYGON_FORK: ${{ secrets.RPC_URL_POLYGON_FORK }} RPC_URL_ROBINHOOD_FORK: ${{ secrets.RPC_URL_ROBINHOOD_FORK }} + RPC_URL_BSC_FORK: ${{ secrets.RPC_URL_BSC_FORK }} RPC_URL_SEPOLIA_FORK: ${{ secrets.RPC_URL_SEPOLIA_FORK }} diff --git a/.github/workflows/rainix-tag-release.yaml b/.github/workflows/rainix-tag-release.yaml index a327773..48f5fb1 100644 --- a/.github/workflows/rainix-tag-release.yaml +++ b/.github/workflows/rainix-tag-release.yaml @@ -123,6 +123,8 @@ on: required: false RPC_URL_ROBINHOOD_FORK: required: false + RPC_URL_BSC_FORK: + required: false RPC_URL_SEPOLIA_FORK: required: false env: @@ -227,6 +229,8 @@ jobs: RAINIX_RPC_VARS_POLYGON: ${{ vars.RPC_URL_POLYGON_FORK }} RAINIX_RPC_SECRET_ROBINHOOD: ${{ secrets.RPC_URL_ROBINHOOD_FORK }} RAINIX_RPC_VARS_ROBINHOOD: ${{ vars.RPC_URL_ROBINHOOD_FORK }} + RAINIX_RPC_SECRET_BSC: ${{ secrets.RPC_URL_BSC_FORK }} + RAINIX_RPC_VARS_BSC: ${{ vars.RPC_URL_BSC_FORK }} RAINIX_RPC_SECRET_SEPOLIA: ${{ secrets.RPC_URL_SEPOLIA_FORK }} RAINIX_RPC_VARS_SEPOLIA: ${{ vars.RPC_URL_SEPOLIA_FORK }} - name: Verify live chain matches the fresh pins diff --git a/README.md b/README.md index 5407c79..6888ad2 100644 --- a/README.md +++ b/README.md @@ -118,10 +118,11 @@ jobs: `secrets: inherit` is required because the reusable wires the standard fork RPC env vars (`ARBITRUM_RPC_URL`, `BASE_RPC_URL`, `BASE_SEPOLIA_RPC_URL`, -`ETHEREUM_RPC_URL`, `FLARE_RPC_URL`, `HYPEREVM_RPC_URL`, `POLYGON_RPC_URL`, -`ROBINHOOD_RPC_URL`, `SEPOLIA_RPC_URL`, `CI_DEPLOY_SEPOLIA_RPC_URL`) plus -`ETHERSCAN_API_KEY` and `DEPLOYMENT_KEY` from the consumer org's secrets/vars. -Repos that do no fork tests can ignore — empty values are harmless. +`BSC_RPC_URL`, `ETHEREUM_RPC_URL`, `FLARE_RPC_URL`, `HYPEREVM_RPC_URL`, +`POLYGON_RPC_URL`, `ROBINHOOD_RPC_URL`, `SEPOLIA_RPC_URL`, +`CI_DEPLOY_SEPOLIA_RPC_URL`) plus `ETHERSCAN_API_KEY` and `DEPLOYMENT_KEY` from +the consumer org's secrets/vars. Repos that do no fork tests can ignore — empty +values are harmless. `CI_DEPLOY_SEPOLIA_RPC_URL` and the `ETH_RPC_URL` it is bound to are LEGACY and scheduled for removal (rainlanguage/rainix#340). `ETH_RPC_URL` reads as though @@ -278,9 +279,9 @@ any repo in the org pins for that network, three times consecutively. An suite with `trying to fork from an older block with a non-archive node`; a code-only check would select a host that answers no `eth_call` at all; and a single sample would qualify a load balancer that round-robins over a mix of -archive and pruning backends. Ethereum, HyperEVM and Robinhood Chain are -latest-only in every consumer, so they are not held to the archive bar, and -neither are deploy/broadcast paths. +archive and pruning backends. Ethereum, HyperEVM, Robinhood Chain and BNB Smart +Chain are latest-only in every consumer, so they are not held to the archive +bar, and neither are deploy/broadcast paths. **Health also covers load, not just correctness.** Chain id, historical state and historical `eth_call` are all correctness questions, and an endpoint that is diff --git a/rainix-static/src/rpc_preflight.rs b/rainix-static/src/rpc_preflight.rs index 674df72..2e14d2f 100644 --- a/rainix-static/src/rpc_preflight.rs +++ b/rainix-static/src/rpc_preflight.rs @@ -373,6 +373,26 @@ pub(crate) const NETWORKS: &[Network] = &[ "https://robinhood-rpc.publicnode.com", ], }, + Network { + key: "bsc", + env_name: "BSC_RPC_URL", + secret_name: "RPC_URL_BSC_FORK", + chain_id: 56, + // Latest-only in every consumer today (st0x.deploy forks it at head + // for its prod-state and cross-chain parity pins). + archive_blocks: &[], + probe_contract: "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c", // WBNB + // Measured 2026-09-10, same method as the rest of the table: 5/5 on + // the sequential probe, then a 16-way burst, from one non-CI host. + // publicnode and the Binance dataseed each went 5/5 and 16/16. + // Rejected the same day: bsc.drpc.org 4/5 then 6/16; 56.rpc.thirdweb.com + // 5/5 then 0/16 (burst-throttled); binance.llamarpc.com and + // bsc.gateway.tenderly.co refused the light probe outright. + defaults: &[ + "https://bsc-rpc.publicnode.com", + "https://bsc-dataseed.binance.org", + ], + }, ]; /// Split a secret/variable value into candidate URLs.