Skip to content

Commit

Permalink
Add support for defaults (#44)
Browse files Browse the repository at this point in the history
  • Loading branch information
ams9198 authored Oct 6, 2022
1 parent 678b963 commit d4d1f6b
Show file tree
Hide file tree
Showing 20 changed files with 482 additions and 26 deletions.
22 changes: 22 additions & 0 deletions contracts/Loan.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import "./FundingVault.sol";
*/
contract Loan is ILoan {
IServiceConfiguration private immutable _serviceConfiguration;
address private immutable _factory;
ILoanLifeCycleState private _state = ILoanLifeCycleState.Requested;
address private immutable _borrower;
address private immutable _pool;
Expand Down Expand Up @@ -78,6 +79,7 @@ contract Loan is ILoan {

constructor(
IServiceConfiguration serviceConfiguration,
address factory,
address borrower,
address pool,
uint256 duration_,
Expand All @@ -89,6 +91,7 @@ contract Loan is ILoan {
uint256 dropDeadTimestamp
) {
_serviceConfiguration = serviceConfiguration;
_factory = factory;
_borrower = borrower;
_pool = pool;
_collateralVault = new CollateralVault(address(this));
Expand Down Expand Up @@ -231,6 +234,21 @@ contract Loan is ILoan {
return amount;
}

/**
* @inheritdoc ILoan
*/
function markDefaulted()
external
override
onlyPool
atState(ILoanLifeCycleState.Funded)
returns (ILoanLifeCycleState)
{
_state = ILoanLifeCycleState.Defaulted;
emit LifeCycleStateTransition(_state);
return _state;
}

function state() external view returns (ILoanLifeCycleState) {
return _state;
}
Expand All @@ -243,6 +261,10 @@ contract Loan is ILoan {
return _pool;
}

function factory() external view returns (address) {
return _factory;
}

function dropDeadTimestamp() external view returns (uint256) {
return _dropDeadTimestamp;
}
Expand Down
14 changes: 14 additions & 0 deletions contracts/LoanFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ contract LoanFactory {
*/
IServiceConfiguration private _serviceConfiguration;

/**
* @dev Mapping of created loans
*/
mapping(address => bool) private _isLoan;

/**
* @dev Emitted when a Loan is created.
*/
Expand Down Expand Up @@ -43,6 +48,7 @@ contract LoanFactory {
);
Loan loan = new Loan(
_serviceConfiguration,
address(this),
borrower,
pool,
duration,
Expand All @@ -55,6 +61,14 @@ contract LoanFactory {
);
address addr = address(loan);
emit LoanCreated(addr);
_isLoan[addr] = true;
return addr;
}

/**
* @dev Checks whether the address corresponds to a created loan for this factory
*/
function isLoan(address loan) public view returns (bool) {
return _isLoan[loan];
}
}
29 changes: 26 additions & 3 deletions contracts/Pool.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ pragma solidity ^0.8.16;

import "./interfaces/ILoan.sol";
import "./interfaces/IPool.sol";
import "./interfaces/IServiceConfiguration.sol";
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
Expand All @@ -19,6 +20,7 @@ contract Pool is IPool, ERC20 {

IPoolLifeCycleState private _poolLifeCycleState;
address private _manager;
IServiceConfiguration private _serviceConfiguration;
IERC20 private _liquidityAsset;
IPoolConfigurableSettings private _poolSettings;
FirstLossVault private _firstLossVault;
Expand Down Expand Up @@ -94,19 +96,22 @@ contract Pool is IPool, ERC20 {
* @param liquidityAsset asset held by the poo
* @param poolManager manager of the pool
* @param poolSettings configurable settings for the pool
* @param serviceConfiguration address of global service configuration
* @param tokenName Name used for issued pool tokens
* @param tokenSymbol Symbol used for issued pool tokens
*/
constructor(
address liquidityAsset,
address poolManager,
address serviceConfiguration,
IPoolConfigurableSettings memory poolSettings,
string memory tokenName,
string memory tokenSymbol
) ERC20(tokenName, tokenSymbol) {
_liquidityAsset = IERC20(liquidityAsset);
_poolSettings = poolSettings;
_manager = poolManager;
_serviceConfiguration = IServiceConfiguration(serviceConfiguration);
_firstLossVault = new FirstLossVault(address(this), liquidityAsset);
_setPoolLifeCycleState(IPoolLifeCycleState.Initialized);
}
Expand Down Expand Up @@ -221,13 +226,31 @@ contract Pool is IPool, ERC20 {

_liquidityAsset.safeApprove(address(loan), loan.principal());
loan.fund();
_accountings.activeLoanPrincipals += loan.principal();
}

/**
* @dev Called by the pool manager, marks a loan as in default, updating pool accounting and allowing loan
* collateral to be claimed.
* @inheritdoc IPool
*/
function markLoanAsInDefault(address) external onlyManager {}
function defaultLoan(address loan)
external
onlyManager
atState(IPoolLifeCycleState.Active)
{
require(loan != address(0), "Pool: 0 address");
require(
PoolLib.isPoolLoan(
loan,
address(_serviceConfiguration),
address(this)
),
"Pool: invalid loan"
);

ILoan(loan).markDefaulted();
_accountings.activeLoanPrincipals -= ILoan(loan).principal();
emit LoanDefaulted(loan);
}

/*//////////////////////////////////////////////////////////////
Withdrawal Request Methods
Expand Down
1 change: 1 addition & 0 deletions contracts/PoolFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ contract PoolFactory {
Pool pool = new Pool(
liquidityAsset,
msg.sender,
address(_serviceConfiguration),
settings,
"ValyriaPoolToken",
"VPT"
Expand Down
22 changes: 22 additions & 0 deletions contracts/ServiceConfiguration.sol
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ contract ServiceConfiguration is AccessControl, IServiceConfiguration {

mapping(address => bool) public isLiquidityAsset;

/**
* @dev Holds a reference to valid LoanFactories
*/
mapping(address => bool) public isLoanFactory;

/**
* @dev Emitted when an address is changed.
*/
Expand All @@ -36,6 +41,11 @@ contract ServiceConfiguration is AccessControl, IServiceConfiguration {
*/
event ProtocolPaused(bool paused);

/**
* @dev Emitted when a loan factory is set
*/
event LoanFactorySet(address indexed factory, bool isValid);

/**
* @dev Constructor for the contract, which sets up the default roles and
* owners.
Expand Down Expand Up @@ -78,4 +88,16 @@ contract ServiceConfiguration is AccessControl, IServiceConfiguration {
function isOperator(address addr) external view returns (bool) {
return hasRole(OPERATOR_ROLE, addr);
}

/**
* @inheritdoc IServiceConfiguration
*/
function setLoanFactory(address addr, bool isValid)
external
override
onlyOperator
{
isLoanFactory[addr] = isValid;
emit LoanFactorySet(addr, isValid);
}
}
9 changes: 9 additions & 0 deletions contracts/interfaces/ILoan.sol
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ struct ILoanNonFungibleCollateral {
}

interface ILoan {
/**
* @dev Emitted when a Loan's lifecycle state transitions
*/
event LifeCycleStateTransition(ILoanLifeCycleState state);

/**
* @dev Emitted when collateral is posted to the loan.
*/
Expand All @@ -52,6 +57,8 @@ interface ILoan {

function pool() external view returns (address);

function factory() external view returns (address);

function dropDeadTimestamp() external view returns (uint256);

function cancelRequested() external returns (ILoanLifeCycleState);
Expand Down Expand Up @@ -90,4 +97,6 @@ interface ILoan {
function principal() external returns (uint256);

function fundingVault() external returns (FundingVault);

function markDefaulted() external returns (ILoanLifeCycleState);
}
6 changes: 3 additions & 3 deletions contracts/interfaces/IPool.sol
Original file line number Diff line number Diff line change
Expand Up @@ -142,8 +142,8 @@ interface IPool is IERC4626 {
function fundLoan(address) external;

/**
* @dev Called by the pool manager, marks a loan as in default, updating pool accounting and allowing loan
* collateral to be claimed.
* @dev Called by the pool manager, this marks a loan as in default, triggering liquiditation
* proceedings and updating pool accounting.
*/
function markLoanAsInDefault(address) external;
function defaultLoan(address) external;
}
14 changes: 14 additions & 0 deletions contracts/interfaces/IServiceConfiguration.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,18 @@ interface IServiceConfiguration is IAccessControl {
function paused() external view returns (bool);

function isLiquidityAsset(address addr) external view returns (bool);

/**
* @dev checks if an address is a valid loan factory
* @param addr Address of loan factory
* @return bool whether the loan factory is valid
*/
function isLoanFactory(address addr) external view returns (bool);

/**
* @dev Sets whether a loan factory is valid
* @param addr Address of loan factory
* @param isValid Whether the loan factory is valid
*/
function setLoanFactory(address addr, bool isValid) external;
}
28 changes: 28 additions & 0 deletions contracts/libraries/PoolLib.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol
import {SafeMath} from "@openzeppelin/contracts/utils/math/SafeMath.sol";
import "../interfaces/ILoan.sol";
import "../interfaces/IPool.sol";
import "../interfaces/ILoan.sol";
import "../interfaces/IServiceConfiguration.sol";
import "../FirstLossVault.sol";
import "../LoanFactory.sol";

/**
* @title Collection of functions used by the Pool
Expand Down Expand Up @@ -45,6 +48,11 @@ library PoolLib {
uint256 shares
);

/**
* @dev See IPool for event definition
*/
event LoanDefaulted(address indexed loan);

/**
* @dev Transfers first loss to the vault.
* @param liquidityAsset Pool liquidity asset
Expand Down Expand Up @@ -237,4 +245,24 @@ library PoolLib {
) public view returns (uint256) {
return currentWithdrawPeriod(activatedAt, withdrawalWindowDuration) + 1;
}

/**
* @dev Determines whether an address corresponds to a pool loan
* @param loan address of loan
* @param serviceConfiguration address of service configuration
* @param pool address of pool
*/
function isPoolLoan(
address loan,
address serviceConfiguration,
address pool
) public view returns (bool) {
address factory = ILoan(loan).factory();
return
IServiceConfiguration(serviceConfiguration).isLoanFactory(
factory
) &&
LoanFactory(factory).isLoan(loan) &&
ILoan(loan).pool() == pool;
}
}
9 changes: 9 additions & 0 deletions contracts/mocks/PoolLibTestWrapper.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ pragma solidity ^0.8.16;

import "../libraries/PoolLib.sol";
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "../interfaces/IPool.sol";

/**
* @title PoolLibTestWrapper
Expand Down Expand Up @@ -119,4 +120,12 @@ contract PoolLibTestWrapper is ERC20("PoolLibTest", "PLT") {
_mint
);
}

function isPoolLoan(
address loan,
address serviceConfiguration,
address pool
) public view returns (bool) {
return PoolLib.isPoolLoan(loan, serviceConfiguration, pool);
}
}
12 changes: 11 additions & 1 deletion contracts/permissioned/PermissionedPool.sol
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,20 @@ contract PermissionedPool is Pool {
constructor(
address liquidityAsset,
address poolManager,
address serviceConfiguration,
IPoolConfigurableSettings memory poolSettings,
string memory tokenName,
string memory tokenSymbol
) Pool(liquidityAsset, poolManager, poolSettings, tokenName, tokenSymbol) {
)
Pool(
liquidityAsset,
poolManager,
serviceConfiguration,
poolSettings,
tokenName,
tokenSymbol
)
{
_poolAccessControl = new PoolAccessControl(address(this));
}

Expand Down
3 changes: 2 additions & 1 deletion contracts/permissioned/PermissionedPoolFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,10 @@ contract PermissionedPoolFactory is PoolFactory {
firstLossInitialMinimum,
withdrawRequestPeriodDuration
);
Pool pool = new PermissionedPool(
PermissionedPool pool = new PermissionedPool(
liquidityAsset,
msg.sender,
address(_serviceConfiguration),
settings,
"ValyriaPoolToken",
"VPT"
Expand Down
Loading

0 comments on commit d4d1f6b

Please sign in to comment.