2021-12-02 17:31:51 +00:00
import hre from "hardhat" ;
import hardhatConfig from "../../../hardhat.config" ;
2021-06-01 14:50:52 +00:00
// Instadapp deployment and testing helpers
2021-12-05 19:10:22 +00:00
import { deployAndEnableConnector } from "../../../scripts/tests/deployAndEnableConnector.js"
import { buildDSAv2 } from "../../../scripts/tests/buildDSAv2"
import { encodeSpells } from "../../../scripts/tests/encodeSpells.js"
import { getMasterSigner } from "../../../scripts/tests/getMasterSigner"
2021-06-01 14:50:52 +00:00
// Instadapp instadappAddresses/ABIs
2021-12-02 17:31:51 +00:00
import { instadappAddresses } from "../../../scripts/important/addresses" ;
import { instadappAbi } from "../../../scripts/constant/abis" ;
2021-06-01 14:50:52 +00:00
// Instadapp Liquity Connector artifacts
2021-12-02 17:31:51 +00:00
import connectV2LiquityArtifacts from "../../artifacts/contracts/mainnet/connectors/liquity/main.sol/ConnectV2Liquity.json" ;
import connectV2BasicV1Artifacts from "../../artifacts/contracts/mainnet/connectors/basic/main.sol/ConnectV2Basic.json" ;
import { ethers } from "hardhat" ;
2021-06-01 14:50:52 +00:00
2021-06-08 15:57:36 +00:00
// Instadapp uses a fake address to represent native ETH
2021-12-02 17:31:51 +00:00
import { eth_addr : ETH_ADDRESS } from "../../../scripts/constant/constant" ;
2021-06-08 15:57:36 +00:00
const LIQUITY_CONNECTOR = "LIQUITY-v1-TEST" ;
2021-06-01 14:50:52 +00:00
const LUSD_GAS_COMPENSATION = hre . ethers . utils . parseUnits ( "200" , 18 ) ; // 200 LUSD gas compensation repaid after loan repayment
2021-06-04 11:18:16 +00:00
const LIQUIDATABLE_TROVES_BLOCK_NUMBER = 12478159 ; // Deterministic block number for tests to run against, if you change this, tests will break.
2021-06-01 14:50:52 +00:00
const JUSTIN_SUN_ADDRESS = "0x903d12bf2c57a29f32365917c706ce0e1a84cce3" ; // LQTY whale address
2021-06-04 11:18:16 +00:00
const LIQUIDATABLE_TROVE_ADDRESS = "0xafbeb4cb97f3b08ec2fe07ef0dac15d37013a347" ; // Trove which is liquidatable at blockNumber: LIQUIDATABLE_TROVES_BLOCK_NUMBER
2021-06-01 14:50:52 +00:00
const MAX_GAS = hardhatConfig . networks . hardhat . blockGasLimit ; // Maximum gas limit (12000000)
2021-06-08 15:57:36 +00:00
const INSTADAPP_BASIC_V1_CONNECTOR = "Basic-v1" ;
2021-06-01 14:50:52 +00:00
const openTroveSpell = async (
dsa ,
2021-12-02 17:31:51 +00:00
signer : any ,
depositAmount : any ,
borrowAmount : any ,
upperHint : any ,
lowerHint : any ,
maxFeePercentage : any
2021-06-01 14:50:52 +00:00
) = > {
let address = signer . address ;
if ( signer . address === undefined ) {
address = await signer . getAddress ( ) ;
}
const openTroveSpell = {
2021-06-08 15:57:36 +00:00
connector : LIQUITY_CONNECTOR ,
2021-06-01 14:50:52 +00:00
method : "open" ,
args : [
depositAmount ,
maxFeePercentage ,
borrowAmount ,
upperHint ,
lowerHint ,
2021-06-30 16:16:05 +00:00
[ 0 , 0 ] ,
[ 0 , 0 ] ,
2021-06-01 14:50:52 +00:00
] ,
} ;
2021-06-30 16:16:05 +00:00
2021-06-04 11:18:16 +00:00
return await dsa
2021-06-01 14:50:52 +00:00
. connect ( signer )
. cast ( . . . encodeSpells ( [ openTroveSpell ] ) , address , {
value : depositAmount ,
} ) ;
} ;
const createDsaTrove = async (
dsa ,
signer ,
2021-06-08 15:57:36 +00:00
liquity ,
2021-06-01 14:50:52 +00:00
depositAmount = hre . ethers . utils . parseEther ( "5" ) ,
borrowAmount = hre . ethers . utils . parseUnits ( "2000" , 18 )
) = > {
const maxFeePercentage = hre . ethers . utils . parseUnits ( "0.5" , 18 ) ; // 0.5% max fee
const { upperHint , lowerHint } = await getTroveInsertionHints (
depositAmount ,
borrowAmount ,
2021-06-08 15:57:36 +00:00
liquity
2021-06-01 14:50:52 +00:00
) ;
return await openTroveSpell (
dsa ,
signer ,
depositAmount ,
borrowAmount ,
upperHint ,
lowerHint ,
maxFeePercentage
) ;
} ;
const sendToken = async ( token , amount , from , to ) = > {
await hre . network . provider . request ( {
method : "hardhat_impersonateAccount" ,
params : [ from ] ,
} ) ;
const signer = await hre . ethers . provider . getSigner ( from ) ;
2021-06-08 15:57:36 +00:00
return await token . connect ( signer ) . transfer ( to , amount , {
gasPrice : 0 ,
} ) ;
2021-06-01 14:50:52 +00:00
} ;
2021-06-04 11:18:16 +00:00
const resetInitialState = async ( walletAddress , contracts , isDebug = false ) = > {
const liquity = await deployAndConnect ( contracts , isDebug ) ;
const dsa = await buildDSAv2 ( walletAddress ) ;
return [ liquity , dsa ] ;
} ;
2021-06-01 14:50:52 +00:00
const resetHardhatBlockNumber = async ( blockNumber ) = > {
return await hre . network . provider . request ( {
method : "hardhat_reset" ,
params : [
{
forking : {
jsonRpcUrl : hardhatConfig.networks.hardhat.forking.url ,
blockNumber ,
} ,
} ,
] ,
} ) ;
} ;
const deployAndConnect = async ( contracts , isDebug = false ) = > {
// Pin Liquity tests to a particular block number to create deterministic state (Ether price etc.)
2021-06-04 11:18:16 +00:00
await resetHardhatBlockNumber ( LIQUIDATABLE_TROVES_BLOCK_NUMBER ) ;
2021-06-01 14:50:52 +00:00
const liquity = {
troveManager : null ,
borrowerOperations : null ,
stabilityPool : null ,
lusdToken : null ,
lqtyToken : null ,
activePool : null ,
priceFeed : null ,
hintHelpers : null ,
sortedTroves : null ,
staking : null ,
2021-06-04 11:18:16 +00:00
collSurplus : null ,
2021-06-01 14:50:52 +00:00
} ;
const masterSigner = await getMasterSigner ( ) ;
const instaConnectorsV2 = await ethers . getContractAt (
instadappAbi . core . connectorsV2 ,
instadappAddresses . core . connectorsV2
) ;
const connector = await deployAndEnableConnector ( {
2021-06-08 15:57:36 +00:00
connectorName : LIQUITY_CONNECTOR ,
2021-06-01 14:50:52 +00:00
contractArtifact : connectV2LiquityArtifacts ,
signer : masterSigner ,
connectors : instaConnectorsV2 ,
} ) ;
isDebug &&
2021-06-08 15:57:36 +00:00
console . log ( ` ${ LIQUITY_CONNECTOR } Connector address ` , connector . address ) ;
2021-06-01 14:50:52 +00:00
const basicConnector = await deployAndEnableConnector ( {
connectorName : "Basic-v1" ,
contractArtifact : connectV2BasicV1Artifacts ,
signer : masterSigner ,
connectors : instaConnectorsV2 ,
} ) ;
isDebug && console . log ( "Basic-v1 Connector address" , basicConnector . address ) ;
liquity . troveManager = new ethers . Contract (
contracts . TROVE_MANAGER_ADDRESS ,
contracts . TROVE_MANAGER_ABI ,
ethers . provider
) ;
liquity . borrowerOperations = new ethers . Contract (
contracts . BORROWER_OPERATIONS_ADDRESS ,
contracts . BORROWER_OPERATIONS_ABI ,
ethers . provider
) ;
liquity . stabilityPool = new ethers . Contract (
contracts . STABILITY_POOL_ADDRESS ,
contracts . STABILITY_POOL_ABI ,
ethers . provider
) ;
liquity . lusdToken = new ethers . Contract (
contracts . LUSD_TOKEN_ADDRESS ,
contracts . LUSD_TOKEN_ABI ,
ethers . provider
) ;
liquity . lqtyToken = new ethers . Contract (
contracts . LQTY_TOKEN_ADDRESS ,
contracts . LQTY_TOKEN_ABI ,
ethers . provider
) ;
liquity . activePool = new ethers . Contract (
contracts . ACTIVE_POOL_ADDRESS ,
contracts . ACTIVE_POOL_ABI ,
ethers . provider
) ;
liquity . priceFeed = new ethers . Contract (
contracts . PRICE_FEED_ADDRESS ,
contracts . PRICE_FEED_ABI ,
ethers . provider
) ;
liquity . hintHelpers = new ethers . Contract (
contracts . HINT_HELPERS_ADDRESS ,
contracts . HINT_HELPERS_ABI ,
ethers . provider
) ;
liquity . sortedTroves = new ethers . Contract (
contracts . SORTED_TROVES_ADDRESS ,
contracts . SORTED_TROVES_ABI ,
ethers . provider
) ;
liquity . staking = new ethers . Contract (
contracts . STAKING_ADDRESS ,
contracts . STAKING_ABI ,
ethers . provider
) ;
2021-06-04 11:18:16 +00:00
liquity . collSurplus = new ethers . Contract (
contracts . COLL_SURPLUS_ADDRESS ,
contracts . COLL_SURPLUS_ABI ,
ethers . provider
) ;
2021-06-01 14:50:52 +00:00
return liquity ;
} ;
2021-06-08 15:57:36 +00:00
const getTroveInsertionHints = async ( depositAmount , borrowAmount , liquity ) = > {
const nominalCR = await liquity . hintHelpers . computeNominalCR (
2021-06-01 14:50:52 +00:00
depositAmount ,
borrowAmount
) ;
2021-06-08 15:57:36 +00:00
const {
hintAddress ,
latestRandomSeed ,
} = await liquity . hintHelpers . getApproxHint ( nominalCR , 50 , 1298379 , {
gasLimit : MAX_GAS ,
} ) ;
2021-06-01 14:50:52 +00:00
randomSeed = latestRandomSeed ;
2021-06-08 15:57:36 +00:00
const {
0 : upperHint ,
1 : lowerHint ,
} = await liquity . sortedTroves . findInsertPosition (
2021-06-01 14:50:52 +00:00
nominalCR ,
hintAddress ,
hintAddress ,
{
gasLimit : MAX_GAS ,
}
) ;
return {
upperHint ,
lowerHint ,
} ;
} ;
let randomSeed = 4223 ;
2021-06-08 15:57:36 +00:00
const getRedemptionHints = async ( amount , liquity ) = > {
const ethPrice = await liquity . priceFeed . callStatic . fetchPrice ( ) ;
2021-06-01 14:50:52 +00:00
const [
firstRedemptionHint ,
partialRedemptionHintNicr ,
2021-06-08 15:57:36 +00:00
] = await liquity . hintHelpers . getRedemptionHints ( amount , ethPrice , 0 ) ;
2021-06-01 14:50:52 +00:00
2021-06-08 15:57:36 +00:00
const {
hintAddress ,
latestRandomSeed ,
} = await liquity . hintHelpers . getApproxHint (
2021-06-01 14:50:52 +00:00
partialRedemptionHintNicr ,
50 ,
randomSeed ,
{
gasLimit : MAX_GAS ,
}
) ;
randomSeed = latestRandomSeed ;
2021-06-08 15:57:36 +00:00
const {
0 : upperHint ,
1 : lowerHint ,
} = await liquity . sortedTroves . findInsertPosition (
2021-06-01 14:50:52 +00:00
partialRedemptionHintNicr ,
hintAddress ,
hintAddress ,
{
gasLimit : MAX_GAS ,
}
) ;
return {
partialRedemptionHintNicr ,
firstRedemptionHint ,
upperHint ,
lowerHint ,
} ;
} ;
2021-06-04 14:55:04 +00:00
const redeem = async ( amount , from , wallet , liquity ) = > {
await sendToken ( liquity . lusdToken , amount , from , wallet . address ) ;
2021-06-04 11:18:16 +00:00
const {
partialRedemptionHintNicr ,
firstRedemptionHint ,
upperHint ,
lowerHint ,
2021-06-08 15:57:36 +00:00
} = await getRedemptionHints ( amount , liquity ) ;
2021-06-04 11:18:16 +00:00
const maxFeePercentage = ethers . utils . parseUnits ( "0.5" , 18 ) ; // 0.5% max fee
return await liquity . troveManager
. connect ( wallet )
. redeemCollateral (
amount ,
firstRedemptionHint ,
upperHint ,
lowerHint ,
partialRedemptionHintNicr ,
0 ,
maxFeePercentage ,
{
gasLimit : MAX_GAS , // permit max gas
}
) ;
} ;
2021-06-01 14:50:52 +00:00
module .exports = {
deployAndConnect ,
2021-06-04 11:18:16 +00:00
resetInitialState ,
2021-06-01 14:50:52 +00:00
createDsaTrove ,
sendToken ,
2021-06-04 11:18:16 +00:00
getTroveInsertionHints ,
getRedemptionHints ,
redeem ,
2021-06-08 15:57:36 +00:00
LIQUITY_CONNECTOR ,
2021-06-01 14:50:52 +00:00
LUSD_GAS_COMPENSATION ,
JUSTIN_SUN_ADDRESS ,
LIQUIDATABLE_TROVE_ADDRESS ,
MAX_GAS ,
2021-06-08 15:57:36 +00:00
INSTADAPP_BASIC_V1_CONNECTOR ,
ETH_ADDRESS ,
2021-06-01 14:50:52 +00:00
} ;