There is a function called ownerOf(uint id) that return the address of this specific id. I want to write a function that gets total supply and pass each total supply id to ownerOf and the return address of the owner of that ID I passed and save in an array.
here is my code
and its says: ERC721: owner query for nonexistent token
function GetAllNftOwnerAddress()
public
view
returns (address[] memory)
{
uint256 total = totalSupply();
address[] memory tokenIds;
for (uint256 i; i < total; i++) {
tokenIds[i] = ownerOf(i);
}
return tokenIds;
}
This raised when there's no item with id i in the _owners array.
This could happen when the totalSupply() is different from the length of _owners. Please make sure that the value of totalSupply sync with the _owners.
E.g.
_owners[0] = '0x11'
_owners[1] = '0x22'
_owners[2] = '0x33'
_owners[3] = '0x44'
totalSupply = 4
When we do:
delete _owners[2]
total -= 1
And then try to access:
for (uint256 i; i < total; i++) {
tokenIds[i] = ownerOf(i);
}
You'll get an exception when i == 2 because the _owner[2] = 0x0.
Related
In this part of my smart contract, Remix is displaying an error:
function rebase() public {
for (address wallet in balances) {
uint256 reward = balances[wallet] * 0.002;
balances[wallet] += reward;
totalSupply -= reward;
}
}
The error is:
ParserError: Expected ';' but got reserved keyword 'in'
--> test.sol:70:25: | 70 | for (address wallet in balances) { | ^^
I also tried another method:
function rebase() public {
for (uint i = 0; i < balances.length; i++) {
bytes32 walletHash = balances[i];
address wallet = address(walletHash);
uint256 reward = balances[wallet] * 0.002;
balances[wallet] += reward;
totalSupply -= reward;
}
}
What could be the issue? I tried a lot been on this since yesterday,
I would be very happy if someone could assist me. What I'm trying to do is add the rebase function to the smart contract, where each wallet receives 0.2% / day based on the amount of tokens they have in their wallet.
function rebase() public {
for (uint i = 0; i < balances.length; i++) {
bytes32 walletHash = balances[i];
address wallet = address(walletHash);
uint256 reward = balances[wallet] * 0.002;
balances[wallet] += reward;
totalSupply -= reward;
}
}
for (address wallet in balances) {
This is a JavaScript syntax (and possibly some other languages use it too) but it's not valid syntax in Solidity.
for (uint i = 0; i < balances.length; i++) {
This is a valid Solidity syntax, assuming balances is an array.
If it's a mapping, then you cannot iterate through it, as the list of keys that have set values is unknown.
You might use the iterable mapping pattern. However, a common approach to rebase tokens is to update a multiplier - rather than update balance of each holder.
// how many % of the total supply each address owns
mapping(address => uint256) balancePercentages;
uint256 multiplier;
function rebase(uint256 _multiplier) external {
// the percentage of each holder stays the same
multiplier = _multiplier;
}
function balanceOf(address holder) external view returns (uint256) {
return balancePercentages * multiplier;
}
This my code ..if someone can help ..thanks in advance
pragma solidity ^0.5.16;
pragma experimental ABIEncoderV2 ;
contract Users {
struct Drug { // Vehicle = Drug
string name;
uint Qt;
uint Qs;
uint Qr;
}
event DrugAdded(
string name,
uint Qt,
uint Qs,
uint Qr
);
Drug[] public drugs;
uint counter=0;
function addDrug(string memory _name, uint _Qt, uint _Qs, uint _Qr) public {
drugs.push(
Drug(_name, _Qt,_Qs,_Qr)
);
emit DrugAdded(_name, _Qt,_Qs,_Qr);
counter++;
}
function getdrugs(string memory _name) public view returns (Drug[] memory) {
for(uint i=0;i<counter;i++){
if (keccak256(abi.encodePacked((drugs[i].name))) == keccak256(abi.encodePacked((_name)))){
return drugs[i];
}
}
}
}
i get error in last line:
TypeError: Return argument type struct Users.Drug storage ref is not implicitly convertible to expected type (type of first return variable) struct Users.Drug memory[] memory.
return drugs[i];
^------^
Because of how arrays are stored in memory, Solidity is not able to resize memory arrays. So when you're returning a dynamic-length array with an unknown length, you need to find out and declare its length first (see _getCount() in the example below) - and then fill each of its items.
You can find another example of a very similar thing in this answer.
function getdrugs(string memory _name) public view returns (Drug[] memory) {
Drug[] memory drugsToReturn = new Drug[](_getCount(_name));
uint256 index = 0;
for(uint i=0;i<counter;i++) {
if (keccak256(abi.encodePacked((drugs[i].name))) == keccak256(abi.encodePacked((_name)))){
drugsToReturn[index] = drugs[i];
index++;
}
}
return drugsToReturn;
}
function _getCount(string memory _name) private view returns (uint256) {
uint256 count = 0;
for(uint i=0;i<counter;i++) {
if (keccak256(abi.encodePacked((drugs[i].name))) == keccak256(abi.encodePacked((_name)))){
count++;
}
}
return count;
}
i'm new with solidity and i'm currently struggling iterating through a mapping index to get the values from a Struct
struct Stakes {
uint256 stakeDate;
uint256 stakeAmount;
}
mapping (address => Stakes[]) public addressToStaked;
function stake (uint256 _amount) public {
require(_amount > 0, "You must stake more than 0");
addressToStaked[msg.sender].push(Stakes(block.timestamp, _amount));
}
function returnStaked () public view returns (uint256[][] memory) {
uint256[][] memory result;
for (uint256 i = 0; i < 2; i++){
result[i] = [addressToStaked[msg.sender][i].stakeDate, addressToStaked[msg.sender][i].stakeAmount];
}
return result;
}
As shown on the code, i'm able to push the Struct Values into the mapping, but when i try to read the values as in the returnStaked function i get the error:
TypeError: Type uint256[2] memory is not implicitly convertible to expected type uint256[] memory.
I am not sure but i think you can't iterate through mapping to get values.. if you want to get the stake for the particular address .. below code will work..
function returnStaked (address addressStaked) public view returns (Stakes[] memory) {
return addressToStaked[addressStaked];
}
I will list some links for your references and if i found the way to do it.. i will update here...
https://solidity-by-example.org/app/iterable-mapping/
https://ethereum.stackexchange.com/questions/15337/can-we-get-all-elements-stored-in-a-mapping-in-the-contract
https://programtheblockchain.com/posts/2018/03/09/understanding-ethereum-smart-contract-storage/
I want to return an array of structs because i want to output all my data.
//SPDX-License-Identifier:MIT
pragma solidity ^0.8.0;
contract MyContract
{
mapping(uint256 => People) dataList;
uint256[] countArr;
struct People{
string name;
uint256 favNum;
}
In this function, i set the data of my struct object and then include it in my mapping.
function setPerson(string memory _name,uint256 _id, uint256 _favNum) public {
dataList[_id]= People(_name,_favNum);
countArr.push(_id);
}
This function here gets me the data of my specified struct object.
function getPerson(uint _id) public view returns(string memory,uint256){
return (dataList[_id].name, dataList[_id].favNum);
}
Now here is the function i think that is causing me trouble because in this function i want to return not the data of a single People object but all of my data and whenever i run this function on my REMIX IDE console it shows me the error: call to MyContract.getAllData errored: VM error: revert. revert
The transaction has been reverted to the initial state.
Note: The called function should be payable if you send value and the value you send should be less than your current balance.
function getAllData()public view returns(People[] memory){
uint256 count = countArr.length;
uint256 i = 0;
People[] memory outputL= new People[](count);
while(count >= 0){
(string memory nam,uint256 num) = getPerson(count-1);
People memory temp = People(nam,num);
outputL[i]=temp;
count--;
i++;
}
return outputL;
}
}
Can anyone help and explain what is wrong and how can i get it running?
This version of the getAllData function works as you expect:
function getAllData() public view returns (People[] memory) {
uint256 count = countArr.length;
People[] memory outputL = new People[](count);
while(count > 0) {
count--;
(string memory nam, uint256 num) = getPerson(countArr[count]);
People memory temp = People(nam, num);
outputL[count] = temp;
}
return outputL;
}
Feel free to ask if you have any questions about the changes.
I'm learning solidity by writing a contract to store and retrieve patient medical records. Does anyone know why the functions "getRecordByAddressMap" and "getRecordByAddressStruct" don't work? They compile, but the transactions revert.
The logic is quite simple, the functions iterate through the mapping (or array in the other case), checks if the addresses match, adds the structs to an array, then returns that array.
What am I missing here?
contract PatientRecords{
uint256 public recordID = 1;
mapping (uint256 => mapping (address => Records)) records;
struct Records {
address patient;
address hospital;
uint256 admissionDate;
uint256 dischargeDate;
uint256 visitReason;
}
Records[] recordsarray;
Records[] getstructs;
constructor() {
addRecord(0x3719dB98b075Ff10886Fc29431Ffc2006fFF0005,
0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266, 20220320, 20220330, 1);
addRecord(0x3719dB98b075Ff10886Fc29431Ffc2006fFF0005,
0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266, 20220333, 20220333, 2);
addRecord(0x60814DB6b62fE178d7F91239078e3c20fB857E04,
0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266, 20220310, 20220311, 3);
}
// Add a record to the mapping
function addRecord (
address _patientAddress,
address _hospital,
uint256 _admissionDate,
uint256 _dischargeDate,
uint256 _visitReason)
public
{
records[recordID][_patientAddress].patient = _patientAddress;
records[recordID][_patientAddress].hospital = _hospital;
records[recordID][_patientAddress].admissionDate = _admissionDate;
records[recordID][_patientAddress].dischargeDate = _dischargeDate;
records[recordID][_patientAddress].visitReason = _visitReason;
recordsarray.push(Records(_patientAddress, _hospital, _admissionDate, _dischargeDate, _visitReason));
recordID++;
}
// Retrieve a record by the patient address and record ID (count)
function getRecordByID(address _patientAddress, uint256 _recordID) public view returns(Records memory) {
return records[_recordID][_patientAddress];
}
// Retrieve a record by the patient address (Mapping method)
function getRecordByAddressMap(address _patientAddress) public view returns (Records[] memory){
Records[] memory rec = new Records[](recordID);
for (uint i = 1; i < recordID; i++) {
if (_patientAddress == records[i][_patientAddress].patient == true) {
rec[i] = records[i][_patientAddress];
} else {
continue;
}
}
return rec;
}
// Retrieve a record by the patient address (Struct method)
function getRecordByAddressStruct(address _patientAddress) public returns(Records[] memory) {
Records[] storage _getstructs = getstructs;
for (uint i = 1; i < recordID; i++) {
if (_patientAddress == recordsarray[i].patient == true) {
Records memory newRecord = Records({
patient: recordsarray[i].patient,
hospital: recordsarray[i].hospital,
admissionDate: recordsarray[i].admissionDate,
dischargeDate: recordsarray[i].dischargeDate,
visitReason: recordsarray[i].visitReason
});
_getstructs.push(newRecord);
} else {
continue;
}
}
return _getstructs;
}
}
When you iterate with for keyword, you don't use record Id try to use [array].lenght.
In your case, in getRecordByAddressMap function change it in this way:
// Retrieve a record by the patient address (Mapping method)
function getRecordByAddressMap(address _patientAddress) public view returns (Records[] memory){
Records[] memory rec = new Records[](recordID);
for (uint i = 1; i <= rec.length; i++) {
if (_patientAddress == records[i][_patientAddress].patient == true) {
rec[i] = records[i][_patientAddress];
} else {
continue;
}
}
return rec;
}
And in getRecordByAddressStruct function change it with this:
// Retrieve a record by the patient address (Struct method)
function getRecordByAddressStruct(address _patientAddress) public returns(Records[] memory) {
Records[] storage _getstructs = getstructs;
for (uint i = 1; i < _getstructs.length; i++) {
if (_patientAddress == recordsarray[i].patient == true) {
Records memory newRecord = Records({
patient: recordsarray[i].patient,
hospital: recordsarray[i].hospital,
admissionDate: recordsarray[i].admissionDate,
dischargeDate: recordsarray[i].dischargeDate,
visitReason: recordsarray[i].visitReason
});
_getstructs.push(newRecord);
} else {
continue;
}
}
return _getstructs;
}