fix: filter out empty bytecode (#1248)
This commit is contained in:
parent
0a031417d8
commit
847110a3fe
|
@ -44,57 +44,57 @@ impl Context {
|
||||||
|
|
||||||
/// Returns all deploy (constructor) implementations
|
/// Returns all deploy (constructor) implementations
|
||||||
pub(crate) fn deployment_methods(&self) -> TokenStream {
|
pub(crate) fn deployment_methods(&self) -> TokenStream {
|
||||||
if self.contract_bytecode.is_some() {
|
if self.contract_bytecode.is_none() {
|
||||||
let ethers_core = ethers_core_crate();
|
// don't generate deploy if no bytecode
|
||||||
let ethers_contract = ethers_contract_crate();
|
return quote! {}
|
||||||
|
|
||||||
let abi_name = self.inline_abi_ident();
|
|
||||||
let get_abi = quote! {
|
|
||||||
#abi_name.clone()
|
|
||||||
};
|
|
||||||
|
|
||||||
let bytecode_name = self.inline_bytecode_ident();
|
|
||||||
let get_bytecode = quote! {
|
|
||||||
#bytecode_name.clone().into()
|
|
||||||
};
|
|
||||||
|
|
||||||
let deploy = quote! {
|
|
||||||
/// Constructs the general purpose `Deployer` instance based on the provided constructor arguments and sends it.
|
|
||||||
/// Returns a new instance of a deployer that returns an instance of this contract after sending the transaction
|
|
||||||
///
|
|
||||||
/// Notes:
|
|
||||||
/// 1. If there are no constructor arguments, you should pass `()` as the argument.
|
|
||||||
/// 1. The default poll duration is 7 seconds.
|
|
||||||
/// 1. The default number of confirmations is 1 block.
|
|
||||||
///
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// Generate contract bindings with `abigen!` and deploy a new contract instance.
|
|
||||||
///
|
|
||||||
/// *Note*: this requires a `bytecode` and `abi` object in the `greeter.json` artifact.
|
|
||||||
///
|
|
||||||
/// ```ignore
|
|
||||||
/// # async fn deploy<M: ethers::providers::Middleware>(client: ::std::sync::Arc<M>) {
|
|
||||||
/// abigen!(Greeter,"../greeter.json");
|
|
||||||
///
|
|
||||||
/// let greeter_contract = Greeter::deploy(client, "Hello world!".to_string()).unwrap().send().await.unwrap();
|
|
||||||
/// let msg = greeter_contract.greet().call().await.unwrap();
|
|
||||||
/// # }
|
|
||||||
/// ```
|
|
||||||
pub fn deploy<T: #ethers_core::abi::Tokenize >(client: ::std::sync::Arc<M>, constructor_args: T) -> Result<#ethers_contract::builders::ContractDeployer<M, Self>, #ethers_contract::ContractError<M>> {
|
|
||||||
let factory = #ethers_contract::ContractFactory::new(#get_abi, #get_bytecode, client);
|
|
||||||
let deployer = factory.deploy(constructor_args)?;
|
|
||||||
let deployer = #ethers_contract::ContractDeployer::new(deployer);
|
|
||||||
Ok(deployer)
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
return deploy
|
|
||||||
}
|
}
|
||||||
|
let ethers_core = ethers_core_crate();
|
||||||
|
let ethers_contract = ethers_contract_crate();
|
||||||
|
|
||||||
quote! {}
|
let abi_name = self.inline_abi_ident();
|
||||||
|
let get_abi = quote! {
|
||||||
|
#abi_name.clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
let bytecode_name = self.inline_bytecode_ident();
|
||||||
|
let get_bytecode = quote! {
|
||||||
|
#bytecode_name.clone().into()
|
||||||
|
};
|
||||||
|
|
||||||
|
let deploy = quote! {
|
||||||
|
/// Constructs the general purpose `Deployer` instance based on the provided constructor arguments and sends it.
|
||||||
|
/// Returns a new instance of a deployer that returns an instance of this contract after sending the transaction
|
||||||
|
///
|
||||||
|
/// Notes:
|
||||||
|
/// 1. If there are no constructor arguments, you should pass `()` as the argument.
|
||||||
|
/// 1. The default poll duration is 7 seconds.
|
||||||
|
/// 1. The default number of confirmations is 1 block.
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// Generate contract bindings with `abigen!` and deploy a new contract instance.
|
||||||
|
///
|
||||||
|
/// *Note*: this requires a `bytecode` and `abi` object in the `greeter.json` artifact.
|
||||||
|
///
|
||||||
|
/// ```ignore
|
||||||
|
/// # async fn deploy<M: ethers::providers::Middleware>(client: ::std::sync::Arc<M>) {
|
||||||
|
/// abigen!(Greeter,"../greeter.json");
|
||||||
|
///
|
||||||
|
/// let greeter_contract = Greeter::deploy(client, "Hello world!".to_string()).unwrap().send().await.unwrap();
|
||||||
|
/// let msg = greeter_contract.greet().call().await.unwrap();
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
pub fn deploy<T: #ethers_core::abi::Tokenize >(client: ::std::sync::Arc<M>, constructor_args: T) -> Result<#ethers_contract::builders::ContractDeployer<M, Self>, #ethers_contract::ContractError<M>> {
|
||||||
|
let factory = #ethers_contract::ContractFactory::new(#get_abi, #get_bytecode, client);
|
||||||
|
let deployer = factory.deploy(constructor_args)?;
|
||||||
|
let deployer = #ethers_contract::ContractDeployer::new(deployer);
|
||||||
|
Ok(deployer)
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
deploy
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Expands to the corresponding struct type based on the inputs of the given function
|
/// Expands to the corresponding struct type based on the inputs of the given function
|
||||||
|
|
|
@ -168,10 +168,18 @@ impl<'de> Visitor<'de> for AbiObjectVisitor {
|
||||||
abi = Some(RawAbi(map.next_value::<Vec<Item>>()?));
|
abi = Some(RawAbi(map.next_value::<Vec<Item>>()?));
|
||||||
}
|
}
|
||||||
"bytecode" | "byteCode" => {
|
"bytecode" | "byteCode" => {
|
||||||
bytecode = map.next_value::<BytecodeObject>().ok().map(|obj| obj.object);
|
bytecode = map
|
||||||
|
.next_value::<BytecodeObject>()
|
||||||
|
.ok()
|
||||||
|
.map(|obj| obj.object)
|
||||||
|
.filter(|bytecode| !bytecode.0.is_empty());
|
||||||
}
|
}
|
||||||
"bin" => {
|
"bin" => {
|
||||||
bytecode = map.next_value::<DeserializeBytes>().ok().map(|b| b.0);
|
bytecode = map
|
||||||
|
.next_value::<DeserializeBytes>()
|
||||||
|
.ok()
|
||||||
|
.map(|b| b.0)
|
||||||
|
.filter(|b| !b.0.is_empty());
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
map.next_value::<serde::de::IgnoredAny>()?;
|
map.next_value::<serde::de::IgnoredAny>()?;
|
||||||
|
@ -185,7 +193,7 @@ impl<'de> Visitor<'de> for AbiObjectVisitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'de> Deserialize<'de> for AbiObject {
|
impl<'de> Deserialize<'de> for AbiObject {
|
||||||
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
where
|
where
|
||||||
D: Deserializer<'de>,
|
D: Deserializer<'de>,
|
||||||
{
|
{
|
||||||
|
@ -269,4 +277,30 @@ mod tests {
|
||||||
let artifact = include_str!("../../tests/solidity-contracts/greeter.json");
|
let artifact = include_str!("../../tests/solidity-contracts/greeter.json");
|
||||||
assert_has_bytecode(artifact);
|
assert_has_bytecode(artifact);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn ignores_empty_bytecode() {
|
||||||
|
let abi_str = r#"[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"number","type":"uint64"}],"name":"MyEvent","type":"event"},{"inputs":[],"name":"greet","outputs":[],"stateMutability":"nonpayable","type":"function"}]"#;
|
||||||
|
let s = format!(r#"{{"abi": {}, "bin" : "0x" }}"#, abi_str);
|
||||||
|
|
||||||
|
match serde_json::from_str::<JsonAbi>(&s).unwrap() {
|
||||||
|
JsonAbi::Object(abi) => {
|
||||||
|
assert!(abi.bytecode.is_none());
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
panic!("expected abi object")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let s = format!(r#"{{"abi": {}, "bytecode" : {{ "object": "0x" }} }}"#, abi_str);
|
||||||
|
|
||||||
|
match serde_json::from_str::<JsonAbi>(&s).unwrap() {
|
||||||
|
JsonAbi::Object(abi) => {
|
||||||
|
assert!(abi.bytecode.is_none());
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
panic!("expected abi object")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue