Solidity Address Book Smart Contract returns error when trying to create new mapping entry - solidity

I'm learning Solidity and I am trying to make an Address Book smart contract. Right now the code allows the user to create an account of sorts using the createBook function.
contract AddressBook {
struct ownerInfo{
string ownerAlias;
}
string[] Alias;
mapping(address => ownerInfo) public ownerToAlias;
function createBook(string memory _ownerAlias) public{
for(uint i = 0; i <= Alias.length; i++) {
require(keccak256(abi.encodePacked(_ownerAlias)) != keccak256(abi.encodePacked(Alias[i])));
ownerToAlias[msg.sender] = ownerInfo(_ownerAlias);
Alias.push(_ownerAlias);
}
}
}
There are no errors when compiling or deploying, but the createBook function returns an error. The problem seems to come from the require() function which I'm using to check whether the input'd name is already in use.
I expected the code to work when I pass in "Address Book Name" for the first time, and return an error when I try to pass in the same string again.

The condition of the for loop needs to be: for(uint i = 0; i < Alias.length; i++)
because as it is right now the loop will continue forever, because you push a new element to the Alias array at the end, the condition will always be true. The length of the Array will always be equal to i as they both increment by one after every loop

Related

How can I delete an element from a nested mapping

I have a nested mapping that goes from address to planId to struct(subscription)
mapping(address => mapping(uint => subscription)) public subscriptions
I have a function to cancel a specific plan that has been created but when I trigger the function I got an error that says
The transaction ran out of gas. Please increase the Gas Limit.
When I debugged the error the debugger points the error inside the cancel function at the code line below
function cancel(uint planId) external {
Subscription storage subscription = subscriptions[msg.sender][planId];
require(
subscription.subscriber != address(0),
'this subscription does not exist'
);
delete subscriptions[msg.sender][planId]; // this one
emit SubscriptionCancelled(msg.sender, planId, block.timestamp);
}
How can I fix that error?
Thanks
I am facing a similar problem. Here's what I did, I realized that it's not possible to assign a default value to a nested mapping once you change it.
In your example, you can try assigning a struct with different values(which you can consider as a replacement for default) and then it wont throw error.
Following is my example:
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.0;
contract test{
mapping(address=> mapping(uint => uint)) public address_id_liked;
function register(uint id) external{
address_id_liked[msg.sender][id] = 1;
}
function test_(uint index) external view returns(uint) {
uint out = address_id_liked[msg.sender][index];
return(out);
}
function ops(uint id, uint num) external {
address_id_liked[msg.sender][id] = num;
}
}
In the ops function, I wanted my mapping to have a default value but it's not happening. So I tried inputting the value which I want to assign to nested mapping. And it's taking all uint values except 0(the default)
P.S- I was using mapping(address=> mapping(uint => bool)) public address_id_liked previously. But I am unable to delete/assign false, hence I tried with uint.
Hope this helps!

How to swap array elements using destructuring in Solidity?

I want to delete data from an array. But deleting data from a particular array index creates a gap in the array. Hence, I am swapping the array[i] with array[array.length-1] and popping out the array. I tried to do it with a destructuring technique that is supported in Solidity yet it turns out the values do not tend to swap. While swapping using the "temp" variable seems to work perfectly fine but it consumes more gas.
There's a warning that solidity throws which I am not able to understand.
Warning: This assignment performs two copies to storage. Since storage copies do not first copy to a temporary location, one of them might be overwritten before the second is executed and thus may have unexpected effects. It is safer to perform the copies separately or assign to storage pointers first.
Can anyone help?
Please find the code below:
struct Details{
uint256 id;
address walletAddress;
string fullName;
uint256 phoneNumber;
string residentialAddress;
}
Details [] public userDetails;
function deleteData(uint256 _id) public onlyOwner returns(string memory){
for(uint256 i=0;i<userDetails.length;i++)
{
if (userDetails[i].id==_id){
(userDetails[i],userDetails[userDetails.length-1])=(userDetails[userDetails.length-1],userDetails[i]);
userDetails.pop();
}
}
}
You can just assign the last item to the place of the deleted one (effectively duplicating the last item for the moment), and then delete the last item.
if (userDetails[i].id == _id) {
userDetails[i] = userDetails[userDetails.length-1];
userDetails.pop();
break;
}

Solidity: Dedupping string keys inside a pure function

I am trying to define a mapping to use inside a function as a means of quickly determining whether a key exists. I realize I could also use an array and loop thorugh it but that seems like it might get expensive. But that you can't create mappings dynamically, and if I create a state variable for the purpose, then I have the problem of clearing state between calls to this function which makes it pricey.
Here is what I was tyring to do, any suggestions for the most efficient method to dedupe a set of strings inside a pure function?
function dedupe(string[] memory keys) public pure returns(string[] memory) {
string[] memory deduped;
mapping(string=>bool) map;
string memory ikey;
for(uint i=0; i<keys.length; i++) {
ikey = keys[i];
if (!map[ikey]) {
map[ikey]=true;
deduped.push(ikey);
}
}
return deduped;
}

Solidity: Nested mapping access cannot be at return

i'm writing simple smart contract for learning.
I wrote a contract as
contract A {
mapping(address => mapping(uint32 => uint32)) data;
..
function getData(address addr, index id) public view {
return data[addr][id];
}
}
And it returns compile error
TypeError: Different number of arguments in return statement than in returns declaration
In right that line.
Maybe there is miswriting in my code data[addr][index] , which one should be fixed,
or just a bug of Solidity?
Weirdly, i found answer right after posting..
Simply added returns keywords like
function getData(address addr, index id) public view returns(uint32) {
...
then works fine.
For others, i'll leave this question as is.

Example Oraclize files return 0: string: when called in Remix

I want to use Oraclize in Remix, to test it. I'm too stupid to use their examples.
How can I make this work?
From their Github I took the YouTube-Views code and copied it into Remix
pragma solidity >= 0.5.0 < 0.6.0;
import "github.com/oraclize/ethereum-api/oraclizeAPI.sol";
contract YoutubeViews is usingOraclize {
string public viewsCount;
event LogYoutubeViewCount(string views);
event LogNewOraclizeQuery(string description);
constructor()
public
{
update(); // Update views on contract creation...
}
function __callback(
bytes32 _myid,
string memory _result
)
public
{
require(msg.sender == oraclize_cbAddress());
viewsCount = _result;
emit LogYoutubeViewCount(viewsCount);
// Do something with viewsCount, like tipping the author if viewsCount > X?
}
function update()
public
payable
{
emit LogNewOraclizeQuery("Oraclize query was sent, standing by for the answer...");
oraclize_query("URL", 'html(https://www.youtube.com/watch?v=9bZkp7q19f0).xpath(//*[contains(#class, "watch-view-count")]/text())');
}
}
When I use the viewCount it returns:
0: string:
This happens with all the other examples aswell.
With WolframAlpha eg. I also get the following error:
transact to WolframAlpha.update errored: VM error: revert.
revert The transaction has been reverted to the initial state.
Note: The constructor should be payable if you send value. Debug the transaction to get more information.
Ok you don't see the answer like a normal result in Remix:
You have to go under settings and open the Oraclize plug in.
If you then deploy the contract and or click update, you get the result shown in the plug in.