Skip to content

Commit 4b4e0e5

Browse files
authored
Merge pull request #543 from anoma/feature/stable-megaeth-aurora
feat(bindings): deployed v1.1.0 to stable, megaeth, and aurora
2 parents 0b9d368 + 25c5ffe commit 4b4e0e5

9 files changed

Lines changed: 163 additions & 67 deletions

File tree

.github/workflows/bindings.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ jobs:
1212
runs-on: macos-latest
1313
env:
1414
ALCHEMY_API_KEY: ${{ secrets.ALCHEMY_API_KEY }}
15+
NOWNODES_API_KEY: ${{ secrets.NOWNODES_API_KEY }}
1516

1617
steps:
1718
- name: Checkout repository
@@ -30,8 +31,6 @@ jobs:
3031

3132
- name: Install Foundry
3233
uses: foundry-rs/foundry-toolchain@v1
33-
with:
34-
version: v1.7.0
3534

3635
- name: Show Foundry version
3736
run: forge --version

.github/workflows/contracts.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,6 @@ jobs:
2222

2323
- name: Install Foundry
2424
uses: foundry-rs/foundry-toolchain@v1
25-
with:
26-
version: v1.7.0
2725

2826
- name: Show Foundry version
2927
run: forge --version

bindings/src/addresses.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,19 @@ pub fn protocol_adapter_deployments_map() -> HashMap<NamedChain, Address> {
3535
),
3636
(
3737
NamedChain::Monad,
38-
address!("0x2D2Fa19aFdbb20DC73737ca5f075cfAE00Cd90C2"),
38+
address!("0x2D2Fa19aFdbb20DC73737ca5f075cfAE00Cd90C2"), // NOTE: Non-deterministic deployment
39+
),
40+
(
41+
NamedChain::StableMainnet,
42+
address!("0x2D2Fa19aFdbb20DC73737ca5f075cfAE00Cd90C2"), // NOTE: Non-deterministic deployment
43+
),
44+
(
45+
NamedChain::MegaEth,
46+
address!("0x2D2Fa19aFdbb20DC73737ca5f075cfAE00Cd90C2"), // NOTE: Non-deterministic deployment
47+
),
48+
(
49+
NamedChain::Aurora,
50+
address!("0x2D2Fa19aFdbb20DC73737ca5f075cfAE00Cd90C2"), // NOTE: Non-deterministic deployment
3951
),
4052
])
4153
}

bindings/src/helpers.rs

Lines changed: 118 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -3,57 +3,143 @@ use alloy_chains::NamedChain;
33
use std::env;
44
use thiserror::Error;
55

6-
pub type AlchemyResult<T> = Result<T, AlchemyError>;
6+
pub type RpcUrlResult<T> = Result<T, RpcUrlError>;
77

88
#[derive(Error, Debug, Clone)]
9-
pub enum AlchemyError {
10-
#[error("The alchemy subdomain was not found for this chain.")]
9+
pub enum RpcUrlError {
10+
#[error("No RPC provider subdomain was found for this chain.")]
1111
SubdomainNotFound,
12-
#[error("The Alchemy API key is not set in the environment.")]
12+
#[error("The RPC provider API key is not set in the environment.")]
1313
ApiKeyEnvVarNotSet,
1414
#[error("The url could not be parsed.")]
1515
UrlParsingError,
1616
}
1717

18-
/// Returns the Alchemy RPC URL for the given chain.
19-
pub fn alchemy_url(chain: &NamedChain) -> AlchemyResult<Url> {
20-
dotenvy::dotenv().ok();
18+
/// The RPC providers we can build URLs for.
19+
///
20+
/// Each variant knows how to turn a `(subdomain, api_key)` pair into a URL and
21+
/// which environment variable holds its API key. Add a variant here when
22+
/// onboarding a new provider, then wire its chains up in [`rpc_provider`].
23+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
24+
pub enum RpcProvider {
25+
Alchemy,
26+
NowNodes,
27+
}
28+
29+
impl RpcProvider {
30+
/// The environment variable holding this provider's API key.
31+
pub const fn api_key_env_var(self) -> &'static str {
32+
match self {
33+
RpcProvider::Alchemy => "ALCHEMY_API_KEY",
34+
RpcProvider::NowNodes => "NOWNODES_API_KEY",
35+
}
36+
}
37+
38+
/// Builds the RPC URL for the given subdomain, reading the API key from the
39+
/// environment.
40+
fn build_url(self, subdomain: &str) -> RpcUrlResult<Url> {
41+
let api_key =
42+
env::var(self.api_key_env_var()).map_err(|_| RpcUrlError::ApiKeyEnvVarNotSet)?;
2143

22-
format!(
23-
"https://{subdomain}.g.alchemy.com/v2/{api_key}",
24-
subdomain = alchemy_subdomain(chain)?,
25-
api_key = env::var("ALCHEMY_API_KEY").map_err(|_| AlchemyError::ApiKeyEnvVarNotSet)?
26-
)
27-
.parse()
28-
.map_err(|_| AlchemyError::UrlParsingError)
44+
let url = match self {
45+
RpcProvider::Alchemy => format!("https://{subdomain}.g.alchemy.com/v2/{api_key}"),
46+
RpcProvider::NowNodes => format!("https://{subdomain}.nownodes.io/{api_key}"),
47+
};
48+
49+
url.parse().map_err(|_| RpcUrlError::UrlParsingError)
50+
}
2951
}
3052

31-
/// Returns the Alchemy subdomain for the given chain.
32-
pub fn alchemy_subdomain(chain: &NamedChain) -> AlchemyResult<&'static str> {
53+
/// Returns the RPC provider and subdomain configured for the given chain.
54+
///
55+
/// This is the single place that maps chains to providers; extend it when a new
56+
/// chain is added or moved between providers. Chains served by Alchemy and those
57+
/// served by NowNodes are matched side by side here.
58+
pub fn rpc_provider(chain: &NamedChain) -> RpcUrlResult<(RpcProvider, &'static str)> {
3359
use NamedChain::*;
60+
use RpcProvider::*;
3461

35-
match chain {
36-
Mainnet => Ok("eth-mainnet"),
37-
Sepolia => Ok("eth-sepolia"),
62+
Ok(match chain {
63+
// Alchemy
64+
Mainnet => (Alchemy, "eth-mainnet"),
65+
Sepolia => (Alchemy, "eth-sepolia"),
66+
//
67+
Arbitrum => (Alchemy, "arb-mainnet"),
68+
ArbitrumSepolia => (Alchemy, "arb-sepolia"),
3869
//
39-
Arbitrum => Ok("arb-mainnet"),
40-
ArbitrumSepolia => Ok("arb-sepolia"),
70+
Optimism => (Alchemy, "opt-mainnet"),
71+
OptimismSepolia => (Alchemy, "opt-sepolia"),
4172
//
42-
Optimism => Ok("opt-mainnet"),
43-
OptimismSepolia => Ok("opt-sepolia"),
73+
Base => (Alchemy, "base-mainnet"),
74+
BaseSepolia => (Alchemy, "base-sepolia"),
4475
//
45-
Base => Ok("base-mainnet"),
46-
BaseSepolia => Ok("base-sepolia"),
76+
Polygon => (Alchemy, "polygon-mainnet"),
77+
PolygonAmoy => (Alchemy, "polygon-amoy"),
4778
//
48-
Polygon => Ok("polygon-mainnet"),
49-
PolygonAmoy => Ok("polygon-amoy"),
79+
BinanceSmartChain => (Alchemy, "bnb-mainnet"),
80+
BinanceSmartChainTestnet => (Alchemy, "bnb-testnet"),
5081
//
51-
BinanceSmartChain => Ok("bnb-mainnet"),
52-
BinanceSmartChainTestnet => Ok("bnb-testnet"),
82+
Monad => (Alchemy, "monad-mainnet"),
83+
MonadTestnet => (Alchemy, "monad-testnet"),
5384
//
54-
Monad => Ok("monad-mainnet"),
55-
MonadTestnet => Ok("monad-testnet"),
85+
StableMainnet => (Alchemy, "stable-mainnet"),
86+
StableTestnet => (Alchemy, "stable-testnet"),
87+
//
88+
MegaEth => (Alchemy, "megaeth-mainnet"),
89+
MegaEthTestnet => (Alchemy, "megaeth-testnet"),
90+
91+
// NowNodes
92+
Aurora => (NowNodes, "aurora"),
93+
94+
_ => return Err(RpcUrlError::SubdomainNotFound),
95+
})
96+
}
97+
98+
/// Returns the RPC URL for the given chain, using whichever provider is
99+
/// configured for it in [`rpc_provider`].
100+
pub fn rpc_url(chain: &NamedChain) -> RpcUrlResult<Url> {
101+
dotenvy::dotenv().ok();
102+
103+
let (provider, subdomain) = rpc_provider(chain)?;
104+
provider.build_url(subdomain)
105+
}
106+
107+
// ---------------------------------------------------------------------------
108+
// Backwards-compatible API
109+
//
110+
// The helpers below predate [`rpc_url`]/[`rpc_provider`] and are kept so
111+
// existing callers keep compiling. Prefer [`rpc_url`] for new code.
112+
// ---------------------------------------------------------------------------
113+
114+
/// Backwards-compatible alias for [`RpcUrlResult`].
115+
pub type AlchemyResult<T> = RpcUrlResult<T>;
116+
/// Backwards-compatible alias for [`RpcUrlError`].
117+
pub type AlchemyError = RpcUrlError;
118+
119+
/// Returns the Alchemy RPC URL for the given chain.
120+
pub fn alchemy_url(chain: &NamedChain) -> RpcUrlResult<Url> {
121+
dotenvy::dotenv().ok();
122+
RpcProvider::Alchemy.build_url(alchemy_subdomain(chain)?)
123+
}
124+
125+
/// Returns the Alchemy subdomain for the given chain.
126+
pub fn alchemy_subdomain(chain: &NamedChain) -> RpcUrlResult<&'static str> {
127+
match rpc_provider(chain)? {
128+
(RpcProvider::Alchemy, subdomain) => Ok(subdomain),
129+
_ => Err(RpcUrlError::SubdomainNotFound),
130+
}
131+
}
132+
133+
/// Returns the NowNodes RPC URL for the given chain.
134+
pub fn nownodes_url(chain: &NamedChain) -> RpcUrlResult<Url> {
135+
dotenvy::dotenv().ok();
136+
RpcProvider::NowNodes.build_url(nownodes_subdomain(chain)?)
137+
}
56138

57-
_ => Err(AlchemyError::SubdomainNotFound),
139+
/// Returns the NowNodes subdomain for the given chain.
140+
pub fn nownodes_subdomain(chain: &NamedChain) -> RpcUrlResult<&'static str> {
141+
match rpc_provider(chain)? {
142+
(RpcProvider::NowNodes, subdomain) => Ok(subdomain),
143+
_ => Err(RpcUrlError::SubdomainNotFound),
58144
}
59145
}

bindings/tests/contract.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use anoma_pa_evm_bindings::addresses::protocol_adapter_deployments_map;
88
use anoma_pa_evm_bindings::contract::protocol_adapter;
99
use anoma_pa_evm_bindings::generated::protocol_adapter;
1010
use anoma_pa_evm_bindings::generated::versioning_lib_external;
11-
use anoma_pa_evm_bindings::helpers::alchemy_url;
11+
use anoma_pa_evm_bindings::helpers::rpc_url;
1212

1313
#[tokio::test]
1414
async fn versions_of_deployed_protocol_adapters_match_the_expected_version() {
@@ -72,7 +72,7 @@ async fn call_executes_the_empty_tx_on_all_supported_chains() {
7272
async fn pa_instance(
7373
chain: &NamedChain,
7474
) -> protocol_adapter::ProtocolAdapter::ProtocolAdapterInstance<DynProvider> {
75-
let rpc_url = alchemy_url(chain).expect("Couldn't get RPC URL for chain");
75+
let rpc_url = rpc_url(chain).expect("Couldn't get RPC URL for chain");
7676

7777
let provider = ProviderBuilder::new()
7878
.connect_anvil_with_wallet_and_config(|a| a.fork(rpc_url))

contracts/.env-example

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,7 @@
33
## The Alchemy API key (see https://www.alchemy.com/)
44

55
export ALCHEMY_API_KEY=<ALCHEMY_API_KEY>
6+
7+
## The Nownodes API key (see https://nownodes.io/)
8+
9+
export NOWNODES_API_KEY=<NOWNODES_API_KEY>

contracts/foundry.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,5 +71,9 @@ bsc = "https://bnb-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}"
7171
bsc-testnet = "https://bnb-testnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}"
7272
monad = "https://monad-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}"
7373
monad-testnet = "https://monad-testnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}"
74+
stable-mainnet = "https://stable-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}"
75+
megaeth = "https://megaeth-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}"
76+
77+
aurora = "https://aurora.nownodes.io/${NOWNODES_API_KEY}"
7478

7579
localhost = "http://localhost:8545"

contracts/script/DeployProtocolAdapter.s.sol

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,22 @@ contract DeployProtocolAdapter is Script {
6464
name: "bsc-testnet", chainId: 97, riscZeroVerifierRouter: 0x7C1B7b8fEB636eA9Ecd32152Bce2744a0EEf39C7
6565
});
6666
_supportNetwork({name: "bsc", chainId: 56, riscZeroVerifierRouter: 0x7C1B7b8fEB636eA9Ecd32152Bce2744a0EEf39C7});
67+
6768
_supportNetwork({
6869
name: "monad", chainId: 143, riscZeroVerifierRouter: 0x8cFdF6D8D1b141897D542aa07Afd27e37694dF7f
6970
});
71+
72+
_supportNetwork({
73+
name: "stable-mainnet", chainId: 988, riscZeroVerifierRouter: 0x8cFdF6D8D1b141897D542aa07Afd27e37694dF7f
74+
});
75+
76+
_supportNetwork({
77+
name: "megaeth", chainId: 4326, riscZeroVerifierRouter: 0x8cFdF6D8D1b141897D542aa07Afd27e37694dF7f
78+
});
79+
80+
_supportNetwork({
81+
name: "aurora", chainId: 1313161554, riscZeroVerifierRouter: 0x8cFdF6D8D1b141897D542aa07Afd27e37694dF7f
82+
});
7083
}
7184

7285
/// @notice Deploys the protocol adapter contract on supported networks and allows for test deployments.

justfile

Lines changed: 8 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,14 @@ contracts-gen-bindings:
6161
contracts-simulate chain *args:
6262
@echo "IS_TEST_DEPLOYMENT: $IS_TEST_DEPLOYMENT"
6363
@echo "EMERGENCY_STOP_CALLER: $EMERGENCY_STOP_CALLER"
64+
@just contracts-clean
6465
cd contracts && forge script script/DeployProtocolAdapter.s.sol:DeployProtocolAdapter \
6566
--sig "run(bool,address)" $IS_TEST_DEPLOYMENT $EMERGENCY_STOP_CALLER \
6667
--rpc-url {{chain}} {{ args }}
6768

6869
# Deploy protocol adapter
6970
contracts-deploy deployer chain *args:
71+
@just contracts-clean
7072
cd contracts && forge script script/DeployProtocolAdapter.s.sol:DeployProtocolAdapter \
7173
--sig "run(bool,address)" $IS_TEST_DEPLOYMENT $EMERGENCY_STOP_CALLER \
7274
--broadcast --rpc-url {{chain}} --account {{deployer}} {{ args }}
@@ -89,41 +91,19 @@ contracts-verify-etherscan address chain *args:
8991
src/ProtocolAdapter.sol:ProtocolAdapter \
9092
--chain {{chain}} --verifier etherscan --watch {{ args }}
9193

94+
# Verify on a custom explorer
95+
contracts-verify-custom address chain verifier-url *args:
96+
cd contracts && forge verify-contract {{address}} \
97+
src/ProtocolAdapter.sol:ProtocolAdapter \
98+
--chain {{chain}} --verifier-url {{verifier-url}} --watch {{ args }}
99+
92100
# Verify on both sourcify and etherscan
93101
contracts-verify address chain: (contracts-verify-sourcify address chain) (contracts-verify-etherscan address chain)
94102

95103
# Publish contracts
96104
contracts-publish version *args:
97105
cd contracts && forge soldeer push anoma-pa-evm~{{version}} {{ args }}
98106

99-
# --- RISC Zero Verifier ---
100-
101-
# Simulate RISC Zero verifier deployment (dry-run)
102-
risczero-simulate admin guardian chain *args:
103-
cd contracts && FOUNDRY_EVM_VERSION=cancun forge script \
104-
test/script/DeployRiscZeroContracts.s.sol:DeployRiscZeroContracts \
105-
--sig "run(address,address)" {{admin}} {{guardian}} \
106-
--rpc-url {{chain}} {{ args }}
107-
108-
# Deploy RISC Zero verifier (router + groth16 + emergency stop)
109-
risczero-deploy deployer admin guardian chain *args:
110-
cd contracts && FOUNDRY_EVM_VERSION=cancun forge script \
111-
test/script/DeployRiscZeroContracts.s.sol:DeployRiscZeroContracts \
112-
--sig "run(address,address)" {{admin}} {{guardian}} \
113-
--broadcast --rpc-url {{chain}} --account {{deployer}} {{ args }}
114-
115-
# Verify RISC Zero verifier contracts on Sourcify
116-
risczero-verify groth16 estop router chain *args:
117-
cd contracts && FOUNDRY_EVM_VERSION=cancun forge verify-contract {{groth16}} \
118-
dependencies/risc0-risc0-ethereum-3.0.1/contracts/src/groth16/RiscZeroGroth16Verifier.sol:RiscZeroGroth16Verifier \
119-
--chain {{chain}} --verifier sourcify {{ args }}
120-
cd contracts && FOUNDRY_EVM_VERSION=cancun forge verify-contract {{estop}} \
121-
dependencies/risc0-risc0-ethereum-3.0.1/contracts/src/RiscZeroVerifierEmergencyStop.sol:RiscZeroVerifierEmergencyStop \
122-
--chain {{chain}} --verifier sourcify {{ args }}
123-
cd contracts && FOUNDRY_EVM_VERSION=cancun forge verify-contract {{router}} \
124-
dependencies/risc0-risc0-ethereum-3.0.1/contracts/src/RiscZeroVerifierRouter.sol:RiscZeroVerifierRouter \
125-
--chain {{chain}} --verifier sourcify {{ args }}
126-
127107
# --- Bindings ---
128108

129109
# Clean bindings

0 commit comments

Comments
 (0)