Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Receivable E2E testing #374

Merged
merged 14 commits into from
Apr 15, 2024
4 changes: 2 additions & 2 deletions hardhat.base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import { HardhatUserConfig } from "hardhat/types";
// Hardhat tasks
import "./tasks/advance-epoch";
import "./tasks/advance-week-and-drawdown-receivable";
import "./tasks/prepare-tranches-flc-for-withdrawal";
import "./tasks/withdraw-from-tranches";
import "./tasks/log-incomes";
import "./tasks/withdraw-and-close-pool";

const EMPTY_URL = "empty url";
const EMPTY_PRIVATE_KEY = "0x0000000000000000000000000000000000000000000000000000000000000000";
Expand Down
2 changes: 1 addition & 1 deletion scripts/deploy-all-local-test-pools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { deployPools } from "./deploy-local-test-pools";

(async () => {
try {
await deployPools({ shouldAdvanceTime: false });
await deployPools();
} catch (error) {
console.error(error);
process.exitCode = 1;
Expand Down
2 changes: 1 addition & 1 deletion scripts/deploy-credit-line-pools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { deployPools } from "./deploy-local-test-pools";

(async () => {
try {
await deployPools({ onlyDeployPoolName: LocalPoolName.CreditLine });
await deployPools(LocalPoolName.CreditLine);
} catch (error) {
console.error(error);
process.exitCode = 1;
Expand Down
162 changes: 66 additions & 96 deletions scripts/deploy-local-test-pools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { BigNumber as BN } from "ethers";
import { ethers } from "hardhat";
import moment from "moment";

import { getAccountSigners } from "../tasks/utils";
import {
CreditContractName,
CreditManagerContractName,
Expand All @@ -14,60 +15,15 @@ import {
import { CONSTANTS, LocalPoolName } from "../test/constants";
import { overrideFirstLossCoverConfig, toToken } from "../test/TestUtils";
import {
Calendar,
CreditDueManager,
CreditLine,
CreditLineManager,
EpochManager,
FirstLossCover,
HumaConfig,
MockToken,
Pool,
PoolConfig,
PoolFeeManager,
PoolSafe,
Receivable,
ReceivableBackedCreditLine,
RiskAdjustedTranchesPolicy,
TrancheVault,
ReceivableBackedCreditLineManager,
} from "../typechain-types";
import { advanceChainTime } from "./utils";

let defaultDeployer: SignerWithAddress,
protocolOwner: SignerWithAddress,
treasury: SignerWithAddress,
sentinelServiceAccount: SignerWithAddress;
let poolOwner: SignerWithAddress,
poolOwnerTreasury: SignerWithAddress,
evaluationAgent: SignerWithAddress,
poolOperator: SignerWithAddress;
let juniorLender: SignerWithAddress,
seniorLender: SignerWithAddress,
lenderRedemptionActive: SignerWithAddress,
borrowerActive: SignerWithAddress,
borrowerApproved: SignerWithAddress,
borrowerNoAutopay: SignerWithAddress,
borrowerAutopayReady: SignerWithAddress,
borrowerLate: SignerWithAddress,
borrowerDefault: SignerWithAddress;

let humaConfigContract: HumaConfig, mockTokenContract: MockToken;
let poolConfigContract: PoolConfig,
poolFeeManagerContract: PoolFeeManager,
poolSafeContract: PoolSafe,
calendarContract: Calendar,
borrowerFirstLossCoverContract: FirstLossCover,
adminFirstLossCoverContract: FirstLossCover,
tranchesPolicyContract: RiskAdjustedTranchesPolicy,
poolContract: Pool,
epochManagerContract: EpochManager,
seniorTrancheVaultContract: TrancheVault,
juniorTrancheVaultContract: TrancheVault,
creditContract: CreditLine | ReceivableBackedCreditLine,
creditDueManagerContract: CreditDueManager,
creditManagerContract: CreditLineManager,
receivableContract: Receivable;

const poolsToDeploy: {
creditContract: CreditContractName;
manager: CreditManagerContractName;
Expand All @@ -86,7 +42,12 @@ const poolsToDeploy: {
// Add more pools as needed
];

async function depositFirstLossCover(coverContract: FirstLossCover, account: SignerWithAddress) {
async function depositFirstLossCover(
coverContract: FirstLossCover,
mockTokenContract: MockToken,
poolOwner: SignerWithAddress,
account: SignerWithAddress,
) {
await coverContract.connect(poolOwner).addCoverProvider(account.address);
await mockTokenContract
.connect(account)
Expand All @@ -110,7 +71,7 @@ async function deployPool(
console.log(`Pool name: ${poolName}`);
}
console.log(`Starting block timestamp: ${await time.latest()}`);
[
const {
defaultDeployer,
protocolOwner,
treasury,
Expand All @@ -123,22 +84,17 @@ async function deployPool(
seniorLender,
lenderRedemptionActive,
borrowerActive,
borrowerApproved,
borrowerNoAutopay,
borrowerAutopayReady,
borrowerLate,
borrowerDefault,
] = await ethers.getSigners();
} = await getAccountSigners(ethers);

console.log("Deploying and setting up protocol contracts");
[humaConfigContract, mockTokenContract] = await deployProtocolContracts(
const [humaConfigContract, mockTokenContract] = await deployProtocolContracts(
protocolOwner,
treasury,
sentinelServiceAccount,
poolOwner,
);

[
const [
poolConfigContract,
poolFeeManagerContract,
poolSafeContract,
Expand All @@ -150,9 +106,9 @@ async function deployPool(
epochManagerContract,
seniorTrancheVaultContract,
juniorTrancheVaultContract,
creditContract as unknown,
creditContract,
creditDueManagerContract,
creditManagerContract as unknown,
creditManagerContract,
receivableContract,
] = await deployAndSetupPoolContracts(
humaConfigContract,
Expand All @@ -170,7 +126,12 @@ async function deployPool(
);

// Deposit first loss cover
await depositFirstLossCover(borrowerFirstLossCoverContract, borrowerActive);
await depositFirstLossCover(
borrowerFirstLossCoverContract,
mockTokenContract,
poolOwner,
borrowerActive,
);

// Set first loss cover liquidity cap
const totalAssetsBorrowerFLC = await borrowerFirstLossCoverContract.totalAssets();
Expand Down Expand Up @@ -208,15 +169,17 @@ async function deployPool(

if (poolName === LocalPoolName.CreditLine) {
console.log("Drawing down from CreditLine");
await creditManagerContract.connect(evaluationAgent).approveBorrower(
borrowerActive.address,
toToken(100_000),
5, // numOfPeriods
1217, // yieldInBps
toToken(0),
0,
true,
);
await (creditManagerContract as CreditLineManager)
.connect(evaluationAgent)
.approveBorrower(
borrowerActive.address,
toToken(100_000),
5, // numOfPeriods
1217, // yieldInBps
toToken(0),
0,
true,
);
const borrowAmount = toToken(100_000);

// Drawing down credit line
Expand Down Expand Up @@ -244,21 +207,30 @@ async function deployPool(
lateFeeBps,
});

console.log("Drawing down from CreditLine");
await creditManagerContract.connect(evaluationAgent).approveBorrower(
borrowerActive.address,
toToken(100_000),
5, // numOfPeriods
1217, // yieldInBps
toToken(0),
0,
true,
);
console.log("Drawing down from ReceivableBackedCreditLine");
await (creditManagerContract as ReceivableBackedCreditLineManager)
.connect(evaluationAgent)
.approveBorrower(
borrowerActive.address,
toToken(100_000),
5, // numOfPeriods
1217, // yieldInBps
toToken(0),
0,
true,
);
const borrowAmount = toToken(100_000);

const currentBlockTimestamp = await time.latest();
await receivableContract
.connect(borrowerActive)
.createReceivable(1, borrowAmount, moment().add(7, "days").hour(0).unix(), "", "");
.createReceivable(
1,
borrowAmount,
moment.unix(currentBlockTimestamp).add(7, "days").hour(0).unix(),
"",
"",
);
const receivableId = await receivableContract.tokenOfOwnerByIndex(
borrowerActive.address,
0,
Expand All @@ -273,13 +245,13 @@ async function deployPool(

console.log("=====================================");
console.log("Accounts:");
console.log(`Junior lender: ${juniorLender.address}`);
console.log(`Senior lender: ${seniorLender.address}`);
console.log(`Borrower: ${borrowerActive.address}`);
console.log(`Junior lender: ${juniorLender.address}`);
console.log(`Senior lender: ${seniorLender.address}`);
console.log(`Borrower: ${borrowerActive.address}`);
console.log(`Sentinel Service: ${sentinelServiceAccount.address}`);
console.log(`Pool owner: ${poolOwner.address}`);
console.log(`Pool owner: ${poolOwner.address}`);
console.log("-------------------------------------");

console.log("=====================================");
console.log("Addresses:");
console.log(`Pool: ${poolContract.address}`);
console.log(`Epoch manager: ${epochManagerContract.address}`);
Expand All @@ -292,23 +264,21 @@ async function deployPool(
console.log(`Credit: ${creditContract.address}`);
console.log(`Credit manager: ${creditManagerContract.address}`);
console.log(`Borrower FLC: ${borrowerFirstLossCoverContract.address}`);
console.log(`Admin FLC: ${adminFirstLossCoverContract.address}`);

console.log(`Admin FLC: ${adminFirstLossCoverContract.address}`);
if (poolName === LocalPoolName.ReceivableBackedCreditLine) {
console.log(`Receivable: ${receivableContract.address}`);
}
console.log("=====================================");
console.log(`Current block timestamp: ${await time.latest()}`);
}

export async function deployPools({
onlyDeployPoolName = undefined,
shouldAdvanceTime = true,
}: {
onlyDeployPoolName?: LocalPoolName;
shouldAdvanceTime?: boolean;
}) {
export async function deployPools(
onlyDeployPoolName: LocalPoolName | undefined = undefined,
shouldAdvanceTime: boolean = true,
) {
try {
if (shouldAdvanceTime) {
// always set the date to the 8th of the next month
const blockchainStartDate = moment().utc().add(1, "month").date(8).startOf("day");
// always set the date to the 1st of the next month
const blockchainStartDate = moment().utc().add(1, "month").startOf("month");
await advanceChainTime(blockchainStartDate);
}

Expand Down
2 changes: 1 addition & 1 deletion scripts/deploy-receivable-backed-credit-line-pools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { deployPools } from "./deploy-local-test-pools";

(async () => {
try {
await deployPools({ onlyDeployPoolName: LocalPoolName.ReceivableBackedCreditLine });
await deployPools(LocalPoolName.ReceivableBackedCreditLine);
} catch (error) {
console.error(error);
process.exitCode = 1;
Expand Down
8 changes: 5 additions & 3 deletions tasks/advance-epoch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { HardhatRuntimeEnvironment } from "hardhat/types/runtime";
task("advanceEpoch", "Advances time in the local blockchain based on options")
.addParam(
"poolConfigAddr",
"The address of the Pool Config whose epoch you wish to advance to next",
"The PoolConfig contract address of the pool in question",
)
.setAction(async (taskArgs: { poolConfigAddr: string }, hre: HardhatRuntimeEnvironment) => {
console.log("Advancing to next epoch");
Expand All @@ -23,7 +23,7 @@ task("advanceEpoch", "Advances time in the local blockchain based on options")
poolSettings.payPeriodDuration,
currentBlockTimestamp,
);
const timestampToAdvance = nextEpochStartTime.toNumber() - currentBlockTimestamp;
const timestampToAdvance = nextEpochStartTime.toNumber();

if (timestampToAdvance < currentBlockTimestamp) {
console.log("The selected milestone is in the past. Exiting.");
Expand All @@ -33,6 +33,8 @@ task("advanceEpoch", "Advances time in the local blockchain based on options")
console.log(`Advancing blockchain to ${timestampToAdvance}`);

// Simulate the passage of time by advancing the time on the Hardhat Network
await hre.network.provider.send("evm_setNextBlockTimestamp", [timestampToAdvance]);
await hre.network.provider.send("evm_setNextBlockTimestamp", [timestampToAdvance + 60]);
await hre.network.provider.send("evm_mine");
await hre.network.provider.send("evm_mine");
await hre.network.provider.send("evm_mine");
});
Loading
Loading