0

I have a contract A that has a mapping and an array of addresses. I want to pass them into contract B, and perform some calculations with them every time contract B receives money.

How can I do that?

contract A {
  mapping (address => uint256) _balances;
  address[] internal _holders;
}

contract B {
  receive () {
     for (let i = 0; i < _holders.length; i++) {
      if (_balances[_holders[i]] > 100) {
         //do something
      }
    } 
  }
}

Thank you.

1 Answer 1

1

Instead you could create a function in contract A that when called will return a list of holders that have > 100 balance.

But finally, the implementation you settle on is really going to depend on the scale of your data. E.g. if there are many holders, but only a few of them will have > 100 balance, it might make sense to keep track of them in an EnumerableSet called e.g. richHolders, which you would only update when an account’s balance crosses the 100 line in either direction. You could then have contract A expose richHolders to contract B.

On the other hand, if richHolders is going to be very large, B.receive is going to be very heavy on gas. A preferable pattern would be something like this:

pragma solidity 0.8.15;

contract A {
  mapping(address => uint256) public balances;
}

contract B {
    A immutable private _a;

    constructor(A a) {
        _a = a;
    }

    uint256 num = 0;

    struct ReceiveCall {
        address msgSender;
        uint256 msgValue;
        mapping(address => bool) didSomething;
    }

    mapping(uint256 => ReceiveCall) private _receiveCalls;

    receive() external payable {
        ReceiveCall storage thisReceiveCall = _receiveCalls[num++];
        thisReceiveCall.msgSender = msg.sender;
        thisReceiveCall.msgValue = msg.value;
    }

    function doSomething(uint256 receiveCallNum) external {
        require(_a.balances(msg.sender) > 100);
        ReceiveCall storage receiveCall = _receiveCalls[receiveCallNum];
        require(!receiveCall.didSomething[msg.sender]);
        // do something with previous receive data
        receiveCall.didSomething[msg.sender] = true;
    }
}

In this way, receive is kept light, and then rich holders can call and pay for doSomething themselves.

P.S. In my suggested solution, the list of rich holders might change between the time receive is called and the time the individual rich holders call doSomething. So the behaviour is different than yours. But maybe you can find a way to reuse the concept of devising a pull solution instead of a push solution, rather than reusing the exact code itself. This was the intention of my answer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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