-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathcollab_banking
More file actions
212 lines (170 loc) · 8.14 KB
/
collab_banking
File metadata and controls
212 lines (170 loc) · 8.14 KB
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
203
204
205
206
207
208
209
210
211
212
pragma solidity ^0.6.11;
// Assumptions:
// - banks require no minimum reserve
// - interest is the same for savings account and loans
// - everyone and every bank is allowed to borrow money and to the same conditions (no risk premium)
// - the central bank gives out interest-free loans
// - interbank transfers are free of interest, because the lender of lenders (central bank) can provide liquidity for free
// - interbank transfers and central bank loans need to be recorded in a central bank registry, by timestamp
// - negative interest rates are not permitted in (commercial) banks
contract CentralBank {
uint CbLoans;
uint MaxCbLoans = 2e20;
uint maxInterestRate = 30;
struct bank {
Bank bank;
address owner;
uint interestRate;
}
struct tx { // interbank transaction structure
address lender;
address receiver;
uint time;
uint amount;
}
mapping(address => bank) banks;
Bank[] bankList;
mapping(uint => tx) Tx;
uint[] TxList;
function registerBank(Bank commBank, address owner, uint interestRate) external returns(bool){ // register a new bank
if (0 <= interestRate && interestRate < maxInterestRate) {
//"InterestRate must be within 0% and 100%!"
return false;
}
banks[owner] = bank(commBank, owner, interestRate);
bankList.push(commBank);
return true;
}
function getOtherBanks() external returns(Bank[] memory) { // get an array of addresses from registered banks
return bankList;
}
function registerTx(address receiver, address lender, uint amount) public { // register interbank and central bank transactions
uint time = uint(now);
Tx[time] = (lender, receiver, time, amount); //TODO: has error
TxList.push(time);
}
function cbLend(address payable receiver, uint amount) external { // central bank lending (to commercial bank only)
require(CbLoans+amount <= MaxCbLoans, "Amount exceeds max permitted CB loans!");
registerTx(receiver, address(this), amount);
CbLoans += amount;
receiver.transfer(amount);
}
function repayCb(address sender, uint amount) external { // bank repaying central bank loans
registerTx(address(this), sender, amount);
CbLoans -= amount;
}
}
contract Bank {
uint private interestRate; // interest rate in %
address private owner; // owner of the bank
uint private bankReserve;
CentralBank cBank; // init central bank
constructor(CentralBank centralBank) public {
owner = msg.sender;
interestRate = 20;
bankReserve = 1000;
cBank = centralBank;
require(cBank.registerBank(this, owner, interestRate), "Interest rate condition was not met.");
}
struct accountHolder {
uint accountBal;
uint lendAmount;
uint lastUpdateTime;
}
mapping(address => accountHolder) users;
function accountInfo() public view returns(accountHolder memory) { // return account information
return users[msg.sender];
}
function withdraw(uint withdrawAmt) external { // withdraw money from account
users[msg.sender].accountBal = getInterestWithBal(users[msg.sender].accountBal);
require(withdrawAmt <= users[msg.sender].accountBal, "Account lacks sufficient balance.");
if (withdrawAmt > bankReserve) {
interBankTransfer(withdrawAmt - bankReserve);
bankReserve = 0;
} else {
bankReserve -= withdrawAmt;
}
users[msg.sender].accountBal -= withdrawAmt;
msg.sender.transfer(withdrawAmt);
}
function deposit() external payable { // deposit money in account
users[msg.sender].accountBal = getInterestWithBal(users[msg.sender].accountBal) + msg.value;
bankReserve += msg.value;
}
function lend(uint lendAmt) public { // lend money from bank
if (lendAmt > bankReserve) {
interBankTransfer(lendAmt - bankReserve);
bankReserve = 0;
} else {
bankReserve -= lendAmt;
}
users[msg.sender].lendAmount += lendAmt;
users[msg.sender].lastUpdateTime = now;
msg.sender.transfer(lendAmt);
}
function repayLoan() external payable { // repay open loan amount to bank
uint amount = msg.value;
users[msg.sender].lendAmount = getInterestWithBal(users[msg.sender].lendAmount) - amount;
bankReserve += amount;
}
function getInterestRate() public view returns(uint) { // get current bank interest rate
return interestRate;
}
function updateInterestRate(uint newInterestRate) public { // update current bank interest rate
require(msg.sender == owner, "You are not allowed to update the interest rate!");
require(0 < newInterestRate && newInterestRate < 100, "InterestRate must be within 0% and 100%");
interestRate = newInterestRate;
}
function internalCustomerTransfer(address destination, uint amount) external { // transfer money from one account to another within bank
require(amount <= users[msg.sender].accountBal, "Balance is not sufficient");
users[msg.sender].accountBal = getInterestWithBal(users[msg.sender].accountBal) - amount;
users[destination].accountBal = getInterestWithBal(users[destination].accountBal) + amount;
}
//TODO: external customer transfer
// This is not a hard requirement and quite frankly hard to implement. Dropping this for now.
function getInterestWithBal(uint balance) private returns(uint) {
uint months = uint(ufixed(now- users[msg.sender].lastUpdateTime)/(60*60*24*30));
ufixed interest = ufixed(balance *interestRate*months)/1200;
//uint interest = principle*(1+interestRate/100/12)**(months) - int(principle); // Cannot implement compound interest as interestRate/100/12 will always result to 0 as we can't float ^ int in solidity
users[msg.sender].lastUpdateTime = now;
return balance + uint(interest);
}
function interBankTransfer(uint amount) private { // transfer money from one bank to another
Bank[] memory bankList = cBank.getOtherBanks(); //TODO: does not work as expected
uint i = 0;
uint len = bankList.length;
while (i < len) {
if (this != bankList[i]) {
Bank bank = bankList[i];
if(bank.getAdvance(amount)) {
bankReserve += amount;
break;
}
}
i+=1;
}
address b = bankList[i]; //TODO: due to error above, does not work as expected
payBank(b, amount);
if (i < len) { // register inter bank transfer in central bank
cBank.registerTx(address(this), b, amount);
} else { // get fund from central bank!
cBank.cbLend(address(this), amount); //TODO: error
}
}
function payBank(address payable b, uint amount) private {
b.transfer(amount);
}
function repayCb(uint amount) public payable { // repay central bank loans
cBank.repayCb(address(this), amount);
cBank.transfer(amount); //TODO: this does not work. Get explicit address of CB and then transfer
}
function getAdvance(uint amount) public returns(bool) {
if (bankReserve < amount) {
return false;
}
// Other Banks will also be treated as User
users[msg.sender].lendAmount = getInterestWithBal(users[msg.sender].lendAmount) + amount;
bankReserve -= amount;
return true;
}
}