Solidity Struct – How to Return a Struct of a Specific User in Solidity

reactsolidity

I'm working on a smart contract that allows users to pay for monthly subscriptions like Netflix, Amazon, etc…

I created a function fetchMysubscription within my smart contract that allows each user to fetch his subscription. It works just fine when I tested it on a remix IDE.

But when I called the function inside a function on the front end (React) so each user can fetch his subscription. The only subscription that appears is the owner of the contract subscription with his address and other information but when I tried to create another subscription with another address the subscription of the owner persisted.

Solidity:

struct Subscription {
        address payable subscriber;
        uint start;
        uint nextPayment;
        bool activated;
    }

    
    /* nested mapping from address to id to Subscription */ 
    mapping(address => mapping(uint => Subscription)) private AllSubscriptions;

    // /* User can fetch it own Loan */ 
    function fetchMysubscription(uint256 planId) external view returns(
            address subscriber,
            uint start,
            uint nextPayment,
            bool activated
    ) {

        Subscription storage currentSubscription = AllSubscriptions[msg.sender][planId];

        if(currentSubscription.subscriber == msg.sender) {
            return (
            currentSubscription.subscriber,
            currentSubscription.start,
            currentSubscription.nextPayment,
            currentSubscription.activated
           );
        }
           
    }

React:

// /*Fetch Subscription */
  async function fetchSubscription() {
    const data = await blockchain.smartContract.methods.fetchMySubscription("0").call();

    const status = (data.activated).toString();
    let startDay = (moment.unix(data.start)).toString();
    let nextPayment = (moment.unix(data.nextPayment)).toString();

      let item = {
        subscriber : data.subscriber,
        start: startDay,
        nextPayment: nextPayment,
        activated: status
      }

      setSubscriptionData(item); // state of array
  }

What I'm missing?

Best Answer

You shouldn't use msg.sender within a view function, since there's no transaction (msg) being sent. Read about the difference between a call and a transaction.

To correctly fetch an account's subscription, you'll have to add an address user parameter to your call, which the caller will provide.

function fetchMysubscription(address user, uint256 planId)
    external
    view
    returns (Subscription memory)
{
    return AllSubscriptions[user][planId];
}

Other improvements -

  • You can return the struct instead of a tuple of its fields
  • No need to check currentSubscription.subscriber == user since you have a mapping that fetches the correct account in the first place.