Solidity Blockchain - Memory,Storage and mapping explanation brief explanation [closed] - cryptography

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 1 year ago.
Improve this question
Kindly someone can explain me about mapping,storage and memory breifly with examples ? I am not clear with some articles
Thanks!!

STORAGE AND MEMORY
Storage and Memory keywords in Solidity are analogous to Computer’s hard drive and Computer’s RAM. Much like RAM, Memory in Solidity is a temporary place to store data whereas Storage holds data between function calls. The Solidity Smart Contract can use any amount of memory during the execution but once the execution stops, the Memory is completely wiped off for the next execution.
Whereas Storage on the other hand is persistent, each execution of the Smart contract has access to the data previously stored on the storage area.
Every transaction on Ethereum Virtual Machine costs us some amount of Gas. The lower the Gas consumption the better is your Solidity code. The Gas consumption of Memory is not very significant as compared to the gas consumption of Storage. Therefore, it is always better to use Memory for intermediate calculations and store the final result in Storage.
State variables and Local Variables of structs, array are always
stored in storage by default.
Function arguments are in memory.
Whenever a new instance of an array is created using the keyword
‘memory’, a new copy of that variable is created.
Changing the array value of the new instance does not affect the
original array.
Example#1: In the below example, a contract is created to demonstrate the ‘storage’ keyword.
pragma solidity ^0.4.17;
// Creating a contract
contract helloGeeks
{
// Initialising array numbers
int[] public numbers;
// Function to insert values
// in the array numbers
function Numbers() public
{
numbers.push(1);
numbers.push(2);
//Creating a new instance
int[] storage myArray = numbers;
// Adding value to the
// first index of the new Instance
myArray[0] = 0;
}
}
Output:
When we retrieve the value of the array numbers in the above code, Note that the output of the array is [0,2] and not [1,2].
Example#2: In the below example, a contract is created to demonstrate the keyword ‘memory’.
pragma solidity ^0.4.17;
// Creating a contract
contract helloGeeks
{
// Initialising array numbers
int[] public numbers;
// Function to insert
// values in the array
// numbers
function Numbers() public
{
numbers.push(1);
numbers.push(2);
//creating a new instance
int[] memory myArray = numbers;
// Adding value to the first
// index of the array myArray
myArray[0] = 0;
}
}
Output:
When we retrieve the value of the array numbers in the above code, Note that the output of the array is [1,2]. In this case, changing the value of myArray does not affect the value in the array numbers, this because the function stopped, the the array wasn't saved
MAPPINGS
Mappings are a totally different thing.
These are used to store the data in the form of key-value pairs, a key can be any of the built-in data types but reference types are not allowed while the value can be of any type.
Mappings are mostly (but not limited to) used to associate the unique Ethereum address with the associated value type.
The mappings are quite similar to an array
mapping(key => value) <name>;
Example#1:
pragma solidity ^0.4.17;
// Creating a contract
contract helloGeeks
{
// Initialising mapping of user balance
mapping(address => uint) balance;
// Function to insert user balance
function Insert(address _user, uint _amount) public
{
//insert the amount to a specific user
balance[_user] = _amount
}
//function to view the balance
function View(address _user) public view returns(uint)
{
//see the value inside the mapping, it will return the balance of _user
return balance[_user];
}
}

Related

a public function calls another internal or private function in solidity

What I see in several smart contracts, written with solidity, is that a public function is written whose job is just calling another function, which is private or internal.
Here is an example from erc20burnable.sol
In this function _burn is internal, but burn is public.
`
function burn(uint256 amount) public virtual {
_burn(_msgSender(), amount);
}
`
or here is another one in erc1155.sol
`
function safeBatchTransferFrom(
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) public virtual override {
require(
from == _msgSender() || isApprovedForAll(from, _msgSender()),
"ERC1155: caller is not token owner or approved"
);
_safeBatchTransferFrom(from, to, ids, amounts, data);
}
`
What is the benefit of this structure? why it is common in smart contracts?
Thanks.
One reason for this, I guess, is this way we will be able to override parents, or add modifiers, etc.
It's a common practice used in other OOP languages as well.
One of the reasons is code reusability. If the same snippet (e.g. decrease balance of one address, increase balance of other address, and emit an event) is used in multiple methods (e.g. both transfer() and transferFrom()), you can bundle them into one private function (e.g. _transfer()). And then call this private function from both public functions. When you need to make a change in the code logic, you'll be able to make it in just one place instead of having to search for multiple places and leaving some out by mistake.
Other common reason - you already answered it yourself. This approach allows you to allow the user to specify only some params - for example the amount. But the user cannot specify from which address are the tokens going to be burned - it's always from their address. Even though the private function _burn() allows to specify the burner, the user is not allowed to specify it.

Solidity storing timestamp/value data that's easily accessible

I have an interesting use case that I can't seem to solve.
Problem: Tokens get X points per day. I want to freeze ERC721 tokens (they have IDs) for a certain period of time. During that time, they get 0 points per day.
I have the following to calculate points:
uint32 public constant SECONDS_IN_DAY = 1 days;
struct UserInfo {
uint256 itemCount;
uint256 pendingPoints;
uint256 lastUpdate;
}
mapping(address => UserInfo) public userInfo;
function pending(address account) public view returns (uint256) {
uint256 pendingPoints = userInfo[account].pendingPoints + (((block.timestamp - userInfo[account].lastUpdate) / SECONDS_IN_DAY) * (userInfo[account].itemCount));
return pendingPoints;
}
modifier updatePoints(address account) {
userInfo[account].pendingPoints = pending(account);
userInfo[account].lastUpdate = block.timestamp;
_;
}
The problem I can't figure out:
How do I store when each token is freezed for how long so that I can accurately determine when to reduce points in the pending function.
Do this in a gas efficient way.
I've thought about adding a mapping that holds a timestamp and the amount per day that gets reduced in UserInfo struct but then I would have no way to retrieve this information.
mapping(uint256 => uint256) perDayPointDeductions;
What can I try next?
Maybe something like snapshots or/and a chainlink keeper could be a reliable solution to this problem, and maybe you could check how some staking mechanism works since the problem you are facing is similar staking
I'm not sure if I understand the issue well, but in this case I would store the data offchain e.g. tools https://thegraph.com/en/
Where I would emit events in functions that would just store my data on TheGraph. From there I can then read this data and determine what happens to the tokens and when they will be frozen. (Gas Efficient)
But if you need to do this directly in the contract ( hence avoiding the offchain). I would go for https://docs.chain.link/docs/chainlink-keepers/introduction/

How to call _mint() on erc721 without emit Transfer

I've read here that it is possible to mint 2^256 nfts in a single transaction. I've tried to achieve this by directly assigning _owners and _balances mappings but ofc these are private variables so i can't change them. I tried making an _mint() override but that also didn't work. How does this process work?
For simplification, let's do a 10k NFTs scenario.
It's not about invoking a single mint() function 10k times, rather than building your contract logic in a way that allows setting up a range of valid IDs.
Using the MFS part of IPFS, you can upload multiple files into a folder using the same directory ID and actual file names. Example:
https://ipfs.io/ipfs/<dir_id_abc>/1.json
https://ipfs.io/ipfs/<dir_id_abc>/2.json
https://ipfs.io/ipfs/<dir_id_abc>/3.json
etc...
These metadata files contain links to the images.
Your contract can then implement a custom function that shadows an authorized address as an owner of the NFT if both following conditions are met:
The ID is in a valid range (in our case 1-10k)
The NFT is not owned by anybody else (i.e. it's owned by the default address 0x0)
function _exists(uint256 tokenId) override internal view returns (bool) {
if (tokenId >= 1 && tokenId <= 10000) {
return true;
}
return super._exists(tokenId);
}
function ownerOf(uint256 tokenId) override public view returns (address) {
address owner = _owners[tokenId];
// The ID is in a valid range (in our case 1-10k)
// The NFT is not owned by anybody else (i.e. it's owned by the default address 0x0)
if (tokenId >= 1 && tokenId <= 10000 && owner == address(0x0)) {
// shadows an authorized address as an owner
return address(0x123);
}
return super.ownerOf(tokenId);
}
The tokenURI() function then validates the token existence (using the _exists() function) and returns the final URI concatenated from the base URI (https://ipfs.io/ipfs/<dir_id_abc>/), the ID, and the .json suffix.
Mind that this approach does not work on the OpenZeppelin implementation, as their _owners property is private and not readable from child contracts. But you can take this snippet as an inspiration for a custom implementation that allows simulating an arbitrary default owner of 10k (or even 2^256) tokens.
Tbh I don't know how that could be possible without paying ungodly amounts of gas. Why are you trying to mint that many tokens? Are you trying to get all the NFTs in a collection? If so, you'll have to pay the gas costs for every mint regardless.

I'm creating a smart contract to interact with specific NFTs. Is there a function to filter a specific NFT contract address?

I wanted to create a smart contract that only interacts with a specific NFT. I know there is a "tokenID" attribute I don't think this is unique. Cronoscan shows multiple collections that have the same tokenIDs. Does anyone know if smart contracts can filter based on a contract address? I'd like to accomplish this with as little gas as possible.
Sorry if this is a basic question but I've Googled and searched this message board for the answer but was not able to find on other that someone trying to sell their service.
I Google and search Stack Overflow but could not find an answer.
Yes, each contract will have their own set of ids and therefore they are not unique between contracts only unique for each contract.
This checks if the code size for the address is > 0. This will have to be implemented on a new contract or you will have to find an existing contract with this functionality to view/execute it
function isContract(address addressValue) public view returns (bool) {
uint size;
assembly { size := extcodesize(addressValue) }
return size > 0;
}
Also notice this is a view function and for that reason wont cost any gas to execute.
In regards to someone selling it as a service, you can get it yourself by just deploying this contract on whatever main net you want (by the sounds of it Cronos).
'// SPDX-License-Identifier: MIT
pragma solidity 0.8.7;
contract ContractIdentifier{
function isContract(address addressValue) public view returns (bool) {
uint size;
assembly { size := extcodesize(addressValue) }
return size > 0;
}
}

When to use memory or storage in solidity, a simple example

I still don't really understand the use of memory and storage in solidity. I have written a simple code to store information from books indexed by a key, as in the example below. Since I'm using a mapping, the compiler throws an error if I try to declare books as storage. But he forces me to declare the new book as a memory. Apparently the code works, but I don't understand what is happening behind the scenes. Is the books array a storage-type variable? and what is it referencing to, exactly? Grateful if anyone can explain.
pragma solidity >=0.7.0 <0.9.0;
contract RegisterBook {
struct Book {
string info1;
string info2;
}
mapping(string => Book) public books;
function registerBook(string memory info1, string memory info2, string memory key) public returns (bool success) {
Book memory newBook;
newBook.info1 = info1;
newBook.info2 = info2;
books[key] = newBook;
return true;
}
}
Well, long history short, memory as the name says is just the memory, all the variables declared inside a function and the structs declared as memory are stored there and after every execution the memory is cleaned up, you can think on it like a ram, and the storage is the "permanent storage" you can think of it like a hard drive, all the variables that are declared outside of a function are stored there, the storage values are stored in the storage slots, each one of the storage slots have 32 bytes available, remember that each write on one storage variable cost more than in a memory variable, so try to limit their use if you can