-
Notifications
You must be signed in to change notification settings - Fork 1
/
smartcontract.sol
203 lines (165 loc) · 7.7 KB
/
smartcontract.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./LiquidityPool.sol";
import "https://github.com/molecule-protocol/molecule-core/blob/main/src/v2/interfaces/IMoleculeController.sol";
import "./MyCustomController.sol";
contract MicroEther {
MyCustomController public myCustomController; //can be used for additional conditions to control the transactions
// in order to prevent them
IMoleculeController public moleculeGeneralSanctionController;
uint[] public regionalIds;
constructor(MyCustomController _myCustomController, IMoleculeController _moleculeGeneralSanctionController) {
myCustomController = _myCustomController; //can be used for additional conditions to control the transactions
// in order to prevent them
moleculeGeneralSanctionController = _moleculeGeneralSanctionController;
}
function addRegionalId(uint _regionalId) external {
regionalIds.push(_regionalId);
}
/*function myFunction() external {
require(moleculeGeneralSanctionController.check(regionalIds, msg.sender), "Address is sanctioned.");
require(myCustomController.check(msg.sender), "Address is not authorized.");
}*/
LiquidityPool private liquidityPool;
address constant LIQUIDITY_POOL_ADDRESS = 0x7EF2e0048f5bAeDe046f6BF797943daF4ED8CB47;
enum RepaymentMethod { Monthly, Quarterly, Yearly }
enum LoanType { Uncollateralized, SocialCollateral }
struct Loan {
address payable borrower;
uint256 amount;
uint256 dueDate;
uint256 interestRate;
RepaymentMethod repaymentMethod;
LoanType loanType;
int8 numGuarantors;
int8 actualGuarantors;
bool isFunded;
}
uint256 private loanIDCounter = 0;
mapping(address => int) public creditScores;
mapping(uint256 => Loan) public loans;
mapping(uint256 => address[]) public loanGuarantors;
uint256 constant MIN_GUARANTORS = 10;
int constant UNC_COLLATERAL_THRESHOLD = 50;
int constant SCORE_DECREASE_BORROWER = 40;
int constant SCORE_INCREASE_BORROWER = 10;
int constant SCORE_DECREASE_GUARANTOR = 10;
int constant SCORE_INCREASE_GUARANTOR = 2;
int constant MINIMUM_SCORE = -70;
int constant MAX_SCORE = 100;
event LoanApplied(uint256 loanId, address indexed borrower);
event LoanGuaranteed(uint256 loanId, address indexed guarantor);
event LoanFunded(uint256 loanId);
constructor() {
liquidityPool = LiquidityPool(LIQUIDITY_POOL_ADDRESS);
creditScores[msg.sender] = 0;
}
function calculateInterestRate(address borrower, LoanType collateral) private view returns (uint256) {
int score = creditScores[borrower];
uint256 Rmin;
uint256 Rmax;
if(collateral == LoanType.SocialCollateral) {
Rmin = 2;
Rmax = 6;
} else {
Rmin = 10;
Rmax = 15;
}
uint256 R = Rmin + ((Rmax - Rmin) * (100 - uint256(score))) / 200;
return R;
}
function applyForLoan(
uint256 _loanAmount,
uint256 _dueDate,
RepaymentMethod _repaymentMethod,
LoanType _loanType,
int8 _numGuarantors
) public returns (uint256) {
require(moleculeGeneralSanctionController.check(regionalIds, msg.sender), "Address is sanctioned.");
require(creditScores[msg.sender] >= MINIMUM_SCORE, "Credit score too low");
require(_numGuarantors >= 5 && _numGuarantors <= 20, "Invalid number of guarantors");
uint256 interestRate = calculateInterestRate(msg.sender, _loanType);
if(_loanType == LoanType.Uncollateralized) {
require(creditScores[msg.sender] > UNC_COLLATERAL_THRESHOLD, "Credit score not sufficient for uncollateralized loan");
} else if(_loanType == LoanType.SocialCollateral) {
creditScores[msg.sender] += _numGuarantors;
if (creditScores[msg.sender] > MAX_SCORE) {
creditScores[msg.sender] = MAX_SCORE;
}
}
loanIDCounter++;
loans[loanIDCounter] = Loan({
borrower: payable(msg.sender),
amount: _loanAmount,
dueDate: _dueDate,
interestRate: interestRate,
repaymentMethod: _repaymentMethod,
loanType: _loanType,
numGuarantors: _numGuarantors,
actualGuarantors: 0,
isFunded: false
});
emit LoanApplied(loanIDCounter, msg.sender);
return loanIDCounter;
}
// In the future, Guarantors have to be verified by World ID
// To guarantee that they are all individual people
function guaranteeLoan(uint256 _loanId) external {
Loan storage loan = loans[_loanId];
require(loan.loanType == LoanType.SocialCollateral, "Only social collateral loans can be guaranteed");
require((int256)(loanGuarantors[_loanId].length) < loan.numGuarantors, "This loan already has enough guarantors");
loanGuarantors[_loanId].push(msg.sender);
emit LoanGuaranteed(_loanId, msg.sender);
if ((int256)(loanGuarantors[_loanId].length) == loan.numGuarantors) {
loan.isFunded = true;
emit LoanFunded(_loanId);
}
}
function repayLoan(uint256 _loanId) external payable {
Loan storage loan = loans[_loanId];
require(msg.sender == loan.borrower, "Only the borrower can repay");
uint256 expectedRepayment = loans[_loanId].amount + (loans[_loanId].amount * calculateInterestRate(loans[_loanId].borrower, loans[_loanId].loanType) / 100);
require(msg.value == expectedRepayment, "Incorrect repayment amount");
if (block.timestamp <= loan.dueDate) {
creditScores[loan.borrower] += SCORE_INCREASE_BORROWER;
for (uint256 i = 0; i < loanGuarantors[_loanId].length; i++) {
creditScores[loanGuarantors[_loanId][i]] += SCORE_INCREASE_GUARANTOR;
}
} else {
creditScores[loan.borrower] -= SCORE_DECREASE_BORROWER;
for (uint256 i = 0; i < loanGuarantors[_loanId].length; i++) {
creditScores[loanGuarantors[_loanId][i]] -= SCORE_DECREASE_GUARANTOR;
}
}
// Transfer the ether to a safe storage or use it to fund other loans.
// For this example, let's assume there's an owner/admin that collects repayments.
// The "owner" could be a multi-signature wallet, another smart contract, or a centralized entity.
address payable owner = payable(address(this)); // Replace with the desired address
owner.transfer(msg.value);
// Repay the liquidity pool
liquidityPool.deposit(msg.value);
}
function vouchForLoan(uint256 _loanID) public {
Loan storage loan = loans[_loanID];
require(loan.loanType == LoanType.SocialCollateral, "Can only vouch for social collateral loans");
require(loan.actualGuarantors < loan.numGuarantors, "Already has enough guarantors");
loanGuarantors[_loanID].push(msg.sender);
loan.actualGuarantors++;
if (loan.actualGuarantors == loan.numGuarantors) {
emit LoanFunded(_loanID);
}
}
function fundLoan(uint256 _loanId) internal {
Loan storage loan = loans[_loanId];
require(loan.isFunded == false, "Loan already funded");
uint256 interest = calculateInterestRate(msg.sender, loan.loanType);
uint256 totalAmount = loan.amount + (loan.amount * interest / 100);
// Withdraw funds from the liquidity pool
liquidityPool.withdraw(totalAmount);
loan.isFunded = true;
payable(msg.sender).transfer(totalAmount); // sending funds to the borrower
emit LoanFunded(_loanId);
}
function addFunds() external payable {}
receive() external payable {}
}