balance.rs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546
  1. // SPDX-License-Identifier: Apache-2.0
  2. use crate::{account_new, build_solidity, AccountMeta, AccountState, BorshToken, Pubkey};
  3. use anchor_syn::idl::IdlInstruction;
  4. use num_bigint::BigInt;
  5. #[test]
  6. fn get_balance() {
  7. let mut vm = build_solidity(
  8. r#"
  9. contract c {
  10. function test(address addr) public view returns (uint64) {
  11. return addr.balance;
  12. }
  13. }"#,
  14. );
  15. let data_account = vm.initialize_data_account();
  16. vm.function("new")
  17. .accounts(vec![("dataAccount", data_account)])
  18. .call();
  19. let new = account_new();
  20. vm.account_data.insert(
  21. new,
  22. AccountState {
  23. data: Vec::new(),
  24. owner: None,
  25. lamports: 102,
  26. },
  27. );
  28. let returns = vm
  29. .function("test")
  30. .arguments(&[BorshToken::Address(new)])
  31. .accounts(vec![("dataAccount", data_account)])
  32. .remaining_accounts(&[AccountMeta {
  33. pubkey: Pubkey(new),
  34. is_signer: false,
  35. is_writable: false,
  36. }])
  37. .call()
  38. .unwrap();
  39. assert_eq!(
  40. returns,
  41. BorshToken::Uint {
  42. width: 64,
  43. value: BigInt::from(102u8),
  44. }
  45. );
  46. }
  47. #[test]
  48. fn send_fails() {
  49. let mut vm = build_solidity(
  50. r#"
  51. contract c {
  52. function send(address payable addr, uint64 amount) public returns (bool) {
  53. return addr.send(amount);
  54. }
  55. }"#,
  56. );
  57. let data_account = vm.initialize_data_account();
  58. vm.function("new")
  59. .accounts(vec![("dataAccount", data_account)])
  60. .call();
  61. let new = account_new();
  62. vm.account_data.insert(
  63. new,
  64. AccountState {
  65. data: Vec::new(),
  66. owner: None,
  67. lamports: 0,
  68. },
  69. );
  70. let returns = vm
  71. .function("send")
  72. .arguments(&[
  73. BorshToken::Address(new),
  74. BorshToken::Uint {
  75. width: 64,
  76. value: BigInt::from(102u8),
  77. },
  78. ])
  79. .accounts(vec![("dataAccount", data_account)])
  80. .remaining_accounts(&[AccountMeta {
  81. pubkey: Pubkey(new),
  82. is_signer: false,
  83. is_writable: true,
  84. }])
  85. .call()
  86. .unwrap();
  87. assert_eq!(returns, BorshToken::Bool(false));
  88. }
  89. #[test]
  90. fn send_succeeds() {
  91. let mut vm = build_solidity(
  92. r#"
  93. contract c {
  94. constructor() payable {}
  95. function send(address payable addr, uint64 amount) public returns (bool) {
  96. return addr.send(amount);
  97. }
  98. }"#,
  99. );
  100. let data_account = vm.initialize_data_account();
  101. vm.account_data.get_mut(&data_account).unwrap().lamports = 103;
  102. vm.function("new")
  103. .accounts(vec![("dataAccount", data_account)])
  104. .call();
  105. let new = account_new();
  106. vm.account_data.insert(
  107. new,
  108. AccountState {
  109. data: Vec::new(),
  110. owner: None,
  111. lamports: 5,
  112. },
  113. );
  114. let returns = vm
  115. .function("send")
  116. .arguments(&[
  117. BorshToken::FixedBytes(new.to_vec()),
  118. BorshToken::Uint {
  119. width: 64,
  120. value: BigInt::from(102u8),
  121. },
  122. ])
  123. .accounts(vec![("dataAccount", data_account)])
  124. .remaining_accounts(&[AccountMeta {
  125. pubkey: Pubkey(new),
  126. is_signer: false,
  127. is_writable: true,
  128. }])
  129. .call()
  130. .unwrap();
  131. assert_eq!(returns, BorshToken::Bool(true));
  132. assert_eq!(vm.account_data.get_mut(&new).unwrap().lamports, 107);
  133. assert_eq!(vm.account_data.get_mut(&data_account).unwrap().lamports, 1);
  134. }
  135. #[test]
  136. fn send_overflows() {
  137. let mut vm = build_solidity(
  138. r#"
  139. contract c {
  140. function send(address payable addr, uint64 amount) public returns (bool) {
  141. return addr.send(amount);
  142. }
  143. }"#,
  144. );
  145. let data_account = vm.initialize_data_account();
  146. vm.account_data.get_mut(&data_account).unwrap().lamports = 103;
  147. vm.function("new")
  148. .accounts(vec![("dataAccount", data_account)])
  149. .call();
  150. let new = account_new();
  151. vm.account_data.insert(
  152. new,
  153. AccountState {
  154. data: Vec::new(),
  155. owner: None,
  156. lamports: u64::MAX - 101,
  157. },
  158. );
  159. let returns = vm
  160. .function("send")
  161. .arguments(&[
  162. BorshToken::Address(new),
  163. BorshToken::Uint {
  164. width: 64,
  165. value: BigInt::from(102u8),
  166. },
  167. ])
  168. .accounts(vec![("dataAccount", data_account)])
  169. .remaining_accounts(&[AccountMeta {
  170. pubkey: Pubkey(new),
  171. is_signer: false,
  172. is_writable: true,
  173. }])
  174. .call()
  175. .unwrap();
  176. assert_eq!(returns, BorshToken::Bool(false));
  177. assert_eq!(
  178. vm.account_data.get_mut(&new).unwrap().lamports,
  179. u64::MAX - 101
  180. );
  181. assert_eq!(
  182. vm.account_data.get_mut(&data_account).unwrap().lamports,
  183. 103
  184. );
  185. }
  186. #[test]
  187. fn transfer_succeeds() {
  188. let mut vm = build_solidity(
  189. r#"
  190. contract c {
  191. function transfer(address payable addr, uint64 amount) public {
  192. addr.transfer(amount);
  193. }
  194. }"#,
  195. );
  196. let data_account = vm.initialize_data_account();
  197. vm.account_data.get_mut(&data_account).unwrap().lamports = 103;
  198. vm.function("new")
  199. .accounts(vec![("dataAccount", data_account)])
  200. .call();
  201. let new = account_new();
  202. vm.account_data.insert(
  203. new,
  204. AccountState {
  205. data: Vec::new(),
  206. owner: None,
  207. lamports: 5,
  208. },
  209. );
  210. vm.function("transfer")
  211. .arguments(&[
  212. BorshToken::Address(new),
  213. BorshToken::Uint {
  214. width: 64,
  215. value: BigInt::from(102u8),
  216. },
  217. ])
  218. .accounts(vec![("dataAccount", data_account)])
  219. .remaining_accounts(&[AccountMeta {
  220. pubkey: Pubkey(new),
  221. is_signer: false,
  222. is_writable: true,
  223. }])
  224. .call();
  225. assert_eq!(vm.account_data.get_mut(&new).unwrap().lamports, 107);
  226. assert_eq!(vm.account_data.get_mut(&data_account).unwrap().lamports, 1);
  227. }
  228. #[test]
  229. fn transfer_fails_not_enough() {
  230. let mut vm = build_solidity(
  231. r#"
  232. contract c {
  233. function transfer(address payable addr, uint64 amount) public {
  234. addr.transfer(amount);
  235. }
  236. }"#,
  237. );
  238. let data_account = vm.initialize_data_account();
  239. vm.account_data.get_mut(&data_account).unwrap().lamports = 103;
  240. vm.function("new")
  241. .accounts(vec![("dataAccount", data_account)])
  242. .call();
  243. let new = account_new();
  244. vm.account_data.insert(
  245. new,
  246. AccountState {
  247. data: Vec::new(),
  248. owner: None,
  249. lamports: 5,
  250. },
  251. );
  252. let res = vm
  253. .function("transfer")
  254. .arguments(&[
  255. BorshToken::Address(new),
  256. BorshToken::Uint {
  257. width: 64,
  258. value: BigInt::from(104u8),
  259. },
  260. ])
  261. .accounts(vec![("dataAccount", data_account)])
  262. .remaining_accounts(&[AccountMeta {
  263. pubkey: Pubkey(new),
  264. is_signer: false,
  265. is_writable: true,
  266. }])
  267. .must_fail();
  268. assert!(res.is_err());
  269. // Ensure the balance in the account has not overflowed
  270. assert_eq!(vm.account_data[&data_account].lamports, 103);
  271. assert_eq!(vm.account_data[&new].lamports, 5);
  272. vm.function("transfer")
  273. .arguments(&[
  274. BorshToken::Address(new),
  275. BorshToken::Uint {
  276. width: 64,
  277. value: BigInt::from(103u8),
  278. },
  279. ])
  280. .accounts(vec![("dataAccount", data_account)])
  281. .remaining_accounts(&[AccountMeta {
  282. pubkey: Pubkey(new),
  283. is_signer: false,
  284. is_writable: true,
  285. }])
  286. .call();
  287. assert_eq!(vm.account_data[&data_account].lamports, 0);
  288. assert_eq!(vm.account_data[&new].lamports, 108);
  289. }
  290. #[test]
  291. fn transfer_fails_overflow() {
  292. let mut vm = build_solidity(
  293. r#"
  294. contract c {
  295. constructor() payable {}
  296. function transfer(address payable addr, uint64 amount) public {
  297. addr.transfer(amount);
  298. }
  299. }"#,
  300. );
  301. let data_account = vm.initialize_data_account();
  302. vm.account_data.get_mut(&data_account).unwrap().lamports = 104;
  303. vm.function("new")
  304. .accounts(vec![("dataAccount", data_account)])
  305. .call();
  306. let new = account_new();
  307. vm.account_data.insert(
  308. new,
  309. AccountState {
  310. data: Vec::new(),
  311. owner: None,
  312. lamports: u64::MAX - 100,
  313. },
  314. );
  315. let res = vm
  316. .function("transfer")
  317. .arguments(&[
  318. BorshToken::FixedBytes(new.to_vec()),
  319. BorshToken::Uint {
  320. width: 64,
  321. value: BigInt::from(104u8),
  322. },
  323. ])
  324. .accounts(vec![("dataAccount", data_account)])
  325. .remaining_accounts(&[AccountMeta {
  326. pubkey: Pubkey(new),
  327. is_writable: false,
  328. is_signer: true,
  329. }])
  330. .must_fail();
  331. assert!(res.is_err());
  332. // Ensure no change in the values
  333. assert_eq!(vm.account_data[&new].lamports, u64::MAX - 100);
  334. assert_eq!(vm.account_data[&data_account].lamports, 104);
  335. vm.function("transfer")
  336. .arguments(&[
  337. BorshToken::FixedBytes(new.to_vec()),
  338. BorshToken::Uint {
  339. width: 64,
  340. value: BigInt::from(100u8),
  341. },
  342. ])
  343. .accounts(vec![("dataAccount", data_account)])
  344. .remaining_accounts(&[AccountMeta {
  345. pubkey: Pubkey(new),
  346. is_writable: false,
  347. is_signer: true,
  348. }])
  349. .call();
  350. assert_eq!(vm.account_data[&new].lamports, u64::MAX);
  351. assert_eq!(vm.account_data[&data_account].lamports, 4);
  352. }
  353. #[test]
  354. fn fallback() {
  355. let mut vm = build_solidity(
  356. r#"
  357. contract c {
  358. fallback() external {
  359. print("fallback");
  360. }
  361. }"#,
  362. );
  363. let data_account = vm.initialize_data_account();
  364. vm.function("new")
  365. .accounts(vec![("dataAccount", data_account)])
  366. .call();
  367. if let Some(idl) = &vm.stack[0].idl {
  368. let mut idl = idl.clone();
  369. idl.instructions.push(IdlInstruction {
  370. name: "extinct".to_string(),
  371. docs: None,
  372. accounts: vec![],
  373. args: vec![],
  374. returns: None,
  375. });
  376. vm.stack[0].idl = Some(idl);
  377. }
  378. vm.function("extinct").call();
  379. assert_eq!(vm.logs, "fallback");
  380. }
  381. #[test]
  382. fn value_overflows() {
  383. let mut vm = build_solidity(
  384. r#"
  385. contract c {
  386. constructor() payable {}
  387. function send(address payable addr, uint128 amount) public returns (bool) {
  388. return addr.send(amount);
  389. }
  390. }"#,
  391. );
  392. let data_account = vm.initialize_data_account();
  393. vm.account_data.get_mut(&data_account).unwrap().lamports = 103;
  394. vm.function("new")
  395. .accounts(vec![("dataAccount", data_account)])
  396. .call();
  397. let new = account_new();
  398. vm.account_data.insert(
  399. new,
  400. AccountState {
  401. data: Vec::new(),
  402. owner: None,
  403. lamports: u64::MAX - 101,
  404. },
  405. );
  406. let res = vm
  407. .function("send")
  408. .arguments(&[
  409. BorshToken::Address(new),
  410. BorshToken::Uint {
  411. width: 128,
  412. value: BigInt::from(u64::MAX as u128 + 1),
  413. },
  414. ])
  415. .accounts(vec![("dataAccount", data_account)])
  416. .remaining_accounts(&[AccountMeta {
  417. pubkey: Pubkey(new),
  418. is_signer: false,
  419. is_writable: true,
  420. }])
  421. .must_fail();
  422. assert_eq!(res.unwrap(), 4294967296);
  423. let res = vm
  424. .function("send")
  425. .arguments(&[
  426. BorshToken::Address(new),
  427. BorshToken::Uint {
  428. width: 128,
  429. value: BigInt::from(u128::MAX),
  430. },
  431. ])
  432. .accounts(vec![("dataAccount", data_account)])
  433. .remaining_accounts(&[AccountMeta {
  434. pubkey: Pubkey(new),
  435. is_signer: false,
  436. is_writable: true,
  437. }])
  438. .must_fail();
  439. assert_eq!(res.unwrap(), 4294967296);
  440. let returns = vm
  441. .function("send")
  442. .arguments(&[
  443. BorshToken::Address(new),
  444. BorshToken::Uint {
  445. width: 128,
  446. value: BigInt::from(102u8),
  447. },
  448. ])
  449. .accounts(vec![("dataAccount", data_account)])
  450. .remaining_accounts(&[AccountMeta {
  451. pubkey: Pubkey(new),
  452. is_signer: false,
  453. is_writable: true,
  454. }])
  455. .call()
  456. .unwrap();
  457. assert_eq!(returns, BorshToken::Bool(false));
  458. assert_eq!(
  459. vm.account_data.get_mut(&new).unwrap().lamports,
  460. u64::MAX - 101
  461. );
  462. assert_eq!(
  463. vm.account_data.get_mut(&data_account).unwrap().lamports,
  464. 103
  465. );
  466. }