-
Notifications
You must be signed in to change notification settings - Fork 6.2k
Open
Labels
high effortA lot to implement but still doable by a single person. The task is large or difficult.A lot to implement but still doable by a single person. The task is large or difficult.high impactChanges are very prominent and affect users or the project in a major way.Changes are very prominent and affect users or the project in a major way.language design
Any changes to the language, e.g. new featuresAny changes to the language, e.g. new featuresmust haveSomething we consider an essential part of Solidity 1.0.Something we consider an essential part of Solidity 1.0.needs designThe proposal is too vague to be implemented right awayThe proposal is too vague to be implemented right away

Description
How can we call an external code, and reliably catch errors?
Consider the following code, which tries to create "safeBalance
" method, which calls balanceOf and never reverts.
(spoiler: try/catch
doesn't catch a lot of cases)
- It returns a proper balance of an external token
- It properly catches revert in the external balanceOf method
But....
- it crashes if calling non-existent address (e.g.
address(0)
) - it crashes if the target contract doesn't have that method.
- it crashes if the target contract returns wrong number of arguments.
So basically, we can't rely on try/catch ...
The only alternative is to resort to low-level call (address.call()
) and manually parse the result - in realSafeBalance()
This solution is error-prone, type-unsafe and more expensive in its gas usage.
pragma solidity ^0.8.17;
//SPDX-License-Identifier: MIT
interface IERC20 {
function balanceOf(address) external returns (uint);
}
contract ATestSafeBalance {
event Debug(uint bal);
constructor () {
IERC20 a;
// a = IERC20(address(this));
// a = IERC20(address(0));
// a = new Token();
// a = new RevertToken();
a = IERC20(address(new NoReturnValue()));
uint bal = pseudoSafeBalance(a,address(this));
emit Debug(bal);
}
function pseudoSafeBalance(IERC20 token, address addr) public returns (uint) {
try token.balanceOf(addr) returns (uint ret) {
return ret;
}
catch {
return 11111;
}
}
function realSafeBalance(IERC20 token, address addr) public returns (uint retBalance) {
(bool success, bytes memory ret) = address(token).call(abi.encodeCall(IERC20.balanceOf, addr));
if (!success || ret.length != 32) return 11111;
(retBalance) = abi.decode(ret, (uint));
}
}
contract NoReturnValue {
function balanceOf(address) external {
}
}
contract RevertToken is IERC20 {
function balanceOf(address) external override returns (uint) {
revert("just because");
}
}
contract Token is IERC20 {
function balanceOf(address) external override returns (uint) {
return 1;
}
}
asami0
Metadata
Metadata
Assignees
Labels
high effortA lot to implement but still doable by a single person. The task is large or difficult.A lot to implement but still doable by a single person. The task is large or difficult.high impactChanges are very prominent and affect users or the project in a major way.Changes are very prominent and affect users or the project in a major way.language design
Any changes to the language, e.g. new featuresAny changes to the language, e.g. new featuresmust haveSomething we consider an essential part of Solidity 1.0.Something we consider an essential part of Solidity 1.0.needs designThe proposal is too vague to be implemented right awayThe proposal is too vague to be implemented right away
