2021-08-28 21:06:29 +00:00
|
|
|
#![cfg(feature = "abigen")]
|
2021-03-16 19:37:19 +00:00
|
|
|
//! Test cases to validate the `abigen!` macro
|
2021-10-18 10:28:38 +00:00
|
|
|
use ethers_contract::{abigen, AbiDecode, AbiEncode, EthEvent};
|
2021-10-02 14:34:01 +00:00
|
|
|
use ethers_core::abi::{Address, Tokenizable};
|
2021-10-22 11:25:46 +00:00
|
|
|
use ethers_core::types::{transaction::eip2718::TypedTransaction, Eip1559TransactionRequest, U256};
|
|
|
|
use ethers_core::utils::Solc;
|
2021-10-02 14:34:01 +00:00
|
|
|
use ethers_providers::Provider;
|
2021-10-22 11:25:46 +00:00
|
|
|
use std::convert::TryFrom;
|
2021-10-02 14:34:01 +00:00
|
|
|
use std::sync::Arc;
|
2021-03-16 19:37:19 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn can_gen_human_readable() {
|
|
|
|
abigen!(
|
|
|
|
SimpleContract,
|
|
|
|
r#"[
|
|
|
|
event ValueChanged(address indexed author, string oldValue, string newValue)
|
|
|
|
]"#,
|
|
|
|
event_derives(serde::Deserialize, serde::Serialize)
|
|
|
|
);
|
|
|
|
assert_eq!("ValueChanged", ValueChangedFilter::name());
|
|
|
|
assert_eq!(
|
|
|
|
"ValueChanged(address,string,string)",
|
|
|
|
ValueChangedFilter::abi_signature()
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2021-10-11 14:18:09 +00:00
|
|
|
#[test]
|
|
|
|
fn can_gen_human_readable_multiple() {
|
|
|
|
abigen!(
|
|
|
|
SimpleContract1,
|
|
|
|
r#"[
|
|
|
|
event ValueChanged1(address indexed author, string oldValue, string newValue)
|
|
|
|
]"#,
|
|
|
|
event_derives(serde::Deserialize, serde::Serialize);
|
|
|
|
|
|
|
|
SimpleContract2,
|
|
|
|
r#"[
|
|
|
|
event ValueChanged2(address indexed author, string oldValue, string newValue)
|
|
|
|
]"#,
|
|
|
|
event_derives(serde::Deserialize, serde::Serialize)
|
|
|
|
);
|
|
|
|
assert_eq!("ValueChanged1", ValueChanged1Filter::name());
|
|
|
|
assert_eq!(
|
|
|
|
"ValueChanged1(address,string,string)",
|
|
|
|
ValueChanged1Filter::abi_signature()
|
|
|
|
);
|
|
|
|
assert_eq!("ValueChanged2", ValueChanged2Filter::name());
|
|
|
|
assert_eq!(
|
|
|
|
"ValueChanged2(address,string,string)",
|
|
|
|
ValueChanged2Filter::abi_signature()
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2021-03-16 19:37:19 +00:00
|
|
|
#[test]
|
|
|
|
fn can_gen_structs_readable() {
|
|
|
|
abigen!(
|
|
|
|
SimpleContract,
|
|
|
|
r#"[
|
|
|
|
struct Value {address addr; string value;}
|
|
|
|
struct Addresses {address[] addr; string s;}
|
|
|
|
event ValueChanged(Value indexed old, Value newValue, Addresses _a)
|
|
|
|
]"#,
|
|
|
|
event_derives(serde::Deserialize, serde::Serialize)
|
|
|
|
);
|
|
|
|
let value = Addresses {
|
|
|
|
addr: vec!["eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee".parse().unwrap()],
|
|
|
|
s: "hello".to_string(),
|
|
|
|
};
|
|
|
|
let token = value.clone().into_token();
|
|
|
|
assert_eq!(value, Addresses::from_token(token).unwrap());
|
|
|
|
|
|
|
|
assert_eq!("ValueChanged", ValueChangedFilter::name());
|
|
|
|
assert_eq!(
|
|
|
|
"ValueChanged((address,string),(address,string),(address[],string))",
|
|
|
|
ValueChangedFilter::abi_signature()
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2021-08-16 07:29:44 +00:00
|
|
|
#[test]
|
|
|
|
fn can_gen_structs_with_arrays_readable() {
|
|
|
|
abigen!(
|
|
|
|
SimpleContract,
|
|
|
|
r#"[
|
|
|
|
struct Value {address addr; string value;}
|
|
|
|
struct Addresses {address[] addr; string s;}
|
|
|
|
event ValueChanged(Value indexed old, Value newValue, Addresses[] _a)
|
|
|
|
]"#,
|
|
|
|
event_derives(serde::Deserialize, serde::Serialize)
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
"ValueChanged((address,string),(address,string),(address[],string)[])",
|
|
|
|
ValueChangedFilter::abi_signature()
|
|
|
|
);
|
|
|
|
}
|
2021-03-16 19:37:19 +00:00
|
|
|
|
2021-08-16 07:29:44 +00:00
|
|
|
fn assert_tokenizeable<T: Tokenizable>() {}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn can_generate_internal_structs() {
|
|
|
|
abigen!(
|
|
|
|
VerifierContract,
|
|
|
|
"ethers-contract/tests/solidity-contracts/verifier_abi.json",
|
|
|
|
event_derives(serde::Deserialize, serde::Serialize)
|
|
|
|
);
|
|
|
|
assert_tokenizeable::<VerifyingKey>();
|
|
|
|
assert_tokenizeable::<G1Point>();
|
|
|
|
assert_tokenizeable::<G2Point>();
|
|
|
|
}
|
2021-10-02 14:34:01 +00:00
|
|
|
|
2021-10-11 14:18:09 +00:00
|
|
|
#[test]
|
|
|
|
fn can_generate_internal_structs_multiple() {
|
|
|
|
// NOTE: nesting here is necessary due to how tests are structured...
|
|
|
|
use contract::*;
|
|
|
|
mod contract {
|
|
|
|
use super::*;
|
|
|
|
abigen!(
|
|
|
|
VerifierContract,
|
|
|
|
"ethers-contract/tests/solidity-contracts/verifier_abi.json",
|
|
|
|
event_derives(serde::Deserialize, serde::Serialize);
|
|
|
|
|
|
|
|
MyOtherVerifierContract,
|
|
|
|
"ethers-contract/tests/solidity-contracts/verifier_abi.json",
|
|
|
|
event_derives(serde::Deserialize, serde::Serialize);
|
|
|
|
);
|
|
|
|
}
|
|
|
|
assert_tokenizeable::<VerifyingKey>();
|
|
|
|
assert_tokenizeable::<G1Point>();
|
|
|
|
assert_tokenizeable::<G2Point>();
|
|
|
|
|
|
|
|
let (provider, _) = Provider::mocked();
|
|
|
|
let client = Arc::new(provider);
|
|
|
|
|
|
|
|
let g1 = G1Point {
|
|
|
|
x: U256::zero(),
|
|
|
|
y: U256::zero(),
|
|
|
|
};
|
|
|
|
let g2 = G2Point {
|
|
|
|
x: [U256::zero(), U256::zero()],
|
|
|
|
y: [U256::zero(), U256::zero()],
|
|
|
|
};
|
|
|
|
let vk = VerifyingKey {
|
|
|
|
alfa_1: g1.clone(),
|
|
|
|
beta_2: g2.clone(),
|
|
|
|
gamma_2: g2.clone(),
|
|
|
|
delta_2: g2.clone(),
|
|
|
|
ic: vec![g1.clone()],
|
|
|
|
};
|
|
|
|
let proof = Proof {
|
|
|
|
a: g1.clone(),
|
|
|
|
b: g2,
|
|
|
|
c: g1,
|
|
|
|
};
|
|
|
|
|
|
|
|
// ensure both contracts use the same types
|
|
|
|
let contract = VerifierContract::new(Address::zero(), client.clone());
|
|
|
|
let _ = contract.verify(vec![], proof.clone(), vk.clone());
|
|
|
|
let contract = MyOtherVerifierContract::new(Address::zero(), client);
|
|
|
|
let _ = contract.verify(vec![], proof, vk);
|
|
|
|
}
|
|
|
|
|
2021-10-02 14:34:01 +00:00
|
|
|
#[test]
|
|
|
|
fn can_gen_human_readable_with_structs() {
|
|
|
|
abigen!(
|
|
|
|
SimpleContract,
|
|
|
|
r#"[
|
|
|
|
struct Foo { uint256 x; }
|
|
|
|
function foo(Foo memory x)
|
2021-10-18 10:28:38 +00:00
|
|
|
function bar(uint256 x, uint256 y, address addr)
|
|
|
|
yeet(uint256,uint256,address)
|
2021-10-02 14:34:01 +00:00
|
|
|
]"#,
|
|
|
|
event_derives(serde::Deserialize, serde::Serialize)
|
|
|
|
);
|
|
|
|
assert_tokenizeable::<Foo>();
|
|
|
|
|
|
|
|
let (client, _mock) = Provider::mocked();
|
|
|
|
let contract = SimpleContract::new(Address::default(), Arc::new(client));
|
2021-10-10 08:31:34 +00:00
|
|
|
let f = Foo { x: 100u64.into() };
|
|
|
|
let _ = contract.foo(f);
|
2021-10-18 10:28:38 +00:00
|
|
|
|
|
|
|
let call = BarCall {
|
|
|
|
x: 1u64.into(),
|
|
|
|
y: 0u64.into(),
|
|
|
|
addr: Address::random(),
|
|
|
|
};
|
|
|
|
let encoded_call = contract.encode("bar", (call.x, call.y, call.addr)).unwrap();
|
|
|
|
assert_eq!(encoded_call, call.clone().encode().unwrap());
|
|
|
|
let decoded_call = BarCall::decode(encoded_call.as_ref()).unwrap();
|
|
|
|
assert_eq!(call, decoded_call);
|
|
|
|
|
|
|
|
let contract_call = SimpleContractCalls::Bar(call);
|
|
|
|
let decoded_enum = SimpleContractCalls::decode(encoded_call.as_ref()).unwrap();
|
|
|
|
assert_eq!(contract_call, decoded_enum);
|
|
|
|
assert_eq!(encoded_call, contract_call.encode().unwrap());
|
|
|
|
|
|
|
|
let call = YeetCall(1u64.into(), 0u64.into(), Address::zero());
|
|
|
|
let encoded_call = contract.encode("yeet", (call.0, call.1, call.2)).unwrap();
|
|
|
|
assert_eq!(encoded_call, call.clone().encode().unwrap());
|
|
|
|
let decoded_call = YeetCall::decode(encoded_call.as_ref()).unwrap();
|
|
|
|
assert_eq!(call, decoded_call);
|
|
|
|
|
|
|
|
let contract_call = SimpleContractCalls::Yeet(call.clone());
|
|
|
|
let decoded_enum = SimpleContractCalls::decode(encoded_call.as_ref()).unwrap();
|
|
|
|
assert_eq!(contract_call, decoded_enum);
|
|
|
|
assert_eq!(contract_call, call.into());
|
|
|
|
assert_eq!(encoded_call, contract_call.encode().unwrap());
|
2021-10-02 14:34:01 +00:00
|
|
|
}
|
2021-10-13 09:53:43 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn can_handle_overloaded_functions() {
|
|
|
|
abigen!(
|
|
|
|
SimpleContract,
|
|
|
|
r#"[
|
|
|
|
getValue() (uint256)
|
|
|
|
getValue(uint256 otherValue) (uint256)
|
|
|
|
getValue(uint256 otherValue, address addr) (uint256)
|
|
|
|
]"#
|
|
|
|
);
|
|
|
|
|
|
|
|
let (provider, _) = Provider::mocked();
|
|
|
|
let client = Arc::new(provider);
|
|
|
|
let contract = SimpleContract::new(Address::zero(), client);
|
|
|
|
// ensure both functions are callable
|
|
|
|
let _ = contract.get_value();
|
|
|
|
let _ = contract.get_value_with_other_value(1337u64.into());
|
|
|
|
let _ = contract.get_value_with_other_value_and_addr(1337u64.into(), Address::zero());
|
2021-10-18 10:28:38 +00:00
|
|
|
|
|
|
|
let call = GetValueCall;
|
|
|
|
|
|
|
|
let encoded_call = contract.encode("getValue", ()).unwrap();
|
|
|
|
assert_eq!(encoded_call, call.clone().encode().unwrap());
|
|
|
|
let decoded_call = GetValueCall::decode(encoded_call.as_ref()).unwrap();
|
|
|
|
assert_eq!(call, decoded_call);
|
|
|
|
|
|
|
|
let contract_call = SimpleContractCalls::GetValue(call);
|
|
|
|
let decoded_enum = SimpleContractCalls::decode(encoded_call.as_ref()).unwrap();
|
|
|
|
assert_eq!(contract_call, decoded_enum);
|
|
|
|
assert_eq!(encoded_call, contract_call.encode().unwrap());
|
|
|
|
|
|
|
|
let call = GetValueWithOtherValueCall {
|
|
|
|
other_value: 420u64.into(),
|
|
|
|
};
|
|
|
|
|
|
|
|
let encoded_call = contract
|
|
|
|
.encode_with_selector([15, 244, 201, 22], call.other_value)
|
|
|
|
.unwrap();
|
|
|
|
assert_eq!(encoded_call, call.clone().encode().unwrap());
|
|
|
|
let decoded_call = GetValueWithOtherValueCall::decode(encoded_call.as_ref()).unwrap();
|
|
|
|
assert_eq!(call, decoded_call);
|
|
|
|
|
|
|
|
let contract_call = SimpleContractCalls::GetValueWithOtherValue(call);
|
|
|
|
let decoded_enum = SimpleContractCalls::decode(encoded_call.as_ref()).unwrap();
|
|
|
|
assert_eq!(contract_call, decoded_enum);
|
|
|
|
assert_eq!(encoded_call, contract_call.encode().unwrap());
|
|
|
|
|
|
|
|
let call = GetValueWithOtherValueAndAddrCall {
|
|
|
|
other_value: 420u64.into(),
|
|
|
|
addr: Address::random(),
|
|
|
|
};
|
|
|
|
|
|
|
|
let encoded_call = contract
|
|
|
|
.encode_with_selector([14, 97, 29, 56], (call.other_value, call.addr))
|
|
|
|
.unwrap();
|
|
|
|
let decoded_call = GetValueWithOtherValueAndAddrCall::decode(encoded_call.as_ref()).unwrap();
|
|
|
|
assert_eq!(call, decoded_call);
|
|
|
|
|
|
|
|
let contract_call = SimpleContractCalls::GetValueWithOtherValueAndAddr(call);
|
|
|
|
let decoded_enum = SimpleContractCalls::decode(encoded_call.as_ref()).unwrap();
|
|
|
|
assert_eq!(contract_call, decoded_enum);
|
|
|
|
assert_eq!(encoded_call, contract_call.encode().unwrap());
|
2021-10-13 09:53:43 +00:00
|
|
|
}
|
2021-10-22 11:25:46 +00:00
|
|
|
|
|
|
|
#[tokio::test]
|
|
|
|
async fn can_handle_underscore_functions() {
|
|
|
|
abigen!(
|
|
|
|
SimpleStorage,
|
|
|
|
r#"[
|
|
|
|
_hashPuzzle() (uint256)
|
|
|
|
]"#;
|
|
|
|
|
|
|
|
SimpleStorage2,
|
|
|
|
"ethers-contract/tests/solidity-contracts/simplestorage_abi.json",
|
|
|
|
);
|
|
|
|
|
|
|
|
// launcht the network & connect to it
|
|
|
|
let ganache = ethers_core::utils::Ganache::new().spawn();
|
|
|
|
let from = ganache.addresses()[0].clone();
|
|
|
|
let provider = Provider::try_from(ganache.endpoint())
|
|
|
|
.unwrap()
|
|
|
|
.with_sender(from)
|
|
|
|
.interval(std::time::Duration::from_millis(10));
|
|
|
|
let client = Arc::new(provider);
|
|
|
|
|
|
|
|
let compiled = Solc::new("./tests/solidity-contracts/SimpleStorage.sol")
|
|
|
|
.build()
|
|
|
|
.unwrap();
|
|
|
|
let compiled = compiled.get("SimpleStorage").unwrap();
|
|
|
|
let factory = ethers_contract::ContractFactory::new(
|
|
|
|
compiled.abi.clone(),
|
|
|
|
compiled.bytecode.clone(),
|
|
|
|
client.clone(),
|
|
|
|
);
|
|
|
|
let addr = factory
|
|
|
|
.deploy("hi".to_string())
|
|
|
|
.unwrap()
|
|
|
|
.legacy()
|
|
|
|
.send()
|
|
|
|
.await
|
|
|
|
.unwrap()
|
|
|
|
.address();
|
|
|
|
|
|
|
|
// connect to the contract
|
|
|
|
let contract = SimpleStorage::new(addr, client.clone());
|
|
|
|
let contract2 = SimpleStorage2::new(addr, client.clone());
|
|
|
|
|
|
|
|
let res = contract.hash_puzzle().call().await.unwrap();
|
|
|
|
let res2 = contract2.hash_puzzle().call().await.unwrap();
|
|
|
|
let res3 = contract
|
|
|
|
.method::<_, U256>("_hashPuzzle", ())
|
|
|
|
.unwrap()
|
|
|
|
.call()
|
|
|
|
.await
|
|
|
|
.unwrap();
|
|
|
|
let res4 = contract2
|
|
|
|
.method::<_, U256>("_hashPuzzle", ())
|
|
|
|
.unwrap()
|
|
|
|
.call()
|
|
|
|
.await
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
// Manual call construction
|
|
|
|
use ethers_providers::Middleware;
|
|
|
|
// TODO: How do we handle underscores for calls here?
|
|
|
|
let data = simplestorage_mod::HashPuzzleCall.encode().unwrap();
|
|
|
|
let tx = Eip1559TransactionRequest::new().data(data).to(addr);
|
|
|
|
let tx = TypedTransaction::Eip1559(tx);
|
|
|
|
let res5 = client.call(&tx, None).await.unwrap();
|
|
|
|
let res5 = U256::from(res5.as_ref());
|
|
|
|
assert_eq!(res, 100.into());
|
|
|
|
assert_eq!(res, res2);
|
|
|
|
assert_eq!(res, res3);
|
|
|
|
assert_eq!(res, res4);
|
|
|
|
assert_eq!(res, res5);
|
|
|
|
}
|