0

my code

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract SharedWallet {
    address public deployer;
    uint256 public totalCredits;

    enum TransactionStatus { Pending, Debited, Failed }

    struct Transaction {
        uint256 amount;
        TransactionStatus status;
        mapping(address => bool) approvals;
        uint256 approvalsCount;
    }

    mapping(address => bool) public members;
    Transaction[] public transactions;

    constructor(address[] memory _members, uint256 _credits) {
        require(_members.length > 0, "At least one member required");
        require(_credits > 0, "Credits must be greater than 0");
        require(!isMember(msg.sender, _members), "Deployer cannot be a member");

        deployer = msg.sender;
        totalCredits = _credits;

        for (uint256 i = 0; i < _members.length; i++) {
            members[_members[i]] = true;
        }
    }

    modifier onlyDeployer() {
        require(msg.sender == deployer, "Only deployer can call this function");
        _;
    }

    modifier onlyMembers() {
        require(isMember(msg.sender, getMembers()), "Only team members can call this function");
        _;
    }

    function isMember(address _address, address[] memory _members) internal pure returns (bool) {
        for (uint256 i = 0; i < _members.length; i++) {
            if (_address == _members[i]) {
                return true;
            }
        }
        return false;
    }

    function setWallet(address[] memory _members, uint256 _credits) public onlyDeployer {
        require(_members.length > 0, "At least one member required");
        require(!isMember(deployer, _members), "Deployer cannot be a member");
        require(totalCredits == 0, "Wallet is already initialized");
        require(_credits > 0, "Credits must be greater than 0");

        for (uint256 i = 0; i < _members.length; i++) {
            members[_members[i]] = true;
        }

        totalCredits = _credits;
    }

    function spend(uint256 _amount) public onlyMembers {
        require(_amount > 0, "Amount must be greater than 0");

        transactions.push(Transaction({
            amount: _amount,
            status: TransactionStatus.Pending,
            approvalsCount: 1
        }));
    }

    function approve(uint256 _n) public onlyMembers {
        require(_n < transactions.length, "Invalid transaction index");
        require(!transactions[_n].approvals[msg.sender], "Already approved or rejected");
        require(transactions[_n].status == TransactionStatus.Pending, "Transaction is not pending");

        transactions[_n].approvals[msg.sender] = true;
        transactions[_n].approvalsCount++;

        if (transactions[_n].approvalsCount >= (membersCount() * 7) / 10) {
            transactions[_n].status = TransactionStatus.Debited;
            if (transactions[_n].amount <= totalCredits) {
                totalCredits -= transactions[_n].amount;
            } else {
                transactions[_n].status = TransactionStatus.Failed;
            }
        }
    }

    function reject(uint256 _n) public onlyMembers {
        require(_n < transactions.length, "Invalid transaction index");
        require(!transactions[_n].approvals[msg.sender], "Already approved or rejected");
        require(transactions[_n].status == TransactionStatus.Pending, "Transaction is not pending");

        transactions[_n].approvals[msg.sender] = true;
        transactions[_n].approvalsCount++;

        if (transactions[_n].approvalsCount > (membersCount() * 3) / 10) {
            transactions[_n].status = TransactionStatus.Failed;
        }
    }

    function credits() public onlyMembers view returns (uint256) {
        return totalCredits;
    }

    function viewTransaction(uint256 _n) public onlyMembers view returns (uint256 amount, string memory status) {
        require(_n < transactions.length, "Invalid transaction index");
        amount = transactions[_n].amount;
        if (transactions[_n].status == TransactionStatus.Pending) {
            status = "pending";
        } else if (transactions[_n].status == TransactionStatus.Debited) {
            status = "debited";
        } else if (transactions[_n].status == TransactionStatus.Failed) {
            status = "failed";
        }
    }

    function transactionStats() public onlyMembers view returns (uint256 debitedCount, uint256 pendingCount, uint256 failedCount) {
        for (uint256 i = 0; i < transactions.length; i++) {
            if (transactions[i].status == TransactionStatus.Debited) {
                debitedCount++;
            } else if (transactions[i].status == TransactionStatus.Pending) {
                pendingCount++;
            } else if (transactions[i].status == TransactionStatus.Failed) {
                failedCount++;
            }
        }
    }

    function getMembers() public view returns (address[] memory) {
        address[] memory teamMembers = new address[](membersCount());
        uint256 memberIndex = 0;
        for (uint256 i = 0; i < transactions.length; i++) {
            if (members[transactions[i].receiver]) {
                teamMembers[memberIndex] = transactions[i].receiver;
                memberIndex++;
            }
        }
        return teamMembers;
    }

    function membersCount() public view returns (uint256) {
        uint256 count = 0;
        for (uint256 i = 0; i < transactions.length; i++) {
            if (members[transactions[i].receiver]) {
                count++;
            }
        }
        return count;
    }
}

error is in line 65.

1 Answer 1

1

I hope this will answer your question and help you with your issue.

First of all, structs with nested mappings can only be accessed through storage, so you can not create the "Transaction" struct in memory, which is what you're trying to do here. Secondly, you can't use ".push()" on an array of structs with nested mappings.

So, I'll admit to not have read through your entire source code, but I believe I have a pretty good guess to how, you'll solve this issue. First you need to create a state variable for counting transactions. Let's call this "txCount". Then you'll replace the code in your "spend" function with the following code:

Transaction[] storage transaction = transactions[txCount];

transaction.amount = _amount;
transaction.status = TransactionStatus.Pending;
transaction.approvals[msg.sender] = true;
transaction.approvalsCount++;

txCount++;

I hope this will help you out! :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.