2021-06-01 14:50:52 +00:00
const hre = require ( "hardhat" ) ;
const hardhatConfig = require ( "../../hardhat.config" ) ;
// Instadapp deployment and testing helpers
const deployAndEnableConnector = require ( "../../scripts/deployAndEnableConnector.js" ) ;
const encodeSpells = require ( "../../scripts/encodeSpells.js" ) ;
const getMasterSigner = require ( "../../scripts/getMasterSigner" ) ;
2021-06-04 11:18:16 +00:00
const buildDSAv2 = require ( "../../scripts/buildDSAv2" ) ;
2021-06-01 14:50:52 +00:00
// Instadapp instadappAddresses/ABIs
const instadappAddresses = require ( "../../scripts/constant/addresses" ) ;
const instadappAbi = require ( "../../scripts/constant/abis" ) ;
// Instadapp Liquity Connector artifacts
const connectV2LiquityArtifacts = require ( "../../artifacts/contracts/mainnet/connectors/liquity/main.sol/ConnectV2Liquity.json" ) ;
const connectV2BasicV1Artifacts = require ( "../../artifacts/contracts/mainnet/connectors/basic/main.sol/ConnectV2Basic.json" ) ;
2021-06-04 11:18:16 +00:00
const { ethers } = require ( "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
const { eth _addr : ETH _ADDRESS } = require ( "../../scripts/constant/constant" ) ;
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 ,
signer ,
depositAmount ,
borrowAmount ,
upperHint ,
lowerHint ,
maxFeePercentage
) => {
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
} ;