diff --git a/contracts/Interest.sol b/contracts/Interest.sol index 16ed6dc..0b3f67d 100644 --- a/contracts/Interest.sol +++ b/contracts/Interest.sol @@ -1,6 +1,10 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; +import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol"; +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import "@openzeppelin/contracts/access/Ownable.sol"; + contract Loan { address public borrower; bool public paid; @@ -27,7 +31,11 @@ contract Loan { contract LoanInterestCalculator { uint256 public riskPremium = 110; // Represents a 10% premium (will get divided by 100 later) - function calculateInterest(uint256 amount, uint256 exchangeRate, uint256 creditScore) public view returns (uint256) { + function calculateInterest( + uint256 amount, + uint256 exchangeRate, + uint256 creditScore + ) public view returns (uint256) { // Calculate interest based on the risk premium and credit score uint256 baseInterest = (amount * riskPremium) / (100 * exchangeRate); uint256 creditScoreFactor; @@ -53,34 +61,36 @@ contract LoanInterestCalculator { } } -contract LendingPool { +contract BondedKT is ERC20Burnable, Ownable { + constructor() ERC20("BondedKT", "BKT") {} +} + +contract LendingPool is Ownable { + BondedKT public bondedToken; Loan[] public loans; LoanInterestCalculator public interestCalculator; - address public owner; mapping(address => uint256) public usersCollateralDict; mapping(address => uint256) public usersBorrowedDict; - - - modifier onlyOwner() { - require(msg.sender == owner, "Not the owner"); - _; - } - event LoanCreated(address indexed borrower, uint indexed loanedAmount); constructor(address _interestCalculator) { + bondedToken = new BondedKT(); owner = msg.sender; interestCalculator = LoanInterestCalculator(_interestCalculator); } - function createLoan ( + function createLoan( address _borrower, uint _loanedAmount, uint _creditScore ) external onlyOwner { // Calculate interest using the LoanInterestCalculator - uint interest = interestCalculator.calculateInterest(_loanedAmount, 1, _creditScore); + uint interest = interestCalculator.calculateInterest( + _loanedAmount, + 1, + _creditScore + ); // Create a new Loan instance Loan newLoan = new Loan( @@ -94,7 +104,74 @@ contract LendingPool { loans.push(newLoan); } + function requestLoan( + uint _loanedAmount, + uint _creditScore + ) external returns (uint loanId) { + // Calculate interest using the LoanInterestCalculator + uint interest = interestCalculator.calculateInterest( + _loanedAmount, + 1, + _creditScore + ); + + // Create a new Loan instance + Loan newLoan = new Loan( + msg.sender, + _loanedAmount, + interest, + block.timestamp + 30 days // Loan duration of 30 days in this example + ); + + // Add the loan to the list of loans in the pool + loans.push(newLoan); + + // Return the loanId + return loans.length - 1; + } + + function repay(uint loanId) external payable { + Loan storage loan = loans[loanId]; + + // Check that the borrower is the one calling the function + require( + msg.sender == loan.borrower, + "Only the borrower can repay the loan" + ); + + // Check that the borrower is repaying the correct amount + require( + msg.value == loan.loanedAmount + loan.interest_rate, + "Incorrect repayment amount" + ); + + // Mark the loan as paid + loan.paid = true; + } + + function fund() external payable { + // Mint bonded tokens equivalent to the amount of Ether sent and transfer them to the sender + bondedToken.mint(msg.sender, msg.value); + } + + function withdraw(uint256 amount) external { + // Check that the lender has enough bonded tokens + require( + bondedToken.balanceOf(msg.sender) >= amount, + "Not enough tokens" + ); + + // Check that the contract has enough balance to cover the withdrawal + require( + address(this).balance >= amount, + "Not enough funds in the pool" + ); + + // Transfer the funds plus interest from the pool to the lender + payable(msg.sender).transfer(amount + interest); + } + function getLoanCount() external view returns (uint) { return loans.length; } -} \ No newline at end of file +} diff --git a/package-lock.json b/package-lock.json index 3003884..bcd77e3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "name": "variable_lending_pool", "version": "0.1.0", "dependencies": { + "@openzeppelin/contracts": "^5.0.0", "@testing-library/jest-dom": "^5.17.0", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", @@ -3197,6 +3198,11 @@ "node": ">= 8" } }, + "node_modules/@openzeppelin/contracts": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@openzeppelin/contracts/-/contracts-5.0.0.tgz", + "integrity": "sha512-bv2sdS6LKqVVMLI5+zqnNrNU/CA+6z6CmwFXm/MzmOPBRSO5reEJN7z0Gbzvs0/bv/MZZXNklubpwy3v2+azsw==" + }, "node_modules/@pmmmwh/react-refresh-webpack-plugin": { "version": "0.5.11", "resolved": "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.11.tgz", @@ -20016,6 +20022,11 @@ "fastq": "^1.6.0" } }, + "@openzeppelin/contracts": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@openzeppelin/contracts/-/contracts-5.0.0.tgz", + "integrity": "sha512-bv2sdS6LKqVVMLI5+zqnNrNU/CA+6z6CmwFXm/MzmOPBRSO5reEJN7z0Gbzvs0/bv/MZZXNklubpwy3v2+azsw==" + }, "@pmmmwh/react-refresh-webpack-plugin": { "version": "0.5.11", "resolved": "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.11.tgz", diff --git a/package.json b/package.json index 90626a3..32e77c6 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,7 @@ "version": "0.1.0", "private": true, "dependencies": { + "@openzeppelin/contracts": "^5.0.0", "@testing-library/jest-dom": "^5.17.0", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0",