How to return the content of an array carrying multiple data types? - solidity

contract minter {
//instantiate ERC20 contract
ERC20 erc20 = ERC20 (0x2C31Db3Cc686CBf0EF2325a468f622137A42Da31);
//keep track of created ERC20 addresses
ERC20 [] public tokenList;
mapping (address => uint) balances;
//make msg.sender the owner
address owner_ = msg.sender;
function createERC20 (string memory name_, string memory symbol_, uint totalSupply_) public {
erc20 = new ERC20 (name_, symbol_, totalSupply_, owner_);
tokenList.push(erc20);
}
function getList () public view returns (address [] memory){
return tokenList();
}
}
I tried to use this contract as a factory for the already deployed contract ERC20 at the address. The minting appears to work, but I have a problem to track the data of the mints. I thought I could just push the array tokenList with the data inside of the createERC20 function, but I do not get how I can display the contents of the array with the getList function. I have seen people using structs to store the data, but is it possible to instantiate ERC20 to a struct?
I tried multiple different approaches for the getter function, but I just do not seem to find the right solution.

Your tokenList items are of type contract. If you return ERC20[] from the function, they will get converted to an array of addresses.
function getList() public view returns (ERC20[] memory){
return tokenList;
}

Related

How to access function of a contract instantiated with new?

I'm instantiating the contract called "Elector", applying new inside the function below, so far it works and the result is this one:
The contract is instantiated in memory with this address.
So, how do I access the getInformation() function inside this contract to use both in this main contract and in ethers in the dApp?
MAIN CONTRACT:
function updateConfirmedVotes(uint candidateId, VoteType electorVoteType) public {
_updateTotalElectoresVoted();
_pollingByCandidate[candidateId].votes.total += 1;
_pollingByCandidate[candidateId].votes.totalPercentage = _calculePercentageOfVote(_pollingByCandidate[candidateId].votes.total);
_pollingByCandidate[candidateId].electors.push(new _Elector({wallet: msg.sender, vote: electorVoteType}));
}
ELECTOR CONTRACT:
contract _Elector {
address private _wallet;
VoteType private _vote = VoteType.DID_NOT_VOTED;
constructor(address wallet, VoteType vote) {
_wallet = wallet;
_vote = vote;
}
function getInformation() external view returns (address, VoteType) {
return (_wallet, _vote);
}
}
Define a contract type variable within your Main contract, passing it pointer to the newly deployed Elector contract. Then you can invoke external/public functions defined by the contract type on the external address.
pragma solidity ^0.8;
contract Elector {
// ...
}
contract Main {
Elector elector;
function deployElector() external {
// returns pointer to the newly deployed contract
elector = new Elector();
}
function getInformationFromElector() external view returns (address, Elector.VoteType) {
// calls the external contract
return elector.getInformation();
}
}

How to run multiples contracts functionalities in a single contract Solidity

I'm new to Solidity but I can't find much information about my problem.
For example, I want to make different contracts for different functionalities (I see them as classes)
For example
Main contract
// SPDX-License-Identifier: None
pragma solidity >=0.8.6;
import "./AuthContract.sol";
contract Contract {
string public message;
constructor() {
message = "test";
}
function getMessage() public view returns(string memory) {
return message;
}
}
and second contract
contract Auth {
struct UserDetail {
address addr;
string name;
string password;
string CNIC;
bool isUserLoggedIn;
}
mapping(address => UserDetail) user;
// user registration function
function register(
address _address,
string memory _name,
string memory _password,
string memory _cnic
) public returns (bool) {
require(user[_address].addr != msg.sender);
user[_address].addr = _address;
user[_address].name = _name;
user[_address].password = _password;
user[_address].CNIC = _cnic;
user[_address].isUserLoggedIn = false;
return true;
}
// user login function
function login(address _address, string memory _password)
public
returns (bool)
{
if (
keccak256(abi.encodePacked(user[_address].password)) ==
keccak256(abi.encodePacked(_password))
) {
user[_address].isUserLoggedIn = true;
return user[_address].isUserLoggedIn;
} else {
return false;
}
}
// check the user logged In or not
function checkIsUserLogged(address _address) public view returns (bool) {
return (user[_address].isUserLoggedIn);
}
// logout the user
function logout(address _address) public {
user[_address].isUserLoggedIn = false;
}
}
How could I use the functionalities from that contract in the main contract?
Is such a thing possible in the blockchain?
I am quite new here also but i can solve your problem, if not solve i can lead you to a good path .
so firstly you said you want to create multiple contract for different functionalities, this is good but keep in my you are going to exhaust a lot of gas.
so the answer to your problem is easy you can just read it and implement it.
if you want to use a contract in the Another contract (main in your case) you can do it in two ways(according to my knowledge there might be other).
using new keyword
using address of your previously deployed contract
we will be using the First case as i suppose you havenot deployed the second contract yet
In Order to do it you can use
Auth myObj=new Auth();
This will create a new instance of the contract Auth in your main contract and now you can use the Auth contract's function in your Main contract.you can create a function copy the above line and you can use the Functions using dot operator.
myObj.register(_address,_name,moreandmore);
I believe this will solve your problem if not you can ask it.
Thank You!

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;

Solidity - why does fallback() get called even though address.call{value:msg.value}("") does not have data?

The following contract calls another contract using an interface method (code to change):
pragma solidity 0.8.7;
interface MyStorage {
function setStorageValue(uint256) external;
}
contract StorageFactory {
uint256 storageValue;
constructor(uint256 _storageValue) {
storage = _storageValue;
}
function initStorage(MyStorage store) public payable {
store.setStorageValue(storageValue);
address payable storeAddress = payable(address(store));
storeAddress.call{value: msg.value}("");
}
}
Following is the StorageContract (code cannot be changed):
pragma solidity 0.8.7;
contract Storage {
int _storageValue;
function setStorageValue(int storageValue) public {
_storageValue = storageValue;
}
receive() external payable {
require(_storageValue == -1 || address(this).balance <= uint(_storageValue), "Invalid storage value");
}
fallback() external {
_storageValue = -1;
}
}
I use a test to call initStorage of the first contract by passing a Storage object, where the test is meant to fail because the value is set to a large amount. But somehow, the fallback() function seems to get called, setting the value to -1. I can't figure out why. Any help is appreciated.
Due to the solidity doc:
The fallback function is executed on a call to the contract if none of the other functions match the given function signature, or if no data was supplied at all and there is no receive Ether function. The fallback function always receives data, but in order to also receive Ether it must be marked payable.
Your function getting called because there's no overloading for the function
function setStorageValue(uint256 storageValue) public
So change the storageValue from int to uint256 will help.

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.