Guest User

UweBank

a guest
Nov 20th, 2021
88
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 32.53 KB | None | 0 0
  1. // SPDX-License-Identifier: MIT
  2. pragma solidity 0.7.0;
  3.  
  4. interface IBank {
  5. struct Account { // Note that token values have an 18 decimal precision
  6. uint256 deposit; // accumulated deposits made into the account
  7. uint256 interest; // accumulated interest
  8. uint256 lastInterestBlock; // block at which interest was last computed
  9. }
  10. // Event emitted when a user makes a deposit
  11. event Deposit(
  12. address indexed _from, // account of user who deposited
  13. address indexed token, // token that was deposited
  14. uint256 amount // amount of token that was deposited
  15. );
  16. // Event emitted when a user makes a withdrawal
  17. event Withdraw(
  18. address indexed _from, // account of user who withdrew funds
  19. address indexed token, // token that was withdrawn
  20. uint256 amount // amount of token that was withdrawn
  21. );
  22. // Event emitted when a user borrows funds
  23. event Borrow(
  24. address indexed _from, // account who borrowed the funds
  25. address indexed token, // token that was borrowed
  26. uint256 amount, // amount of token that was borrowed
  27. uint256 newCollateralRatio // collateral ratio for the account, after the borrow
  28. );
  29. // Event emitted when a user (partially) repays a loan
  30. event Repay(
  31. address indexed _from, // accout which repaid the loan
  32. address indexed token, // token that was borrowed and repaid
  33. uint256 remainingDebt // amount that still remains to be paid (including interest)
  34. );
  35. // Event emitted when a loan is liquidated
  36. event Liquidate(
  37. address indexed liquidator, // account which performs the liquidation
  38. address indexed accountLiquidated, // account which is liquidated
  39. address indexed collateralToken, // token which was used as collateral
  40. // for the loan (not the token borrowed)
  41. uint256 amountOfCollateral, // amount of collateral token which is sent to the liquidator
  42. uint256 amountSentBack // amount of borrowed token that is sent back to the
  43. // liquidator in case the amount that the liquidator
  44. // sent for liquidation was higher than the debt of the liquidated account
  45. );
  46. /**
  47. * The purpose of this function is to allow end-users to deposit a given
  48. * token amount into their bank account.
  49. * @param token - the address of the token to deposit. If this address is
  50. * set to 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE then
  51. * the token to deposit is ETH.
  52. * @param amount - the amount of the given token to deposit.
  53. * @return - true if the deposit was successful, otherwise revert.
  54. */
  55. function deposit(address token, uint256 amount) payable external returns (bool);
  56.  
  57. /**
  58. * The purpose of this function is to allow end-users to withdraw a given
  59. * token amount from their bank account. Upon withdrawal, the user must
  60. * automatically receive a 3% interest rate per 100 blocks on their deposit.
  61. * @param token - the address of the token to withdraw. If this address is
  62. * set to 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE then
  63. * the token to withdraw is ETH.
  64. * @param amount - the amount of the given token to withdraw. If this param
  65. * is set to 0, then the maximum amount available in the
  66. * caller's account should be withdrawn.
  67. * @return - the amount that was withdrawn plus interest upon success,
  68. * otherwise revert.
  69. */
  70. function withdraw(address token, uint256 amount) external returns (uint256);
  71.  
  72. /**
  73. * The purpose of this function is to allow users to borrow funds by using their
  74. * deposited funds as collateral. The minimum ratio of deposited funds over
  75. * borrowed funds must not be less than 150%.
  76. * @param token - the address of the token to borrow. This address must be
  77. * set to 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE, otherwise
  78. * the transaction must revert.
  79. * @param amount - the amount to borrow. If this amount is set to zero (0),
  80. * then the amount borrowed should be the maximum allowed,
  81. * while respecting the collateral ratio of 150%.
  82. * @return - the current collateral ratio.
  83. */
  84. function borrow(address token, uint256 amount) external returns (uint256);
  85.  
  86. /**
  87. * The purpose of this function is to allow users to repay their loans.
  88. * Loans can be repaid partially or entirely. When replaying a loan, an
  89. * interest payment is also required. The interest on a loan is equal to
  90. * 5% of the amount lent per 100 blocks. If the loan is repaid earlier,
  91. * or later then the interest should be proportional to the number of
  92. * blocks that the amount was borrowed for.
  93. * @param token - the address of the token to repay. If this address is
  94. * set to 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE then
  95. * the token is ETH.
  96. * @param amount - the amount to repay including the interest.
  97. * @return - the amount still left to pay for this loan, excluding interest.
  98. */
  99. function repay(address token, uint256 amount) payable external returns (uint256);
  100.  
  101. /**
  102. * The purpose of this function is to allow so called keepers to collect bad
  103. * debt, that is in case the collateral ratio goes below 150% for any loan.
  104. * @param token - the address of the token used as collateral for the loan.
  105. * @param account - the account that took out the loan that is now undercollateralized.
  106. * @return - true if the liquidation was successful, otherwise revert.
  107. */
  108. function liquidate(address token, address account) payable external returns (bool);
  109.  
  110. /**
  111. * The purpose of this function is to return the collateral ratio for any account.
  112. * The collateral ratio is computed as the value deposited divided by the value
  113. * borrowed. However, if no value is borrowed then the function should return
  114. * uint256 MAX_INT = type(uint256).max
  115. * @param token - the address of the deposited token used a collateral for the loan.
  116. * @param account - the account that took out the loan.
  117. * @return - the value of the collateral ratio with 2 percentage decimals, e.g. 1% = 100.
  118. * If the account has no deposits for the given token then return zero (0).
  119. * If the account has deposited token, but has not borrowed anything then
  120. * return MAX_INT.
  121. */
  122. function getCollateralRatio(address token, address account) view external returns (uint256);
  123.  
  124. /**
  125. * The purpose of this function is to return the balance that the caller
  126. * has in their own account for the given token (including interest).
  127. * @param token - the address of the token for which the balance is computed.
  128. * @return - the value of the caller's balance with interest, excluding debts.
  129. */
  130. function getBalance(address token) view external returns (uint256);
  131. }
  132.  
  133.  
  134. contract UweBank is IBank {
  135. address price_orakle;
  136. address hak_token;
  137. //address owner;
  138.  
  139. struct Loan {
  140. uint256 sum;
  141. uint256 collateral;
  142. uint256 interest;
  143. uint256 lastInterestBlock;
  144. }
  145.  
  146. mapping(address => mapping(address => Account)) public accounts;
  147. mapping(address => mapping(address => Loan)) public loans;
  148.  
  149. constructor(address _price_orakle, address _HAK_token) {
  150. price_orakle = _price_orakle;
  151. hak_token = _HAK_token;
  152. //owner = msg.sender;
  153. }
  154.  
  155. function calcLoanInteresst(address from, address token) internal returns (bool success) {
  156. require(from != address(0));
  157. if(loans[from][token].lastInterestBlock == 0) { return false; }
  158. uint256 interest_temp = (block.number - loans[from][token].lastInterestBlock) * 10e14 * 5;
  159. loans[from][token].interest += (loans[from][token].sum * interest_temp) / 10e18;
  160. return true;
  161. }
  162.  
  163. function calcInterest(address from, address token, uint256 percentage) internal returns (bool success) {
  164. require(from != address(0));
  165. if(accounts[from][token].lastInterestBlock == 0) { return false; }
  166. uint256 interest_temp = (block.number - accounts[from][token].lastInterestBlock) * 10e14 * percentage;
  167. accounts[from][token].interest += (accounts[from][token].deposit * interest_temp) / 10e18;
  168. return true;
  169. }
  170.  
  171. function calcPotentiolInterest(address from, address token, uint256 percentage) view internal returns (uint256) {
  172. require(from != address(0));
  173. if(accounts[from][token].lastInterestBlock == 0) { return 0; }
  174. uint256 interest_temp = (block.number - accounts[from][token].lastInterestBlock) * 10e14 * percentage;
  175. return (accounts[from][token].deposit * interest_temp) / 10e18;
  176. }
  177.  
  178. function getBalanceOfAddress(address from, address token) view internal returns (uint256) {
  179. require(from != address(0));
  180. return accounts[from][token].deposit + accounts[from][token].interest;
  181. }
  182.  
  183. /**
  184. * The purpose of this function is to allow end-users to deposit a given
  185. * token amount into their bank account.
  186. * @param token - the address of the token to deposit. If this address is
  187. * set to 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE then
  188. * the token to deposit is ETH.
  189. * @param amount - the amount of the given token to deposit.
  190. * @return - true if the deposit was successful, otherwise revert.
  191. */
  192. function deposit(address token, uint256 amount) payable override external returns (bool) {
  193. require(msg.sender != address(0));
  194. require(token != address(0));
  195. require(amount > 0);
  196.  
  197. if(token == 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) {
  198. if(msg.value == amount) {
  199. calcInterest(msg.sender, token, 3);
  200. accounts[msg.sender][token].deposit = msg.value;
  201. accounts[msg.sender][token].lastInterestBlock = block.number;
  202. emit Deposit(msg.sender, token, amount);
  203. return true;
  204. }
  205. } else {
  206. IERC20 hak = IERC20(hak_token);
  207.  
  208. require(hak.balanceOf(msg.sender) >= amount);
  209. require(hak.allowance(msg.sender, address(this)) >= amount);
  210.  
  211. calcInterest(msg.sender, token, 3);
  212. accounts[msg.sender][token].lastInterestBlock = block.number;
  213.  
  214. if(hak.transferFrom(msg.sender, address(this), amount)) {
  215. accounts[msg.sender][token].deposit += amount;
  216. emit Deposit(msg.sender, token, amount);
  217. return true;
  218. }
  219. }
  220. revert();
  221. }
  222.  
  223. /**
  224. * The purpose of this function is to allow end-users to withdraw a given
  225. * token amount from their bank account. Upon withdrawal, the user must
  226. * automatically receive a 3% interest rate per 100 blocks on their deposit.
  227. * @param token - the address of the token to withdraw. If this address is
  228. * set to 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE then
  229. * the token to withdraw is ETH.
  230. * @param amount - the amount of the given token to withdraw. If this param
  231. * is set to 0, then the maximum amount available in the
  232. * caller's account should be withdrawn.
  233. * @return - the amount that was withdrawn plus interest upon success,
  234. * otherwise revert.
  235. */
  236. function withdraw(address token, uint256 amount) override external returns (uint256) {
  237. require(msg.sender != address(0));
  238. require(amount >= 0);
  239. require(token != address(0));
  240.  
  241. if(amount != 0) {
  242. require(getBalanceOfAddress(msg.sender, token) + calcPotentiolInterest(msg.sender, token, 3) >= amount);
  243. }
  244.  
  245. if(token == 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) {
  246. if(amount == 0) {
  247. calcInterest(msg.sender, token, 3);
  248. uint256 balance = getBalanceOfAddress(msg.sender, token);
  249. accounts[msg.sender][token].deposit = 0;
  250. accounts[msg.sender][token].interest = 0;
  251. accounts[msg.sender][token].lastInterestBlock = block.number;
  252.  
  253. if(msg.sender.send(balance)) {
  254. emit Withdraw(msg.sender, token, balance);
  255. return balance;
  256. }
  257. } else {
  258. calcInterest(msg.sender, token, 3);
  259. accounts[msg.sender][token].lastInterestBlock = block.number;
  260.  
  261. if(accounts[msg.sender][token].interest >= amount) {
  262. accounts[msg.sender][token].interest -= amount;
  263. } else {
  264. accounts[msg.sender][token].deposit -= (amount - accounts[msg.sender][token].interest);
  265. accounts[msg.sender][token].interest = 0;
  266. }
  267.  
  268. if(msg.sender.send(amount)) {
  269. emit Withdraw(msg.sender, token, amount);
  270. return amount;
  271. }
  272. }
  273. } else {
  274. IERC20 hak = IERC20(hak_token);
  275.  
  276. if(amount == 0) {
  277. calcInterest(msg.sender, token, 3);
  278. uint256 balance = getBalanceOfAddress(msg.sender, token);
  279. accounts[msg.sender][token].deposit = 0;
  280. accounts[msg.sender][token].interest = 0;
  281. accounts[msg.sender][token].lastInterestBlock = block.number;
  282.  
  283. require(hak.balanceOf(address(this)) >= balance);
  284.  
  285. if(hak.transfer(msg.sender, balance)) {
  286. emit Withdraw(msg.sender, token, balance);
  287. return balance;
  288. }
  289. } else {
  290. calcInterest(msg.sender, token, 3);
  291. accounts[msg.sender][token].lastInterestBlock = block.number;
  292.  
  293. if(accounts[msg.sender][token].interest >= amount) {
  294. accounts[msg.sender][token].interest -= amount;
  295. } else {
  296. accounts[msg.sender][token].deposit -= (amount - accounts[msg.sender][token].interest);
  297. accounts[msg.sender][token].interest = 0;
  298. }
  299.  
  300. require(hak.balanceOf(address(this)) >= amount);
  301.  
  302. if(hak.transfer(msg.sender, amount)) {
  303. emit Withdraw(msg.sender, token, amount);
  304. return amount;
  305. }
  306. }
  307. }
  308. revert();
  309. }
  310.  
  311. /**
  312. * The purpose of this function is to allow users to borrow funds by using their
  313. * deposited funds as collateral. The minimum ratio of deposited funds over
  314. * borrowed funds must not be less than 150%.
  315. * @param token - the address of the token to borrow. This address must be
  316. * set to 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE, otherwise
  317. * the transaction must revert.
  318. * @param amount - the amount to borrow. If this amount is set to zero (0),
  319. * then the amount borrowed should be the maximum allowed,
  320. * while respecting the collateral ratio of 150%.
  321. * @return - the current collateral ratio.
  322. */
  323. function borrow(address token, uint256 amount) override external returns (uint256) {
  324. //getVirtualPrice(address token) view external returns (uint256);
  325. IPriceOracle price = IPriceOracle(price_orakle);
  326. address tokenETH = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
  327. uint256 col = this.getCollateralRatio(token, msg.sender);
  328.  
  329. if(col < 15000) {
  330. col = 15000;
  331. }
  332. //uint256 col_amount = col * amount / 10000;
  333.  
  334. if(token == tokenETH) {
  335. calcLoanInteresst(msg.sender, token);
  336. loans[msg.sender][token].lastInterestBlock = block.number;
  337.  
  338. uint256 col_amount = (col * (amount * (10e18 / price.getVirtualPrice(hak_token)))) / 10000;
  339. require(getBalanceOfAddress(msg.sender, hak_token) + calcPotentiolInterest(msg.sender, hak_token, 3) >= col_amount);
  340.  
  341. calcInterest(msg.sender, hak_token, 3);
  342. accounts[msg.sender][hak_token].lastInterestBlock = block.number;
  343.  
  344. if(accounts[msg.sender][hak_token].interest >= col_amount) {
  345. accounts[msg.sender][hak_token].interest -= col_amount;
  346. } else {
  347. accounts[msg.sender][hak_token].deposit -= (col_amount - accounts[msg.sender][hak_token].interest);
  348. accounts[msg.sender][hak_token].interest = 0;
  349. }
  350.  
  351. loans[msg.sender][token].sum = amount;
  352. loans[msg.sender][token].collateral = col_amount;
  353. if(msg.sender.send(amount)) {
  354. emit Borrow(msg.sender, token, amount, this.getCollateralRatio(token, msg.sender));
  355. return col;
  356. }
  357.  
  358. } else if(token == hak_token){
  359. calcLoanInteresst(msg.sender, token);
  360. loans[msg.sender][token].lastInterestBlock = block.number;
  361.  
  362. IERC20 hak = IERC20(hak_token);
  363. uint256 col_amount = (col * ((amount * price.getVirtualPrice(hak_token))) / 10e18) / 10000;
  364. require(getBalanceOfAddress(msg.sender, tokenETH) + calcPotentiolInterest(msg.sender, tokenETH, 3) >= col);
  365.  
  366. calcInterest(msg.sender, tokenETH, 3);
  367. accounts[msg.sender][tokenETH].lastInterestBlock = block.number;
  368.  
  369. if(accounts[msg.sender][tokenETH].interest >= col_amount) {
  370. accounts[msg.sender][tokenETH].interest -= col_amount;
  371. } else {
  372. accounts[msg.sender][tokenETH].deposit -= (col_amount - accounts[msg.sender][tokenETH].interest);
  373. accounts[msg.sender][tokenETH].interest = 0;
  374. }
  375.  
  376. loans[msg.sender][token].sum = amount;
  377. loans[msg.sender][token].collateral = col_amount;
  378.  
  379. if(hak.transfer(msg.sender, amount)) {
  380. emit Borrow(msg.sender, token, amount, this.getCollateralRatio(token, msg.sender));
  381. return col;
  382. }
  383. }
  384. revert();
  385. }
  386.  
  387. /**
  388. * The purpose of this function is to allow users to repay their loans.
  389. * Loans can be repaid partially or entirely. When repaying a loan, an
  390. * interest payment is also required. The interest on a loan is equal to
  391. * 5% of the amount lent per 100 blocks. If the loan is repaid earlier,
  392. * or later then the interest should be proportional to the number of
  393. * blocks that the amount was borrowed for.
  394. * @param token - the address of the token to repay. If this address is
  395. * set to 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE then
  396. * the token is ETH.
  397. * @param amount - the amount to repay including the interest.
  398. * @return - the amount still left to pay for this loan, excluding interest.
  399. */
  400. function repay(address token, uint256 amount) override payable external returns (uint256) {
  401. address tokenETH = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
  402. //loans[msg.sender][token].sum = (loans[msg.sender][token].sum * (5 * 10e16)) / 10e18 + loans[msg.sender][token].sum;
  403. calcLoanInteresst(msg.sender, token);
  404. loans[msg.sender][token].lastInterestBlock = block.number;
  405. if(token == tokenETH) {
  406. //require(amount == msg.value);
  407. if(amount >= loans[msg.sender][token].sum + loans[msg.sender][token].interest) {
  408. loans[msg.sender][token].sum = 0;
  409. loans[msg.sender][token].interest = 0;
  410. if(amount - (loans[msg.sender][token].sum + loans[msg.sender][token].interest) == 0) {
  411. if(msg.sender.send(amount - loans[msg.sender][token].sum + loans[msg.sender][token].interest)) {
  412. accounts[msg.sender][hak_token].deposit += loans[msg.sender][token].collateral;
  413. emit Repay(msg.sender, token, 0);
  414. return 0;
  415. }
  416. }
  417. accounts[msg.sender][hak_token].deposit += loans[msg.sender][token].collateral;
  418. emit Repay(msg.sender, token, 0);
  419. return 0;
  420. } else {
  421. if(loans[msg.sender][token].interest > amount) {
  422. loans[msg.sender][token].interest -= amount;
  423. } else {
  424. loans[msg.sender][token].sum -= amount - loans[msg.sender][token].interest;
  425. loans[msg.sender][token].interest = 0;
  426. }
  427. emit Repay(msg.sender, token, loans[msg.sender][token].sum + loans[msg.sender][token].interest);
  428. return loans[msg.sender][token].sum;
  429. }
  430. } else {
  431. IERC20 hak = IERC20(hak_token);
  432.  
  433. require(hak.allowance(msg.sender, address(this)) >= amount);
  434.  
  435. if(!hak.transferFrom(msg.sender, address(this), amount)) {
  436. revert();
  437. }
  438.  
  439. if(amount >= loans[msg.sender][token].sum + loans[msg.sender][token].interest) {
  440. loans[msg.sender][token].sum = 0;
  441. loans[msg.sender][token].interest = 0;
  442. if(amount - (loans[msg.sender][token].sum + loans[msg.sender][token].interest) == 0) {
  443. if(hak.transfer(msg.sender, amount - loans[msg.sender][token].sum + loans[msg.sender][token].interest)) {
  444. accounts[msg.sender][tokenETH].deposit += loans[msg.sender][token].collateral;
  445. emit Repay(msg.sender, token, 0);
  446. return 0;
  447. }
  448. }
  449. accounts[msg.sender][tokenETH].deposit += loans[msg.sender][token].collateral;
  450. emit Repay(msg.sender, token, 0);
  451. return 0;
  452. } else {
  453. if(loans[msg.sender][token].interest > amount) {
  454. loans[msg.sender][token].interest -= amount;
  455. } else {
  456. loans[msg.sender][token].sum -= amount - loans[msg.sender][token].interest;
  457. loans[msg.sender][token].interest = 0;
  458. }
  459. emit Repay(msg.sender, token, loans[msg.sender][token].sum + loans[msg.sender][token].interest);
  460. return loans[msg.sender][token].sum;
  461. }
  462. }
  463. revert();
  464. }
  465.  
  466. /**
  467. * The purpose of this function is to allow so called keepers to collect bad
  468. * debt, that is in case the collateral ratio goes below 150% for any loan.
  469. * @param token - the address of the token used as collateral for the loan.
  470. * @param account - the account that took out the loan that is now undercollateralized.
  471. * @return - true if the liquidation was successful, otherwise revert.
  472. */
  473. function liquidate(address token, address account) payable override external returns (bool) {
  474. IPriceOracle price = IPriceOracle(price_orakle);
  475. address tokenEth = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
  476. uint256 col = (accounts[account][token].deposit * loans[account][token].interest) / 10e16;
  477. if(token == tokenEth) {
  478. if(col < 15000) {
  479. calcLoanInteresst(account, token);
  480. uint256 liquid = loans[account][token].interest + loans[account][token].sum;
  481. //accounts[account][token].deposit -= loans[account][token].interest + loans[account][token].sum;
  482. if(liquid < accounts[account][token].interest) {
  483. accounts[account][token].interest -= liquid;
  484. accounts[account][hak_token].deposit += loans[account][token].collateral;
  485. emit Liquidate(msg.sender, account, token, 0, liquid);
  486. return true;
  487. } else if(liquid > loans[account][token].interest) {
  488. if(liquid <= loans[account][token].interest + accounts[account][token].deposit) {
  489. loans[account][token].interest = 0;
  490. accounts[account][token].deposit -= liquid - loans[account][token].interest;
  491. accounts[account][hak_token].deposit += loans[account][token].collateral;
  492. emit Liquidate(msg.sender, account, token, 0, liquid);
  493. return true;
  494. } else {
  495. loans[account][token].interest = 0;
  496. accounts[account][token].deposit = 0;
  497. liquid -= loans[account][token].interest + accounts[account][token].deposit;
  498. liquid = (liquid * price.getVirtualPrice(hak_token)) / 10e8;
  499. loans[account][token].collateral -= liquid;
  500. accounts[account][hak_token].deposit += loans[account][token].collateral;
  501. emit Liquidate(msg.sender, account, token, liquid, loans[account][token].collateral);
  502. return true;
  503. }
  504. }
  505. }
  506. } else {
  507. calcLoanInteresst(account, token);
  508. uint256 liquid = loans[account][token].interest + loans[account][token].sum;
  509. //accounts[account][token].deposit -= loans[account][token].interest + loans[account][token].sum;
  510. if(liquid < accounts[account][token].interest) {
  511. accounts[account][token].interest -= liquid;
  512. accounts[account][tokenEth].deposit += loans[account][token].collateral;
  513. emit Liquidate(msg.sender, account, token, 0, liquid);
  514. return true;
  515. } else if(liquid > loans[account][token].interest) {
  516. if(liquid <= loans[account][token].interest + accounts[account][token].deposit) {
  517. loans[account][token].interest = 0;
  518. accounts[account][token].deposit -= liquid - loans[account][token].interest;
  519. accounts[account][tokenEth].deposit += loans[account][token].collateral;
  520. emit Liquidate(msg.sender, account, token, 0, liquid);
  521. return true;
  522. } else {
  523. loans[account][token].interest = 0;
  524. accounts[account][token].deposit = 0;
  525. liquid -= loans[account][token].interest + accounts[account][token].deposit;
  526. liquid *= 10e18 / price.getVirtualPrice(tokenEth);
  527. loans[account][token].collateral -= liquid;
  528. accounts[account][tokenEth].deposit += loans[account][token].collateral;
  529. emit Liquidate(msg.sender, account, token, liquid, loans[account][token].collateral);
  530. return true;
  531. }
  532. }
  533. }
  534. revert();
  535. }
  536.  
  537. /**
  538. * The purpose of this function is to return the collateral ratio for any account.
  539. * The collateral ratio is computed as the value deposited divided by the value
  540. * borrowed. However, if no value is borrowed then the function should return
  541. * uint256 MAX_INT = type(uint256).max
  542. * @param token - the address of the deposited token used a collateral for the loan.
  543. * @param account - the account that took out the loan.
  544. * @return - the value of the collateral ratio with 2 percentage decimals, e.g. 1% = 100.
  545. * If the account has no deposits for the given token then return zero (0).
  546. * If the account has deposited token, but has not borrowed anything then
  547. * return MAX_INT.
  548. */
  549. function getCollateralRatio(address token, address account) view override external returns (uint256) {
  550. require(token != address(0));
  551. require(account != address(0));
  552. if(accounts[account][token].deposit == 0) {
  553. return 0;
  554. }
  555. if(loans[account][token].sum == 0) {
  556. return type(uint256).max;
  557. }
  558. return (accounts[account][token].deposit / loans[account][token].sum) * 100;
  559. }
  560.  
  561. /**
  562. * The purpose of this function is to return the balance that the caller
  563. * has in their own account for the given token (including interest).
  564. * @param token - the address of the token for which the balance is computed.
  565. * @return - the value of the caller's balance with interest, excluding debts.
  566. */
  567. function getBalance(address token) view override external returns (uint256) {
  568. require(msg.sender != address(0));
  569. return accounts[msg.sender][token].deposit + accounts[msg.sender][token].interest;
  570. }
  571. }
  572.  
  573. /**
  574. * @dev Interface of the ERC20 standard as defined in the EIP.
  575. */
  576. interface IERC20 {
  577. /**
  578. * @dev Returns the amount of tokens in existence.
  579. */
  580. function totalSupply() external view returns (uint256);
  581.  
  582. /**
  583. * @dev Returns the amount of tokens owned by `account`.
  584. */
  585. function balanceOf(address account) external view returns (uint256);
  586.  
  587. /**
  588. * @dev Moves `amount` tokens from the caller's account to `recipient`.
  589. *
  590. * Returns a boolean value indicating whether the operation succeeded.
  591. *
  592. * Emits a {Transfer} event.
  593. */
  594. function transfer(address recipient, uint256 amount) external returns (bool);
  595.  
  596. /**
  597. * @dev Returns the remaining number of tokens that `spender` will be
  598. * allowed to spend on behalf of `owner` through {transferFrom}. This is
  599. * zero by default.
  600. *
  601. * This value changes when {approve} or {transferFrom} are called.
  602. */
  603. function allowance(address owner, address spender) external view returns (uint256);
  604.  
  605. /**
  606. * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
  607. *
  608. * Returns a boolean value indicating whether the operation succeeded.
  609. *
  610. * IMPORTANT: Beware that changing an allowance with this method brings the risk
  611. * that someone may use both the old and the new allowance by unfortunate
  612. * transaction ordering. One possible solution to mitigate this race
  613. * condition is to first reduce the spender's allowance to 0 and set the
  614. * desired value afterwards:
  615. * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
  616. *
  617. * Emits an {Approval} event.
  618. */
  619. function approve(address spender, uint256 amount) external returns (bool);
  620.  
  621. /**
  622. * @dev Moves `amount` tokens from `sender` to `recipient` using the
  623. * allowance mechanism. `amount` is then deducted from the caller's
  624. * allowance.
  625. *
  626. * Returns a boolean value indicating whether the operation succeeded.
  627. *
  628. * Emits a {Transfer} event.
  629. */
  630. function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
  631.  
  632. /**
  633. * @dev Emitted when `value` tokens are moved from one account (`from`) to
  634. * another (`to`).
  635. *
  636. * Note that `value` may be zero.
  637. */
  638. event Transfer(address indexed from, address indexed to, uint256 value);
  639.  
  640. /**
  641. * @dev Emitted when the allowance of a `spender` for an `owner` is set by
  642. * a call to {approve}. `value` is the new allowance.
  643. */
  644. event Approval(address indexed owner, address indexed spender, uint256 value);
  645. }
  646.  
  647. interface IPriceOracle {
  648. /**
  649. * The purpose of this function is to retrieve the price of the given token
  650. * in ETH. For example if the price of a HAK token is worth 0.5 ETH, then
  651. * this function will return 500000000000000000 (5e17) because ETH has 18
  652. * decimals. Note that this price is not fixed and might change at any moment,
  653. * according to the demand and supply on the open market.
  654. * @param token - the ERC20 token for which you want to get the price in ETH.
  655. * @return - the price in ETH of the given token at that moment in time.
  656. */
  657. function getVirtualPrice(address token) view external returns (uint256);
  658. }
Advertisement
Add Comment
Please, Sign In to add comment