diff --git a/contracts/MoatAddress.sol b/contracts/MoatAddress.sol index 11a2a86..1367728 100644 --- a/contracts/MoatAddress.sol +++ b/contracts/MoatAddress.sol @@ -1,8 +1,8 @@ // Implement the proper governance mechanism to update the admin address like admin have rights to upgrade anything but not just "admin". Governance will be used to set admin address. +// Or keep AllowedResolver also in MoatAddress contract pragma solidity ^0.4.24; - contract AddressRegistry { event AddressChanged(string name, address target); @@ -30,4 +30,19 @@ contract AddressRegistry { require(addr != address(0), "Not a valid address."); } + // Contract Address >> Asset Owner Address >> Bool + mapping(address => mapping(address => bool)) allowedResolver; + + function allowContract() public { + allowedResolver[getAddr("resolver")][msg.sender] = true; + } + + function disallowContract() public { + allowedResolver[getAddr("resolver")][msg.sender] = false; + } + + function isApprovedResolver(address user) public view returns(bool) { + return allowedResolver[getAddr("resolver")][user]; + } + } \ No newline at end of file diff --git a/contracts/MoatAsset.sol b/contracts/MoatAsset.sol index 4e57c82..1ab24ce 100644 --- a/contracts/MoatAsset.sol +++ b/contracts/MoatAsset.sol @@ -1,10 +1,13 @@ // Allow ERC20 deposits // withdraw the extra assets other than global balance (in case anyone donated for free) and then no need for seperate brokerage calculation +// how the balance of tokens with less than 18 decimals are stored +// update the balance along with "transferAssets" functions and also check the for onlyAllowedResolver pragma solidity ^0.4.24; interface AddressRegistry { function getAddr(string name) external returns(address); + function isApprovedResolver(address user) external returns(bool); } interface token { @@ -16,6 +19,8 @@ interface token { contract Registry { address public registryAddress; + AddressRegistry aRegistry = AddressRegistry(registryAddress); + modifier onlyAdmin() { require( msg.sender == getAddress("admin"), @@ -24,8 +29,15 @@ contract Registry { _; } + modifier onlyAllowedResolver(address user) { + require( + aRegistry.isApprovedResolver(user), + "Permission Denied" + ); + _; + } + function getAddress(string name) internal view returns(address addr) { - AddressRegistry aRegistry = AddressRegistry(registryAddress); addr = aRegistry.getAddr(name); require(addr != address(0), "Invalid Address"); } @@ -33,41 +45,7 @@ contract Registry { } -contract AllowedResolver is Registry { - - // Contract Address >> Asset Owner Address >> Bool - mapping(address => mapping(address => bool)) allowed; - bool public enabled; - modifier onlyAllowedResolver() { - require( - allowed[getAddress("resolver")][msg.sender], - "Permission Denied" - ); - _; - } - - // only the contracts allowed for asset owners can withdraw assets and update balance on behalf - function allowContract() public { - allowed[getAddress("resolver")][msg.sender] = true; - } - - function disallowContract() public { - allowed[getAddress("resolver")][msg.sender] = false; - } - - // enableAC & disableAC will completely stop the withdrawal of assets on behalf (additional security check) - function enableAC() public onlyAdmin { - enabled = true; - } - - function disableAC() public onlyAdmin { - enabled = false; - } - -} - - -contract AssetDB is AllowedResolver { +contract AssetDB is Registry { // AssetOwner >> TokenAddress >> Balance (as per respective decimals) mapping(address => mapping(address => uint)) balances; @@ -101,7 +79,7 @@ contract AssetDB is AllowedResolver { uint amt, bool add, address target - ) public onlyAllowedResolver + ) public onlyAllowedResolver(target) { if (add) { balances[target][tokenAddr] += amt; @@ -110,19 +88,19 @@ contract AssetDB is AllowedResolver { } } - function transferAssets( - address tokenAddress, - uint amount, - address sendTo - ) public onlyAllowedResolver - { - if (tokenAddress == eth) { - sendTo.transfer(amount); - } else { - token tokenFunctions = token(tokenAddress); - tokenFunctions.transfer(sendTo, amount); - } - } + // function transferAssets( + // address tokenAddress, + // uint amount, + // address sendTo + // ) public onlyAllowedResolver + // { + // if (tokenAddress == eth) { + // sendTo.transfer(amount); + // } else { + // token tokenFunctions = token(tokenAddress); + // tokenFunctions.transfer(sendTo, amount); + // } + // } } @@ -131,7 +109,6 @@ contract MoatAsset is AssetDB { constructor(address rAddr) public { registryAddress = rAddr; - enableAC(); } // received ether directly from protocols like Kyber Network diff --git a/contracts/protocols/MoatKyber.sol b/contracts/protocols/MoatKyber.sol index e1ed964..f2d2b12 100644 --- a/contracts/protocols/MoatKyber.sol +++ b/contracts/protocols/MoatKyber.sol @@ -45,7 +45,7 @@ contract Registry { } -contract KyberSwap is Registry { +contract Trade is Registry { event Swapped(address src, uint srcAmt, address dest, uint destAmt); @@ -86,7 +86,7 @@ contract KyberSwap is Registry { } -contract KyberInit is KyberSwap { +contract MoatKyber is Trade { constructor(address rAddr) public { registryAddress = rAddr; diff --git a/contracts/protocols/MoatMaker.sol b/contracts/protocols/MoatMaker.sol index 2ae6fe6..8bb8f28 100644 --- a/contracts/protocols/MoatMaker.sol +++ b/contracts/protocols/MoatMaker.sol @@ -1,3 +1,168 @@ -// MakerDAO integration -// https://github.com/cryptoPay-ETHSF/SmartContract/blob/master/CryptoPayKovan.sol -// this contract will be the owner of all the CDPs, upgrading this means all the data need to be migrated \ No newline at end of file +// transfer or get back ownership of CDP +// this contract will be the owner of all the CDPs, upgrading this means all the data need to be migrated +// factor the WETH to PETH conversion rate +// run an event after changing the CDP ownership +// implement repay loan function +// implement allowed functionalities like MoatAsset as CDPs are owned by this contract + +pragma solidity 0.4.24; + +interface token { + function transfer(address receiver, uint amount) external returns(bool); + function balanceOf(address who) external returns(uint256); + function approve(address spender, uint256 value) external returns (bool); + function transferFrom(address from, address to, uint amt) external returns (bool); +} + +interface AddressRegistry { + function getAddr(string name) external returns(address); + function isApprovedResolver(address user) external returns(bool); +} + +interface MakerCDP { + function open() external returns (bytes32 cup); + function join(uint wad) external; // Join PETH + function exit(uint wad) external; // Exit PETH + function give(bytes32 cup, address guy) external; + function lock(bytes32 cup, uint wad) external; + function free(bytes32 cup, uint wad) external; + function draw(bytes32 cup, uint wad) external; + function wipe(bytes32 cup, uint wad) external; + function shut(bytes32 cup) external; + function bite(bytes32 cup) external; +} + +interface WETHFace { + function deposit() external payable; + function withdraw(uint wad) external; +} + + +contract Registry { + + address public registryAddress; + AddressRegistry aRegistry = AddressRegistry(registryAddress); + + modifier onlyAdmin() { + require( + msg.sender == getAddress("admin"), + "Permission Denied" + ); + _; + } + + function getAddress(string name) internal view returns(address addr) { + addr = aRegistry.getAddr(name); + require(addr != address(0), "Invalid Address"); + } + +} + + +contract GlobalVar is Registry { + + address public WETH = 0xd0a1e359811322d97991e03f863a0c30c2cf029c; + address public PETH = 0xf4d791139ce033ad35db2b2201435fad668b1b64; + address public MKR = 0xaaf64bfcc32d0f15873a02163e7e500671a4ffcd; + address public DAI = 0xc4375b7de8af5a38a93548eb8453a498222c4ff2; + + address public CDPAddr = 0xa71937147b55Deb8a530C7229C442Fd3F31b7db2; + MakerCDP DAILoanMaster = MakerCDP(CDPAddr); + + mapping (address => bytes32) public borrowerCDPs; // borrower >>> CDP Bytes + +} + + +contract BorrowTasks is GlobalVar { + + function openCDP() internal returns (bytes32) { + return DAILoanMaster.open(); + } + + function ETH_WETH(uint weiAmt) internal { + WETHFace wethFunction = WETHFace(WETH); + wethFunction.deposit.value(weiAmt)(); + } + + function WETH_PETH(uint weiAmt) internal { + DAILoanMaster.join(weiAmt); + } + + function PETH_CDP(address borrower, uint weiAmt) internal { + DAILoanMaster.lock(borrowerCDPs[borrower], weiAmt); + } + + function transferCDP(address nextOwner) public { + require(nextOwner != 0, "Invalid Address."); + DAILoanMaster.give(borrowerCDPs[msg.sender], nextOwner); + } + + function ApproveERC20() public { + token WETHtkn = token(WETH); + WETHtkn.approve(CDPAddr, 2**256 - 1); + token PETHtkn = token(PETH); + PETHtkn.approve(CDPAddr, 2**256 - 1); + token MKRtkn = token(MKR); + MKRtkn.approve(CDPAddr, 2**256 - 1); + token DAItkn = token(DAI); + DAItkn.approve(CDPAddr, 2**256 - 1); + } + +} + + +contract Borrow is BorrowTasks { + + modifier securedResolver(address borrower) { + if (borrower != msg.sender) { + require( + msg.sender == getAddress("resolver"), + "Message Sender is not MoatResolver." + ); + require( + aRegistry.isApprovedResolver(borrower), + "MoatResolver is not approved by CDP user." + ); + } + _; + } + + function borrowLoan( + address borrower, + uint lockETH, + uint loanDAI + ) public securedResolver(borrower) { + + if (borrowerCDPs[borrower] == 0x0000000000000000000000000000000000000000000000000000000000000000) { + borrowerCDPs[borrower] = openCDP(); + } + + if (lockETH != 0) { + ETH_WETH(lockETH); + WETH_PETH(lockETH - lockETH/1000); + PETH_CDP(borrower, lockETH - lockETH/1000); + // event for locking ETH + } + + if (loanDAI != 0) { + DAILoanMaster.draw(borrowerCDPs[borrower], loanDAI); + token tokenFunctions = token(DAI); + tokenFunctions.transfer(getAddress("asset"), loanDAI); + // event for drawing DAI + } + + } + +} + + +contract MoatMaker is Borrow { + + constructor() public { + ApproveERC20(); + } + + function () public payable {} + +} \ No newline at end of file