abi.rs 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. // SPDX-License-Identifier: Apache-2.0
  2. use crate::{build_wasm, load_abi};
  3. use ink_metadata::{InkProject, TypeSpec};
  4. use once_cell::sync::Lazy;
  5. use scale_info::{
  6. form::PortableForm, Path, TypeDef, TypeDefComposite, TypeDefPrimitive, TypeDefVariant,
  7. };
  8. use std::sync::Mutex;
  9. macro_rules! path {
  10. ($( $segments:expr ),*) => {
  11. Path::from_segments_unchecked([$($segments),*].iter().map(ToString::to_string))
  12. }
  13. }
  14. /// Partially mimicking the ink! "mother" integration test.
  15. static MOTHER: Lazy<Mutex<(InkProject, InkProject)>> = Lazy::new(|| {
  16. let src = r#"
  17. import "polkadot";
  18. contract Mother {
  19. enum Status {
  20. NotStarted,
  21. OpeningPeriod
  22. }
  23. struct Auction {
  24. string name;
  25. Hash subject;
  26. uint64[3] terms;
  27. Status status;
  28. bool finalized;
  29. bytes vector;
  30. }
  31. Auction auction;
  32. mapping(address => uint128) balances;
  33. function echo_auction(Auction _auction) public pure returns (Auction) {
  34. return _auction;
  35. }
  36. }"#;
  37. let solang_abi = load_abi(&build_wasm(src, false, false)[0].1);
  38. let ink_str = std::fs::read_to_string("testdata/ink/mother.json").unwrap();
  39. let ink_abi: InkProject = serde_json::from_str(&ink_str).unwrap();
  40. Mutex::new((solang_abi, ink_abi))
  41. });
  42. fn eq_display(a: &TypeSpec<PortableForm>, b: &TypeSpec<PortableForm>) {
  43. assert_eq!(a.display_name(), b.display_name());
  44. }
  45. #[test]
  46. fn environment_matches_ink() {
  47. let mother = MOTHER.lock().unwrap();
  48. let (solang, ink) = (mother.0.spec().environment(), mother.1.spec().environment());
  49. eq_display(solang.timestamp(), ink.timestamp());
  50. eq_display(solang.account_id(), ink.account_id());
  51. eq_display(solang.hash(), ink.hash());
  52. eq_display(solang.balance(), ink.balance());
  53. eq_display(solang.block_number(), ink.block_number());
  54. assert_eq!(solang.max_event_topics(), ink.max_event_topics());
  55. }
  56. #[test]
  57. fn address_type_path_exists() {
  58. let mother = MOTHER.lock().unwrap();
  59. let (solang, ink) = (mother.0.registry(), mother.1.registry());
  60. let ink_address = &ink.types[8].ty.path;
  61. assert!(solang.types.iter().any(|t| &t.ty.path == ink_address));
  62. }
  63. #[test]
  64. fn hash_type_path_exists() {
  65. let mother = MOTHER.lock().unwrap();
  66. let (solang, ink) = (mother.0.registry(), mother.1.registry());
  67. let ink_hash = &ink.types[1].ty.path;
  68. assert!(solang.types.iter().any(|t| &t.ty.path == ink_hash));
  69. }
  70. #[test]
  71. fn inherited_externally_callable_functions() {
  72. let src = r##"
  73. interface IERC165 {
  74. function supportsInterface(bytes4 interfaceId) external view returns (bool);
  75. }
  76. interface IERC1155 is IERC165 {}
  77. contract ERC165 is IERC165 {
  78. function supportsInterface(
  79. bytes4 interfaceId
  80. ) public view virtual override returns (bool) {}
  81. }
  82. contract ERC1155 is ERC165, IERC1155 {
  83. function supportsInterface(
  84. bytes4 interfaceId
  85. ) public view virtual override(ERC165, IERC165) returns (bool) {}
  86. }
  87. contract MyToken is ERC1155 {}
  88. "##;
  89. let abi = load_abi(&build_wasm(src, false, false)[0].1);
  90. let messages = abi.spec().messages();
  91. assert_eq!(messages.len(), 1);
  92. assert_eq!(messages[0].label(), "supportsInterface");
  93. }
  94. /// Ensure that the correct selector and data type for Error(String) and
  95. /// Panic(uint256) is present in the metadata.
  96. #[test]
  97. fn error_and_panic_in_lang_error() {
  98. let src = r##"
  99. contract Foo { uint public foo; }
  100. "##;
  101. let abi = load_abi(&build_wasm(src, false, false)[0].1);
  102. // Find them in lang_error
  103. let (error_ty_id, panic_ty_id) = match &abi
  104. .registry()
  105. .resolve(abi.spec().lang_error().ty().id)
  106. .unwrap()
  107. .type_def
  108. {
  109. TypeDef::<PortableForm>::Variant(TypeDefVariant::<PortableForm> { variants }) => {
  110. let error = variants.iter().find(|v| v.name == "Error").unwrap();
  111. let panic = variants.iter().find(|v| v.name == "Panic").unwrap();
  112. (error.fields[0].ty.id, panic.fields[0].ty.id)
  113. }
  114. _ => panic!("unexpected lang_err type def"),
  115. };
  116. // Asserts for Error
  117. let error_ty = abi.registry().resolve(error_ty_id).unwrap();
  118. let error_ty_id = match &error_ty.type_def {
  119. TypeDef::<PortableForm>::Composite(TypeDefComposite::<PortableForm> { fields }) => {
  120. assert_eq!(error_ty.path, path!("0x08c379a0"));
  121. fields[0].ty.id
  122. }
  123. _ => panic!("expected Error(string) type"),
  124. };
  125. let error_ty = abi.registry().resolve(error_ty_id).unwrap();
  126. match &error_ty.type_def {
  127. TypeDef::<PortableForm>::Primitive(TypeDefPrimitive::Str) => {
  128. assert_eq!(error_ty.path, path!("string"))
  129. }
  130. _ => panic!("expected Error(string) type"),
  131. };
  132. // Asserts for Panic
  133. let panic_ty = abi.registry().resolve(panic_ty_id).unwrap();
  134. let panic_ty_id = match &panic_ty.type_def {
  135. TypeDef::<PortableForm>::Composite(TypeDefComposite::<PortableForm> { fields }) => {
  136. assert_eq!(panic_ty.path, path!("0x4e487b71"));
  137. fields[0].ty.id
  138. }
  139. _ => panic!("expected Panic(uint256) type"),
  140. };
  141. let panic_ty = abi.registry().resolve(panic_ty_id).unwrap();
  142. match &panic_ty.type_def {
  143. TypeDef::<PortableForm>::Primitive(TypeDefPrimitive::U256) => {
  144. assert_eq!(panic_ty.path, path!("uint256"))
  145. }
  146. _ => panic!("expected Panic(uint256) type"),
  147. };
  148. }
  149. /// Ensure that custom errors end up correctly in the metadata.
  150. #[test]
  151. fn custom_errors_in_metadata() {
  152. let src = r#"
  153. struct Bar { uint foo; string bar; }
  154. error Custom(Bar);
  155. error Unauthorized();
  156. error ERC721InsufficientApproval(string operator, uint256 tokenId);
  157. contract VendingMachine { uint public foo; }"#;
  158. let abi = load_abi(&build_wasm(src, false, false)[0].1);
  159. // Find them in lang_error
  160. let (error_ty_id, custom_ty_id, erc721_ty_id) = match &abi
  161. .registry()
  162. .resolve(abi.spec().lang_error().ty().id)
  163. .unwrap()
  164. .type_def
  165. {
  166. TypeDef::<PortableForm>::Variant(TypeDefVariant::<PortableForm> { variants }) => {
  167. let unauthorized = variants.iter().find(|v| v.name == "Unauthorized").unwrap();
  168. let custom = variants.iter().find(|v| v.name == "Custom").unwrap();
  169. let erc721 = variants
  170. .iter()
  171. .find(|v| v.name == "ERC721InsufficientApproval")
  172. .unwrap();
  173. (
  174. unauthorized.fields[0].ty.id,
  175. custom.fields[0].ty.id,
  176. erc721.fields[0].ty.id,
  177. )
  178. }
  179. _ => panic!("unexpected lang_err type def"),
  180. };
  181. // Asserts for Unauthorized
  182. let unauthorized_ty = abi.registry().resolve(error_ty_id).unwrap();
  183. match &unauthorized_ty.type_def {
  184. TypeDef::<PortableForm>::Composite(TypeDefComposite::<PortableForm> { fields }) => {
  185. assert_eq!(unauthorized_ty.path, path!("0x82b42900"));
  186. assert!(fields.is_empty());
  187. }
  188. _ => panic!("expected Unauthorized() type"),
  189. }
  190. // Asserts for Custom(Bar)
  191. let custom_ty = abi.registry().resolve(custom_ty_id).unwrap();
  192. let custom_ty_id = match &custom_ty.type_def {
  193. TypeDef::<PortableForm>::Composite(TypeDefComposite::<PortableForm> { fields }) => {
  194. assert_eq!(custom_ty.path, path!("0x49dfe8ce"));
  195. fields[0].ty.id
  196. }
  197. _ => panic!("expected Foo(Bar) type"),
  198. };
  199. let custom_ty = abi.registry().resolve(custom_ty_id).unwrap();
  200. match &custom_ty.type_def {
  201. TypeDef::<PortableForm>::Composite(TypeDefComposite { fields }) => {
  202. assert_eq!(custom_ty.path, path!("Bar"));
  203. assert_eq!(fields.len(), 2);
  204. let foo = &fields[0];
  205. assert_eq!(foo.name.as_ref().unwrap(), "foo");
  206. let foo_ty = abi.registry().resolve(foo.ty.id).unwrap();
  207. match &foo_ty.type_def {
  208. TypeDef::<PortableForm>::Primitive(TypeDefPrimitive::U256) => {
  209. assert_eq!(foo_ty.path, path!("uint256"))
  210. }
  211. _ => panic!("expected uint256 type"),
  212. }
  213. let bar = &fields[1];
  214. assert_eq!(bar.name.as_ref().unwrap(), "bar");
  215. let bar_ty = abi.registry().resolve(bar.ty.id).unwrap();
  216. match &bar_ty.type_def {
  217. TypeDef::<PortableForm>::Primitive(TypeDefPrimitive::Str) => {
  218. assert_eq!(bar_ty.path, path!("string"))
  219. }
  220. _ => panic!("expected string type"),
  221. }
  222. }
  223. _ => panic!("expected Foo(Bar) type"),
  224. };
  225. // Asserts for ERC721InsufficientApproval
  226. let erc721_ty = abi.registry().resolve(erc721_ty_id).unwrap();
  227. let (operator, token_id) = match &erc721_ty.type_def {
  228. TypeDef::<PortableForm>::Composite(TypeDefComposite::<PortableForm> { fields }) => {
  229. assert_eq!(erc721_ty.path, path!("0x8799e34a"));
  230. assert_eq!(fields.len(), 2);
  231. (&fields[0], &fields[1])
  232. }
  233. _ => panic!("expected ERC721InsufficientApproval(string,uint256) type"),
  234. };
  235. let operator_ty = abi.registry().resolve(operator.ty.id).unwrap();
  236. match &operator_ty.type_def {
  237. TypeDef::<PortableForm>::Primitive(TypeDefPrimitive::Str) => {
  238. assert_eq!(operator_ty.path, path!("string"))
  239. }
  240. _ => panic!("expected string type"),
  241. }
  242. let bar_ty = abi.registry().resolve(token_id.ty.id).unwrap();
  243. match &bar_ty.type_def {
  244. TypeDef::<PortableForm>::Primitive(TypeDefPrimitive::U256) => {
  245. assert_eq!(bar_ty.path, path!("uint256"))
  246. }
  247. _ => panic!("expected uint256 type"),
  248. }
  249. }