ethers_etherscan/
verify.rs1use crate::{Client, Response, Result};
2use ethers_core::types::Address;
3use serde::{Deserialize, Serialize};
4use std::collections::HashMap;
5
6#[derive(Debug, Clone, Serialize, Deserialize)]
8pub struct VerifyContract {
9 #[serde(rename = "contractaddress")]
10 pub address: Address,
11 #[serde(rename = "sourceCode")]
12 pub source: String,
13 #[serde(rename = "codeformat")]
14 pub code_format: CodeFormat,
15 #[serde(rename = "contractname")]
18 pub contract_name: String,
19 #[serde(rename = "compilerversion")]
20 pub compiler_version: String,
21 #[serde(rename = "optimizationUsed", skip_serializing_if = "Option::is_none")]
23 pub optimization_used: Option<String>,
24 #[serde(skip_serializing_if = "Option::is_none")]
26 pub runs: Option<String>,
27 #[serde(rename = "constructorArguements", skip_serializing_if = "Option::is_none")]
37 pub constructor_arguments: Option<String>,
38 #[serde(rename = "constructorArguments", skip_serializing_if = "Option::is_none")]
41 pub blockscout_constructor_arguments: Option<String>,
42 #[serde(rename = "evmversion", skip_serializing_if = "Option::is_none")]
44 pub evm_version: Option<String>,
45 #[serde(flatten)]
46 pub other: HashMap<String, String>,
47}
48
49impl VerifyContract {
50 pub fn new(
51 address: Address,
52 contract_name: String,
53 source: String,
54 compiler_version: String,
55 ) -> Self {
56 Self {
57 address,
58 source,
59 code_format: Default::default(),
60 contract_name,
61 compiler_version,
62 optimization_used: None,
63 runs: None,
64 constructor_arguments: None,
65 blockscout_constructor_arguments: None,
66 evm_version: None,
67 other: Default::default(),
68 }
69 }
70
71 #[must_use]
72 pub fn runs(mut self, runs: u32) -> Self {
73 self.runs = Some(format!("{runs}"));
74 self
75 }
76
77 #[must_use]
78 pub fn optimization(self, optimization: bool) -> Self {
79 if optimization {
80 self.optimized()
81 } else {
82 self.not_optimized()
83 }
84 }
85
86 #[must_use]
87 pub fn optimized(mut self) -> Self {
88 self.optimization_used = Some("1".to_string());
89 self
90 }
91
92 #[must_use]
93 pub fn not_optimized(mut self) -> Self {
94 self.optimization_used = Some("0".to_string());
95 self
96 }
97
98 #[must_use]
99 pub fn code_format(mut self, code_format: CodeFormat) -> Self {
100 self.code_format = code_format;
101 self
102 }
103
104 #[must_use]
105 pub fn evm_version(mut self, evm_version: impl Into<String>) -> Self {
106 self.evm_version = Some(evm_version.into());
107 self
108 }
109
110 #[must_use]
111 pub fn constructor_arguments(
112 mut self,
113 constructor_arguments: Option<impl Into<String>>,
114 ) -> Self {
115 let constructor_args = constructor_arguments.map(|s| {
116 s.into()
117 .trim()
118 .trim_start_matches("0x")
120 .to_string()
121 });
122 self.constructor_arguments = constructor_args.clone();
123 self.blockscout_constructor_arguments = constructor_args;
124 self
125 }
126}
127
128#[derive(Debug, Clone, Serialize, Deserialize)]
130pub struct VerifyProxyContract {
131 pub address: Address,
133 #[serde(default, rename = "expectedimplementation", skip_serializing_if = "Option::is_none")]
135 pub expected_impl: Option<Address>,
136}
137
138#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
139pub enum CodeFormat {
140 #[serde(rename = "solidity-single-file")]
141 SingleFile,
142
143 #[default]
144 #[serde(rename = "solidity-standard-json-input")]
145 StandardJsonInput,
146}
147
148impl AsRef<str> for CodeFormat {
149 fn as_ref(&self) -> &str {
150 match self {
151 CodeFormat::SingleFile => "solidity-single-file",
152 CodeFormat::StandardJsonInput => "solidity-standard-json-input",
153 }
154 }
155}
156
157impl Client {
158 pub async fn submit_contract_verification(
160 &self,
161 contract: &VerifyContract,
162 ) -> Result<Response<String>> {
163 let body = self.create_query("contract", "verifysourcecode", contract);
164 self.post_form(&body).await
165 }
166
167 pub async fn check_contract_verification_status(
170 &self,
171 guid: impl AsRef<str>,
172 ) -> Result<Response<String>> {
173 let body = self.create_query(
174 "contract",
175 "checkverifystatus",
176 HashMap::from([("guid", guid.as_ref())]),
177 );
178 self.post_form(&body).await
179 }
180
181 pub async fn submit_proxy_contract_verification(
183 &self,
184 contract: &VerifyProxyContract,
185 ) -> Result<Response<String>> {
186 let body = self.create_query("contract", "verifyproxycontract", contract);
187 self.post_form(&body).await
188 }
189
190 pub async fn check_proxy_contract_verification_status(
193 &self,
194 guid: impl AsRef<str>,
195 ) -> Result<Response<String>> {
196 let body = self.create_query(
197 "contract",
198 "checkproxyverification",
199 HashMap::from([("guid", guid.as_ref())]),
200 );
201 self.post_form(&body).await
202 }
203}