Contract functionA call contract functionB ,and functionA can storage value - function

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.

Related

What is Interface signature in solidity?

I'm going through the source code for the ERC-1155 token standard and I came across this block of code
bytes4 constant private INTERFACE_SIGNATURE_ERC165 = 0x01ffc9a7;
bytes4 constant private INTERFACE_SIGNATURE_ERC1155 = 0xd9b67a26;
function supportsInterface(bytes4 _interfaceID) override external view returns (bool) {
if (_interfaceID == INTERFACE_SIGNATURE_ERC165 ||
_interfaceID == INTERFACE_SIGNATURE_ERC1155) {
return true;
}
return false;
}
I don't quite understand what the benefit of this function is used for.
Also, where do you get the INTERFACE_SIGNATURE constants from?
Could someone please explain?
I believe there is a good explanation for this on openzeppelin docs.
but just to give a short answer, suppose you sent ERC20 tokens to a contract that lacks the ability to transfer it so these tokens are forever locked in the contract. To avoid this kind of things, when you do a safetranser it will first check whether the receiver is capable of receiving it or not and in that case this function is called.
As for INTERFACE_SIGNATURE you can give it a read here.

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

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. :)

Aave aaveLendingPool.withdraw() return value validation

I am writing a pull payment function and, as with any external call it is good practice validate the result and check successful execution. I am using the following interface:
interface IAaveLendingPool {
function deposit(
address asset,
uint256 amount,
address onBehalfOf,
uint16 referralCode
) external;
function withdraw(
address asset,
uint256 amount,
address to
) external;
function getReservesList() external view returns (address[] memory);
}
aAveLendingPool= IAaveLendingPool(0x0543958349aAve_pooladdress)
The interface provided by Aave doesn't specify a return either. The withdraw function of the LendingPool.sol contract returns external override whenNotPaused returns (uint256).
The question: Can I use the returned uint to validate successful execution or aAveLendingPool.withdraw() returns a boolean? Will the following work as expected?
///#notice assigns dai to caller
require( aaveLendingPool.withdraw(
address(dai),
amount,
msg.sender), "Error, contract does not have enough DAI")
Please provide a solidity docs link to external function call return value, if any.
According to the Consensys Diligence Aave V2 audit:
ERC20 implementations are not always consistent. Some implementations of transfer and transferFrom could return ‘false’ on failure instead of reverting. It is safer to wrap such calls into require() statements to these failures.
Therefore, wrapping the transfer call in a require check is safe and sufficient.
require( aaveLendingPool.withdraw(
address(dai),
amount,
msg.sender), "Error, contract does not have enough DAI")

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;
}
}

Linking together smart contracts at deployment

I'm building an application that is comprised of 3 smart contracts. The aim is to have the controller control the other two (contract A and B in the image). Previously, if I wanted to restrict the access to a smart contact, I would do it through a modifier
Example:
modifier onlyController {
require(msg.sender == controller);
_;
}
At contact creation, the smart contract would set controller to be equal to whatever ethereum address I want to make these calls ( for example the address that deployed the smart contract). The issue is that now I want the address of the controller smart contract to be the controller (in the modifier). How would it be best to do this considering I want to deploy these set of smart contacts at the same time using truffle. What would be the best way to link these, so that the controller smart contract is only able to make calls to A and B. Moreover, how does the controller have to be implemented so that the user can call function in A and B going through the controller ( so the user calls a function in the controller, then the controller calls the corresponding function in A or B)?
I am no expert in Solidity. But trying to answer as I find it little bit interesting.
You seem to be trying to implement a proxy pattern which is very common in other programming languages like java in such a way that you are providing very restricted access to certain classes in this case contracts.
In Proxy design pattern both the proxy and the class to be restricted would be implementing the same interface! I do not know much about your smart contract details.
Assuming Contract A and B implementing the same interface:
Lets assume the interface is Base.
interface Base{
function getValue() external view returns (string);
}
I need to provide controlled access to the ContractA and ContractB so only the controller could call. So lets create a modifier.
contract ControlledAccess{
address controller;
constructor() public {
controller = msg.sender;
}
modifier onlyController() {
require(msg.sender == controller);
_;
}
}
Now ContractA and ContractB should implement interface Base and inherit ControlledAccess contract.
contract ContractA is Base, ControlledAccess{
function getValue() public view onlyController returns (string){
return "Hi";
}
}
contract ContractB is Base, ControlledAccess{
function getValue() public view onlyController returns (string){
return "Hello";
}
}
In order to set the controller address to be the ProxyController address, ProxyController itself should create these contracts in its constructor. As our ProxyController contract should be able to control more than 1 contract, I think mapping might be a good choice.
contract ProxyController is Base{
string public contractKey = "a";
mapping(string => Base) base;
constructor() public {
base["a"]=new ContractA();
base["b"]=new ContractB();
}
function setContractKey(string _contractKey) public{
contractKey = _contractKey;
}
function getValue() public view returns (string){
return base[contractKey].getValue();
}
}
so you can switch to A & B via setContractKey.
Assuming there is no common functionalities between A and B :
Remove the interface in the above example.Then implement something like this.
contract ProxyController{
ContractA a;
ContractB b;
constructor() public {
a=new ContractA();
b=new ContractB();
}
function AgetValue() public view returns (string){
return a.getValue();
}
function BgetValue() public view returns (string){
return b.getValue();
}
}
I tested this and it seems to be working fine. However I am not sure of other issues like performance etc.
Can't you easily set up the controller contract as
contract ControllerContract is ContractA, ContractB {
...
}
Thus giving it access to the functions in both contract A and contract B?
I'm not sure why this way would be worse than how you are describing.
You can find some solutions at the following links:
1.) https://ethereum.stackexchange.com/questions/36524/multiple-smart-contracts
2.) https://ethereum.stackexchange.com/questions/37055/where-how-to-host-several-connected-smart-contracts
A complete article on Interactions between Smart Contracts with Solidity:
https://zupzup.org/smart-contract-interaction/
A link to another article and a sample project: https://hackernoon.com/ethereum-smart-contracts-lifecycle-multiple-contracts-message-sender-e9195ceff3ec
Hope it solves your problem. Also, you can join this community for exclusivity: https://ethereum.stackexchange.com/