import { ethers } from "hardhat" ; import { expect } from "chai" ; import { assertBNClosePercent } from "@utils/assertions" ; import { BN , simpleToExactAmount } from "@utils/math" ; import { MassetMachine , StandardAccounts , FeederMachine , FeederDetails } from "@utils/machines" ; describe ( "Feeder Pools" , ( ) => { let sa ; let feederMachine ; let feeder ; const runSetup = async ( useLendingMarkets = false , useInterestValidator = false , feederWeights ? , mAssetWeights ? ) : Promise < void > => { feeder = await feederMachine . deployFeeder ( feederWeights , mAssetWeights , useLendingMarkets , useInterestValidator ) ; } ; before ( "Init contract" , async ( ) => { const accounts = await ethers . getSigners ( ) ; const mAssetMachine = await new MassetMachine ( ) . initAccounts ( accounts ) ; feederMachine = await new FeederMachine ( mAssetMachine ) ; sa = mAssetMachine . sa ; await runSetup ( ) ; } ) ; describe ( "testing some mints" , ( ) => { before ( async ( ) => { await runSetup ( ) ; } ) ; it ( "should mint multi locally" , async ( ) => { const { bAssets , pool } = feeder ; const dataStart = await feederMachine . getBasketComposition ( feeder ) ; const approvals = await Promise . all ( bAssets . map ( ( b ) => feederMachine . approveFeeder ( b , pool . address , 100 ) ) ) ; await pool . mintMulti ( bAssets . map ( ( b ) => b . address ) , approvals , 99 , sa . default . address ) ; const dataEnd = await feederMachine . getBasketComposition ( feeder ) ; expect ( dataEnd . totalSupply . sub ( dataStart . totalSupply ) ) . to . eq ( simpleToExactAmount ( 200 , 18 ) ) ; } ) ; it ( "should fail to mintMulti with mpAsset" , async ( ) => { const { pool , mAssetDetails } = feeder ; const { bAssets } = mAssetDetails ; await expect ( pool . mintMulti ( [ bAssets [ 0 ] . address ] , [ simpleToExactAmount ( 10 ) ] , simpleToExactAmount ( 9 ) , sa . default . address ) ) . to . be . revertedWith ( "Invalid asset" ) ; } ) ; it ( "should mint single locally" , async ( ) => { const { pool , mAsset , fAsset } = feeder ; const dataStart = await feederMachine . getBasketComposition ( feeder ) ; let approval = await feederMachine . approveFeeder ( mAsset , pool . address , 10 ) ; await pool . mint ( mAsset . address , approval , simpleToExactAmount ( "9.5" ) , sa . default . address ) ; const dataMid = await feederMachine . getBasketComposition ( feeder ) ; assertBNClosePercent ( dataMid . totalSupply , dataStart . totalSupply . add ( approval ) , "0.1" ) ; expect ( dataMid . bAssets [ 0 ] . actualBalance , "mAsset should be transferred" ) . eq ( dataStart . bAssets [ 0 ] . actualBalance . add ( approval ) ) ; expect ( dataMid . bAssets [ 0 ] . vaultBalance , "mAsset vault balance should increase" ) . eq ( dataStart . bAssets [ 0 ] . vaultBalance . add ( approval ) ) ; approval = await feederMachine . approveFeeder ( fAsset , pool . address , 10 ) ; await pool . mint ( fAsset . address , approval , simpleToExactAmount ( "9.5" ) , sa . default . address ) ; const dataEnd = await feederMachine . getBasketComposition ( feeder ) ; assertBNClosePercent ( dataEnd . totalSupply , dataMid . totalSupply . add ( approval ) , "0.1" ) ; expect ( dataEnd . bAssets [ 1 ] . actualBalance , "fAsset should be transferred" ) . eq ( dataMid . bAssets [ 1 ] . actualBalance . add ( approval ) ) ; expect ( dataEnd . bAssets [ 1 ] . vaultBalance , "fAsset vault balance should increase" ) . eq ( dataMid . bAssets [ 1 ] . vaultBalance . add ( approval ) ) ; } ) ; it ( "should mint single via main pool" , async ( ) => { const { pool , mAssetDetails } = feeder ; const { bAssets } = mAssetDetails ; const dataStart = await feederMachine . getBasketComposition ( feeder ) ; let approval = await feederMachine . approveFeeder ( bAssets [ 0 ] , pool . address , 10 ) ; await pool . mint ( bAssets [ 0 ] . address , approval , simpleToExactAmount ( "9.5" ) , sa . default . address ) ; const dataMid = await feederMachine . getBasketComposition ( feeder ) ; assertBNClosePercent ( dataMid . totalSupply . sub ( dataStart . totalSupply ) , approval , "0.1" , "Total supply should increase" ) ; assertBNClosePercent ( dataMid . bAssets [ 0 ] . actualBalance , dataStart . bAssets [ 0 ] . actualBalance . add ( simpleToExactAmount ( 10 ) ) , "0.1" , "mAsset should deposit" ) ; assertBNClosePercent ( dataMid . bAssets [ 0 ] . vaultBalance , dataStart . bAssets [ 0 ] . vaultBalance . add ( simpleToExactAmount ( 10 ) ) , "0.1" , "mAsset vaultBalance should increase" ) ; approval = await feederMachine . approveFeeder ( bAssets [ 1 ] , pool . address , 10 ) ; await pool . mint ( bAssets [ 1 ] . address , approval , simpleToExactAmount ( "9.5" ) , sa . default . address ) ; const dataEnd = await feederMachine . getBasketComposition ( feeder ) ; assertBNClosePercent ( dataEnd . totalSupply . sub ( dataMid . totalSupply ) , simpleToExactAmount ( 10 ) , "0.1" , "Total supply should increase" ) ; assertBNClosePercent ( dataEnd . bAssets [ 0 ] . actualBalance , dataMid . bAssets [ 0 ] . actualBalance . add ( simpleToExactAmount ( 10 ) ) , "0.1" , "mAsset should deposit" ) ; assertBNClosePercent ( dataEnd . bAssets [ 0 ] . vaultBalance , dataMid . bAssets [ 0 ] . vaultBalance . add ( simpleToExactAmount ( 10 ) ) , "0.1" , "mAsset vaultBalance should increase" ) ; } ) ; } ) ; describe ( "testing some swaps" , ( ) => { before ( async ( ) => { await runSetup ( ) ; } ) ; it ( "should swap locally" , async ( ) => { const { pool , mAsset , fAsset } = feeder ; const dataStart = await feederMachine . getBasketComposition ( feeder ) ; let approval = await feederMachine . approveFeeder ( mAsset , pool . address , 10 ) ; await pool . swap ( mAsset . address , fAsset . address , approval , simpleToExactAmount ( "9.5" ) , sa . default . address ) ; const dataMid = await feederMachine . getBasketComposition ( feeder ) ; expect ( dataMid . totalSupply ) . eq ( dataStart . totalSupply ) ; expect ( dataMid . bAssets [ 0 ] . actualBalance . sub ( dataStart . bAssets [ 0 ] . actualBalance ) , "mAsset should be transferred" ) . eq ( approval ) ; assertBNClosePercent ( dataStart . bAssets [ 1 ] . actualBalance . sub ( dataMid . bAssets [ 1 ] . actualBalance ) , approval , "0.3" , "fAsset should be transferred" ) ; expect ( dataMid . bAssets [ 0 ] . vaultBalance , "mAsset vault balance should increase" ) . eq ( dataStart . bAssets [ 0 ] . vaultBalance . add ( approval ) ) ; assertBNClosePercent ( dataMid . bAssets [ 1 ] . vaultBalance , dataStart . bAssets [ 1 ] . vaultBalance . sub ( approval ) , "0.3" , "fAsset vaultBalance should decrease" ) ; approval = await feederMachine . approveFeeder ( fAsset , pool . address , 10 ) ; await pool . swap ( fAsset . address , mAsset . address , approval , simpleToExactAmount ( "9.5" ) , sa . default . address ) ; } ) ; it ( "should swap into mpAsset" , async ( ) => { const { pool , fAsset , mAssetDetails } = feeder ; const { bAssets } = mAssetDetails ; const dataStart = await feederMachine . getBasketComposition ( feeder ) ; const approval = await feederMachine . approveFeeder ( fAsset , pool . address , 10 ) ; await pool . swap ( fAsset . address , bAssets [ 0 ] . address , approval , simpleToExactAmount ( "9.5" ) , sa . default . address ) ; const dataMid = await feederMachine . getBasketComposition ( feeder ) ; expect ( dataMid . totalSupply ) . eq ( dataStart . totalSupply ) ; expect ( dataMid . bAssets [ 1 ] . actualBalance . sub ( dataStart . bAssets [ 1 ] . actualBalance ) , "fAsset should be transferred in" ) . eq ( approval ) ; assertBNClosePercent ( dataStart . bAssets [ 0 ] . actualBalance . sub ( dataMid . bAssets [ 0 ] . actualBalance ) , approval , "0.3" , "mAsset should be transferred out" ) ; expect ( dataMid . bAssets [ 1 ] . vaultBalance . sub ( dataStart . bAssets [ 1 ] . vaultBalance ) , "fAsset vaultBalance should increase" ) . eq ( approval ) ; assertBNClosePercent ( dataStart . bAssets [ 0 ] . vaultBalance . sub ( dataMid . bAssets [ 0 ] . vaultBalance ) , approval , "0.3" , "mAsset vault balance should decrease" ) ; } ) ; it ( "should swap out of mpAsset" , async ( ) => { const { pool , fAsset , mAssetDetails } = feeder ; const { bAssets } = mAssetDetails ; const dataStart = await feederMachine . getBasketComposition ( feeder ) ; const approval = await feederMachine . approveFeeder ( bAssets [ 0 ] , pool . address , 10 ) ; await pool . swap ( bAssets [ 0 ] . address , fAsset . address , approval , simpleToExactAmount ( "9.5" ) , sa . default . address ) ; const dataMid = await feederMachine . getBasketComposition ( feeder ) ; expect ( dataMid . totalSupply ) . eq ( dataStart . totalSupply ) ; assertBNClosePercent ( dataMid . bAssets [ 0 ] . actualBalance . sub ( dataStart . bAssets [ 0 ] . actualBalance ) , approval , "0.3" , "mAsset should be transferred in" ) ; assertBNClosePercent ( dataStart . bAssets [ 1 ] . actualBalance . sub ( dataMid . bAssets [ 1 ] . actualBalance ) , approval , "0.3" , "fAsset should be transferred out" ) ; assertBNClosePercent ( dataMid . bAssets [ 0 ] . vaultBalance . sub ( dataStart . bAssets [ 0 ] . vaultBalance ) , approval , "0.3" , "mAsset vault balance should increase" ) ; assertBNClosePercent ( dataStart . bAssets [ 1 ] . vaultBalance . sub ( dataMid . bAssets [ 1 ] . vaultBalance ) , approval , "0.3" , "fAsset vault balance should decrease" ) ; } ) ; it ( "should fail to swap mpAsset <> mAsset" , async ( ) => { const { pool , mAsset , mAssetDetails } = feeder ; const { bAssets } = mAssetDetails ; await expect ( pool . swap ( bAssets [ 0 ] . address , mAsset . address , simpleToExactAmount ( 1 ) , simpleToExactAmount ( 1 ) , sa . default . address ) ) . to . be . revertedWith ( "Invalid pair" ) ; await expect ( pool . swap ( mAsset . address , bAssets [ 0 ] . address , simpleToExactAmount ( 1 ) , simpleToExactAmount ( 1 ) , sa . default . address ) ) . to . be . revertedWith ( "Invalid pair" ) ; } ) ; it ( "should fail to swap mpAsset <> mpAsset" , async ( ) => { const { pool , mAssetDetails } = feeder ; const { bAssets } = mAssetDetails ; await expect ( pool . swap ( bAssets [ 1 ] . address , bAssets [ 0 ] . address , simpleToExactAmount ( 1 ) , simpleToExactAmount ( 1 ) , sa . default . address ) ) . to . be . revertedWith ( "Invalid pair" ) ; } ) ; } ) ; describe ( "testing some single redemptions" , ( ) => { before ( async ( ) => { await runSetup ( ) ; } ) ; it ( "should redeem locally" , async ( ) => { const { pool , mAsset , fAsset } = feeder ; const dataStart = await feederMachine . getBasketComposition ( feeder ) ; await pool . redeem ( mAsset . address , simpleToExactAmount ( 10 ) , simpleToExactAmount ( "9.5" ) , sa . default . address ) ; const dataMid = await feederMachine . getBasketComposition ( feeder ) ; expect ( dataMid . totalSupply ) . eq ( dataStart . totalSupply . sub ( simpleToExactAmount ( 10 ) ) ) ; assertBNClosePercent ( dataStart . bAssets [ 0 ] . actualBalance . sub ( dataMid . bAssets [ 0 ] . actualBalance ) , simpleToExactAmount ( 10 ) , "0.3" , "mAsset should be transferred out" ) ; assertBNClosePercent ( dataStart . bAssets [ 0 ] . vaultBalance . sub ( dataMid . bAssets [ 0 ] . vaultBalance ) , simpleToExactAmount ( 10 ) , "0.3" , "mAsset vault balance should decrease" ) ; await pool . redeem ( fAsset . address , simpleToExactAmount ( 10 ) , simpleToExactAmount ( "9.5" ) , sa . default . address ) ; } ) ; it ( "should redeem into mpAsset" , async ( ) => { const { pool , mAssetDetails } = feeder ; const { bAssets } = mAssetDetails ; const dataStart = await feederMachine . getBasketComposition ( feeder ) ; await pool . redeem ( bAssets [ 0 ] . address , simpleToExactAmount ( 10 ) , simpleToExactAmount ( "9.5" ) , sa . default . address ) ; const dataMid = await feederMachine . getBasketComposition ( feeder ) ; expect ( dataMid . totalSupply ) . eq ( dataStart . totalSupply . sub ( simpleToExactAmount ( 10 ) ) ) ; assertBNClosePercent ( dataStart . bAssets [ 0 ] . vaultBalance . sub ( dataMid . bAssets [ 0 ] . vaultBalance ) , simpleToExactAmount ( 10 ) , "0.3" , "mAsset vault balance should decrease" ) ; } ) ; } ) ; describe ( "testing some exact redemptions" , ( ) => { before ( async ( ) => { await runSetup ( ) ; } ) ; it ( "should redeem locally" , async ( ) => { const { pool , mAsset , fAsset } = feeder ; const dataStart = await feederMachine . getBasketComposition ( feeder ) ; await pool . redeemExactBassets ( [ mAsset . address ] , [ simpleToExactAmount ( 10 ) ] , simpleToExactAmount ( 11 ) , sa . default . address ) ; const dataMid = await feederMachine . getBasketComposition ( feeder ) ; assertBNClosePercent ( dataMid . totalSupply , dataStart . totalSupply . sub ( simpleToExactAmount ( 10 ) ) ) ; expect ( dataStart . bAssets [ 0 ] . actualBalance . sub ( dataMid . bAssets [ 0 ] . actualBalance ) , "mAsset should be transferred out" ) . eq ( simpleToExactAmount ( 10 ) ) ; expect ( dataStart . bAssets [ 0 ] . vaultBalance . sub ( dataMid . bAssets [ 0 ] . vaultBalance ) , "mAsset vb should decrease" ) . eq ( simpleToExactAmount ( 10 ) ) ; await pool . redeemExactBassets ( [ fAsset . address ] , [ simpleToExactAmount ( 10 ) ] , simpleToExactAmount ( 11 ) , sa . default . address ) ; await pool . redeemExactBassets ( [ mAsset . address , fAsset . address ] , [ simpleToExactAmount ( 1 ) , simpleToExactAmount ( 1 ) ] , simpleToExactAmount ( "2.5" ) , sa . default . address ) ; } ) ; it ( "should fail to redeem into mpAsset" , async ( ) => { const { pool , mAssetDetails } = feeder ; const { bAssets } = mAssetDetails ; await expect ( pool . redeemExactBassets ( [ bAssets [ 0 ] . address ] , [ simpleToExactAmount ( 10 ) ] , simpleToExactAmount ( 11 ) , sa . default . address ) ) . to . be . revertedWith ( "Invalid asset" ) ; } ) ; } ) ; } ) ;