Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[audit] #8: _isContract optimization #53

Merged
merged 2 commits into from
Jun 26, 2024
Merged

[audit] #8: _isContract optimization #53

merged 2 commits into from
Jun 26, 2024

Conversation

stevieraykatz
Copy link
Collaborator

@stevieraykatz stevieraykatz commented Jun 25, 2024

This PR removes the assembly method _isContract and instead just uses address.code.legnth. The ~40 gas saved by the assembly does not justify the readability hit.

From Spearbit:
Description
One can avoid extra operations by using a named return variable.

Recommendation
Use a named return variable and let the compiler solc take care of the conversion to bool:

function _isContract(address addr) internal view returns (bool result) {
    assembly {
        result := extcodesize(addr)
    }
}

function _isContract(address addr) internal view returns (bool) {
uint32 size;
/// @return result `true` if `extcodesize` > 0, else `false`.
function _isContract(address addr) internal view returns (bool result) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the context on this check? a contract could later be deployed to this address?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If a user wants to set the reverse resolver name for a contract that they own, they can call this as the owner instead of needing to add reverse claiming logic to their contract logic.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't this check superfluous? The owner() call / check will fail if its an EOA?
image

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This reverts with a generic EVMError which isn't caught by the Try statement. Trace from a targeted test case:

[12293] TryTest::test_noCheck_noOwner()
    ├─ [0] VM::addr(<pk>) [staticcall]
    │   └─ ← [Return] noOwner: [0x28179DE316fe4178155beB9FdE329eE3ddA9C8D8]
    ├─ [0] VM::label(noOwner: [0x28179DE316fe4178155beB9FdE329eE3ddA9C8D8], "noOwner")
    │   └─ ← [Return] 
    ├─ [3101] Try::ownsContractNoCheck(noOwner: [0x28179DE316fe4178155beB9FdE329eE3ddA9C8D8]) [staticcall]
    │   ├─ [0] noOwner::owner() [staticcall]
    │   │   └─ ← [Stop] 
    │   └─ ← [Revert] EvmError: Revert
    └─ ← [Revert] EvmError: Revert

[PASS] test_withCheck_noOwner() (gas: 12733)
Traces:
  [12733] TryTest::test_withCheck_noOwner()
    ├─ [0] VM::addr(<pk>) [staticcall]
    │   └─ ← [Return] noOwner: [0x28179DE316fe4178155beB9FdE329eE3ddA9C8D8]
    ├─ [0] VM::label(noOwner: [0x28179DE316fe4178155beB9FdE329eE3ddA9C8D8], "noOwner")
    │   └─ ← [Return] 
    ├─ [2985] Try::ownsContractWithCheck(noOwner: [0x28179DE316fe4178155beB9FdE329eE3ddA9C8D8]) [staticcall]
    │   └─ ← [Return] false
    ├─ [0] VM::assertFalse(false) [staticcall]
    │   └─ ← [Return] 
    └─ ← [Stop] 

@stevieraykatz stevieraykatz merged commit fbad20c into main Jun 26, 2024
3 checks passed
@stevieraykatz stevieraykatz deleted the cantina#8 branch June 26, 2024 17:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants