mirror of
https://github.com/Instadapp/smart-contract.git
synced 2024-07-29 22:08:07 +00:00
comments added
This commit is contained in:
parent
22f70fdc12
commit
7bbfa509b7
|
@ -178,7 +178,7 @@ contract Helper is DSMath {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dev get uniswap DAI exchange
|
* @dev get InstaDApp Liquidity contract
|
||||||
*/
|
*/
|
||||||
function getLiquidityAddr() public pure returns (address liquidity) {
|
function getLiquidityAddr() public pure returns (address liquidity) {
|
||||||
// liquidity = ;
|
// liquidity = ;
|
||||||
|
@ -192,48 +192,41 @@ contract Helper is DSMath {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dev get Compound Comptroller Address
|
* @dev get Compound Oracle Address
|
||||||
*/
|
*/
|
||||||
function getCompOracleAddress() public pure returns (address troller) {
|
function getCompOracleAddress() public pure returns (address troller) {
|
||||||
troller = 0xe7664229833AE4Abf4E269b8F23a86B657E2338D;
|
troller = 0xe7664229833AE4Abf4E269b8F23a86B657E2338D;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dev get Compound Comptroller Address
|
* @dev get CETH Address
|
||||||
*/
|
*/
|
||||||
function getCETHAddress() public pure returns (address cEth) {
|
function getCETHAddress() public pure returns (address cEth) {
|
||||||
cEth = 0x4Ddc2D193948926D02f9B1fE9e1daa0718270ED5;
|
cEth = 0x4Ddc2D193948926D02f9B1fE9e1daa0718270ED5;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dev get Compound Comptroller Address
|
* @dev get DAI Address
|
||||||
*/
|
*/
|
||||||
function getDAIAddress() public pure returns (address dai) {
|
function getDAIAddress() public pure returns (address dai) {
|
||||||
dai = 0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359;
|
dai = 0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dev get Compound Comptroller Address
|
* @dev get CDAI Address
|
||||||
*/
|
*/
|
||||||
function getCDAIAddress() public pure returns (address cDai) {
|
function getCDAIAddress() public pure returns (address cDai) {
|
||||||
cDai = 0xF5DCe57282A584D2746FaF1593d3121Fcac444dC;
|
cDai = 0xF5DCe57282A584D2746FaF1593d3121Fcac444dC;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dev get CDP bytes by CDP ID
|
* @dev setting allowance to compound contracts for the "user proxy" if required
|
||||||
*/
|
|
||||||
function getCDPBytes(uint cdpNum) public pure returns (bytes32 cup) {
|
|
||||||
cup = bytes32(cdpNum);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @dev setting allowance to compound for the "user proxy" if required
|
|
||||||
*/
|
*/
|
||||||
function setApproval(address erc20, uint srcAmt, address to) internal {
|
function setApproval(address erc20, uint srcAmt, address to) internal {
|
||||||
TokenInterface erc20Contract = TokenInterface(erc20);
|
TokenInterface erc20Contract = TokenInterface(erc20);
|
||||||
uint tokenAllowance = erc20Contract.allowance(address(this), to);
|
uint tokenAllowance = erc20Contract.allowance(address(this), to);
|
||||||
if (srcAmt > tokenAllowance) {
|
if (srcAmt > tokenAllowance) {
|
||||||
erc20Contract.approve(to, 2**255);
|
erc20Contract.approve(to, uint(-1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -249,33 +242,25 @@ contract MakerHelper is Helper {
|
||||||
event LogWipe(uint cdpNum, uint daiAmt, uint mkrFee, uint daiFee, address owner);
|
event LogWipe(uint cdpNum, uint daiAmt, uint mkrFee, uint daiFee, address owner);
|
||||||
event LogShut(uint cdpNum);
|
event LogShut(uint cdpNum);
|
||||||
|
|
||||||
function getCDPStats(bytes32 cup) public view returns (uint ethCol, uint daiDebt) {
|
|
||||||
TubInterface tub = TubInterface(getSaiTubAddress());
|
|
||||||
(, uint pethCol, uint debt,) = tub.cups(cup);
|
|
||||||
ethCol = rmul(pethCol, tub.per()); // get ETH col from PETH col
|
|
||||||
daiDebt = debt;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dev get final Ratio of Maker CDP
|
* @dev Allowance to Maker's contract
|
||||||
* @param ethCol amount of ETH Col to add in existing Col
|
|
||||||
* @param daiDebt amount of DAI Debt to add in existing Debt
|
|
||||||
*/
|
*/
|
||||||
function getMakerRatio(bytes32 cup, uint ethCol, uint daiDebt) public view returns (uint ratio) {
|
|
||||||
(uint makerCol, uint makerDebt) = getCDPStats(cup);
|
|
||||||
makerCol += ethCol;
|
|
||||||
makerDebt += daiDebt;
|
|
||||||
uint usdPerEth = uint(MakerOracleInterface(getOracleAddress()).read());
|
|
||||||
uint makerColInUSD = wmul(makerCol, usdPerEth);
|
|
||||||
ratio = wdiv(makerDebt, makerColInUSD);
|
|
||||||
}
|
|
||||||
|
|
||||||
function setMakerAllowance(TokenInterface _token, address _spender) internal {
|
function setMakerAllowance(TokenInterface _token, address _spender) internal {
|
||||||
if (_token.allowance(address(this), _spender) != uint(-1)) {
|
if (_token.allowance(address(this), _spender) != uint(-1)) {
|
||||||
_token.approve(_spender, uint(-1));
|
_token.approve(_spender, uint(-1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev CDP stats by Bytes
|
||||||
|
*/
|
||||||
|
function getCDPStats(bytes32 cup) internal view returns (uint ethCol, uint daiDebt) {
|
||||||
|
TubInterface tub = TubInterface(getSaiTubAddress());
|
||||||
|
(, uint pethCol, uint debt,) = tub.cups(cup);
|
||||||
|
ethCol = rmul(pethCol, tub.per()); // get ETH col from PETH col
|
||||||
|
daiDebt = debt;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -286,6 +271,9 @@ contract CompoundHelper is MakerHelper {
|
||||||
event LogBorrow(address erc20, address cErc20, uint tokenAmt, address owner);
|
event LogBorrow(address erc20, address cErc20, uint tokenAmt, address owner);
|
||||||
event LogRepay(address erc20, address cErc20, uint tokenAmt, address owner);
|
event LogRepay(address erc20, address cErc20, uint tokenAmt, address owner);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Compound Enter Market which allows borrowing
|
||||||
|
*/
|
||||||
function enterMarket(address cErc20) internal {
|
function enterMarket(address cErc20) internal {
|
||||||
ComptrollerInterface troller = ComptrollerInterface(getComptrollerAddress());
|
ComptrollerInterface troller = ComptrollerInterface(getComptrollerAddress());
|
||||||
address[] memory markets = troller.getAssetsIn(address(this));
|
address[] memory markets = troller.getAssetsIn(address(this));
|
||||||
|
@ -307,6 +295,9 @@ contract CompoundHelper is MakerHelper {
|
||||||
|
|
||||||
contract MakerResolver is CompoundHelper {
|
contract MakerResolver is CompoundHelper {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Open new CDP
|
||||||
|
*/
|
||||||
function open() internal returns (uint) {
|
function open() internal returns (uint) {
|
||||||
bytes32 cup = TubInterface(getSaiTubAddress()).open();
|
bytes32 cup = TubInterface(getSaiTubAddress()).open();
|
||||||
emit LogOpen(uint(cup), address(this));
|
emit LogOpen(uint(cup), address(this));
|
||||||
|
@ -320,6 +311,9 @@ contract MakerResolver is CompoundHelper {
|
||||||
TubInterface(getSaiTubAddress()).give(bytes32(cdpNum), nextOwner);
|
TubInterface(getSaiTubAddress()).give(bytes32(cdpNum), nextOwner);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Pay CDP debt
|
||||||
|
*/
|
||||||
function wipe(uint cdpNum, uint _wad) internal returns (uint daiAmt) {
|
function wipe(uint cdpNum, uint _wad) internal returns (uint daiAmt) {
|
||||||
if (_wad > 0) {
|
if (_wad > 0) {
|
||||||
TubInterface tub = TubInterface(getSaiTubAddress());
|
TubInterface tub = TubInterface(getSaiTubAddress());
|
||||||
|
@ -370,6 +364,9 @@ contract MakerResolver is CompoundHelper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Withdraw CDP
|
||||||
|
*/
|
||||||
function free(uint cdpNum, uint jam) internal {
|
function free(uint cdpNum, uint jam) internal {
|
||||||
if (jam > 0) {
|
if (jam > 0) {
|
||||||
bytes32 cup = bytes32(cdpNum);
|
bytes32 cup = bytes32(cdpNum);
|
||||||
|
@ -391,6 +388,9 @@ contract MakerResolver is CompoundHelper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Deposit Collateral
|
||||||
|
*/
|
||||||
function lock(uint cdpNum, uint ethAmt) internal {
|
function lock(uint cdpNum, uint ethAmt) internal {
|
||||||
if (ethAmt > 0) {
|
if (ethAmt > 0) {
|
||||||
bytes32 cup = bytes32(cdpNum);
|
bytes32 cup = bytes32(cdpNum);
|
||||||
|
@ -416,6 +416,9 @@ contract MakerResolver is CompoundHelper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Borrow DAI Debt
|
||||||
|
*/
|
||||||
function draw(uint cdpNum, uint _wad) internal {
|
function draw(uint cdpNum, uint _wad) internal {
|
||||||
bytes32 cup = bytes32(cdpNum);
|
bytes32 cup = bytes32(cdpNum);
|
||||||
if (_wad > 0) {
|
if (_wad > 0) {
|
||||||
|
@ -428,6 +431,9 @@ contract MakerResolver is CompoundHelper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Check if entered amt is valid or not (Used in makerToCompound)
|
||||||
|
*/
|
||||||
function checkCDP(bytes32 cup, uint ethAmt, uint daiAmt) internal returns (uint ethCol, uint daiDebt) {
|
function checkCDP(bytes32 cup, uint ethAmt, uint daiAmt) internal returns (uint ethCol, uint daiDebt) {
|
||||||
TubInterface tub = TubInterface(getSaiTubAddress());
|
TubInterface tub = TubInterface(getSaiTubAddress());
|
||||||
ethCol = rmul(tub.ink(cup), tub.per()); // get ETH col from PETH col
|
ethCol = rmul(tub.ink(cup), tub.per()); // get ETH col from PETH col
|
||||||
|
@ -436,11 +442,17 @@ contract MakerResolver is CompoundHelper {
|
||||||
ethCol = ethAmt < ethCol ? ethAmt : ethCol; // if ETH amount > max Col. Set max col
|
ethCol = ethAmt < ethCol ? ethAmt : ethCol; // if ETH amount > max Col. Set max col
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Run wipe & Free function together
|
||||||
|
*/
|
||||||
function wipeAndFreeMaker(uint cdpNum, uint jam, uint _wad) internal returns (uint daiAmt) {
|
function wipeAndFreeMaker(uint cdpNum, uint jam, uint _wad) internal returns (uint daiAmt) {
|
||||||
daiAmt = wipe(cdpNum, _wad);
|
daiAmt = wipe(cdpNum, _wad);
|
||||||
free(cdpNum, jam);
|
free(cdpNum, jam);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Run Lock & Draw function together
|
||||||
|
*/
|
||||||
function lockAndDrawMaker(uint cdpNum, uint jam, uint _wad) internal {
|
function lockAndDrawMaker(uint cdpNum, uint jam, uint _wad) internal {
|
||||||
lock(cdpNum, jam);
|
lock(cdpNum, jam);
|
||||||
draw(cdpNum, _wad);
|
draw(cdpNum, _wad);
|
||||||
|
@ -452,7 +464,7 @@ contract MakerResolver is CompoundHelper {
|
||||||
contract CompoundResolver is MakerResolver {
|
contract CompoundResolver is MakerResolver {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dev Deposit ETH and mint Compound Tokens
|
* @dev Deposit ETH and mint CETH
|
||||||
*/
|
*/
|
||||||
function mintCEth(uint tokenAmt) internal {
|
function mintCEth(uint tokenAmt) internal {
|
||||||
enterMarket(getCETHAddress());
|
enterMarket(getCETHAddress());
|
||||||
|
@ -528,18 +540,24 @@ contract CompoundResolver is MakerResolver {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev run mint & borrow together
|
||||||
|
*/
|
||||||
function mintAndBorrowComp(uint ethAmt, uint daiAmt) internal {
|
function mintAndBorrowComp(uint ethAmt, uint daiAmt) internal {
|
||||||
mintCEth(ethAmt);
|
mintCEth(ethAmt);
|
||||||
borrowDAIComp(daiAmt);
|
borrowDAIComp(daiAmt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev run payback & redeem together
|
||||||
|
*/
|
||||||
function paybackAndRedeemComp(uint ethCol, uint daiDebt) internal returns (uint ethAmt, uint daiAmt) {
|
function paybackAndRedeemComp(uint ethCol, uint daiDebt) internal returns (uint ethAmt, uint daiAmt) {
|
||||||
daiAmt = repayDaiComp(daiDebt);
|
daiAmt = repayDaiComp(daiDebt);
|
||||||
ethAmt = redeemCETH(ethCol);
|
ethAmt = redeemCETH(ethCol);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dev If col/debt > user's balance/borrow. Then set max
|
* @dev Check if entered amt is valid or not (Used in makerToCompound)
|
||||||
*/
|
*/
|
||||||
function checkCompound(uint ethAmt, uint daiAmt) internal returns (uint ethCol, uint daiDebt) {
|
function checkCompound(uint ethAmt, uint daiAmt) internal returns (uint ethCol, uint daiDebt) {
|
||||||
CTokenInterface cEthContract = CTokenInterface(getCETHAddress());
|
CTokenInterface cEthContract = CTokenInterface(getCETHAddress());
|
||||||
|
@ -562,11 +580,13 @@ contract Bridge is CompoundResolver {
|
||||||
event LogCompoundToMaker(uint ethAmt, uint daiAmt);
|
event LogCompoundToMaker(uint ethAmt, uint daiAmt);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dev MakerDAO to Compound
|
* @dev convert Maker CDP into Compound Collateral
|
||||||
*/
|
*/
|
||||||
function makerToCompound(uint cdpId, uint ethQty, uint daiQty) public {
|
function makerToCompound(uint cdpId, uint ethQty, uint daiQty) public {
|
||||||
(uint ethAmt, uint daiDebt) = checkCDP(bytes32(cdpId), ethQty, daiQty);
|
(uint ethAmt, uint daiDebt) = checkCDP(bytes32(cdpId), ethQty, daiQty);
|
||||||
uint daiAmt = wipeAndFreeMaker(cdpId, ethAmt, daiDebt); // Getting Liquidity inside Wipe function
|
uint daiAmt = wipeAndFreeMaker(cdpId, ethAmt, daiDebt); // Getting Liquidity inside Wipe function
|
||||||
|
enterMarket(getCETHAddress());
|
||||||
|
enterMarket(getCDAIAddress());
|
||||||
mintAndBorrowComp(ethAmt, daiAmt); // Returning Liquidity inside Borrow function
|
mintAndBorrowComp(ethAmt, daiAmt); // Returning Liquidity inside Borrow function
|
||||||
emit LogMakerToCompound(ethAmt, daiAmt);
|
emit LogMakerToCompound(ethAmt, daiAmt);
|
||||||
}
|
}
|
||||||
|
|
|
@ -108,7 +108,7 @@ contract ProvideLiquidity is Helper {
|
||||||
mapping (address => uint) public totalDeposits;
|
mapping (address => uint) public totalDeposits;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dev Deposit DAI for liquidity
|
* @dev Deposit Token for liquidity
|
||||||
*/
|
*/
|
||||||
function depositToken(address tknAddr, address ctknAddr, uint amt) public payable {
|
function depositToken(address tknAddr, address ctknAddr, uint amt) public payable {
|
||||||
if (tknAddr != ethAddr) {
|
if (tknAddr != ethAddr) {
|
||||||
|
@ -203,6 +203,9 @@ contract AccessLiquidity is ProvideLiquidity {
|
||||||
_;
|
_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Redeem CTokens and use them on InstaDApp's contract wallets
|
||||||
|
*/
|
||||||
function redeemTknAndTransfer(address tknAddr, address ctknAddr, uint tknAmt) public isUserWallet {
|
function redeemTknAndTransfer(address tknAddr, address ctknAddr, uint tknAmt) public isUserWallet {
|
||||||
if (tknAmt > 0) {
|
if (tknAmt > 0) {
|
||||||
if (tknAddr != ethAddr) {
|
if (tknAddr != ethAddr) {
|
||||||
|
@ -224,7 +227,10 @@ contract AccessLiquidity is ProvideLiquidity {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function mintTknBack(address tknAddr, address ctknAddr, uint tknAmt) public payable {
|
/**
|
||||||
|
* @dev Mint back redeemed tokens
|
||||||
|
*/
|
||||||
|
function mintTknBack(address tknAddr, address ctknAddr, uint tknAmt) public payable isUserWallet {
|
||||||
if (tknAmt > 0) {
|
if (tknAmt > 0) {
|
||||||
if (tknAddr != ethAddr) {
|
if (tknAddr != ethAddr) {
|
||||||
CTokenInterface ctknContract = CTokenInterface(ctknAddr);
|
CTokenInterface ctknContract = CTokenInterface(ctknAddr);
|
||||||
|
@ -241,6 +247,9 @@ contract AccessLiquidity is ProvideLiquidity {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Borrow tokens and use them on InstaDApp's contract wallets
|
||||||
|
*/
|
||||||
function borrowTknAndTransfer(address tknAddr, address ctknAddr, uint tknAmt) public isUserWallet {
|
function borrowTknAndTransfer(address tknAddr, address ctknAddr, uint tknAmt) public isUserWallet {
|
||||||
if (tknAmt > 0) {
|
if (tknAmt > 0) {
|
||||||
CTokenInterface ctknContract = CTokenInterface(ctknAddr);
|
CTokenInterface ctknContract = CTokenInterface(ctknAddr);
|
||||||
|
@ -261,7 +270,10 @@ contract AccessLiquidity is ProvideLiquidity {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function payBorrowBack(address tknAddr, address ctknAddr, uint tknAmt) public payable {
|
/**
|
||||||
|
* @dev Payback borrow tokens
|
||||||
|
*/
|
||||||
|
function payBorrowBack(address tknAddr, address ctknAddr, uint tknAmt) public payable isUserWallet {
|
||||||
if (tknAmt > 0) {
|
if (tknAmt > 0) {
|
||||||
if (tknAddr != ethAddr) {
|
if (tknAddr != ethAddr) {
|
||||||
CTokenInterface ctknContract = CTokenInterface(ctknAddr);
|
CTokenInterface ctknContract = CTokenInterface(ctknAddr);
|
||||||
|
@ -278,12 +290,15 @@ contract AccessLiquidity is ProvideLiquidity {
|
||||||
|
|
||||||
contract AdminStuff is AccessLiquidity {
|
contract AdminStuff is AccessLiquidity {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Give approval to other addresses
|
||||||
|
*/
|
||||||
function setApproval(address erc20, uint srcAmt, address to) public {
|
function setApproval(address erc20, uint srcAmt, address to) public {
|
||||||
require(msg.sender == adminOne || msg.sender == adminTwo, "Not admin address");
|
require(msg.sender == adminOne || msg.sender == adminTwo, "Not admin address");
|
||||||
ERC20Interface erc20Contract = ERC20Interface(erc20);
|
ERC20Interface erc20Contract = ERC20Interface(erc20);
|
||||||
uint tokenAllowance = erc20Contract.allowance(address(this), to);
|
uint tokenAllowance = erc20Contract.allowance(address(this), to);
|
||||||
if (srcAmt > tokenAllowance) {
|
if (srcAmt > tokenAllowance) {
|
||||||
erc20Contract.approve(to, 2**255);
|
erc20Contract.approve(to, uint(-1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -324,12 +339,18 @@ contract AdminStuff is AccessLiquidity {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enter Compound Market to enable borrowing
|
||||||
|
*/
|
||||||
function enterMarket(address[] memory cTknAddrArr) internal {
|
function enterMarket(address[] memory cTknAddrArr) internal {
|
||||||
require(msg.sender == adminOne || msg.sender == adminTwo, "Not admin address");
|
require(msg.sender == adminOne || msg.sender == adminTwo, "Not admin address");
|
||||||
ComptrollerInterface troller = ComptrollerInterface(comptrollerAddr);
|
ComptrollerInterface troller = ComptrollerInterface(comptrollerAddr);
|
||||||
troller.enterMarkets(cTknAddrArr);
|
troller.enterMarkets(cTknAddrArr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enter Compound Market to disable borrowing
|
||||||
|
*/
|
||||||
function exitMarket(address cErc20) internal {
|
function exitMarket(address cErc20) internal {
|
||||||
require(msg.sender == adminOne || msg.sender == adminTwo, "Not admin address");
|
require(msg.sender == adminOne || msg.sender == adminTwo, "Not admin address");
|
||||||
ComptrollerInterface troller = ComptrollerInterface(comptrollerAddr);
|
ComptrollerInterface troller = ComptrollerInterface(comptrollerAddr);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user