How is a map initialised in memory - javascript

I just tarted to write solidity and i have some questions that i could not find the answer to.
When you declare a map like this:
struct UserAccount{
string name;
uint id;
}
mapping (address => UserAccount) public accounts;
How will that be initialised? or with what?
For example, accessing
accounts[0x79d66c53ad6f1847288c0d06c01a2b38c38f15bc]
will return an instance of an UserAccount? If yes, that means that the map creates an instance of UserAccount for every possible address? Doesn't that consume very much memory? If not, then how comes you can do this:
accounts[_address].name = _name;
?
And the second question:
I keep reference in my contract of an address that is the owner, the address that created the contract:
address public owner;
constructor() public {
owner = msg.sender;
}
After i call this function:
uint userCount=0;
mapping (address => UserAccount) public accounts;
function createAccount(string _name, uint _id, address _address) onlyOwner() public {
UserAccount user;
user.name = _name;
user.id = _id;
accounts[_address] = user;
userCount += 1;
// accounts[_address].name = _name;
// accounts[_address].id = _id;
// userCount += 1;
emit UserCreated(_address, _id, _name);
}
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
the owner address changes. The commented lines from createAccount function are the way to do it, i know, but i want to understand why it does not work.
To clarify my problem i will also post a js test.
beforeEach(async () => {
voting = await Voting.new({from: owner});
});
it("Should delete poll, as owner", async () =>{
var name = "Sandu";
console.log("LOCAL OWNER= " + owner);
console.log("OWNER BEFORE CREATE ACCOUNT FROM SOL= " + await voting.owner());
await voting.createAccount(name, 1, firstUser,{from:owner});
console.log("OWNER AFTER CREATE ACCOUNT FROM SOL= " + await voting.owner());
var pollName = "First Poll";
var endDateS="2018-08-11T10:20:30Z";
var endDate=new Date(endDateS)
await voting.createPoll(pollName, 1, endDate.getTime()/1000,{from:firstUser});
try{
await voting.deletePollById(1,{from: owner});
}catch(err){
console.log(err.message);
}
assert.notEqual(pollName, await voting.getPollById(1));
});
The test above prints this:
LOCAL OWNER= 0x79d66c53ad6f1847288c0d06c01a2b38c38f15bc //Owner that o have in my js file local, first address from the ganache accounts.
OWNER BEFORE CREATE ACCOUNT FROM SOL= 0x79d66c53ad6f1847288c0d06c01a2b38c38f15bc //The owner account from my contract before calling the function
OWNER AFTER CREATE ACCOUNT FROM SOL= 0x000000000000000000000000000000000000000a //The owner account from my contract after calling the function
I can't understand why the value from owner changes as i don't touch that in my function.
If anyone can help it would be much appreciated. Again, i know the right way to do it but i am posting this out of the desire to understand what i am doing not to get the job done.

Please do not post multiple questions in a single post as it will result in the question being closed as too broad.
For your first question, all variables have an initial default value. From the Solidity docs:
Mappings can be seen as hash tables which are virtually initialized such that every possible key exists and is mapped to a value whose byte-representation is all zeros: a type’s default value.
No storage is used for zero values.
For your second question, you're overwriting the state variable because you're using a storage variable where you should be using a memory variable. See the answer provided here: what are state variables in solidity?

Related

How to make a function Range() (python) in javascript when the range of number is a call of smart contract

I'm trying to build a frontend application using ethers.js from a smart contract that mints one of four houses of Hogwarts.
The contract:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "#openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
//Chainlink's VRFConsumerBase (Chainlink Verifiable Random Function)
//Link: https://docs.chain.link/docs/intermediates-tutorial/
//Github repo: https://github.com/smartcontractkit/chainlink/blob/develop/contracts/src/v0.8/VRFConsumerBase.sol
import "#chainlink/contracts/src/v0.8/VRFConsumerBase.sol";
//A ERC721 contractc alias NFT Contract will mint one of four houses of Hogwarts.
//Have you always enjoyed being part of one of the houses of Hogwarts?
//Well, you are in the right place!
//This Smart Contract will extract your Hogwarts household as the talking hat!
contract HogwartsHouses is ERC721URIStorage, VRFConsumerBase {
uint256 public tokenCounter;
bytes32 public keyhash;
uint256 public fee;
mapping(uint256 => Raffle) public tokenIdToRaffle;
mapping(bytes32 => address) public requestIdToSender;
event requestCollectible(bytes32 indexed requestId, address requester);
event raffleAssigned(uint256 indexed tokenId, Raffle raffle);
//This are the different houses that one can extract
enum Raffle {
GRYFFINDOR,
HUFFLEPUFF,
RAVENCLAW,
SLYTHERIN
}
constructor(
address _vrfCoordinator,
address _linkToken,
bytes32 _keyhash,
uint256 _fee
)
public
VRFConsumerBase(_vrfCoordinator, _linkToken)
ERC721("Houses", "HOM")
{
tokenCounter = 0;
keyhash = _keyhash;
fee = _fee;
}
function createCollectible() public returns (bytes32) {
//We want the user who called createCollectoible to be the same user
//who gets assigned the tokenId
bytes32 requestId = requestRandomness(keyhash, fee); //This is going to create our randomness request to get random Houses of Howarts.
//We can get the original caller of create collectible
requestIdToSender[requestId] = msg.sender;
emit requestCollectible(requestId, msg.sender);
}
//Function fulfillRandomness: which is the function that receives and does something
//with verified randomness.
function fulfillRandomness(bytes32 requestId, uint256 randomNumber)
internal
override
{
//Select a houses based of this randomNumber
Raffle raffle = Raffle(randomNumber % 4);
//This is the way how each tokenId is going
//to have a very specific Hogwarts Houses
uint256 newTokenId = tokenCounter;
//tokenURI based on the houses Hogwarts
tokenIdToRaffle[newTokenId] = raffle;
emit raffleAssigned(newTokenId, raffle);
address owner = requestIdToSender[requestId];
_safeMint(owner, newTokenId);
tokenCounter = tokenCounter + 1;
}
function setTokenURI(uint256 tokenId, string memory _tokenURI) public {
//Only the owner of the tokenId can be update the tokenURI
require(
_isApprovedOrOwner(_msgSender(), tokenId), //Imported from OpenZeppelin
"ERC721: caller is not owner no approved!"
);
_setTokenURI(tokenId, _tokenURI);
}
}
I'm trying to write this function in javascript:
raffle_metadata_dic = {
"GRYFFINDOR": "https://ipfs.io/ipfs/QmXJcdftXeX9ndcmsPFijRNtyMM49yvSnb8AcveMKWq61c?filename=GRYFFINDOR.json",
"HUFFLEPUFF": "https://ipfs.io/ipfs/QmPz1mxmqUGQUUuVNFWYUPU5BF6dU5MBCQ5xmG3c63pDMN?filename=HUFFLEPUFF.json",
"RAVENCLAW": "https://ipfs.io/ipfs/QmUH9J2eY2Cuu4m5raGCg2XmGqZrd6NuvTatzgwWX1Jm6z?filename=RAVENCLAW.json",
"SLYTHERIN": "https://ipfs.io/ipfs/QmPvjuj32AFV9yye7agrxSzty4Y5nCvesNkzgmYjJciA2f?filename=SLYTHERIN.json",
}
def main():
print(f"Working on {network.show_active()}")
hogwarts_houses = HogwartsHouses[-1]
number_of_collectibles = hogwarts_houses.tokenCounter()
print(f"You have {number_of_collectibles} tokenIds")
for token_id in range(number_of_collectibles):
raffle = get_raffle(hogwarts_houses.tokenIdToRaffle(token_id))
# Check to see if already have a token
if not hogwarts_houses.tokenURI(token_id).startswith("https://"):
print(f"Setting tokenURI of {token_id}")
set_token_uri(token_id, hogwarts_houses, raffle_metadata_dic[raffle])
def set_token_uri(token_id, nft_contract, tokenURI):
account = get_account()
tx = nft_contract.setTokenURI(token_id, tokenURI, {"from": account})
tx.wait(1)
print(
f"Awesome! You can view your NFT at {OPENSEA_URL.format(nft_contract.address, token_id)}"
)
print("Please wait up to 20 minutes, and hit the refresh metadata button")
For the full code: https://github.com/Pif50/Progetto-Ethereum-Web3-di-Pier-Francesco-Tripodi
So, for tokenid in range(number of collectible):
numeber_of_collectible, is hogwarts_houses.tokenCounter(). tokenCounter is a counter of the token that already have
I'm trying to write this for loop in javascript.
I know in javascript there isn't the function Range() and I know this function is to write from scratch.

Solana token ownership

is there any way to check that user A owns spl token B inside solana contract? Maybe there is safe method to check it outside.
I need it to give some privileges to users, which own mine nfts. Users would write data to program only when they have nft.
To check the owner of an SPL token account from within a program, you'll have to deserialize it and check the owner field, ie:
use solana_program::{
account_info::next_account_info, account_info::AccountInfo, entrypoint,
entrypoint::ProgramResult, pubkey::Pubkey, program_pack::Pack,
};
use spl_token::state::Account;
entrypoint!(process_instruction);
const EXPECTED_OWNER: Pubkey = Pubkey::new_from_array([1; 32]);
fn process_instruction(
program_id: &Pubkey,
accounts: &[AccountInfo],
instruction_data: &[u8],
) -> ProgramResult {
let account_info_iter = &mut accounts.iter();
let spl_token_account_info = next_account_info(account_info_iter)?;
let spl_token_account_data = spl_token_account_info.try_borrow_data()?;
let spl_token_account = Account::unpack(&spl_token_account_data)?;
if spl_token_account.owner == EXPECTED_OWNER {
// your logic here
}
}
Note that I haven't tried to compile this, so use with caution!

Getting the address of a contract deployed by another contract

I am trying to deploy a contract from another factory contract and then return the address of the newly created contract. The address it returns however is the transaction hash not the contract address. I believe this is because the contract is not yet mined when the address is returned. When I deploy a contract using the web3 deploy it seems to wait until the contract is deployed before outputting the address.
The factory contract:
contract Factory {
mapping(uint256 => Contract) deployedContracts;
uint256 numContracts;
function Factory(){
numContracts = 0;
}
function createContract (uint32 name) returns (address){
deployedContracts[numContracts] = new Contract(name);
numContracts++;
return deployedContracts[numContracts];
}}
This is how I am calling the createContract function.
factory.createContract(2,function(err, res){
if (err){
console.log(err)
}else{
console.log(res)
}
});
Consider the below example. There are a number of ways you can get the address of the contract:
contract Object {
string name;
function Object(String _name) {
name = _name
}
}
contract ObjectFactory {
function createObject(string name) returns (address objectAddress) {
return address(new Object(name));
}
}
1 Store the Address and Return it:
Store the address in the contract as an attribute and retrieve it using a normal getter method.
contract ObjectFactory {
Object public theObj;
function createObject(string name) returns (address objectAddress) {
theObj = address(new Object(name));
return theObj;
}
}
2 Call Before You Make A Transaction
You can make a call before you make a transaction:
var address = web3.eth.contract(objectFactoryAbi)
.at(contractFactoryAddress)
.createObject.call("object");
Once you have the address perform the transaction:
var txHash = web3.eth.contract(objectFactoryAbi)
.at(contractFactoryAddress)
.createObject("object", { gas: price, from: accountAddress });
3 Calculate the Future Address
Otherwise, you can calculate the address of the future contract like so:
var ethJsUtil = require('ethereumjs-util');
var futureAddress = ethJsUtil.bufferToHex(ethJsUtil.generateAddress(
contractFactoryAddress,
await web3.eth.getTransactionCount(contractFactoryAddress)));
We ran across this problem today, and we're solving it as follows:
In the creation of the new contract raise an event.
Then once the block has been mined use the transaction hash and call web3.eth.getTransaction:
http://web3js.readthedocs.io/en/1.0/web3-eth.html#gettransaction
Then look at the logs object and you should find the event called by your newly created contract with its address.
Note: this assumes you're able to update the Solidity code for the contract being created, or that it already calls such an event upon creation.

Using Pointers for ios App & Javascript website

I have an iphone app created as a multiplication game and saves the following into a class called 'Results'.
PFObject *Results = [PFObject objectWithClassName:#"Result"];
[Results setObject:levelNumberLabel.text forKey:#"LevelNumber"];
[Results saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) etc.
I also have a class called 'currentUser' that stores the following:
PFObject *currentUser = [PFObject objectWithClassName:#"currentUser"];
[currentUser setObject:_firstnameLabel.text forKey:#"SFirstName"];
I want to run a javascript query that 'links' these two tables. I have a point
er set up called 'currentuser' in the currentUser class and a pointer called 'currentResult'.. These hold no value (undefined).
How am I able to merge these classes together? Will it be a case of linking it through the app or using javascript? I'm slightly confused. Here is my javascript code
var Show = Parse.Object.extend("Result");
var query = new Parse.Query(Show);
query.include('currentUser');
query.find({
success: function(shows) {
for(var i = 0; i < shows.length; i++) {
var show = results[i];
var surname = results.get('SSurname');
console.log(i);
var users = show.get('currentUser');
var username = users.get("SFirstName");
$(".success").append(username + " on " + surname + "<br/>");
Any questions/help please let me know.
Any help on the subject would be greatly appreciated
Parse already gives us a User class (PFUser). Consider starting with that one.
Next, create a class that represents the result of play. "Result" (singular) is an okay name for that. It can have string and number attributes as you see fit. (name those starting with lower case, e.g. "levelNumber"). To associate a result with a user, the Result table must also have a pointer attribute to the User, call it "user".
In Objective-C, when its time to save the result of play:
PFUser *user = [PFUser currentUser]; // this is the signed in PFUser
PFObject *result = [PFObject objectWithClassName:#"Result"];
result[#"user"] = user;
result[#"some_other_col_name"] = some_other_value;
[result saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
// ...
}];
In JS, to find the all of the results created by the play of some user:
// if this is called in a cloud function, the request.user will be
// the PFUser on the client that made the request
function resultsForUser(user) {
var query = new Parse.Query("Result");
query.equalTo("user" user);
return query.find().then(function(results) {
// results are the Result objects whose user is the given user
}, function (error) {
});
}

Function to add and remove a username

In my chat application project, I am trying to broadcast usernames to all the users whenever a new user is connected to a server. and remove a username whenever the user leaves the server. The below is the code which I have tried by going through tutorials. (please check the file.js file which is not showing the desired output)
Chat.cs (Working) --> Implements "Hub" class of SignalR
public class Chat : Hub
{
/* showing only related content */
static ConcurrentDictionary<string, User> _users = new ConcurrentDictionary<string, User>();
public override Task OnDisconnected()
{
var user = _users[Context.ConnectionId]; //user as ConnectionId
User removedUser; //new class object
_users.TryRemove(Context.ConnectionId, out removedUser);
return Clients.All.leave(user, DateTime.Now.ToString()); //dynamic expression
}
public void Joined()
{
User user = new User(Context.ConnectionId, Clients.Caller.username);
_users.TryAdd(user.ConnectionID, user);
Clients.All.joins(user.ConnectionID, user.Name, DateTime.Now); //dynamic expression
}
}
User.cs (Working)
public class User
{
public User(string ConnID, string Username)
{
Name = Username;
ConnectionID = ConnID;
}
public string Name { get; set; }
public string ConnectionID { get; set; }
}
file.js (not working)
var chatUsername = window.prompt("Enter Username:", ""); //username
var chat = $.connection.chat; //connection
//
chat.client.joins = function (ConnectionId, name, Date) {
ConnectionId = 1; /* given value to just test */
name = chatUsername;
};
chat.client.leave = function (user, date) {
user = ""; //making the string empty so that the disconnected user value will be lost.
};
//Here is the connection which calls the "Joined" function of the server (Chat.cs)
What should I write in file.js functions (joins and leave) so that I will get the desired result as I mentioned above. Before asking here, I have gone through this site which is doing the same but including additional javascript files(knockout.js and json) which I dont want to include.(bcos I am new to jquery).
In order to pass UserNames to the client you can take your dictionary and in your joined server side method you could change the SignalR line to be:
Clients.All.joins(_users.Values); //dynamic expression
Then the client version of joins would be:
chat.client.joins = function (users) {
for(var i = users.length - 1; i >= 0; i--) {
alert("User Name: " + users[i].Name + "\nUser Connection ID: " + users[i].ConnectionID);
}
};
Of course you can handle the user information differently than alerting it, but that's the gist of how to handle the data. Lastly, I'd recommend against passing down the connection ID to everyone because a third party could then easily hijack it.

Categories