33} from "@nomicfoundation/hardhat-toolbox/network-helpers" ;
44import { expect } from "chai" ;
55import hre from "hardhat" ;
6+ import { Signature , resolveAddress , MaxUint256 , getBigInt } from "ethers" ;
67import {
78 getCreateAddress , getContractAt , deploy ,
89 ZERO_ADDRESS , ZERO_BYTES32 ,
@@ -38,7 +39,7 @@ describe("LiquidityHub", function () {
3839 await deploy ( "LiquidityHub" , deployer , { nonce : startingNonce + 1 } , lpToken . target , liquidityPool . target )
3940 ) as LiquidityHub ;
4041 const liquidityHubInit = ( await liquidityHubImpl . initialize . populateTransaction (
41- usdc . target , admin . address , admin . address )
42+ usdc . target , admin . address , admin . address , getBigInt ( MaxUint256 ) * USDC / LP )
4243 ) . data ;
4344 const liquidityHubProxy = ( await deploy (
4445 "TransparentUpgradeableProxy" , deployer , { nonce : startingNonce + 2 } ,
@@ -55,7 +56,7 @@ describe("LiquidityHub", function () {
5556 } ;
5657
5758 it ( "Should have default values" , async function ( ) {
58- const { lpToken, liquidityHub, usdc, user, user2, liquidityPool} = await loadFixture ( deployAll ) ;
59+ const { lpToken, liquidityHub, usdc, user, user2, liquidityPool, USDC , LP } = await loadFixture ( deployAll ) ;
5960
6061 expect ( await liquidityHub . SHARES ( ) ) . to . equal ( lpToken . target ) ;
6162 expect ( await liquidityHub . LIQUIDITY_POOL ( ) ) . to . equal ( liquidityPool . target ) ;
@@ -64,6 +65,9 @@ describe("LiquidityHub", function () {
6465 expect ( await liquidityHub . totalSupply ( ) ) . to . equal ( 0n ) ;
6566 expect ( await liquidityHub . totalAssets ( ) ) . to . equal ( 0n ) ;
6667 expect ( await liquidityHub . allowance ( user . address , user2 . address ) ) . to . equal ( 0n ) ;
68+ expect ( await liquidityHub . assetsLimit ( ) ) . to . equal ( getBigInt ( MaxUint256 ) * USDC / LP ) ;
69+ expect ( await liquidityHub . maxDeposit ( ZERO_ADDRESS ) ) . to . equal ( getBigInt ( MaxUint256 ) * USDC / LP ) ;
70+ expect ( await liquidityHub . maxMint ( ZERO_ADDRESS ) ) . to . equal ( getBigInt ( MaxUint256 ) * USDC / LP * LP / USDC ) ;
6771
6872 await expect ( liquidityHub . name ( ) )
6973 . to . be . revertedWithCustomError ( liquidityHub , "NotImplemented()" ) ;
@@ -507,7 +511,213 @@ describe("LiquidityHub", function () {
507511 expect ( await usdc . balanceOf ( liquidityHub . target ) ) . to . equal ( 0n ) ;
508512 } ) ;
509513
510- it . skip ( "Should allow deposits and withdrawals after adjustment with increased assets" , async function ( ) { } ) ;
514+ it ( "Should allow deposits and withdrawals after adjustment with increased assets" , async function ( ) {
515+ const {
516+ lpToken, liquidityHub, usdc, deployer, user, user2, USDC , LP ,
517+ liquidityPool, admin,
518+ } = await loadFixture ( deployAll ) ;
519+
520+ await usdc . connect ( deployer ) . transfer ( user . address , 20n * USDC ) ;
521+ await usdc . connect ( deployer ) . transfer ( user2 . address , 40n * USDC ) ;
522+ await usdc . connect ( user ) . approve ( liquidityHub . target , 20n * USDC ) ;
523+ await usdc . connect ( user2 ) . approve ( liquidityHub . target , 40n * USDC ) ;
524+ await liquidityHub . connect ( user ) . deposit ( 10n * USDC , user . address ) ;
525+ await liquidityHub . connect ( user2 ) . deposit ( 20n * USDC , user2 . address ) ;
526+ expect ( await lpToken . balanceOf ( user . address ) ) . to . equal ( 10n * LP ) ;
527+ expect ( await lpToken . balanceOf ( user2 . address ) ) . to . equal ( 20n * LP ) ;
528+ expect ( await lpToken . totalSupply ( ) ) . to . equal ( 30n * LP ) ;
529+ expect ( await liquidityHub . totalSupply ( ) ) . to . equal ( 30n * LP ) ;
530+ expect ( await liquidityHub . totalAssets ( ) ) . to . equal ( 30n * USDC ) ;
531+ expect ( await liquidityHub . balanceOf ( user . address ) ) . to . equal ( 10n * LP ) ;
532+ expect ( await liquidityHub . balanceOf ( user2 . address ) ) . to . equal ( 20n * LP ) ;
533+ expect ( await usdc . balanceOf ( user . address ) ) . to . equal ( 10n * USDC ) ;
534+ expect ( await usdc . balanceOf ( user2 . address ) ) . to . equal ( 20n * USDC ) ;
535+ expect ( await usdc . balanceOf ( liquidityPool . target ) ) . to . equal ( 30n * USDC ) ;
536+ expect ( await usdc . balanceOf ( liquidityHub . target ) ) . to . equal ( 0n ) ;
537+
538+ await liquidityHub . connect ( admin ) . adjustTotalAssets ( 12n * USDC , INCREASE ) ;
539+ expect ( await liquidityHub . totalAssets ( ) ) . to . equal ( 42n * USDC ) ;
540+ await liquidityHub . connect ( user ) . redeem ( 5n * LP , user . address , user . address ) ;
541+ await liquidityHub . connect ( user2 ) . redeem ( 10n * LP , user2 . address , user2 . address ) ;
542+ await liquidityHub . connect ( user ) . deposit ( 7n * USDC , user . address ) ;
543+ await liquidityHub . connect ( user2 ) . deposit ( 14n * USDC , user2 . address ) ;
544+ expect ( await lpToken . balanceOf ( user . address ) ) . to . equal ( 10n * LP ) ;
545+ expect ( await lpToken . balanceOf ( user2 . address ) ) . to . equal ( 20n * LP ) ;
546+ expect ( await lpToken . totalSupply ( ) ) . to . equal ( 30n * LP ) ;
547+ expect ( await liquidityHub . totalSupply ( ) ) . to . equal ( 30n * LP ) ;
548+ expect ( await liquidityHub . totalAssets ( ) ) . to . equal ( 42n * USDC ) ;
549+ expect ( await liquidityHub . balanceOf ( user . address ) ) . to . equal ( 10n * LP ) ;
550+ expect ( await liquidityHub . balanceOf ( user2 . address ) ) . to . equal ( 20n * LP ) ;
551+ expect ( await usdc . balanceOf ( user . address ) ) . to . equal ( 10n * USDC ) ;
552+ expect ( await usdc . balanceOf ( user2 . address ) ) . to . equal ( 20n * USDC ) ;
553+ expect ( await usdc . balanceOf ( liquidityPool . target ) ) . to . equal ( 30n * USDC ) ;
554+ expect ( await usdc . balanceOf ( liquidityHub . target ) ) . to . equal ( 0n ) ;
555+ } ) ;
556+
557+ it ( "Should allow deposits and withdrawals after adjustment with decreased assets" , async function ( ) {
558+ const {
559+ lpToken, liquidityHub, usdc, deployer, user, user2, USDC , LP ,
560+ liquidityPool, admin,
561+ } = await loadFixture ( deployAll ) ;
562+
563+ await usdc . connect ( deployer ) . transfer ( user . address , 20n * USDC ) ;
564+ await usdc . connect ( deployer ) . transfer ( user2 . address , 40n * USDC ) ;
565+ await usdc . connect ( user ) . approve ( liquidityHub . target , 20n * USDC ) ;
566+ await usdc . connect ( user2 ) . approve ( liquidityHub . target , 40n * USDC ) ;
567+ await liquidityHub . connect ( user ) . deposit ( 10n * USDC , user . address ) ;
568+ await liquidityHub . connect ( user2 ) . deposit ( 20n * USDC , user2 . address ) ;
569+ expect ( await lpToken . balanceOf ( user . address ) ) . to . equal ( 10n * LP ) ;
570+ expect ( await lpToken . balanceOf ( user2 . address ) ) . to . equal ( 20n * LP ) ;
571+ expect ( await lpToken . totalSupply ( ) ) . to . equal ( 30n * LP ) ;
572+ expect ( await liquidityHub . totalSupply ( ) ) . to . equal ( 30n * LP ) ;
573+ expect ( await liquidityHub . totalAssets ( ) ) . to . equal ( 30n * USDC ) ;
574+ expect ( await liquidityHub . balanceOf ( user . address ) ) . to . equal ( 10n * LP ) ;
575+ expect ( await liquidityHub . balanceOf ( user2 . address ) ) . to . equal ( 20n * LP ) ;
576+ expect ( await usdc . balanceOf ( user . address ) ) . to . equal ( 10n * USDC ) ;
577+ expect ( await usdc . balanceOf ( user2 . address ) ) . to . equal ( 20n * USDC ) ;
578+ expect ( await usdc . balanceOf ( liquidityPool . target ) ) . to . equal ( 30n * USDC ) ;
579+ expect ( await usdc . balanceOf ( liquidityHub . target ) ) . to . equal ( 0n ) ;
511580
512- it . skip ( "Should allow deposits and withdrawals after adjustment with decreased assets" , async function ( ) { } ) ;
581+ await liquidityHub . connect ( admin ) . adjustTotalAssets ( 27n * USDC , DECREASE ) ;
582+ expect ( await liquidityHub . totalAssets ( ) ) . to . equal ( 3n * USDC ) ;
583+ await liquidityHub . connect ( user ) . redeem ( 10n * LP , user . address , user . address ) ;
584+ await liquidityHub . connect ( user2 ) . redeem ( 20n * LP , user2 . address , user2 . address ) ;
585+ await liquidityHub . connect ( user ) . deposit ( 6n * USDC , user . address ) ;
586+ await liquidityHub . connect ( user2 ) . deposit ( 12n * USDC , user2 . address ) ;
587+ expect ( await lpToken . balanceOf ( user . address ) ) . to . equal ( 6n * LP ) ;
588+ expect ( await lpToken . balanceOf ( user2 . address ) ) . to . equal ( 12n * LP ) ;
589+ expect ( await lpToken . totalSupply ( ) ) . to . equal ( 18n * LP ) ;
590+ expect ( await liquidityHub . totalSupply ( ) ) . to . equal ( 18n * LP ) ;
591+ expect ( await liquidityHub . totalAssets ( ) ) . to . equal ( 18n * USDC ) ;
592+ expect ( await liquidityHub . balanceOf ( user . address ) ) . to . equal ( 6n * LP ) ;
593+ expect ( await liquidityHub . balanceOf ( user2 . address ) ) . to . equal ( 12n * LP ) ;
594+ expect ( await usdc . balanceOf ( user . address ) ) . to . equal ( 5n * USDC ) ;
595+ expect ( await usdc . balanceOf ( user2 . address ) ) . to . equal ( 10n * USDC ) ;
596+ expect ( await usdc . balanceOf ( liquidityPool . target ) ) . to . equal ( 45n * USDC ) ;
597+ expect ( await usdc . balanceOf ( liquidityHub . target ) ) . to . equal ( 0n ) ;
598+ } ) ;
599+
600+ it ( "Should allow to deposit with permit" , async function ( ) {
601+ const { lpToken, liquidityHub, usdc, deployer, user, user2, USDC , LP , liquidityPool} = await loadFixture ( deployAll ) ;
602+
603+ const domain = {
604+ name : "Circle USD" ,
605+ version : "1" ,
606+ chainId : hre . network . config . chainId ,
607+ verifyingContract : await resolveAddress ( usdc ) ,
608+ } ;
609+
610+ const types = {
611+ Permit : [
612+ { name : "owner" , type : "address" } ,
613+ { name : "spender" , type : "address" } ,
614+ { name : "value" , type : "uint256" } ,
615+ { name : "nonce" , type : "uint256" } ,
616+ { name : "deadline" , type : "uint256" } ,
617+ ] ,
618+ } ;
619+
620+ await usdc . connect ( deployer ) . transfer ( user . address , 10n * USDC ) ;
621+ const permitSig = Signature . from ( await user . signTypedData ( domain , types , {
622+ owner : user . address ,
623+ spender : liquidityHub . target ,
624+ value : 10n * USDC ,
625+ nonce : 0n ,
626+ deadline : 2000000000n ,
627+ } ) ) ;
628+ const tx = liquidityHub . connect ( user ) . depositWithPermit (
629+ 10n * USDC ,
630+ user2 . address ,
631+ 2000000000n ,
632+ permitSig . v ,
633+ permitSig . r ,
634+ permitSig . s ,
635+ ) ;
636+ await expect ( tx )
637+ . to . emit ( lpToken , "Transfer" )
638+ . withArgs ( ZERO_ADDRESS , user2 . address , 10n * LP ) ;
639+ await expect ( tx )
640+ . to . emit ( usdc , "Transfer" )
641+ . withArgs ( user . address , liquidityPool . target , 10n * USDC ) ;
642+ expect ( await lpToken . balanceOf ( user . address ) ) . to . equal ( 0n ) ;
643+ expect ( await lpToken . balanceOf ( user2 . address ) ) . to . equal ( 10n * LP ) ;
644+ expect ( await lpToken . totalSupply ( ) ) . to . equal ( 10n * LP ) ;
645+ expect ( await liquidityHub . totalSupply ( ) ) . to . equal ( 10n * LP ) ;
646+ expect ( await liquidityHub . totalAssets ( ) ) . to . equal ( 10n * USDC ) ;
647+ expect ( await liquidityHub . balanceOf ( user . address ) ) . to . equal ( 0n ) ;
648+ expect ( await liquidityHub . balanceOf ( user2 . address ) ) . to . equal ( 10n * LP ) ;
649+ expect ( await usdc . balanceOf ( user . address ) ) . to . equal ( 0n ) ;
650+ expect ( await usdc . balanceOf ( user2 . address ) ) . to . equal ( 0n ) ;
651+ expect ( await usdc . balanceOf ( liquidityHub . target ) ) . to . equal ( 0n ) ;
652+ expect ( await usdc . balanceOf ( liquidityPool . target ) ) . to . equal ( 10n * USDC ) ;
653+ expect ( await usdc . allowance ( user . address , liquidityHub . target ) ) . to . equal ( 0n ) ;
654+ } ) ;
655+
656+ it ( "Should allow admin to set assets limit" , async function ( ) {
657+ const { liquidityHub, deployer, admin, user, usdc, lpToken, USDC , LP , liquidityPool} = await loadFixture ( deployAll ) ;
658+
659+ const tx = liquidityHub . connect ( admin ) . setAssetsLimit ( 0n ) ;
660+ await expect ( tx )
661+ . to . emit ( liquidityHub , "AssetsLimitSet" )
662+ . withArgs ( getBigInt ( MaxUint256 ) * USDC / LP , 0n ) ;
663+
664+ expect ( await liquidityHub . maxDeposit ( ZERO_ADDRESS ) ) . to . equal ( 0n ) ;
665+ expect ( await liquidityHub . maxMint ( ZERO_ADDRESS ) ) . to . equal ( 0n ) ;
666+
667+ await usdc . connect ( deployer ) . transfer ( user . address , 10n * USDC ) ;
668+ await usdc . connect ( user ) . approve ( liquidityHub . target , 10n * USDC ) ;
669+
670+ await expect ( liquidityHub . connect ( user ) . deposit ( 1n , user . address ) )
671+ . to . be . revertedWithCustomError ( liquidityHub , "ERC4626ExceededMaxDeposit(address,uint256,uint256)" ) ;
672+ await expect ( liquidityHub . connect ( user ) . mint ( LP , user . address ) )
673+ . to . be . revertedWithCustomError ( liquidityHub , "ERC4626ExceededMaxMint(address,uint256,uint256)" ) ;
674+
675+ const tx2 = liquidityHub . connect ( admin ) . setAssetsLimit ( 100n * USDC ) ;
676+ await expect ( tx2 )
677+ . to . emit ( liquidityHub , "AssetsLimitSet" )
678+ . withArgs ( 0n , 100n * USDC ) ;
679+
680+ expect ( await liquidityHub . maxDeposit ( ZERO_ADDRESS ) ) . to . equal ( 100n * USDC ) ;
681+ expect ( await liquidityHub . maxMint ( ZERO_ADDRESS ) ) . to . equal ( 100n * LP ) ;
682+
683+ await liquidityHub . connect ( user ) . deposit ( 10n * USDC , user . address ) ;
684+
685+ expect ( await liquidityHub . maxDeposit ( ZERO_ADDRESS ) ) . to . equal ( 90n * USDC ) ;
686+ expect ( await liquidityHub . maxMint ( ZERO_ADDRESS ) ) . to . equal ( 90n * LP ) ;
687+ expect ( await lpToken . balanceOf ( user . address ) ) . to . equal ( 10n * LP ) ;
688+ expect ( await lpToken . totalSupply ( ) ) . to . equal ( 10n * LP ) ;
689+ expect ( await liquidityHub . totalSupply ( ) ) . to . equal ( 10n * LP ) ;
690+ expect ( await liquidityHub . totalAssets ( ) ) . to . equal ( 10n * USDC ) ;
691+ expect ( await liquidityHub . balanceOf ( user . address ) ) . to . equal ( 10n * LP ) ;
692+ expect ( await usdc . balanceOf ( user . address ) ) . to . equal ( 0n ) ;
693+ expect ( await usdc . balanceOf ( liquidityHub . target ) ) . to . equal ( 0n ) ;
694+ expect ( await usdc . balanceOf ( liquidityPool . target ) ) . to . equal ( 10n * USDC ) ;
695+
696+ await expect ( liquidityHub . connect ( user ) . deposit ( 90n * USDC + 1n , user . address ) )
697+ . to . be . revertedWithCustomError ( liquidityHub , "ERC4626ExceededMaxDeposit(address,uint256,uint256)" ) ;
698+ await expect ( liquidityHub . connect ( user ) . mint ( 90n * LP + 1n , user . address ) )
699+ . to . be . revertedWithCustomError ( liquidityHub , "ERC4626ExceededMaxMint(address,uint256,uint256)" ) ;
700+
701+ await liquidityHub . connect ( admin ) . adjustTotalAssets ( 10n * USDC , INCREASE ) ;
702+
703+ expect ( await liquidityHub . maxDeposit ( ZERO_ADDRESS ) ) . to . equal ( 80n * USDC ) ;
704+ expect ( await liquidityHub . maxMint ( ZERO_ADDRESS ) ) . to . equal ( 40n * LP ) ;
705+
706+ await expect ( liquidityHub . connect ( user ) . deposit ( 80n * USDC + 1n , user . address ) )
707+ . to . be . revertedWithCustomError ( liquidityHub , "ERC4626ExceededMaxDeposit(address,uint256,uint256)" ) ;
708+ await expect ( liquidityHub . connect ( user ) . mint ( 40n * LP + 1n , user . address ) )
709+ . to . be . revertedWithCustomError ( liquidityHub , "ERC4626ExceededMaxMint(address,uint256,uint256)" ) ;
710+
711+ await liquidityHub . connect ( admin ) . adjustTotalAssets ( 10n * USDC , DECREASE ) ;
712+
713+ expect ( await liquidityHub . maxDeposit ( ZERO_ADDRESS ) ) . to . equal ( 90n * USDC ) ;
714+ expect ( await liquidityHub . maxMint ( ZERO_ADDRESS ) ) . to . equal ( 90n * LP ) ;
715+ } ) ;
716+
717+ it ( "Should not allow others to set assets limit" , async function ( ) {
718+ const { liquidityHub, user} = await loadFixture ( deployAll ) ;
719+
720+ await expect ( liquidityHub . connect ( user ) . setAssetsLimit ( 0n ) )
721+ . to . be . revertedWithCustomError ( liquidityHub , "AccessControlUnauthorizedAccount(address,bytes32)" ) ;
722+ } ) ;
513723} ) ;
0 commit comments