Try to return an array in a for loop - solidity

I am very new to Solidity, so sorry for the silly question. I am trying to add an element of a struct and then return it, here is my code:
struct Flat {
uint256 priceInWei;
address currentOccupant;
bool flatIsAvailable;
}
Flat[8] public flatDB;
modifier landlordOnly() {
require(msg.sender == landlordAddress);
_;
}
constructor() public {
landlordAddress = msg.sender;
for (uint i=0; i<8; i++) {
flatDB[i].flatIsAvailable = true;
if (i % 2 == 0) {
flatDB[i].priceInWei = 0.1 ether;
} else {
flatDB[i].priceInWei = 0.2 ether;
}
}
}
uint256[] array;
function getFlatDB() payable public returns (uint256) {
for (uint i=0; i<8; i++) {
array.push(flatDB[i].priceInWei);
}
return array;
}
But when I try to compile I have an error at line 41:
TypeError: Return argument type uint256[] storage ref is not implicitly convertible to expected type (type of first return variable) uint256. return array; ^---^
Can someone explain me what's wrong? Thanks!

Seems like the return type you have (uint256) doesn't correspond to the type you're actually trying to return (uint256[]). Try rewriting your getFlatDB function in the following way:
function getFlatDB() payable public returns (uint256[]) {
uint256[] memory array = new uint256[](8);
for (uint i=0; i<8; i++) {
array[i] = flatDB[i].priceInWei;
}
return array;
}
Note how we declare the temporary fixed size return array inside the function with memory keyword.

Related

TypeError: Explicit type conversion not allowed from "uint256" to "address"

i make simple code, but have error "TypeError: Explicit type conversion not allowed from "uint256" to "address"." Can you help me? I even asked the gpt bot about this error, but it confused me even more)))
in the beginning there was a simple idea - 10k nft, 30 of them immediately after the deposit, the minimum price is indicated and everyone can buy without restriction
`pragma solidity ^0.8.4;
import "#openzeppelin/contracts/token/ERC721/ERC721.sol";
contract Sptzrawef is ERC721 {
// Define the token name, symbol, and maximum supply
uint256 public totalSupply = 10000;
string public tokenURI;
// Define the owner of the contract
address public owner;
// Define the minimum price of the token
uint256 public minPrice;
// Define the mapping for the token ownership
mapping(address => mapping(uint256 => bool)) public tokenOwnership;
// The constructor function
constructor() ERC721("Sptzrawef", "SP") {
tokenURI = "https://nftstorage.link/ipfs/ba.................q3oq/";
owner = msg.sender;
minPrice = 0.025 ether;
totalSupply = 10000;
// Mint 30 tokens immediately upon deployment
for (uint256 i = 1; i <= 30; i++) {
tokenOwnership[msg.sender][i] = true;
}
}
// Function to mint new tokens
function mint(address _to, uint256 _tokenId) public {
require(msg.sender == owner);
require(_tokenId <= totalSupply);
require(tokenOwnership[_to][_tokenId] == false);
tokenOwnership[_to][_tokenId] = true;
totalSupply++;
}
// Function to buy the token
function buy(uint256 _tokenId) public payable {
require(msg.value >= minPrice);
require(tokenOwnership[msg.sender][_tokenId] == false);
require(_tokenId <= totalSupply);
tokenOwnership[msg.sender][_tokenId] = true;
}
function balanceOf() public view returns (uint256) {
return totalSupply;
}
function tokenOfOwnerByIndex(address _owner, uint256 _index) public view returns (uint256) {
uint256 count = 0;
for (uint256 i = 1; i <= totalSupply; i++) {
if (tokenOwnership[_owner][i]) {
if (count == _index) {
return i;
}
count++;
}
}
return 0;
}
function ownerOf(uint256 _tokenId) public view override returns (address) {
require(_tokenId <= totalSupply);
for (uint256 i = 0; i < totalSupply; i++) {
address wallet = address(i); - error at this line
if (tokenOwnership[wallet][_tokenId]) {
return wallet;
}
}
return address(0);
}
}`
I think you are using ownerOf function in the wrong way.
try to create a new "getWalletAddress" function, for example, and use it in this way:
function getWalletAddress(uint256 _tokenId) public view returns (address) {
require(_tokenId <= totalSupply);
for (uint256 i = 0; i < totalSupply; i++) {
address wallet = ownerOf(i);
if (tokenOwnership[wallet][_tokenId]) {
return wallet;
}
}
return address(0);
}
}
Or if you want to override the "ownerOf" function then you should go for this code:
function ownerOf(uint256 _tokenId) public view overrides returns (address) {
require(_tokenId <= totalSupply);
for (uint256 i = 0; i < totalSupply; i++) {
address wallet = _ownerOf(i);
if (tokenOwnership[wallet][_tokenId]) {
return wallet;
}
}
return address(0);
}
}
I hope this help resolve your issue
address is 20bytes and uint256 is 32bytes.
Therefore, you need to use uint160 for the type of i to convert it to address.
Or please convert i into uint160 before converting it to address
address wallet = address(uint160(i));

Push method for an array of structures

contract task_list {
struct tasksStruct {
string name;
uint32 timestamp;
bool is_done;
}
tasksStruct[] tasks;
function add_task(string _name) public {
tasksStruct newTask = tasksStruct(_name, now, false);
tasks.push(newTask);
}
function show_opened_tasks() public view returns (uint) {
uint count_of_opened_tasks = 0;
for (uint i=0; i<tasks.length; i++){
if (!tasks[i].is_done) {
count_of_opened_tasks += 1;
}
}
}
}
how does pushing for an array of structures work here? and why there is an error out of range of the array?
You're missing the data location for the reference types in the add_task() function. After fixing this, you'll be able to push to the array.
// added location `memory` for `name`
function add_task(string memory _name) public {
// added location `memory` for `newTask`
tasksStruct memory newTask = tasksStruct(_name, uint32(now), false);
tasks.push(newTask);
}
Also you probably want to return the count_of_opened_tasks from the show_opened_tasks() function - otherwise you'll always get returned the default value 0.
function show_opened_tasks() public view returns (uint) {
uint count_of_opened_tasks = 0;
for (uint i=0; i<tasks.length; i++){
if (!tasks[i].is_done) {
count_of_opened_tasks += 1;
}
}
// added return
return count_of_opened_tasks;
}

Why can't I return dynamic array in Solidity?

I am trying to return a list of addresses by declaring an array and pushing to it in a for loop. However, Solidity doesn't like when I try to return a dynamic array.
function listMyPromises() public returns(uint256[] memory ){ //lists all my past promises
uint256[] memory List;
for(uint i=0; i<table.length; i++){
if(table[i].userAddress==msg.sender){
List.push(uint256(table[i].friendAddress));
}
}
return List;
}
Solidity is not allowing me to return a array stating that
TypeError: Data location must be "memory" or "calldata" for return parameter in function, but none was given.
However When I add memory in the return parameter I get the error:
TypeError: Member "push" is not available in uint256[] memory outside of storage
I have no clue what to do.
Solidity doesn't allow resizing (e.g. by using .push()) a memory array.
You need to calculate the size beforehand and then create a fixed-size memory array.
Source: docs
So the result is possibly going to look like this
function listMyPromises() public returns(uint256[] memory ){ //lists all my past promises
uint256 count = getCount();
uint256[] memory List = new uint256[](count);
uint256 j;
for (uint i = 0; i < table.length; i++) {
if(table[i].userAddress==msg.sender){
List[j] = uint256(table[i].friendAddress);
j++;
}
}
return List;
}
function getCount() internal view returns (uint) {
uint count;
for (uint i = 0; i < table.length; i++) {
if (table[i].userAddress == msg.sender) {
count++;
}
}
return count;
}
Depending on the datatypes wrapped in the table[i] struct, you might also run into another error. The friendAddress suggests that it's a type address, but it cannot be converted to uint256.

Solidity: Returns filtered array of structs without 'push'

I have this contract with an array of structs:
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
contract Tickets {
struct Ticket {
uint id;
int val;
}
Ticket[] tickets;
function addTicket(uint id, int val) public returns(bool success) {
Ticket memory newTicket;
newTicket.id = id;
newTicket.val = val;
tickets.push(newTicket);
return true;
}
function getTicket(uint id) public view returns(Ticket memory) {
uint index;
for(uint i = 0; i<tickets.length; i++){
if (tickets[i].id == id) {
index = i;
break;
}
}
Ticket memory t = tickets[index];
return t;
}
function findTickets(int val) public view returns(Ticket[] memory) {
Ticket[] memory result;
for(uint i = 0; i<tickets.length; i++){
if (tickets[i].val == val) {
result.push(tickets[i]); // HERE IS THE ERROR
}
}
return result;
}
}
I need to returns a filtered by val array but when I buil this code: result.push(tickets[i].id); it throw this error:
TypeError: Member "push" is not available in struct Tickets.Ticket memory[] memory outside of storage.
How I can implement the filter without using push ?
Returning dynamic-length array of struct is still a bit tricky in Solidity (even in the current 0.8 version). So I made a little workaround to make it work even in the 0.6.
Determine the result count, you'll need it for step 2.
Create a fixed-length array
Fill the fixed-length array
Return the fixed-length array
function findTickets(int val) public view returns(Ticket[] memory) {
uint256 resultCount;
for (uint i = 0; i < tickets.length; i++) {
if (tickets[i].val == val) {
resultCount++; // step 1 - determine the result count
}
}
Ticket[] memory result = new Ticket[](resultCount); // step 2 - create the fixed-length array
uint256 j;
for (uint i = 0; i < tickets.length; i++) {
if (tickets[i].val == val) {
result[j] = tickets[i]; // step 3 - fill the array
j++;
}
}
return result; // step 4 - return
}

Solidity smart contract for lottery, but I can only give the prize for the first one. I want it to give it to all winners

Can't make it gives the prize for all winners, just the first one person that putted the right combination. I think there is a problem with findWinners function but I can't find it. If I make address A the good combination, then B with a not good one, and finally C with also a good one, it only gives the prize to A.
pragma solidity ^0.5.1;
contract Lottery {
Game[] ListGames;
// uint public nbGames = ListGames.length;
uint price = 100000;
uint[6] winnerGame;
// winnerGame = [1,2,3,4,5,6];
address payable[] ListWinners;
uint winnersPayed = 0;
uint expiredGames = 0;
struct Game {
address payable gamer;
uint[6] numbers;
uint date;
bool valid;
}
function setWinner(uint[6] memory _winnerGame) public {
winnerGame = _winnerGame;
}
function findWinners() public returns (address payable[] memory) {
uint size = ListGames.length;
bool win = true;
for (uint j = 0; j < size; j++) {
for (uint i=0; i<6 ; i++) {
if ((ListGames[j].numbers[i] != winnerGame[i]) || !ListGames[j].valid) {
win = false;
}
}
if (win) {
ListGames[j].valid = false;
expiredGames ++;
ListWinners.push(ListGames[j].gamer);
}
}
return ListWinners;
}
function payer() public returns (uint) {
uint nbWinners = ListWinners.length;
uint prize;
if (nbWinners - winnersPayed != 0) {
prize = address(this).balance / (nbWinners- winnersPayed);
for (uint i = 0; i < nbWinners; i++) {
if(ListWinners[i] != address(0)) {
ListWinners[i].transfer(prize);
delete ListWinners[i];
winnersPayed++;
require(ListWinners[i] == address(0));
}
}
}
return nbWinners;
}
modifier costs(uint amount) {
require(msg.value >= amount);
_;
}
function postGame(uint[6] memory _numbers) public payable costs(price) {
Game memory newGame = Game(msg.sender, _numbers, block. timestamp, true);
ListGames.push(newGame);
}
function numberValidGames() public view returns (uint) {
return ListGames.length - expiredGames;
}
function getWinnersList() public view returns (address payable [] memory) {
return ListWinners;
}
function getTime() public view returns (uint) {
return block.timestamp;
}
function getBalance() public view returns (uint) {
return address(this).balance;
}
}