cryptozombies LESSON 1 CHAPTER 13. can not understand the events in cryptozombies - ethereum

I am learning solidity in cryptozombies. I just finished 12 chapters with the good understanding. but, I don't understand the events concept. I want to understand the full code. can somebody help me with that??
pragma solidity >=0.5.0 <0.6.0;
contract ZombieFactory {
event NewZombie(uint zombieId, string name, uint dna);
uint dnaDigits = 16;
uint dnaModulus = 10 ** dnaDigits;
struct Zombie {
string name;
uint dna;
}
Zombie[] public zombies;
function _createZombie(string memory _name, uint _dna) private {
uint id = zombies.push(Zombie(_name, _dna)) - 1;
emit NewZombie(id, _name, _dna);
}
function _generateRandomDna(string memory _str) private view returns (uint) {
uint rand = uint(keccak256(abi.encodePacked(_str)));
return rand % dnaModulus;
}
function createRandomZombie(string memory _name) public {
uint randDna = _generateRandomDna(_name);
_createZombie(_name, randDna);
}
}

The function of the event is that when the caller invokes this function, an additional logs will be added to the transaction content.
For a common example of ERC20 tokens, if the contract creator didn't add the event function when writing the Transfer function, something interesting would happen, the blockchain browser would not display the number of Hodlers properly and it would not show the detailed transaction history of the user-user transfer of ERC20 tokens.
Let's conclude that adding the event function will make it easier for the searcher on the blockchain browser to understand or analyze each transaction, but it will also make it easier for the searcher on the blockchain to find transactions or filter them for some arbitrage :)

Think of Events as the code piece that you put in a place where you want to be notified instantly if something happens there.
contract test{
function Alert() public returns (string memory) {
string memory str = "Alert! Do Something.";
return str;
}
}
for example in this code here you would want to be notified on your end-user screen so in order to that you would want your front-end to be able to get this info! right? and how would you go about doing that? by creating an event with which your front-end can interact with (particularly read from). Therefore you would modify the above code to add event to this as follows:
contract test{
event readAlert(string str);
function Alert() public returns (string memory) {
string memory str = "Alert! Do Something.";
return str;
emit readAlert(str);
}
}
After doing this you can now use the event you just created to do something with the info passed to it on you app front-end.
Let me know if you need further explanation. :)

Related

How to retrieve data from a SmartContract that is not listed in their ABI

I'm trying to retrieve the total supply of an ERC1155 SmartContract. This code was made by my friend and has been deployed. He took the code from OpenZeppelin with Burnable and Pausable presets.
The function totalSupply that I am trying to retrieve exists in the code. But, when I see the ABI, the totalSupply does not included.
(Sorry for small screenshot. Please see this screenshot in the new tab)
MyErc1155Contract compiled
This is where to get the ABI
Full code is here: click_this_to_go_to_pastebin
Then I am trying to write smartcontract to retrieve the totalSupply;
pragma solidity ^0.8.0;
contract TotSup {
uint256 public hasilBal;
uint256 public hasil;
function balanceOf(address erc1155_address,
address user_address,
uint256 nft_id) public {
(bool successA, bytes memory resultA) =
erc1155_address.call(abi.encodeWithSignature(
"balanceOf(address,uint256)",
user_address,
nft_id
));
hasil = abi.decode(resultA, (uint256));
}
function bal(address erc1155_address, uint256 nft_id) public {
(bool successA, bytes memory resultA) =
erc1155_address.call(
abi.encodeWithSignature("totalSupply(uint256)", nft_id
));
hasilBal = abi.decode(resultA, (uint256));
}
}
I test my idea with writing another function balanceOf and it works perfectly.
And for the totalSupply in function bal is fail.
Is it possible to retrieve or calling function which is not included in the ABI? If yes, how to achieve that? And last, why call balanceOf still need for paying gas for just retrieving the data?
When a function exists in the code when you compile the code it reflects in the ABI, Without the function signature, you can't call the function.
As for your second answer, balanceOf in TotSup will cost you gas as it is not a view function.

Check if msg.sender is a specific type of contract

As it is now, anyone can call the setMyString function in the FirstContract. I'm trying to restrict access to that function to an instance of SecondContract. But not one specific instance, any contract of type SecondContract should be able to call setMyString.
contract FirstContract{
String public myString;
function setMyString(String memory what) public {
myString=what;
}
}
contract SecondContract{
address owner;
address firstAddress;
FirstContract firstContract;
constructor(address _1st){
owner=msg.sender;
firstAddress=_1st;
firstContract=FirstContract(firstAddress);
}
function callFirst(String memory what){
require(msg.sender==owner);
firstContract.setMyString("hello");
}
}
Solidity currently doesn't have an easy way to validate an address against an interface.
You can check the bytecode, whether it contains the specified signatures (of the public properties and methods). This requires a bit larger scope than a usual StackOverflow answer, so I'm just going to describe the steps instead of writing the code.
First, define the desired list of signatures (1st 4 bytes of keccak256 hash of the name and arguments datatypes) that you're going to be looking for. You can find more info about signatures in my other answers here and here.
An example in the documentation shows how to get any address's (in your case msg.sender) bytecode as bytes (dynamic-length array).
You'll then need to loop through the returned bytes array and search for the 4-byte signatures.
If you find them all, it means that msg.sender "implements the interface". If any of the signatures is missing in the external contract, it means it doesn't implement the interface.
But... I'd really recommend you to rethink your approach to whitelisting. Yes, you'll need to maintain the list and call setIsSecondContract() when a new SecondContract wants to call the setMyString() function for the first time. But it's more gas efficient for all callers of the FirstContract's setMyString() function, as well as easier to write and test the functionality in the first place.
contract FirstContract{
String public myString;
address owner;
mapping (address => bool) isSecondContract;
modifier onlySecondContract {
require(isSecondContract[msg.sender]);
_;
}
modifier onlyOwner {
require(msg.sender == owner);
_;
}
function setIsSecondContract(address _address, bool _value) public onlyOwner {
isSecondContract[_address] = _value;
}
function setMyString(String memory what) public onlySecondContract {
myString=what;
}
}

Contract functionA call contract functionB ,and functionA can storage value

I have a problem about handle function value.
likes the title ..
I already know contract's function call other contract's function depend on:
addr.call(abi.encodeWithSignature("function(parameter_type)", parameter ));
but what if I want to handle the function's value(ex:bool) temporarily (memory) for condition .
I had seen abi.encodePacked() , but I don't even know what parameter feedback to me (compile error , different parameter type), that I can't even storage it .
Some articles write it only for bytes, uint , but I only want to do condition(bool).
You don't need to do that .call unless you want to preserve the msg.sender.
If the msg.sender does not matter for you, I recommend you to look at interfaces. Now, what you have to do, is to create an interface with the functionB definition of that you want to call, and then call it.
Example:
(some deployed contract)
contract MySecondContract {
function functionB() public returns(bool) {
return true;
}
}
(get the deployed contract address and use it in your code like)
interface IMySecondContract {
function functionB() external returns(bool);
}
contract MyFirstContract {
function functionA() public returns(bool) {
bool result = IMySecondContract(MySecondContract-address-here).functionB();
return result;
}
}
If you do want to keep using .call, here you can see that the .call method returns two values.
Something like
(bool success, bytes myReturn) = addr.call(...);
and then this, might work.
Something else that might help is this new way of debugging.

Ethereum Transaction Error while calling a contract function from another contract

Following smart contract works fine in Remix and Ganache. However doesn't work on private ethereum blockchains like Kaleido or Azure. What am I missing. When I call setA it consumes all gas and then fails.
pragma solidity ^0.4.24;
contract TestA {
uint public someValue;
function setValue(uint a) public returns (bool){
someValue = a;
return true;
}
}
contract TestB {
address public recentA;
function createA() public returns (address) {
recentA = new TestA();
return recentA;
}
function setA() public returns (bool) {
TestA(recentA).setValue(6);
return true;
}
}
I tried your contract in Kaleido, and found even calling eth_estimateGas with very large numbers was resulting in "out of gas".
I changed the setValue cross-contract call to set a gas value, and I was then able to call setA, and estimating the gas for setA showed just 31663.
recentA.setValue.gas(10000)(6);
I suspect this EVM behavior is related to permissioned chains with a gasprice of zero. However, that is speculation as I haven't investigated the internals.
I've also added eth_estimateGas, and support for multiple contracts in a Solidity file, to kaleido-go here in case it's helpful:
https://github.com/kaleido-io/kaleido-go
Another possibility for others encountering "out of gas" calling across contracts - In Geth if a require call fails in a called contract, the error is reported as "out of gas" (rather than "execution reverted", or a detailed reason for the require failing).
You are hitting the limit of gas allowed to be spent per block. Information about gas limit is included into every block, so you can check what's this value is right now in your blockchain. Currently on Ethereum MainNet, GasLimit (per block) is about 8 millions (see here https://etherscan.io/blocks)
To fix this, you can start your blockchain with modified genesis file. Try to increase value of gasLimit parameter in your genesis file, which specifies the maximum amount of gas processed per block. Try "gasLimit": "8000000".
Try to discard the return statement of setValue method in contract TestA.
pragma solidity ^0.4.24;
contract TestA {
uint public someValue;
function setValue(uint a) public {
someValue = a;
}
}

Initialize a big fixed length array in Solidity

I'm building a game on ethereum as my first project and I'm facing with the storage and gas limits. I would like to store a storage smart contract on the blockchain to be queried after the deployment. I really need to initialize a fixed length array with constant values I insert manually. My situation is the following:
contract A {
...some states variables/modifiers and events......
uint[] public vector = new uint[](162);
vector = [.......1, 2, 3,......];
function A () {
....some code....
ContractB contract = new ContractB(vector);
}
....functions....
}
This code doesn't deploy. Apparently I exceed gas limits on remix. I tried the following:
I split the vector in 10 different vectors and then pass just one of them to the constructor. With this the deploy works.
I really need to have just one single vector because it represents the edges set of a graph where ContractB is the data structure to build a graph. Vectors elements are ordered like this:
vector = [edge1From, edge1To, edge2From, edge2To,.......]
and I got 81 edges (162 entries in the vector).
I tought I can create a setData function that push the values in the vector one by one calling this function after the deployment but this is not my case because I need to have the vector filled before the call
ContractB contract = new ContractB(vector);
Now I can see I have two doubts:
1) Am I wrong trying to pass a vector as parameter in a function call inside the A constructor ?
2) I can see that I can create a double mapping for the edges. Something like
mapping (bool => mapping(uint => uint))
but then I will need multi-key valued mappings (more edges starting from the same point) and I will have the problem to initialize all the mappings at once like I do with the vector?
Why does the contract need to be initialized at construction time?
This should work
pragma solidity ^0.4.2;
contract Graph {
address owner;
struct GraphEdge {
uint128 from;
uint128 to;
}
GraphEdge[] public graph;
bool public initialized = false;
constructor() public {
owner = msg.sender;
}
function addEdge(uint128 edgeFrom, uint128 edgeTo) public {
require(!initialized);
graph.push(GraphEdge({
from: edgeFrom,
to: edgeTo
}));
}
function finalize() public {
require(msg.sender == owner);
initialized = true;
}
}
contract ContractB {
Graph graph;
constructor(address graphAddress) public {
Graph _graph = Graph(graphAddress);
require(_graph.initialized());
graph = _graph;
}
}
If the range of values for you array are small enough, you can save on gas consumption by using a more appropriate size for your uints. Ethereum stores values into 32-bytes slots and you pay 20,000 gas for every slot used. If you are able to use a smaller sized uint (remember, uint is the same as uint256), you'll be able to save on gas usage.
For example, consider the following contract:
pragma solidity ^0.4.19;
contract Test {
uint256[100] big;
uint128[100] small;
function addBig(uint8 index, uint256 num) public {
big[index] = num;
}
function addSmall(uint8 index, uint128 num1, uint128 num2) public {
small[index] = num1;
small[index + 1] = num2;
}
}
Calling addBig() each time with a previously unused index will have an execution cost of a little over 20,000 gas and results in one value being added to an array. Calling addSmall() each time will cost about 26,000, but you're adding 2 elements to the array. Both only use 1 slot of storage. You can get even better results if you can go smaller than uint128.
Another option (depending on if you need to manipulate the array data) is to store your vector off chain. You can use an oracle to retrieve data or store your data in IPFS.
If neither of those options work for your use case, then you'll have to change your data structure and/or use multiple transactions to initialize your array.