The main issue with your code is that you are trying to return a uint[]
which is an array
, however you defined your variable as a mapping of mappings, and mapping
and array
are different types.
You could get your code to compile like this:
pragma solidity ^0.4.24;
contract test {
mapping (address => uint[]) public transactions;
constructor() public {
transactions[msg.sender].push(123456);
transactions[msg.sender].push(789101);
transactions[msg.sender].push(865436);
}
function getTransactions() public view returns (uint[]) {
return transactions[msg.sender];
}
}
However in general, I would not recommend a single function which returns all the values. While this may be useable in a web front-end, it will not scale as a normal contract function, since eventually you will reach a number of objects in the array where the gas cost to return them all will be too large for the evm.
Instead, I suggest you break it into two functions:
pragma solidity ^0.4.24;
contract test {
mapping (address => uint[]) public transactions;
constructor() public {
transactions[msg.sender].push(123456);
transactions[msg.sender].push(789101);
transactions[msg.sender].push(865436);
}
function getTransactionsLength() public view returns (uint) {
return transactions[msg.sender].length;
}
function getTransactionsValue(uint index) public view returns (uint) {
return transactions[msg.sender][index];
}
}
One is getTransactionsLength()
, and the other is getTransactionsValue()
. Both of these functions return just a single uint, which means you will have predictable output size and gas costs, which means it can be used in other parts of your contract.
Furthermore, you will also create better user experiences by controlling the number of values you are showing. If you need to show all the values, you could first get the length
, and then loop the value call from 0 to length-1
.
But even better, you may only want to show the last 10 transactions in the UI, where then you can loop from length-1 to length-11
. These may seem like complexities at first, but in reality will be simplifications to your dApp is it grows; things you will really come to appreciate from immutable programs :)
Your issue is that you're retrieving inside userMatchesLookUp()
function an uint256 array and you're returning entire array of struct.
I suggest you to return entire array of struct because in this way you can retrieve all values inside it, like: betAmount and matchId for each match.
I adjusted your smart contract in this way:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract Test {
struct UserStruct {
uint256 betAmount;
uint256 matchId;
}
mapping(address => UserStruct[]) public userStructs;
function appendUserBet( uint256 eventNumber) public payable{
UserStruct memory userStruct = UserStruct(msg.value, eventNumber);
userStructs[msg.sender].push(userStruct);
}
function userStructLookUp(uint eventNumber, address userId) public view returns (UserStruct memory){
uint index = userStructs[userId].length;
for (uint i = 0; i < index; i++) {
if (userStructs[userId][i].matchId == eventNumber) {
return userStructs[userId][i];
}
}
}
// NOTE: I changed your return object with struct array in signature function
function userMatchesLookUp(address userId) public view returns(UserStruct[] memory){
return userStructs[userId];
}
}
Best Answer
Fixed length arrays (e.g.
uint[2] memory
) and dynamic length arrays (e.g.uint[] memory
) are stored in memory differently, as the dynamic length array has to also store the length.From the docs:
Due to this difference it is not possible to convert them automatically. More info is available in the Solidity docs on the internals:
Edit: An alternative for your example would be the usage of a tuple as the return type: