add support for polygonscan and snowtrace for abigen (#666)
This commit is contained in:
parent
ab949f7858
commit
a8b0885c25
|
@ -15,6 +15,11 @@
|
||||||
- Fix `fee_history` to first try with `block_count` encoded as a hex `QUANTITY`.
|
- Fix `fee_history` to first try with `block_count` encoded as a hex `QUANTITY`.
|
||||||
[#668](https://github.com/gakonst/ethers-rs/pull/668)
|
[#668](https://github.com/gakonst/ethers-rs/pull/668)
|
||||||
|
|
||||||
|
## ethers-contract-abigen
|
||||||
|
|
||||||
|
- Implement snowtrace and polygonscan on par with the etherscan integration
|
||||||
|
[#666](https://github.com/gakonst/ethers-rs/pull/666).
|
||||||
|
|
||||||
## ethers-solc
|
## ethers-solc
|
||||||
|
|
||||||
### Unreleased
|
### Unreleased
|
||||||
|
|
|
@ -23,6 +23,12 @@ pub enum Source {
|
||||||
/// An address of a mainnet contract that has been verified on Etherscan.io.
|
/// An address of a mainnet contract that has been verified on Etherscan.io.
|
||||||
Etherscan(Address),
|
Etherscan(Address),
|
||||||
|
|
||||||
|
/// An address of a mainnet contract that has been verified on Polygonscan.com.
|
||||||
|
Polygonscan(Address),
|
||||||
|
|
||||||
|
/// An address of a mainnet contract that has been verified on snowtrace.io.
|
||||||
|
Snowtrace(Address),
|
||||||
|
|
||||||
/// The package identifier of an npm package with a path to a Truffle
|
/// The package identifier of an npm package with a path to a Truffle
|
||||||
/// artifact or ABI to be retrieved from `unpkg.io`.
|
/// artifact or ABI to be retrieved from `unpkg.io`.
|
||||||
Npm(String),
|
Npm(String),
|
||||||
|
@ -91,7 +97,7 @@ impl Source {
|
||||||
let url = base.join(source)?;
|
let url = base.join(source)?;
|
||||||
|
|
||||||
match url.scheme() {
|
match url.scheme() {
|
||||||
"file" => Ok(Source::local(source.to_string())),
|
"file" => Ok(Source::local(source)),
|
||||||
"http" | "https" => match url.host_str() {
|
"http" | "https" => match url.host_str() {
|
||||||
Some("etherscan.io") => Source::etherscan(
|
Some("etherscan.io") => Source::etherscan(
|
||||||
url.path()
|
url.path()
|
||||||
|
@ -99,9 +105,23 @@ impl Source {
|
||||||
.next()
|
.next()
|
||||||
.ok_or_else(|| anyhow!("HTTP URL does not have a path"))?,
|
.ok_or_else(|| anyhow!("HTTP URL does not have a path"))?,
|
||||||
),
|
),
|
||||||
|
Some("polygonscan.com") => Source::polygonscan(
|
||||||
|
url.path()
|
||||||
|
.rsplit('/')
|
||||||
|
.next()
|
||||||
|
.ok_or_else(|| anyhow!("HTTP URL does not have a path"))?,
|
||||||
|
),
|
||||||
|
Some("snowtrace.io") => Source::snowtrace(
|
||||||
|
url.path()
|
||||||
|
.rsplit('/')
|
||||||
|
.next()
|
||||||
|
.ok_or_else(|| anyhow!("HTTP URL does not have a path"))?,
|
||||||
|
),
|
||||||
_ => Ok(Source::Http(url)),
|
_ => Ok(Source::Http(url)),
|
||||||
},
|
},
|
||||||
"etherscan" => Source::etherscan(url.path()),
|
"etherscan" => Source::etherscan(url.path()),
|
||||||
|
"polygonscan" => Source::polygonscan(url.path()),
|
||||||
|
"snowtrace" => Source::snowtrace(url.path()),
|
||||||
"npm" => Ok(Source::npm(url.path())),
|
"npm" => Ok(Source::npm(url.path())),
|
||||||
_ => Err(anyhow!("unsupported URL '{}'", url)),
|
_ => Err(anyhow!("unsupported URL '{}'", url)),
|
||||||
}
|
}
|
||||||
|
@ -130,6 +150,26 @@ impl Source {
|
||||||
Ok(Source::Etherscan(address))
|
Ok(Source::Etherscan(address))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates an Polygonscan source from an address string.
|
||||||
|
pub fn polygonscan<S>(address: S) -> Result<Self>
|
||||||
|
where
|
||||||
|
S: AsRef<str>,
|
||||||
|
{
|
||||||
|
let address = util::parse_address(address)
|
||||||
|
.context("failed to parse address for Polygonscan source")?;
|
||||||
|
Ok(Source::Polygonscan(address))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates an Snowtrace source from an address string.
|
||||||
|
pub fn snowtrace<S>(address: S) -> Result<Self>
|
||||||
|
where
|
||||||
|
S: AsRef<str>,
|
||||||
|
{
|
||||||
|
let address =
|
||||||
|
util::parse_address(address).context("failed to parse address for Snowtrace source")?;
|
||||||
|
Ok(Source::Snowtrace(address))
|
||||||
|
}
|
||||||
|
|
||||||
/// Creates an Etherscan source from an address string.
|
/// Creates an Etherscan source from an address string.
|
||||||
pub fn npm<S>(package_path: S) -> Self
|
pub fn npm<S>(package_path: S) -> Self
|
||||||
where
|
where
|
||||||
|
@ -148,6 +188,8 @@ impl Source {
|
||||||
Source::Local(path) => get_local_contract(path),
|
Source::Local(path) => get_local_contract(path),
|
||||||
Source::Http(_) => panic!("Http abi location are not supported for wasm"),
|
Source::Http(_) => panic!("Http abi location are not supported for wasm"),
|
||||||
Source::Etherscan(_) => panic!("Etherscan abi location are not supported for wasm"),
|
Source::Etherscan(_) => panic!("Etherscan abi location are not supported for wasm"),
|
||||||
|
Source::Polygonscan(_) => panic!("Polygonscan abi location are not supported for wasm"),
|
||||||
|
Source::Snowtrace(_) => panic!("Snowtrace abi location are not supported for wasm"),
|
||||||
Source::Npm(_) => panic!("npm abi location are not supported for wasm"),
|
Source::Npm(_) => panic!("npm abi location are not supported for wasm"),
|
||||||
Source::String(abi) => Ok(abi.clone()),
|
Source::String(abi) => Ok(abi.clone()),
|
||||||
}
|
}
|
||||||
|
@ -155,7 +197,9 @@ impl Source {
|
||||||
match self {
|
match self {
|
||||||
Source::Local(path) => get_local_contract(path),
|
Source::Local(path) => get_local_contract(path),
|
||||||
Source::Http(url) => get_http_contract(url),
|
Source::Http(url) => get_http_contract(url),
|
||||||
Source::Etherscan(address) => get_etherscan_contract(*address),
|
Source::Etherscan(address) => get_etherscan_contract(*address, "etherscan.io"),
|
||||||
|
Source::Polygonscan(address) => get_etherscan_contract(*address, "polygonscan.com"),
|
||||||
|
Source::Snowtrace(address) => get_etherscan_contract(*address, "snowtrace.io"),
|
||||||
Source::Npm(package) => get_npm_contract(package),
|
Source::Npm(package) => get_npm_contract(package),
|
||||||
Source::String(abi) => Ok(abi.clone()),
|
Source::String(abi) => Ok(abi.clone()),
|
||||||
}
|
}
|
||||||
|
@ -211,20 +255,27 @@ fn get_http_contract(url: &Url) -> Result<String> {
|
||||||
/// Retrieves a contract ABI from the Etherscan HTTP API and wraps it in an
|
/// Retrieves a contract ABI from the Etherscan HTTP API and wraps it in an
|
||||||
/// artifact JSON for compatibility with the code generation facilities.
|
/// artifact JSON for compatibility with the code generation facilities.
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
fn get_etherscan_contract(address: Address) -> Result<String> {
|
fn get_etherscan_contract(address: Address, domain: &str) -> Result<String> {
|
||||||
// NOTE: We do not retrieve the bytecode since deploying contracts with the
|
// NOTE: We do not retrieve the bytecode since deploying contracts with the
|
||||||
// same bytecode is unreliable as the libraries have already linked and
|
// same bytecode is unreliable as the libraries have already linked and
|
||||||
// probably don't reference anything when deploying on other networks.
|
// probably don't reference anything when deploying on other networks.
|
||||||
|
|
||||||
let api_key =
|
let api_key = {
|
||||||
env::var("ETHERSCAN_API_KEY").map(|key| format!("&apikey={}", key)).unwrap_or_default();
|
let key_res = match domain {
|
||||||
|
"etherscan.io" => env::var("ETHERSCAN_API_KEY").ok(),
|
||||||
|
"polygonscan.com" => env::var("POLYGONSCAN_API_KEY").ok(),
|
||||||
|
"snowtrace.io" => env::var("SNOWTRACE_API_KEY").ok(),
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
key_res.map(|key| format!("&apikey={}", key)).unwrap_or_default()
|
||||||
|
};
|
||||||
|
|
||||||
let abi_url = format!(
|
let abi_url = format!(
|
||||||
"http://api.etherscan.io/api\
|
"http://api.{}/api?module=contract&action=getabi&address={:?}&format=raw{}",
|
||||||
?module=contract&action=getabi&address={:?}&format=raw{}",
|
domain, address, api_key,
|
||||||
address, api_key,
|
|
||||||
);
|
);
|
||||||
let abi = util::http_get(&abi_url).context("failed to retrieve ABI from Etherscan.io")?;
|
let abi =
|
||||||
|
util::http_get(&abi_url).context(format!("failed to retrieve ABI from {}", domain))?;
|
||||||
Ok(abi)
|
Ok(abi)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -256,10 +307,26 @@ mod tests {
|
||||||
"etherscan:0x0001020304050607080910111213141516171819",
|
"etherscan:0x0001020304050607080910111213141516171819",
|
||||||
Source::etherscan("0x0001020304050607080910111213141516171819").unwrap(),
|
Source::etherscan("0x0001020304050607080910111213141516171819").unwrap(),
|
||||||
),
|
),
|
||||||
|
(
|
||||||
|
"polygonscan:0x0001020304050607080910111213141516171819",
|
||||||
|
Source::polygonscan("0x0001020304050607080910111213141516171819").unwrap(),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"snowtrace:0x0001020304050607080910111213141516171819",
|
||||||
|
Source::snowtrace("0x0001020304050607080910111213141516171819").unwrap(),
|
||||||
|
),
|
||||||
(
|
(
|
||||||
"https://etherscan.io/address/0x0001020304050607080910111213141516171819",
|
"https://etherscan.io/address/0x0001020304050607080910111213141516171819",
|
||||||
Source::etherscan("0x0001020304050607080910111213141516171819").unwrap(),
|
Source::etherscan("0x0001020304050607080910111213141516171819").unwrap(),
|
||||||
),
|
),
|
||||||
|
(
|
||||||
|
"https://polygonscan.com/address/0x0001020304050607080910111213141516171819",
|
||||||
|
Source::polygonscan("0x0001020304050607080910111213141516171819").unwrap(),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"https://snowtrace.io/address/0x0001020304050607080910111213141516171819",
|
||||||
|
Source::snowtrace("0x0001020304050607080910111213141516171819").unwrap(),
|
||||||
|
),
|
||||||
(
|
(
|
||||||
"npm:@openzeppelin/contracts@2.5.0/build/contracts/IERC20.json",
|
"npm:@openzeppelin/contracts@2.5.0/build/contracts/IERC20.json",
|
||||||
Source::npm("@openzeppelin/contracts@2.5.0/build/contracts/IERC20.json"),
|
Source::npm("@openzeppelin/contracts@2.5.0/build/contracts/IERC20.json"),
|
||||||
|
|
Loading…
Reference in New Issue