Closed richard-massless closed 3 years ago
I have discovered that in solidity 0.8.4 one can not return a struct from a mapping in the way I am attempting to do. The solution is to destructure the result when calling a public mapping with struct.
Once again the bug is not with your library. 🤘
The solution when using the above test scenario.
IDebugMappingDeployed.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IDebugMappingDeployed {
struct SomeStruct {
uint256 id;
string name;
}
function getStruct(uint256) external view returns (uint256 id, string memory name); // Destructured the return value
}
DebugMapping.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./IDebugMappingDeployed.sol";
contract DebugMapping {
IDebugMappingDeployed private remoteDeployed;
constructor(address _remoteDeployedAddress) {
remoteDeployed = IDebugMappingDeployed(_remoteDeployedAddress);
}
function getStructFromDeployed(uint256 _item)
public
view
returns (uint256 id, string memory name) // Returns the destructured return value
{
return (remoteDeployed.getStruct(_item));
}
}
DebugMapping.ts (test)
import * as dotenv from "dotenv";
import { expect } from "chai";
import { ethers } from "hardhat";
import { FakeContract, smock } from "@defi-wonderland/smock";
import { Contract, ContractFactory } from "ethers";
import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers";
import { DebugMappingDeployed } from "../typechain";
dotenv.config();
let contractFactory: ContractFactory;
let contract: Contract;
let debugMappingDeployed: FakeContract<DebugMappingDeployed>;
let owner: SignerWithAddress;
describe("DebugMapping", function () {
before(async () => {
[owner] = await ethers.getSigners();
// Fake Contract
debugMappingDeployed = await smock.fake<DebugMappingDeployed>(
"DebugMappingDeployed"
);
// Set up this test contract
contractFactory = await ethers.getContractFactory("DebugMapping", owner);
});
beforeEach(async () => {
contract = await contractFactory.deploy(debugMappingDeployed.address);
await contract.deployed();
});
it("Should return faked struct", async () => {
// debugMappingDeployed.getStruct.returns({ id: 1, name: "one" });
debugMappingDeployed.getStruct.returns([1, "one" ]); // Workaround (https://github.com/defi-wonderland/smock/issues/94)
const struct = await contract.getStructFromDeployed(1);
console.log(struct);
expect(await contract.getStructFromDeployed(1).id).to.equal(1);
});
});
Describe the bug When getting a faked struct from inside a real solidity contract this error is returned from faked struct.
Transaction reverted: function returned an unexpected amount of data
Reproduction steps I wrote out the minimal test example. Let me know if you need more. DebugMapping.sol
DebugMappingDeployed.sol
IDebugMappingDeployed.sol
DebugMapping.ts (test)
Expected behavior The unit test "Should return faked struct" should successful execute
await contract.getStructFromDeployed(1);
and return{id: 1, name: "one" }
.System Specs:
Additional context When running with Mocha Test Explorer plugin for vscode. Stack trace
When running with
hardhat test
Stack trace