MultiSig Wallet contract:

contract MultiSig {

address[] public owners;
uint256 requiredVoteCount;

event Deposit(uint256 amount);
event Approved(address approverOwner, uint256 approvedTransaction);
event ExecuteTransaction(uint256 txId, uint256 amount);
event CreateTransaction(address creator);

struct Transaction{
    //uint256 txId;
    address creator;
    address to;
    uint256 amount;
    uint256 voteCount;
    bool executed;

constructor(address[] memory  _owners, uint256 _requiredVoteCount) {
    require(_owners.length >=2);

    // CHECK  if owners are valid address
    for(uint i; i<_owners.length; i++){
        address owner = _owners[i];
        require(owner != address(0));
        isOwner[owner] = true;
    requiredVoteCount = _requiredVoteCount;


modifier notExecuted(uint256 transactionId) {
    require(transactions[transactionId].executed == false, "Transaction is already executed, you cant revoke");

modifier onlyOwners() {
   require(isOwner[msg.sender] == true, "You arent a owner");

modifier transactionExist(uint256 transactionId){
    require(transactionId ==walletNonce);

//nonce must chane after every transaction
//Noce,, dont forget to make it private
uint256 public walletNonce;

// owners => txId => true||false
mapping(address => mapping(uint256 => bool)) public isApproved;
// txID||walletNonce => Transaction
mapping(uint256 => Transaction) public transactions;
mapping(address => bool) public isOwner;

function createTxProposal(address _to, uint256 _amount) public onlyOwners {
    transactions[walletNonce] = Transaction(msg.sender,_to, _amount,0,false);
    emit CreateTransaction(msg.sender);

function approveTransaction(uint256 _txId) 
    require(isApproved[msg.sender][_txId] == false, "You have already approved");
    transactions[_txId].voteCount +=1;
    isApproved[msg.sender][_txId] = true;


function cancelApprove(uint256 _txId)
    require(isApproved[msg.sender][_txId] == true,
    "You havent approved this transaction"
    transactions[_txId].voteCount -=1;
    isApproved[msg.sender][_txId] = false;

function executeTransaction(uint256 _txId)
    require(transactions[_txId].voteCount >= requiredVoteCount,
     "The Transaction didnt voted enough"

    transactions[_txId].executed = true;
    uint  value = transactions[_txId].amount;

    (bool sent, ) = transactions[_txId].to.call{value: value}("");
    require(sent == true, "transaction couldnt executed");
    walletNonce +=1;
    emit ExecuteTransaction(_txId,transactions[_txId].amount);

function showApprovalCount(uint256 _txId) public view returns(uint256) {
    return transactions[_txId].voteCount;

function showBalance() public view  returns(uint256) {
    return address(this).balance;

receive() external payable {
    emit Deposit(msg.value);

And this is my test contract.

import "forge-std/Test.sol";
import "../src/MultiSig.sol";

contract MultiSigTest is Test {
MultiSig public multisig;

function setUp() public {
    address[] memory sahipler = new address[](2);
    sahipler[0] = 0x5B38Da6a701c568545dCfcB03FcB875f56beddC4;
    sahipler[1] = 0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2;
    multisig = new MultiSig(sahipler,1);
address fakeOwner1 = makeAddr("fake1");
address fakeOwner2 = makeAddr("fake2");
address testReceiver = makeAddr("receiver");

//Test will pass if we get the expected error
function testCreateTxProposal() public {
    vm.expectRevert(bytes("You arent a owner"));

    multisig.createTxProposal(testReceiver, 1000000000000000000);

function testApproveTransaction(uint id) public {

I want acces the data of "Transaction" struct for check it, from "MultiSigTest" contract. I want check it via "transactions" mapping. but i cant because data of struct's cant be accessed externally.

The error is "Indexed expression has to be a type, mapping or array (is function (uint256) view external returns (address,address,uint256,uint256,bool))"

  • Can you please explain your question a little more? Dec 1, 2022 at 9:17
  • I want to acces the data of stuct from another contract. Dec 1, 2022 at 11:13
  • Please clarify your specific problem or provide additional details to highlight exactly what you need. As it's currently written, it's hard to tell exactly what you're asking.
    – Community Bot
    Dec 1, 2022 at 23:24

1 Answer 1


There are 2 issues:

  • you try calling the getters of the transactions mapping using a wrong syntax: args are between parenthesis, not brackets (ie change multisig.transactions[id] for multisig.transactions(id))
  • the value returned by the setter generated by solc is a tuple (ie not the struct with it's naming), you should therefore treat it as "unpacked" values, for instance (using the original Multisig.sol):
function testApproveTransaction(uint id) public {
    (,,,, bool _executed) = multisig.transactions(id);

Alternative is to define yourself the getter in Multisig.sol, which will then be returning the struct as you want (and reuse the test as you have now, except for the bracket/parenthesis) - you might need to use experimental abi in solc versions < 0.8.0:

function getTransaction(uint256 idx) external returns(Transaction memory) {
    return transactions[idx];

Your Answer

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

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