Nesse artigo iremos aprender a como criar um contrato inteligente para realizar multichamada de funções.
Multichamada de funções
Um exemplo de contrato que agrega várias consultas usando um loop for
e staticcall
.
// SPDX-License-Identifier: MITpragma solidity ^0.8.13;contract MultiCall {function multiCall(address[] calldata targets, bytes[] calldata data)externalviewreturns (bytes[] memory){require(targets.length == data.length, "comprimento de destino != comprimento de dados");bytes[] memory results = new bytes[](data.length);for (uint i; i < targets.length; i++) {(bool success, bytes memory result) = targets[i].staticcall(data[i]);require(success, "falha na chamada");results[i] = result;}return results;}}
Contrato para testar MultiCall
// SPDX-License-Identifier: MITpragma solidity ^0.8.13;contract TestMultiCall {function test(uint _i) external pure returns (uint) {return _i;}function getData(uint _i) external pure returns (bytes memory) {return abi.encodeWithSelector(this.test.selector, _i);}}
Multichamada de funções
Um exemplo de chamada de várias funções com uma única transação, usando delegatecall
.
// SPDX-License-Identifier: MITpragma solidity ^0.8.13;contract MultiDelegatecall {error DelegatecallFailed();function multiDelegatecall(bytes[] memory data)externalpayablereturns (bytes[] memory results){results = new bytes[](data.length);for (uint i; i < data.length; i++) {(bool ok, bytes memory res) = address(this).delegatecall(data[i]);if (!ok) {revert DelegatecallFailed();}results[i] = res;}}}// Por que usar multi delegatecall? Por que não multi-chamada?// alice -> multi call --- call ---> test (msg.sender = multi call)// alice -> teste --- delegatecall ---> test (msg.sender = alice)contract TestMultiDelegatecall is MultiDelegatecall {event Log(address caller, string func, uint i);function func1(uint x, uint y) external {// msg.sender = aliceemit Log(msg.sender, "func1", x + y);}function func2() external returns (uint) {// msg.sender = aliceemit Log(msg.sender, "func2", 2);return 111;}mapping(address => uint) public balanceOf;// AVISO: código inseguro quando usado em combinação com multi-delegatecall// o usuário pode cunhar várias vezes pelo preço de msg.valuefunction mint() external payable {balanceOf[msg.sender] += msg.value;}}contract Helper {function getFunc1Data(uint x, uint y) external pure returns (bytes memory) {return abi.encodeWithSelector(TestMultiDelegatecall.func1.selector, x, y);}function getFunc2Data() external pure returns (bytes memory) {return abi.encodeWithSelector(TestMultiDelegatecall.func2.selector);}function getMintData() external pure returns (bytes memory) {return abi.encodeWithSelector(TestMultiDelegatecall.mint.selector);}}