ERC4626.test.js 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612
  1. const { BN, constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers');
  2. const { expect } = require('chai');
  3. const ERC20DecimalsMock = artifacts.require('ERC20DecimalsMock');
  4. const ERC4626Mock = artifacts.require('ERC4626Mock');
  5. const parseToken = (token) => (new BN(token)).mul(new BN('1000000000000'));
  6. const parseShare = (share) => (new BN(share)).mul(new BN('1000000000000000000'));
  7. contract('ERC4626', function (accounts) {
  8. const [ holder, recipient, spender, other, user1, user2 ] = accounts;
  9. const name = 'My Token';
  10. const symbol = 'MTKN';
  11. beforeEach(async function () {
  12. this.token = await ERC20DecimalsMock.new(name, symbol, 12);
  13. this.vault = await ERC4626Mock.new(this.token.address, name + ' Vault', symbol + 'V');
  14. await this.token.mint(holder, web3.utils.toWei('100'));
  15. await this.token.approve(this.vault.address, constants.MAX_UINT256, { from: holder });
  16. await this.vault.approve(spender, constants.MAX_UINT256, { from: holder });
  17. });
  18. it('metadata', async function () {
  19. expect(await this.vault.name()).to.be.equal(name + ' Vault');
  20. expect(await this.vault.symbol()).to.be.equal(symbol + 'V');
  21. expect(await this.vault.asset()).to.be.equal(this.token.address);
  22. });
  23. describe('empty vault: no assets & no shares', function () {
  24. it('status', async function () {
  25. expect(await this.vault.totalAssets()).to.be.bignumber.equal('0');
  26. });
  27. it('deposit', async function () {
  28. expect(await this.vault.maxDeposit(holder)).to.be.bignumber.equal(constants.MAX_UINT256);
  29. expect(await this.vault.previewDeposit(parseToken(1))).to.be.bignumber.equal(parseShare(1));
  30. const { tx } = await this.vault.deposit(parseToken(1), recipient, { from: holder });
  31. expectEvent.inTransaction(tx, this.token, 'Transfer', {
  32. from: holder,
  33. to: this.vault.address,
  34. value: parseToken(1),
  35. });
  36. expectEvent.inTransaction(tx, this.vault, 'Transfer', {
  37. from: constants.ZERO_ADDRESS,
  38. to: recipient,
  39. value: parseShare(1),
  40. });
  41. });
  42. it('mint', async function () {
  43. expect(await this.vault.maxMint(holder)).to.be.bignumber.equal(constants.MAX_UINT256);
  44. expect(await this.vault.previewMint(parseShare(1))).to.be.bignumber.equal(parseToken(1));
  45. const { tx } = await this.vault.mint(parseShare(1), recipient, { from: holder });
  46. expectEvent.inTransaction(tx, this.token, 'Transfer', {
  47. from: holder,
  48. to: this.vault.address,
  49. value: parseToken(1),
  50. });
  51. expectEvent.inTransaction(tx, this.vault, 'Transfer', {
  52. from: constants.ZERO_ADDRESS,
  53. to: recipient,
  54. value: parseShare(1),
  55. });
  56. });
  57. it('withdraw', async function () {
  58. expect(await this.vault.maxWithdraw(holder)).to.be.bignumber.equal('0');
  59. expect(await this.vault.previewWithdraw('0')).to.be.bignumber.equal('0');
  60. const { tx } = await this.vault.withdraw('0', recipient, holder, { from: holder });
  61. expectEvent.inTransaction(tx, this.token, 'Transfer', {
  62. from: this.vault.address,
  63. to: recipient,
  64. value: '0',
  65. });
  66. expectEvent.inTransaction(tx, this.vault, 'Transfer', {
  67. from: holder,
  68. to: constants.ZERO_ADDRESS,
  69. value: '0',
  70. });
  71. });
  72. it('redeem', async function () {
  73. expect(await this.vault.maxRedeem(holder)).to.be.bignumber.equal('0');
  74. expect(await this.vault.previewRedeem('0')).to.be.bignumber.equal('0');
  75. const { tx } = await this.vault.redeem('0', recipient, holder, { from: holder });
  76. expectEvent.inTransaction(tx, this.token, 'Transfer', {
  77. from: this.vault.address,
  78. to: recipient,
  79. value: '0',
  80. });
  81. expectEvent.inTransaction(tx, this.vault, 'Transfer', {
  82. from: holder,
  83. to: constants.ZERO_ADDRESS,
  84. value: '0',
  85. });
  86. });
  87. });
  88. describe('partially empty vault: assets & no shares', function () {
  89. beforeEach(async function () {
  90. await this.token.mint(this.vault.address, parseToken(1)); // 1 token
  91. });
  92. it('status', async function () {
  93. expect(await this.vault.totalAssets()).to.be.bignumber.equal(parseToken(1));
  94. });
  95. it('deposit', async function () {
  96. expect(await this.vault.maxDeposit(holder)).to.be.bignumber.equal(constants.MAX_UINT256);
  97. expect(await this.vault.previewDeposit(parseToken(1))).to.be.bignumber.equal(parseShare(1));
  98. const { tx } = await this.vault.deposit(parseToken(1), recipient, { from: holder });
  99. expectEvent.inTransaction(tx, this.token, 'Transfer', {
  100. from: holder,
  101. to: this.vault.address,
  102. value: parseToken(1),
  103. });
  104. expectEvent.inTransaction(tx, this.vault, 'Transfer', {
  105. from: constants.ZERO_ADDRESS,
  106. to: recipient,
  107. value: parseShare(1),
  108. });
  109. });
  110. it('mint', async function () {
  111. expect(await this.vault.maxMint(holder)).to.be.bignumber.equal(constants.MAX_UINT256);
  112. expect(await this.vault.previewMint(parseShare(1))).to.be.bignumber.equal(parseToken(1));
  113. const { tx } = await this.vault.mint(parseShare(1), recipient, { from: holder });
  114. expectEvent.inTransaction(tx, this.token, 'Transfer', {
  115. from: holder,
  116. to: this.vault.address,
  117. value: parseToken(1),
  118. });
  119. expectEvent.inTransaction(tx, this.vault, 'Transfer', {
  120. from: constants.ZERO_ADDRESS,
  121. to: recipient,
  122. value: parseShare(1),
  123. });
  124. });
  125. it('withdraw', async function () {
  126. expect(await this.vault.maxWithdraw(holder)).to.be.bignumber.equal('0');
  127. expect(await this.vault.previewWithdraw('0')).to.be.bignumber.equal('0');
  128. const { tx } = await this.vault.withdraw('0', recipient, holder, { from: holder });
  129. expectEvent.inTransaction(tx, this.token, 'Transfer', {
  130. from: this.vault.address,
  131. to: recipient,
  132. value: '0',
  133. });
  134. expectEvent.inTransaction(tx, this.vault, 'Transfer', {
  135. from: holder,
  136. to: constants.ZERO_ADDRESS,
  137. value: '0',
  138. });
  139. });
  140. it('redeem', async function () {
  141. expect(await this.vault.maxRedeem(holder)).to.be.bignumber.equal('0');
  142. expect(await this.vault.previewRedeem('0')).to.be.bignumber.equal('0');
  143. const { tx } = await this.vault.redeem('0', recipient, holder, { from: holder });
  144. expectEvent.inTransaction(tx, this.token, 'Transfer', {
  145. from: this.vault.address,
  146. to: recipient,
  147. value: '0',
  148. });
  149. expectEvent.inTransaction(tx, this.vault, 'Transfer', {
  150. from: holder,
  151. to: constants.ZERO_ADDRESS,
  152. value: '0',
  153. });
  154. });
  155. });
  156. describe('partially empty vault: shares & no assets', function () {
  157. beforeEach(async function () {
  158. await this.vault.mockMint(holder, parseShare(1)); // 1 share
  159. });
  160. it('status', async function () {
  161. expect(await this.vault.totalAssets()).to.be.bignumber.equal('0');
  162. });
  163. it('deposit', async function () {
  164. expect(await this.vault.maxDeposit(holder)).to.be.bignumber.equal('0');
  165. // Can deposit 0 (max deposit)
  166. const { tx } = await this.vault.deposit(0, recipient, { from: holder });
  167. expectEvent.inTransaction(tx, this.token, 'Transfer', {
  168. from: holder,
  169. to: this.vault.address,
  170. value: 0,
  171. });
  172. expectEvent.inTransaction(tx, this.vault, 'Transfer', {
  173. from: constants.ZERO_ADDRESS,
  174. to: recipient,
  175. value: 0,
  176. });
  177. // Cannot deposit more than 0
  178. await expectRevert.unspecified(this.vault.previewDeposit(parseToken(1)));
  179. await expectRevert(
  180. this.vault.deposit(parseToken(1), recipient, { from: holder }),
  181. 'ERC4626: deposit more than max',
  182. );
  183. });
  184. it('mint', async function () {
  185. expect(await this.vault.maxMint(holder)).to.be.bignumber.equal(constants.MAX_UINT256);
  186. expect(await this.vault.previewMint(parseShare(1))).to.be.bignumber.equal('0');
  187. const { tx } = await this.vault.mint(parseShare(1), recipient, { from: holder });
  188. expectEvent.inTransaction(tx, this.token, 'Transfer', {
  189. from: holder,
  190. to: this.vault.address,
  191. value: '0',
  192. });
  193. expectEvent.inTransaction(tx, this.vault, 'Transfer', {
  194. from: constants.ZERO_ADDRESS,
  195. to: recipient,
  196. value: parseShare(1),
  197. });
  198. });
  199. it('withdraw', async function () {
  200. expect(await this.vault.maxWithdraw(holder)).to.be.bignumber.equal('0');
  201. expect(await this.vault.previewWithdraw('0')).to.be.bignumber.equal('0');
  202. await expectRevert.unspecified(this.vault.previewWithdraw('1'));
  203. const { tx } = await this.vault.withdraw('0', recipient, holder, { from: holder });
  204. expectEvent.inTransaction(tx, this.token, 'Transfer', {
  205. from: this.vault.address,
  206. to: recipient,
  207. value: '0',
  208. });
  209. expectEvent.inTransaction(tx, this.vault, 'Transfer', {
  210. from: holder,
  211. to: constants.ZERO_ADDRESS,
  212. value: '0',
  213. });
  214. });
  215. it('redeem', async function () {
  216. expect(await this.vault.maxRedeem(holder)).to.be.bignumber.equal(parseShare(1));
  217. expect(await this.vault.previewRedeem(parseShare(1))).to.be.bignumber.equal('0');
  218. const { tx } = await this.vault.redeem(parseShare(1), recipient, holder, { from: holder });
  219. expectEvent.inTransaction(tx, this.token, 'Transfer', {
  220. from: this.vault.address,
  221. to: recipient,
  222. value: '0',
  223. });
  224. expectEvent.inTransaction(tx, this.vault, 'Transfer', {
  225. from: holder,
  226. to: constants.ZERO_ADDRESS,
  227. value: parseShare(1),
  228. });
  229. });
  230. });
  231. describe('full vault: assets & shares', function () {
  232. beforeEach(async function () {
  233. await this.token.mint(this.vault.address, parseToken(1)); // 1 tokens
  234. await this.vault.mockMint(holder, parseShare(100)); // 100 share
  235. });
  236. it('status', async function () {
  237. expect(await this.vault.totalAssets()).to.be.bignumber.equal(parseToken(1));
  238. });
  239. it('deposit', async function () {
  240. expect(await this.vault.maxDeposit(holder)).to.be.bignumber.equal(constants.MAX_UINT256);
  241. expect(await this.vault.previewDeposit(parseToken(1))).to.be.bignumber.equal(parseShare(100));
  242. const { tx } = await this.vault.deposit(parseToken(1), recipient, { from: holder });
  243. expectEvent.inTransaction(tx, this.token, 'Transfer', {
  244. from: holder,
  245. to: this.vault.address,
  246. value: parseToken(1),
  247. });
  248. expectEvent.inTransaction(tx, this.vault, 'Transfer', {
  249. from: constants.ZERO_ADDRESS,
  250. to: recipient,
  251. value: parseShare(100),
  252. });
  253. });
  254. it('mint', async function () {
  255. expect(await this.vault.maxMint(holder)).to.be.bignumber.equal(constants.MAX_UINT256);
  256. expect(await this.vault.previewMint(parseShare(1))).to.be.bignumber.equal(parseToken(1).divn(100));
  257. const { tx } = await this.vault.mint(parseShare(1), recipient, { from: holder });
  258. expectEvent.inTransaction(tx, this.token, 'Transfer', {
  259. from: holder,
  260. to: this.vault.address,
  261. value: parseToken(1).divn(100),
  262. });
  263. expectEvent.inTransaction(tx, this.vault, 'Transfer', {
  264. from: constants.ZERO_ADDRESS,
  265. to: recipient,
  266. value: parseShare(1),
  267. });
  268. });
  269. it('withdraw', async function () {
  270. expect(await this.vault.maxWithdraw(holder)).to.be.bignumber.equal(parseToken(1));
  271. expect(await this.vault.previewWithdraw(parseToken(1))).to.be.bignumber.equal(parseShare(100));
  272. const { tx } = await this.vault.withdraw(parseToken(1), recipient, holder, { from: holder });
  273. expectEvent.inTransaction(tx, this.token, 'Transfer', {
  274. from: this.vault.address,
  275. to: recipient,
  276. value: parseToken(1),
  277. });
  278. expectEvent.inTransaction(tx, this.vault, 'Transfer', {
  279. from: holder,
  280. to: constants.ZERO_ADDRESS,
  281. value: parseShare(100),
  282. });
  283. });
  284. it('withdraw with approval', async function () {
  285. await expectRevert(
  286. this.vault.withdraw(parseToken(1), recipient, holder, { from: other }),
  287. 'ERC20: insufficient allowance',
  288. );
  289. await this.vault.withdraw(parseToken(1), recipient, holder, { from: spender });
  290. });
  291. it('redeem', async function () {
  292. expect(await this.vault.maxRedeem(holder)).to.be.bignumber.equal(parseShare(100));
  293. expect(await this.vault.previewRedeem(parseShare(100))).to.be.bignumber.equal(parseToken(1));
  294. const { tx } = await this.vault.redeem(parseShare(100), recipient, holder, { from: holder });
  295. expectEvent.inTransaction(tx, this.token, 'Transfer', {
  296. from: this.vault.address,
  297. to: recipient,
  298. value: parseToken(1),
  299. });
  300. expectEvent.inTransaction(tx, this.vault, 'Transfer', {
  301. from: holder,
  302. to: constants.ZERO_ADDRESS,
  303. value: parseShare(100),
  304. });
  305. });
  306. it('redeem with approval', async function () {
  307. await expectRevert(
  308. this.vault.redeem(parseShare(100), recipient, holder, { from: other }),
  309. 'ERC20: insufficient allowance',
  310. );
  311. await this.vault.redeem(parseShare(100), recipient, holder, { from: spender });
  312. });
  313. });
  314. /// Scenario inspired by solmate ERC4626 tests:
  315. /// https://github.com/Rari-Capital/solmate/blob/main/src/test/ERC4626.t.sol
  316. it('multiple mint, deposit, redeem & withdrawal', async function () {
  317. // test designed with both asset using similar decimals
  318. this.token = await ERC20DecimalsMock.new(name, symbol, 18);
  319. this.vault = await ERC4626Mock.new(this.token.address, name + ' Vault', symbol + 'V');
  320. await this.token.mint(user1, 4000);
  321. await this.token.mint(user2, 7001);
  322. await this.token.approve(this.vault.address, 4000, { from: user1 });
  323. await this.token.approve(this.vault.address, 7001, { from: user2 });
  324. // 1. Alice mints 2000 shares (costs 2000 tokens)
  325. {
  326. const { tx } = await this.vault.mint(2000, user1, { from: user1 });
  327. expectEvent.inTransaction(tx, this.token, 'Transfer', {
  328. from: user1,
  329. to: this.vault.address,
  330. value: '2000',
  331. });
  332. expectEvent.inTransaction(tx, this.vault, 'Transfer', {
  333. from: constants.ZERO_ADDRESS,
  334. to: user1,
  335. value: '2000',
  336. });
  337. expect(await this.vault.previewDeposit(2000)).to.be.bignumber.equal('2000');
  338. expect(await this.vault.balanceOf(user1)).to.be.bignumber.equal('2000');
  339. expect(await this.vault.balanceOf(user2)).to.be.bignumber.equal('0');
  340. expect(await this.vault.convertToAssets(await this.vault.balanceOf(user1))).to.be.bignumber.equal('2000');
  341. expect(await this.vault.convertToAssets(await this.vault.balanceOf(user2))).to.be.bignumber.equal('0');
  342. expect(await this.vault.totalSupply()).to.be.bignumber.equal('2000');
  343. expect(await this.vault.totalAssets()).to.be.bignumber.equal('2000');
  344. }
  345. // 2. Bob deposits 4000 tokens (mints 4000 shares)
  346. {
  347. const { tx } = await this.vault.mint(4000, user2, { from: user2 });
  348. expectEvent.inTransaction(tx, this.token, 'Transfer', {
  349. from: user2,
  350. to: this.vault.address,
  351. value: '4000',
  352. });
  353. expectEvent.inTransaction(tx, this.vault, 'Transfer', {
  354. from: constants.ZERO_ADDRESS,
  355. to: user2,
  356. value: '4000',
  357. });
  358. expect(await this.vault.previewDeposit(4000)).to.be.bignumber.equal('4000');
  359. expect(await this.vault.balanceOf(user1)).to.be.bignumber.equal('2000');
  360. expect(await this.vault.balanceOf(user2)).to.be.bignumber.equal('4000');
  361. expect(await this.vault.convertToAssets(await this.vault.balanceOf(user1))).to.be.bignumber.equal('2000');
  362. expect(await this.vault.convertToAssets(await this.vault.balanceOf(user2))).to.be.bignumber.equal('4000');
  363. expect(await this.vault.totalSupply()).to.be.bignumber.equal('6000');
  364. expect(await this.vault.totalAssets()).to.be.bignumber.equal('6000');
  365. }
  366. // 3. Vault mutates by +3000 tokens (simulated yield returned from strategy)
  367. await this.token.mint(this.vault.address, 3000);
  368. expect(await this.vault.balanceOf(user1)).to.be.bignumber.equal('2000');
  369. expect(await this.vault.balanceOf(user2)).to.be.bignumber.equal('4000');
  370. expect(await this.vault.convertToAssets(await this.vault.balanceOf(user1))).to.be.bignumber.equal('3000');
  371. expect(await this.vault.convertToAssets(await this.vault.balanceOf(user2))).to.be.bignumber.equal('6000');
  372. expect(await this.vault.totalSupply()).to.be.bignumber.equal('6000');
  373. expect(await this.vault.totalAssets()).to.be.bignumber.equal('9000');
  374. // 4. Alice deposits 2000 tokens (mints 1333 shares)
  375. {
  376. const { tx } = await this.vault.deposit(2000, user1, { from: user1 });
  377. expectEvent.inTransaction(tx, this.token, 'Transfer', {
  378. from: user1,
  379. to: this.vault.address,
  380. value: '2000',
  381. });
  382. expectEvent.inTransaction(tx, this.vault, 'Transfer', {
  383. from: constants.ZERO_ADDRESS,
  384. to: user1,
  385. value: '1333',
  386. });
  387. expect(await this.vault.balanceOf(user1)).to.be.bignumber.equal('3333');
  388. expect(await this.vault.balanceOf(user2)).to.be.bignumber.equal('4000');
  389. expect(await this.vault.convertToAssets(await this.vault.balanceOf(user1))).to.be.bignumber.equal('4999');
  390. expect(await this.vault.convertToAssets(await this.vault.balanceOf(user2))).to.be.bignumber.equal('6000');
  391. expect(await this.vault.totalSupply()).to.be.bignumber.equal('7333');
  392. expect(await this.vault.totalAssets()).to.be.bignumber.equal('11000');
  393. }
  394. // 5. Bob mints 2000 shares (costs 3001 assets)
  395. // NOTE: Bob's assets spent got rounded up
  396. // NOTE: Alices's vault assets got rounded up
  397. {
  398. const { tx } = await this.vault.mint(2000, user2, { from: user2 });
  399. expectEvent.inTransaction(tx, this.token, 'Transfer', {
  400. from: user2,
  401. to: this.vault.address,
  402. value: '3001',
  403. });
  404. expectEvent.inTransaction(tx, this.vault, 'Transfer', {
  405. from: constants.ZERO_ADDRESS,
  406. to: user2,
  407. value: '2000',
  408. });
  409. expect(await this.vault.balanceOf(user1)).to.be.bignumber.equal('3333');
  410. expect(await this.vault.balanceOf(user2)).to.be.bignumber.equal('6000');
  411. expect(await this.vault.convertToAssets(await this.vault.balanceOf(user1))).to.be.bignumber.equal('5000');
  412. expect(await this.vault.convertToAssets(await this.vault.balanceOf(user2))).to.be.bignumber.equal('9000');
  413. expect(await this.vault.totalSupply()).to.be.bignumber.equal('9333');
  414. expect(await this.vault.totalAssets()).to.be.bignumber.equal('14001');
  415. }
  416. // 6. Vault mutates by +3000 tokens
  417. // NOTE: Vault holds 17001 tokens, but sum of assetsOf() is 17000.
  418. await this.token.mint(this.vault.address, 3000);
  419. expect(await this.vault.balanceOf(user1)).to.be.bignumber.equal('3333');
  420. expect(await this.vault.balanceOf(user2)).to.be.bignumber.equal('6000');
  421. expect(await this.vault.convertToAssets(await this.vault.balanceOf(user1))).to.be.bignumber.equal('6071');
  422. expect(await this.vault.convertToAssets(await this.vault.balanceOf(user2))).to.be.bignumber.equal('10929');
  423. expect(await this.vault.totalSupply()).to.be.bignumber.equal('9333');
  424. expect(await this.vault.totalAssets()).to.be.bignumber.equal('17001');
  425. // 7. Alice redeem 1333 shares (2428 assets)
  426. {
  427. const { tx } = await this.vault.redeem(1333, user1, user1, { from: user1 });
  428. expectEvent.inTransaction(tx, this.vault, 'Transfer', {
  429. from: user1,
  430. to: constants.ZERO_ADDRESS,
  431. value: '1333',
  432. });
  433. expectEvent.inTransaction(tx, this.token, 'Transfer', {
  434. from: this.vault.address,
  435. to: user1,
  436. value: '2428',
  437. });
  438. expect(await this.vault.balanceOf(user1)).to.be.bignumber.equal('2000');
  439. expect(await this.vault.balanceOf(user2)).to.be.bignumber.equal('6000');
  440. expect(await this.vault.convertToAssets(await this.vault.balanceOf(user1))).to.be.bignumber.equal('3643');
  441. expect(await this.vault.convertToAssets(await this.vault.balanceOf(user2))).to.be.bignumber.equal('10929');
  442. expect(await this.vault.totalSupply()).to.be.bignumber.equal('8000');
  443. expect(await this.vault.totalAssets()).to.be.bignumber.equal('14573');
  444. }
  445. // 8. Bob withdraws 2929 assets (1608 shares)
  446. {
  447. const { tx } = await this.vault.withdraw(2929, user2, user2, { from: user2 });
  448. expectEvent.inTransaction(tx, this.vault, 'Transfer', {
  449. from: user2,
  450. to: constants.ZERO_ADDRESS,
  451. value: '1608',
  452. });
  453. expectEvent.inTransaction(tx, this.token, 'Transfer', {
  454. from: this.vault.address,
  455. to: user2,
  456. value: '2929',
  457. });
  458. expect(await this.vault.balanceOf(user1)).to.be.bignumber.equal('2000');
  459. expect(await this.vault.balanceOf(user2)).to.be.bignumber.equal('4392');
  460. expect(await this.vault.convertToAssets(await this.vault.balanceOf(user1))).to.be.bignumber.equal('3643');
  461. expect(await this.vault.convertToAssets(await this.vault.balanceOf(user2))).to.be.bignumber.equal('8000');
  462. expect(await this.vault.totalSupply()).to.be.bignumber.equal('6392');
  463. expect(await this.vault.totalAssets()).to.be.bignumber.equal('11644');
  464. }
  465. // 9. Alice withdraws 3643 assets (2000 shares)
  466. // NOTE: Bob's assets have been rounded back up
  467. {
  468. const { tx } = await this.vault.withdraw(3643, user1, user1, { from: user1 });
  469. expectEvent.inTransaction(tx, this.vault, 'Transfer', {
  470. from: user1,
  471. to: constants.ZERO_ADDRESS,
  472. value: '2000',
  473. });
  474. expectEvent.inTransaction(tx, this.token, 'Transfer', {
  475. from: this.vault.address,
  476. to: user1,
  477. value: '3643',
  478. });
  479. expect(await this.vault.balanceOf(user1)).to.be.bignumber.equal('0');
  480. expect(await this.vault.balanceOf(user2)).to.be.bignumber.equal('4392');
  481. expect(await this.vault.convertToAssets(await this.vault.balanceOf(user1))).to.be.bignumber.equal('0');
  482. expect(await this.vault.convertToAssets(await this.vault.balanceOf(user2))).to.be.bignumber.equal('8001');
  483. expect(await this.vault.totalSupply()).to.be.bignumber.equal('4392');
  484. expect(await this.vault.totalAssets()).to.be.bignumber.equal('8001');
  485. }
  486. // 10. Bob redeem 4392 shares (8001 tokens)
  487. {
  488. const { tx } = await this.vault.redeem(4392, user2, user2, { from: user2 });
  489. expectEvent.inTransaction(tx, this.vault, 'Transfer', {
  490. from: user2,
  491. to: constants.ZERO_ADDRESS,
  492. value: '4392',
  493. });
  494. expectEvent.inTransaction(tx, this.token, 'Transfer', {
  495. from: this.vault.address,
  496. to: user2,
  497. value: '8001',
  498. });
  499. expect(await this.vault.balanceOf(user1)).to.be.bignumber.equal('0');
  500. expect(await this.vault.balanceOf(user2)).to.be.bignumber.equal('0');
  501. expect(await this.vault.convertToAssets(await this.vault.balanceOf(user1))).to.be.bignumber.equal('0');
  502. expect(await this.vault.convertToAssets(await this.vault.balanceOf(user2))).to.be.bignumber.equal('0');
  503. expect(await this.vault.totalSupply()).to.be.bignumber.equal('0');
  504. expect(await this.vault.totalAssets()).to.be.bignumber.equal('0');
  505. }
  506. });
  507. });