Hey @filip , Ive modified the multisig wallet so it allows for Dai deposits and then uses the Yearn finance interface to deposit into Yearn and earn an interest(which will also require multisig approval). Im not sure if ive used the enum correctly in the struct and the āifā conditions contained in the functions. Im also not sure if ive written the correct code for the stakeDai and withdrawDai functions?. Im also not sure if any of these functions should be declared as external? I know that i should emit some events and preferably have another parent contract that contains the state variables to be inherited by this contract. I was hoping to get some guidance and feedback before developing this contract any further.
`pragma solidity ^0.7.5;
pragma abicoder v2;
import ā@openzepplin/contracts/token/ERC20/IERC20.solā;
interface IYDAI {
function deposit (uint _amount) external;
function withdraw (uint _shares) external;
function balanceOf (address account) external view returns (uint);
function getPricePerFullShare() external view returns (uint);
}
contract multiSigDefiWallet {
IERC20 dai = IERC20(0x6b175474e89094c44da98b954eedeac495271d0f);
IYDAI yDai = IYDAI(0xC2cB1040220768554cf699b0d863A3cd4324ce32);
address[] public Owners;
uint requiredApprovals;
uint totalEth;
uint totalDai;
uint stakedDai;
enum TransType {trans_Eth, trans_Dai, stake_Dai, withdraw_Dai};
struct Transaction {
TransType tType;
address payable to;
uint amount;
uint numApprovals;
uint Id;
bool confirmed;
bool executed;
}
Transaction[] transactions;
mapping(address => mapping(uint => bool))Approvals;
mapping(address => bool)isOwner;
mapping(address => uint)contributedEth;
mapping(address => uint)contributedDai;
modifier onlyOwners(){
require(isOwner[msg.sender]== true);
_;
}
modifier txExists(uint _txId){
require(_txId < transactions.length);
_;
}
modifier notApproved(uint _txId){
require(Approvals[msg.sender][_txId] == false);
_;
}
modifier notExecuted(uint _txId){
require(transactions[_txId].executed == false);
_;
}
modifier isConfirmed(uint _txId){
require(transactions[_txId].confirmed == true);
_;
}
constructor(address[] memory _owners, uint _requiredApprovals){
require(_owners.length > 0);
require(_requiredApprovals > 0 && _requiredApprovals <= _owners.length);
for (uint i=0; i< _owners.length; i++){
address owner = _owners[i];
require(owner!= address(0);
require(!isOwner[owner]);
isOwner[owner]= true;
Owners.push(owner);
}
requiredApprovals = _requiredApprovals;
}
function depositEth() public payable {
uint amount = msg.value;
totalEth += amount;
contributedEth[msg.sender]+= amount;
}
function depositDai() public payable {
uint amount = msg.value;
require(dai.balanceOf(msg.sender) >= amount);
totalDai += amount;
contributedDai[msg.sender]+= amount;
}
function submitTransaction (uint _amount, address payable _to, transType _tType) public onlyOwners {
if (_tType == TransType.trans_Eth) {
require(_amount <= totalEth);
Transaction memory newTransaction = Transaction (_tType, _to, _amount, 0, transactions.length, false, false);
transactions.push(newTransaction);
}
else if (_tType == TransType.trans_Dai) {
require(_amount <= totalDai);
Transaction memory newTransaction = Transaction (_tType, _to, _amount, 0, transactions.length, false, false);
transactions.push(newTransaction);
}
else if (tType == TransType.stake_Dai) {
require(_amount <= totalDai);
Transaction memory newTransaction = Transaction (_tType, _to, _amount, 0, transactions.length, false, false);
transactions.push(newTransaction);
}
else if (_tType == TransType.withdraw_Dai) {
require(_amount <= stakedDai);
Transaction memory newTransaction = Transaction (_tType, _to, _amount, 0, transactions.length, false, false);
transactions.push(newTransaction);
}
}
function confirmTransaction(uint _Id) public onlyOwners txExists(_Id) notApproved(_Id) notExecuted(_Id){
Approvals[msg.sender][_Id] = true;
transactions[_Id].numApprovals ++ ;
if(transactions[_Id].numApprovals >= requiredApprovals){
transactions[_Id].confirmed = true;
}
}
function executeTransaction(uint_Id) public onlyOwners isConfirmed(_Id){
require(Approvals[msg.sender][_Id] == true);
uint amount = transactions[_Id].amount;
address memory to = transactions[_Id].to;
if (transactions[_Id].tType == TransType.trans_Eth) {
transferEth (to , amount);
}
else if (transactions[_Id].tType == TransType.trans_Dai) {
transferDai (to , amount);
}
else if (transactions[Id].tType == TransType.stake_Dai) {
stakeDai (amount);
}
else if (_transactions[_Id].tType == TransType.withdraw_Dai) {
withdrawDai(amount);
}
transactions[_Id].executed = true;
}
function revokeConfirmation (uint_Id) public onlyOwners txExists(_Id) notExecuted(_Id){
require(Approvals[msg.sender][_Id] == true);
Approvals[msg.sender][_Id] == false;
transactions[_Id].numApprovals --;
if (transactions[_Id].numApprovals < requiredApprovals){
transactions[_Id].confirmed = false;
}
function getStakedDaiDetails() public onlyOwners view returns (uint){
uint price = yDai.getPricePerFullShare();
uint balanceShares = yDai.balanceOf(address(this));
uint totalDaiRewards = balanceShares * price;
uint reward = totalDaiRewards - stakedDai;
return (stakedDai, reward);
}
function transferEth (address _to , uint _amount) internal {
require(_amount > 0);
require(_amount <= totalEth);
_to.call.value(_amount);
totalEth -= _amount;
}
function transferDai (address _to , uint _amount) internal {
require(_amount > 0);
require(_amount <= totalDai);
dai.transfer(_to, _amount);
totalDai -= _amount;
}
function stakeDai (uint_amount) internal {
require(_amount <= totalDai);
dai.approve(address(yDai), _amount);
yDai.deposit (_amount);
totalDai -= _amount;
stakedDai += _amount;
}
function withdrawDai(uint _amount) internal {
require(_amount <= stakedDai);
uint sharePrice = yDai.getPricePerFullShare();
uint shareBalance = _amount / sharePrice;
yDai.withdraw(shareBalance);
totalDai += _amount;
stakedDai -= _amount;
}
}
`