Skip to main content

boundless_market/
deployments.rs

1// Copyright 2026 Boundless Foundation, Inc.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::borrow::Cow;
16
17use alloy::primitives::{address, Address};
18use clap::Args;
19use derive_builder::Builder;
20
21pub use alloy_chains::NamedChain;
22
23pub(crate) const BASE_MAINNET_INDEXER_URL: &str = "https://d2mdvlnmyov1e1.cloudfront.net/";
24pub(crate) const BASE_SEPOLIA_INDEXER_URL: &str = "https://d3kkukmpiqlzm1.cloudfront.net/";
25pub(crate) const SEPOLIA_INDEXER_URL: &str = "https://d3jjbcwhlw21k7.cloudfront.net/";
26
27/// Configuration for a deployment of the Boundless Market.
28// NOTE: See https://github.com/clap-rs/clap/issues/5092#issuecomment-1703980717 about clap usage.
29#[non_exhaustive]
30#[derive(Clone, Debug, Builder, Args)]
31#[group(
32    id = "market_deployment",
33    requires = "boundless_market_address",
34    requires = "set_verifier_address"
35)]
36pub struct Deployment {
37    /// EIP-155 chain ID of the network.
38    #[clap(long = "market-chain-id", env = "MARKET_CHAIN_ID")]
39    #[builder(setter(into, strip_option), default)]
40    pub market_chain_id: Option<u64>,
41
42    /// Address of the [BoundlessMarket] contract.
43    ///
44    /// [BoundlessMarket]: crate::contracts::IBoundlessMarket
45    #[clap(long, env, required = false, long_help = "Address of the BoundlessMarket contract")]
46    #[builder(setter(into))]
47    pub boundless_market_address: Address,
48
49    /// Address of the [RiscZeroVerifierRouter] contract.
50    ///
51    /// The verifier router implements [IRiscZeroVerifier]. Each network has a canonical router,
52    /// that is deployed by the core team. You can additionally deploy and manage your own verifier
53    /// instead. See the [Boundless docs for more details].
54    ///
55    /// [RiscZeroVerifierRouter]: https://github.com/risc0/risc0-ethereum/blob/main/contracts/src/RiscZeroVerifierRouter.sol
56    /// [IRiscZeroVerifier]: https://github.com/risc0/risc0-ethereum/blob/main/contracts/src/IRiscZeroVerifier.sol
57    /// [Boundless docs for more details]: https://docs.boundless.network/developers/smart-contracts/verifier-contracts
58    #[clap(
59        long,
60        env = "VERIFIER_ADDRESS",
61        long_help = "Address of the RiscZeroVerifierRouter contract"
62    )]
63    #[builder(setter(strip_option), default)]
64    pub verifier_router_address: Option<Address>,
65
66    /// Address of the [RiscZeroSetVerifier] contract.
67    ///
68    /// [RiscZeroSetVerifier]: https://github.com/risc0/risc0-ethereum/blob/main/contracts/src/RiscZeroSetVerifier.sol
69    #[clap(long, env, required = false, long_help = "Address of the RiscZeroSetVerifier contract")]
70    #[builder(setter(into))]
71    pub set_verifier_address: Address,
72
73    /// Address of the collateral token contract. The collateral token is an ERC-20.
74    #[clap(long, env)]
75    #[builder(setter(strip_option), default)]
76    pub collateral_token_address: Option<Address>,
77
78    /// URL for the offchain [order stream service].
79    ///
80    /// [order stream service]: crate::order_stream_client
81    #[clap(long, env, long_help = "URL for the offchain order stream service")]
82    #[builder(setter(into, strip_option), default)]
83    pub order_stream_url: Option<Cow<'static, str>>,
84
85    /// Block number when the BoundlessMarket contract was deployed.
86    /// Used as a starting point for event queries.
87    #[clap(skip)]
88    #[builder(setter(strip_option), default)]
89    pub deployment_block: Option<u64>,
90
91    /// Indexer URL for the market.
92    #[clap(long, env, long_help = "URL for the indexer")]
93    #[builder(setter(into, strip_option), default)]
94    pub indexer_url: Option<Cow<'static, str>>,
95}
96
97impl Deployment {
98    /// Create a new [DeploymentBuilder].
99    pub fn builder() -> DeploymentBuilder {
100        Default::default()
101    }
102
103    /// Lookup the [Deployment] for a named chain.
104    pub const fn from_chain(chain: NamedChain) -> Option<Deployment> {
105        match chain {
106            NamedChain::Sepolia => Some(SEPOLIA),
107            NamedChain::Base => Some(BASE),
108            NamedChain::BaseSepolia => Some(BASE_SEPOLIA),
109            _ => None,
110        }
111    }
112
113    /// Lookup the [Deployment] by chain ID.
114    pub fn from_chain_id(chain_id: impl Into<u64>) -> Option<Deployment> {
115        let chain = NamedChain::try_from(chain_id.into()).ok()?;
116        Self::from_chain(chain)
117    }
118
119    /// Check if the collateral token supports permit.
120    /// Some chain's bridged tokens do not support permit, for example Base.
121    pub fn collateral_token_supports_permit(&self) -> bool {
122        self.market_chain_id.map(collateral_token_supports_permit).unwrap_or(false)
123    }
124}
125
126// TODO(#654): Ensure consistency with deployment.toml and with docs
127/// [Deployment] for the Sepolia testnet.
128pub const SEPOLIA: Deployment = Deployment {
129    market_chain_id: Some(NamedChain::Sepolia as u64),
130    boundless_market_address: address!("0xc211b581cb62e3a6d396a592bab34979e1bbba7d"),
131    verifier_router_address: Some(address!("0xb121b667dd2cf27f95f9f5107137696f56f188f6")),
132    set_verifier_address: address!("0xcb9D14347b1e816831ECeE46EC199144F360B55c"),
133    collateral_token_address: Some(address!("0xb4FC69A452D09D2662BD8C3B5BB756902260aE28")),
134    order_stream_url: Some(Cow::Borrowed("https://eth-sepolia.boundless.network")),
135    indexer_url: Some(Cow::Borrowed(SEPOLIA_INDEXER_URL)),
136    deployment_block: None,
137};
138
139/// [Deployment] for the Base mainnet.
140pub const BASE: Deployment = Deployment {
141    market_chain_id: Some(NamedChain::Base as u64),
142    boundless_market_address: address!("0xfd152dadc5183870710fe54f939eae3ab9f0fe82"),
143    verifier_router_address: Some(address!("0xa326b2eb45a5c3c206df905a58970dca57b8719e")),
144    set_verifier_address: address!("0x1Ab08498CfF17b9723ED67143A050c8E8c2e3104"),
145    collateral_token_address: Some(address!("0xAA61bB7777bD01B684347961918f1E07fBbCe7CF")),
146    order_stream_url: Some(Cow::Borrowed("https://base-mainnet.boundless.network")),
147    indexer_url: Some(Cow::Borrowed(BASE_MAINNET_INDEXER_URL)),
148    deployment_block: Some(35060420),
149};
150
151/// [Deployment] for the Base Sepolia.
152pub const BASE_SEPOLIA: Deployment = Deployment {
153    market_chain_id: Some(NamedChain::BaseSepolia as u64),
154    boundless_market_address: address!("0x56da3786061c82214d18e634d2817e86ad42d7ce"),
155    verifier_router_address: Some(address!("0xa326b2eb45a5c3c206df905a58970dca57b8719e")),
156    set_verifier_address: address!("0x1Ab08498CfF17b9723ED67143A050c8E8c2e3104"),
157    collateral_token_address: Some(address!("0x8d4dA4b7938471A919B08F941461b2ed1679d7bb")),
158    order_stream_url: Some(Cow::Borrowed("https://base-sepolia.boundless.network")),
159    indexer_url: Some(Cow::Borrowed(BASE_SEPOLIA_INDEXER_URL)),
160    deployment_block: Some(30570944),
161};
162
163/// Check if the collateral token supports permit.
164/// Some chain's bridged tokens do not support permit, for example Base.
165pub fn collateral_token_supports_permit(chain_id: u64) -> bool {
166    chain_id == 1 || chain_id == 11155111 || chain_id == 31337
167}