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
const CONNECTOR _NAME = "LIQUITY-v1-TEST" ;
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)
const openTroveSpell = async (
dsa ,
signer ,
depositAmount ,
borrowAmount ,
upperHint ,
lowerHint ,
maxFeePercentage
) => {
let address = signer . address ;
if ( signer . address === undefined ) {
address = await signer . getAddress ( ) ;
}
const openTroveSpell = {
connector : CONNECTOR _NAME ,
method : "open" ,
args : [
depositAmount ,
maxFeePercentage ,
borrowAmount ,
upperHint ,
lowerHint ,
0 ,
0 ,
] ,
} ;
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 ,
hintHelpers ,
sortedTroves ,
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 ,
hintHelpers ,
sortedTroves
) ;
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 ) ;
return await token . connect ( signer ) . transfer ( to , amount ) ;
} ;
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 ( {
connectorName : CONNECTOR _NAME ,
contractArtifact : connectV2LiquityArtifacts ,
signer : masterSigner ,
connectors : instaConnectorsV2 ,
} ) ;
isDebug &&
console . log ( ` ${ CONNECTOR _NAME } Connector address ` , connector . address ) ;
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
) ;
isDebug &&
console . log ( "TroveManager contract address" , liquity . troveManager . address ) ;
liquity . borrowerOperations = new ethers . Contract (
contracts . BORROWER _OPERATIONS _ADDRESS ,
contracts . BORROWER _OPERATIONS _ABI ,
ethers . provider
) ;
isDebug &&
console . log (
"BorrowerOperations contract address" ,
liquity . borrowerOperations . address
) ;
liquity . stabilityPool = new ethers . Contract (
contracts . STABILITY _POOL _ADDRESS ,
contracts . STABILITY _POOL _ABI ,
ethers . provider
) ;
isDebug &&
console . log (
"StabilityPool contract address" ,
liquity . stabilityPool . address
) ;
liquity . lusdToken = new ethers . Contract (
contracts . LUSD _TOKEN _ADDRESS ,
contracts . LUSD _TOKEN _ABI ,
ethers . provider
) ;
isDebug &&
console . log ( "LusdToken contract address" , liquity . lusdToken . address ) ;
liquity . lqtyToken = new ethers . Contract (
contracts . LQTY _TOKEN _ADDRESS ,
contracts . LQTY _TOKEN _ABI ,
ethers . provider
) ;
isDebug &&
console . log ( "LqtyToken contract address" , liquity . lqtyToken . address ) ;
liquity . activePool = new ethers . Contract (
contracts . ACTIVE _POOL _ADDRESS ,
contracts . ACTIVE _POOL _ABI ,
ethers . provider
) ;
isDebug &&
console . log ( "ActivePool contract address" , liquity . activePool . address ) ;
liquity . priceFeed = new ethers . Contract (
contracts . PRICE _FEED _ADDRESS ,
contracts . PRICE _FEED _ABI ,
ethers . provider
) ;
isDebug &&
console . log ( "PriceFeed contract address" , liquity . priceFeed . address ) ;
liquity . hintHelpers = new ethers . Contract (
contracts . HINT _HELPERS _ADDRESS ,
contracts . HINT _HELPERS _ABI ,
ethers . provider
) ;
isDebug &&
console . log ( "HintHelpers contract address" , liquity . hintHelpers . address ) ;
liquity . sortedTroves = new ethers . Contract (
contracts . SORTED _TROVES _ADDRESS ,
contracts . SORTED _TROVES _ABI ,
ethers . provider
) ;
isDebug &&
console . log ( "SortedTroves contract address" , liquity . sortedTroves . address ) ;
liquity . staking = new ethers . Contract (
contracts . STAKING _ADDRESS ,
contracts . STAKING _ABI ,
ethers . provider
) ;
isDebug && console . log ( "Staking contract address" , liquity . staking . address ) ;
2021-06-04 11:18:16 +00:00
liquity . collSurplus = new ethers . Contract (
contracts . COLL _SURPLUS _ADDRESS ,
contracts . COLL _SURPLUS _ABI ,
ethers . provider
) ;
isDebug &&
console . log ( "CollSurplus contract address" , liquity . collSurplus . address ) ;
2021-06-01 14:50:52 +00:00
return liquity ;
} ;
const getTroveInsertionHints = async (
depositAmount ,
borrowAmount ,
hintHelpers ,
sortedTroves
) => {
const nominalCR = await hintHelpers . computeNominalCR (
depositAmount ,
borrowAmount
) ;
const { hintAddress , latestRandomSeed } = await hintHelpers . getApproxHint (
nominalCR ,
50 ,
1298379 ,
{
gasLimit : MAX _GAS ,
}
) ;
randomSeed = latestRandomSeed ;
const { 0 : upperHint , 1 : lowerHint } = await sortedTroves . findInsertPosition (
nominalCR ,
hintAddress ,
hintAddress ,
{
gasLimit : MAX _GAS ,
}
) ;
return {
upperHint ,
lowerHint ,
} ;
} ;
let randomSeed = 4223 ;
const getRedemptionHints = async (
amount ,
hintHelpers ,
sortedTroves ,
priceFeed
) => {
const ethPrice = await priceFeed . callStatic . fetchPrice ( ) ;
const [
firstRedemptionHint ,
partialRedemptionHintNicr ,
] = await hintHelpers . getRedemptionHints ( amount , ethPrice , 0 ) ;
const { hintAddress , latestRandomSeed } = await hintHelpers . getApproxHint (
partialRedemptionHintNicr ,
50 ,
randomSeed ,
{
gasLimit : MAX _GAS ,
}
) ;
randomSeed = latestRandomSeed ;
const { 0 : upperHint , 1 : lowerHint } = await sortedTroves . findInsertPosition (
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 ,
} = await getRedemptionHints (
amount ,
liquity . hintHelpers ,
liquity . sortedTroves ,
liquity . priceFeed
) ;
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-01 14:50:52 +00:00
CONNECTOR _NAME ,
LUSD _GAS _COMPENSATION ,
JUSTIN _SUN _ADDRESS ,
LIQUIDATABLE _TROVE _ADDRESS ,
MAX _GAS ,
} ;