0

I'm trying to pass an instance of the Storage structure from StorageController.sol to Publisher.sol. No matter what I do, I get VM Exception while processing transaction: revert in my Truffle test.

Both contracts have pragma experimental ABIEncoderV2; at the top. StorageController.sol is imported by Publisher.

Here's what I tried so far: 1. Using a mapping: StorageController:

mapping(uint256 => Storage) public storages;

Publisher:

Storage memory _storage = _storages.storages(storage_id);

This won't even compile, it says, TypeError: Different number of components on the left hand side (1) than on the right hand side (6).

  1. Using a function

StorageController:

    function getStorage(uint256 i) external view returns(Storage memory) {
        return storages[i];
    }

Publisher

StorageController.Storage memory _storage = _storages.getStorage(storage_id);

Output: VM Exception while processing transaction: revert

  1. Passing a tuple

StorageController:

    function getStorageData(uint256 i) external view 
        returns(bytes32 name, uint256 maxLength, uint256 rank, uint256 writingFee, uint256 sellPrice, bool nonpublic) {
        return ("", 1,1,1,1,false);
    }

(I hardcoded the output values just in case)

Publisher:

(bytes32 name,,,,,) = _storages.getStorageData(storage_id);

Output: same as above.

1

Most probably you are getting this error because your Publisher contract doesn't know about StorageController contract after deployment.

I have written 2 working contracts.

StorageController contract

contract StorageController {
    struct Storage {
        string name;
        uint256 maxLength;
        uint256 rank;
        uint256 writingFee;
        uint256 sellPrice;
        bool nonpublic;
    }

    mapping(uint256 => Storage) public storages;
    uint storageCount = 0;

    constructor() public {
        Storage memory newStorage = Storage({
            name: 'aaa',
            maxLength: 11,
            rank: 12,
            writingFee: 13,
            sellPrice: 14,
            nonpublic: false
        });

        storages[storageCount++] = newStorage;
    }

    function getStorageData(uint256 i) external view 
        returns(string memory name, uint256 maxLength, uint256 rank, uint256 writingFee, uint256 sellPrice, bool nonpublic) {
        return (storages[i].name, storages[i].maxLength,storages[i].rank,storages[i].writingFee,storages[i].sellPrice,storages[i].nonpublic);
    }
}

Publisher contract

contract Publisher {
    StorageController _storages;

    constructor(address storageControllerAddress) public {
        _storages = StorageController(storageControllerAddress);
    }

    function getStorage(uint index) public view returns(string memory, uint256, uint256, uint256, uint256, bool) {
        (string memory name, uint256 maxLength, uint256 rank, uint256 writingFee, uint256 sellPrice,bool nonpublic) = _storages.getStorageData(index);
        return (name, maxLength,rank,writingFee,sellPrice,nonpublic);
    }
}

Note:

  1. solidity 0.5.4 compiler was used and you don't need pragma experimental ABIEncoderV2;
  2. StorageController contract was deployed first. Then its address was used to deploy Publisher contract.
  • Spot on! I had an error in my deployment script, and the _storage reference was not initialized. – ulu Feb 17 at 14:55
  • I could also pass a Storage instance between the contracts using a function that returns Storage: ` function getStorage(uint index) public view returns (Storage)`. However, using a public mapping still doesn't work in 0.5.4. – ulu Feb 17 at 15:02

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.