18 Haziran 2021 Cuma

Calling the Function of Another Contract in Solidity

 When we write Smart Contracts, we can write it in such a way that they can interact with existing deployed contracts. This feature is very powerful as it allows code reusability, ie treating deployed contracts like libraries. There has been a lot of effort done in this space but is still controversial at the time of writing. For example what would happen if the reused contracts are faulty (just like what happened to parity multi-sig wallet hack)?

In this article, I am not debating about the immutability of deployed contracts or whether we should or should not interact with deployed contracts. Instead, I will be focusing on the different techniques to call functions of deployed contracts. I can see some use cases for it and I’ll leave it up to the readers to implement what they believe in.

Let’s say we have deployed a very simple contract called “Deployed” that allows user to set a variable.

and we want to deploy another contract later called “Existing” to change the variable of “a” in the “Deployed” contract.

We do not need the full implementation of the “Deployed” contract, but rather just the function signatures as required by the ABI. Since we have the address of the “Deployed” contract, we could initialised the “Existing” contract with the address and interact with the “Deployed” contract using the existing setA and getA functions accordingly.

This is easy and actually the recommended way to interact with deployed contracts. However, what if we don’t have the ABI of the deployed contract? We can still call the “setA” function of the deployed contract.

Function signatures are 4 bytes long and the formula to generate it is to hash it with the keccak256 function, like so:

We could pass a value to setA inside the call method. However, since the call (as well as delegatecall) method simply passes value over to the contract address and will not get any returned value, it doesn’t know if setA has done its job correctly or not unless we check out the state of the “Delegate” contract.

What if we want to get the returned value from setA? Unfortunately, there is no way to do that unless we use solidity’s assembly code. Are you ready?

Solidity’s assembly code starts with the “assembly” keyword and wrapped in {}. I hope my comments in the code is clear. To get the returned value of setA without ABI, we have to understand how memory works in the EVM. Free memory is available at the 64th Byte (0x40), so we first move our memory pointer there. Then, we append the hexadecimals of the function signature and its argument sequentially at that spot. The function signature is 4 Bytes (0x04) and the argument is 32 Bytes (0x20), so we have 36 Bytes in total (0x24).

Once done, we do the magic “call” which stores the result back in the 64th Byte spot and returns a boolean, ie 1 or 0. The transaction will revert if call fails (returns a 0). Assuming everything is successful, we return the value at the 64th Byte spot, which is the answer we want.

Try the code in remix and see for yourself.

Happy coding.

Hiç yorum yok:

Yorum Gönder