How to return the Entered Value from Mapping Corresponds to address[msg.sender] - solidity

I am hitting hard to creating a lottery smart contract in solidity. I have tried a couple of ways, first I stored all the players address inside an array, but unfortunately that logic fail, just because of slow execution of array (when entries are more 1000+).
Now I am trying mapping mapping(address => Struct) entries;. Now what I have done here. I created a structure with user first ticket number and user last ticket number i.e uint userFstTcktNumber;
uint userLstTcktNumber;
Here is my structure
struct UserInfo {
uint userFstTcktNumber;
uint userLstTcktNumber;
} UserInfo userinfo;
Then I created a mapping
mapping(address => UserInfo ) public entry;
Then I have Created a function to enter the values inside the mapping and structure.
function letsdo(uint first, uint last) public{
entry[msg.sender];
userinfo.userLstTcktNumber = first;
userinfo.userLstTcktNumber = last;
}
Now what I want to do? I just want to get the values from the mapping and structure corresponding to the address, let's say I have 10 entries from 1 to 10 from address "0x617F2E2fD72FD9D5503197092aC168c91465E7f2" . And I have another 50 entries from 11 to 51 from another address "0x14723A09ACff6D2A60DcdF7aA4AFf308FDDC160C".
To return this I am using the function
function get(address) public view returns(uint, uint){
return (userinfo.userFstTcktNumber, userinfo.userLstTcktNumber);
}
But it's not returning me the expected result.
It's always returning the userFstTcktNumber is 0, no matter what address I have passed inside the get().
What's wrong with this code?

You are not really using your map, you need to set the values to be able to search inside it.
function letsdo(uint first, uint last) public {
entry[msg.sender] = UserInfo(first, last);
}
You don't need a get function as well, since entry is already public, you can search directly using entry[<address>]
UserInfo userinfo after your struct is also unnecessary, since you want to work with map, you will need more than just an instance, the letsdo function I mentioned above is already doing it

Hey thanks everyone for helping me out, Actually Last night I sorted it out my own. And here is the full logic for the problem.
pragma solidity ^0.4.18;
contract lottery{
uint public lastTicketNumber = 0;
uint youEntredWithAmount;
address [] public players;
uint public entryFee = 0.01 ether;
struct UserInfo {
uint userFstTcktNumber;
uint userLstTcktNumber;
}
mapping(address => UserInfo ) public entry;
function letsdo(uint first, uint last) public{
players.push(msg.sender);
entry[msg.sender].userFstTcktNumber = first;
entry[msg.sender].userLstTcktNumber = last;
}
function currentLevel(address userAddress) public constant returns (uint, uint) {
return (entry[userAddress].userFstTcktNumber, entry[userAddress].userLstTcktNumber);
}
function numberOfParticipents() public view returns(address [] memory){
return players;
}
}

Related

Does the order of memory arguments in the Solidity function matter?

i'm trying to make the simple storage using Solidity. Here I'm just trying to map name to some number.
The problem is the following: if I use store_first() it does not work (the retrieve() function returns 0 in any case). But if I change the order of the arguments and place the string memory _name before uint256 _favoriteNumber everything works (the retrieve() function returns correct number)
Does the problem relates to the order (if yes, why?) or I missed something else?
// SPDX-License-Identifier: MIT
pragma solidity >0.6.0;
contract SimpleStorage {
mapping(string => uint256) public nameToNumber;
// If i use this function, the retrieve function always returns 0
function store_first(uint256 _favoriteNumber, string memory _name) public {
nameToNumber[_name] = _favoriteNumber;
}
// If i use this function, the retrieve function returns correct number
function store_second(string memory _name, uint256 _favoriteNumber) public {
nameToNumber[_name] = _favoriteNumber;
}
function retrieve(string memory _name) public view returns(uint256){
return nameToNumber[_name];
}
}

TypeError: Type address is not implicitly convertible to expected type uint256

help, I'm getting errors on my code saying: TypeError: Type address is not implicitly convertible to expected type uint256. And I am in desperate need of help. I don't know what to do and if you need the full code pls say so
I think it has something to do with the address though I am not quite sure since I am still a beginner, so I am absolutely clueless so far. If you do know how to help me solve please say so.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import './ERC721.sol';
contract ERC721Enumerable is ERC721 {
uint256[] private _allTokens;
// CHALLENGE! Write out mapping yourself!!
// mapping from tokenId to position in _allTokens array
mapping(uint256 => uint256) private _allTokensIndex;
// mapping of owner to list of all owner token ids
mapping(uint256 => uint256[]) private _ownedTokens;
// mapping from token ID index of the owner tokens list
mapping(uint256 => uint256) private _ownedTokensIndex;
// #notice count NFTs tracked by this contract
// #return A count of valid NFTs tracked by this contract, where each on of
// them has an assigned and queryable ower not equal to the zero address
// #notice Enumerate valid NFT's
// #dev Throws if '_index" >= 'totalSupply()'.
// #param _index A couter less than 'totalSupply()'
// #return The token identifier for the '_index'th NFt,
// (sort order not specified)
//function tokenByIndex(uint256 _index) external view returns (uint256);
// #notice Enumerate NFTs assigned to an owner
// #dev Throws if '_index' >= 'balanceOf(_owner)' or if
// '_owner' is the zero address, representing invalid NFTs.
// #param _owner An address where we are interested in NFTs owned by them
// #param _index A counter less than 'balanceOf(_owner)'
// #return The token identifier for the '_index'th NFT assigned to '_owner',
// (sort order not specfied)
//function tokenOfOwnerByIndex(address _owner, uint256 _index) external view returns (uint256);
function _mint(address to, uint256 tokenId) internal override(ERC721) {
super._mint(to, tokenId);
// 2 things!
// a. add tokens too the owner
// b. all tokens to out totalSupply - allToken
_addTokensToAllTokenEnumeration(tokenId);
_addTokensToOwnerEnumeration(to, tokenId);
}
// add tokens to the _allTokens array and set the position of the tokens indexes
function _addTokensToAllTokenEnumeration(uint256 tokenId) private {
_allTokensIndex[tokenId] = _allTokens.length;
_allTokens.push(tokenId);
}
// two function - one that returns token by the index
// another one thata retruns tokenByOwnerIndex
function tokenByIndex(uint256 index) public view returns(uint256) {
// make sure that the undex is not our of bounds of the
// total supply
require(index < totalSupply(), 'global index is out of bounds');
return _allTokens[index];
}
// return the total supply of the _allTokens array
function totalSupply() public view returns(uint256) {
return _allTokens.length;
}
function _addTokensToOwnerEnumeration(address to, uint256 tokenId) public {
_ownedTokensIndex[tokenId] = _ownedTokens[to].length;
_ownedTokens[to].push(tokenId);
}
}
In your code, your mapping is wrong. In your function _addTokensToOwnerEnumeration() you have taken address as mapping key. but in your declaration you have taken
//this is wrong as per you have used in your function
mapping(uint256=> uint256[]) private _ownedTokens;
// You have to declare like this.
mapping(address=>uint256[]) private _ownedTokens;
_ownedTokens have uint256 as key type it should be address type:
// mapping of owner to list of all owner token ids
mapping(address => uint256[]) private _ownedTokens;

How to test the Solidity-By-Example Mapping smart contract in Remix?

I want to test the following code in Remix. But what is the procedure?
What do I put in the input field for the function labeled set?
Mapping.sol
// https://solidity-by-example.org/mapping
// Mapping
// Maps are created with the syntax mapping(keyType => valueType).
// The keyType can be any built-in value type, bytes, string, or any contract.
// valueType can be any type including another mapping or an array.
// Mappings are not iterable.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
contract Mapping {
// Mapping from address to uint
mapping(address => uint) public myMap;
function get(address _addr) public view returns (uint) {
// Mapping always returns a value.
// If the value was never set, it will return the default value.
return myMap[_addr];
}
function set(address _addr, uint _i) public {
// Update the value at this address
myMap[_addr] = _i;
}
function remove(address _addr) public {
// Reset the value to the default value.
delete myMap[_addr];
}
}
contract NestedMapping {
// Nested mapping (mapping from address to another mapping)
mapping(address => mapping(uint => bool)) public nested;
function get(address _addr1, uint _i) public view returns (bool) {
// You can get values from a nested mapping
// even when it is not initialized
return nested[_addr1][_i];
}
function set(
address _addr1,
uint _i,
bool _boo
) public {
nested[_addr1][_i] = _boo;
}
function remove(address _addr1, uint _i) public {
delete nested[_addr1][_i];
}
}
This code came from Solidity by Example.
When I implement it on Remix, I get the following screen.
At this point, to test it, I think I need to map an address to a uint256, so I enter the following in the field next to the set button:
["0xcf646ed6e21fd0756ec45a6be5e1057fc24a1b8308175ff0b9f97f565b594eb3", 7439]
The value of the address was a randomly generated hash (I suspect the random hash might be a problem?)
I expect to see the set function render the value 7439. But, instead, it throws the following error:
transact to Mapping.set errored: Error encoding arguments: Error: invalid address (argument="address", value=["0xcf646ed6e21fd0756ec45a6be5e1057fc24a1b8308175ff0b9f97f565b594eb3",7439], code=INVALID_ARGUMENT, version=address/5.5.0) (argument=null, value=["0xcf646ed6e21fd0756ec45a6be5e1057fc24a1b8308175ff0b9f97f565b594eb3",7439], code=INVALID_ARGUMENT, version=abi/5.5.0)
What am I doing wrong?
You have generated a random SHA-256 that is of the format of a valid address, but it doesn't exist on the Remix's browser-based (Javascript VM) chain as any account. If it does, you might be just lucky.
If you want to use valid addresses that do exist on the browser-based VM chain, copy and use the addresses in the account section.

How to make an API call in solidity?

I have a smart contract that I’m trying to make, it pays out the winners of my League of Legends tournament. However I’m running into an issue. I need to make an API call to get the winner of the match, I have a simple URL that I’ve make.
"example-winner.com/winner"
And it returns simple JSON with the address of the winner:
{"winner":"0xa7D0......."}
However, I’m not sure how to make the API call to the outside function. I know I need to use some sort of oracle technology.
Any thoughts? Below is my code:
pragma solidity ^0.4.24;
contract LeagueWinners{
address public manager;
address[] public players;
uint256 MINIMUM = 1000000000000000;
constructor() public{
manager = msg.sender;
}
function enter() public payable{
assert(msg.value > MINIMUM);
players.push(msg.sender);
}
function getWinner() public{
assert(msg.sender == manager);
// TODO
// Get the winner from the API call
result = 0; // the result of the API call
players[result].transfer(address(this).balance);
// returns an adress object
// all units of transfer are in wei
players = new address[](0);
// this empties the dynamic array
}
}
You can use Chainlink as your Oracle.
As many have mentioned, you will need an oracle to get your API call. Something that is important to note, your contract is actually asking an oracle to make your API call for you, and not making the API call itself. This is because the blockchain is deterministic. For more information see this thread.
To answer your question, you can use the decentralized oracle service Chainlink.
You'd add a function:
function getWinner()
public
onlyOwner
{
Chainlink.Request memory req = buildChainlinkRequest(JOB, address(this), this.fulfill.selector);
req.add("get", "example-winner.com/winner");
req.add("path", "winner");
sendChainlinkRequestTo(ORACLE, req, ORACLE_PAYMENT);
}
For the purpose of the following exmaple, we are going to pretend you want to return a uint256 instead of an address. You can return a bytes32 and then convert it to an address, but for simplicity let's say the API returns the index of the winner. You'll have to find a node and jobId that can make a http.get request and return a uint256 object. You can find nodes and jobs from market.link. Each testnet (Ropsten, Mainnet, Kovan, etc) has different node addresses, so make sure you pick the right ones.
For this demo, we are going to use LinkPool's ropsten node
address ORACLE=0x83F00b902cbf06E316C95F51cbEeD9D2572a349a;
bytes32 JOB= "c179a8180e034cf5a341488406c32827";
Ideally, you'd choose a number of nodes to run your job, to make it trustless and decentralized. You can read here for more information on precoordinators and aggregating data. disclosure I am the author of that blog
Your full contract would look like:
pragma solidity ^0.6.0;
import "github.com/smartcontractkit/chainlink/evm-contracts/src/v0.6/ChainlinkClient.sol";
contract GetData is ChainlinkClient {
uint256 indexOfWinner;
address public manager;
address payable[] public players;
uint256 MINIMUM = 1000000000000000;
// The address of an oracle
address ORACLE=0x83F00b902cbf06E316C95F51cbEeD9D2572a349a;
//bytes32 JOB= "93fedd3377a54d8dac6b4ceadd78ac34";
bytes32 JOB= "c179a8180e034cf5a341488406c32827";
uint256 ORACLE_PAYMENT = 1 * LINK;
constructor() public {
setPublicChainlinkToken();
manager = msg.sender;
}
function getWinnerAddress()
public
onlyOwner
{
Chainlink.Request memory req = buildChainlinkRequest(JOB, address(this), this.fulfill.selector);
req.add("get", "example-winner.com/winner");
req.add("path", "winner");
sendChainlinkRequestTo(ORACLE, req, ORACLE_PAYMENT);
}
// When the URL finishes, the response is routed to this function
function fulfill(bytes32 _requestId, uint256 _index)
public
recordChainlinkFulfillment(_requestId)
{
indexOfWinner = _index;
assert(msg.sender == manager);
players[indexOfWinner].transfer(address(this).balance);
players = new address payable[](0);
}
function enter() public payable{
assert(msg.value > MINIMUM);
players.push(msg.sender);
}
modifier onlyOwner() {
require(msg.sender == manager);
_;
}
// Allows the owner to withdraw their LINK on this contract
function withdrawLink() external onlyOwner() {
LinkTokenInterface _link = LinkTokenInterface(chainlinkTokenAddress());
require(_link.transfer(msg.sender, _link.balanceOf(address(this))), "Unable to transfer");
}
}
This would do about everything you need.
If you can't adjust the API to return a uint, you can return a bytes32 and then convert it to an address or a string.
function bytes32ToStr(bytes32 _bytes32) public pure returns (string memory) {
bytes memory bytesArray = new bytes(32);
for (uint256 i; i < 32; i++) {
bytesArray[i] = _bytes32[i];
}
return string(bytesArray);
}
You cannot. The vm does not have any I/O outside of the blockchain itself. Instead you will need to tell your smart contract who the winner is and then the smart contract can just read the value of that variable.
This design pattern is also known as the "oracle". Google "Ethereum oracle" for more info.
Basically your web server can call your smart contract. Your smart contract cannot call your web server. If you need your smart contract to access a 3rd party service then your web server will need to make the request then forward the result to solidity by calling a function in your smart contract.
You didn't properly explain what you are trying to do. Are you having trouble with the solidity code? or rather with your server? Here is an edited version. See if it helps.
pragma solidity ^0.4.24;
contract LeagueWinners{
address public manager;
//address[] public players;
uint256 MINIMUM = 1000000000000000;
constructor() public{
manager = msg.sender;
}
struct Player {
address playerAddress;
uint score;
}
Player[] public players;
// i prefer passing arguments this way
function enter(uint value) public payable{
assert(msg.value > MINIMUM);
players.push(Player(msg.sender, value));
}
//call this to get the address of winner
function winningPlayer() public view
returns (address winner)
{
uint winningScore = 0;
for (uint p = 0; p < players.length; p++) {
if (players[p].score > winningScore) {
winningScore = players[p].score;
winner = players[p].playerAddress;
}
}
}
// call this to transfer fund
function getWinner() public{
require(msg.sender == manager, "Only a manager is allowed to perform this operation");
// TODO
address winner = winningPlayer();
// Get the winner from the API call
//uint result = 0; // the result of the API call
winner.transfer(address(this).balance);
// returns an adress object
// all units of transfer are in wei
delete players;
// this empties the dynamic array
}
}
At least that is what I understand by your question.

Array returns "Undeclared identifier. Did you mean "Candidate" or "candidate"?"

when trying to set up an array of structs i get an error that says "Undeclared identifier. Did you mean "Candidate" or "candidate"?"
Ive tried to create an empty array by writing
uint[] memory candidate;
and
bytes[] memory candidate
above the function in which i'm getting errors to instantiate it. However, this doesn't work either and gives errors. It does not compile.
pragma solidity 0.5.0;
contract Election {
string public candidate;
struct Candidate {
uint id;
string name;
uint voteCount;
}
mapping(uint => Candidate) candidate;
uint public candidatesCount;
function createCandidate(string storage name ) private {
candidatesCount ++;
candidates[candidatesCount] = Candidate(candidatesCount, name, 0);
}
function addCandidates () public {
createCandidate("Candidate1");
createCandidate("Candidate2");
}
}
change
mapping(uint => Candidate) candidate;
to
mapping(uint => Candidate) candidates;
and
function createCandidate(string storage name ) private
to
function createCandidate(string memory name ) private