Coinbase Smart Wallet - dharma09's results

Smart Wallet from Coinbase Wallet

General Information

Platform: Code4rena

Start Date: 14/03/2024

Pot Size: $49,000 USDC

Total HM: 3

Participants: 51

Period: 7 days

Judge: 3docSec

Id: 350

League: ETH

Coinbase

Findings Distribution

Researcher Performance

Rank: 46/51

Findings: 1

Award: $13.69

🌟 Selected for report: 0

🚀 Solo Findings: 0

Findings Information

🌟 Selected for report: K42

Also found by: 0x11singh99, 0xAnah, Hajime, SAQ, SM3_SS, albahaca, clara, dharma09, hunter_w3b, naman1778, shamsulhaq123, slvDev

Labels

bug
G (Gas Optimization)
grade-b
sufficient quality report
G-10

Awards

13.6948 USDC - $13.69

External Links

SMART WALLET GAS OPTIMIZATION

Note: The issues addressed here were not reported by the bot, for packing variables, notes explaining the how and why are included

[G-01] Pack structs by reducing variable sizes to save storage slots (saves 2 SLOTS: 4.2k Gas)

Note: The bot report did not cover these instances.

Details

We can replaced string clientDataJSON with bytes32 clientDataJSONHash. Storing the hash instead of the full string can significantly reduce gas costs if the string is relatively large.

For challengeTndex and typeIndex we can reduce data types size which is easily acoomodate large number and we can also reduce size of r,s to store in slot.By doing this we can save 2 slot.

Proof of Code

File: src/WebAuthnSol/WebAuthn.sol
21:  struct WebAuthnAuth {
        /// @dev The WebAuthn authenticator data.
        ///      See https://www.w3.org/TR/webauthn-2/#dom-authenticatorassertionresponse-authenticatordata.
        bytes authenticatorData;
        /// @dev The WebAuthn client data JSON.
        ///      See https://www.w3.org/TR/webauthn-2/#dom-authenticatorresponse-clientdatajson.
        string clientDataJSON;
        /// @dev The index at which "challenge":"..." occurs in `clientDataJSON`.
        uint256 challengeIndex;
        /// @dev The index at which "type":"..." occurs in `clientDataJSON`.
        uint256 typeIndex;
        /// @dev The r value of secp256r1 signature
        uint256 r;
        /// @dev The s value of secp256r1 signature
        uint256 s;
    }

Optimized code:

diff --git a/src/WebAuthnSol/WebAuthn.sol b/src/WebAuthnSol/WebAuthn.sol
index a0b29e5..3887265 100644
--- a/src/WebAuthnSol/WebAuthn.sol
+++ b/src/WebAuthnSol/WebAuthn.sol
@@ -24,15 +24,15 @@ library WebAuthn {
         bytes authenticatorData;
         /// @dev The WebAuthn client data JSON.
         ///      See https://www.w3.org/TR/webauthn-2/#dom-authenticatorresponse-clientdatajson.
-        string clientDataJSON;
+        bytes32 clientDataJSON;
         /// @dev The index at which "challenge":"..." occurs in `clientDataJSON`.
-        uint256 challengeIndex;
+        uint128 challengeIndex;
         /// @dev The index at which "type":"..." occurs in `clientDataJSON`.
-        uint256 typeIndex;
+        uint128 typeIndex;
         /// @dev The r value of secp256r1 signature
-        uint256 r;
+        uint128 r;
         /// @dev The s value of secp256r1 signature
-        uint256 s;
+        uint128 s;
     }

[G-02] State variables can be packed into fewer storage slot (saves 1 SLOTS: 2.1k Gas)

Note: The bot report did not cover these instances.

Pack the following by reducing their size (saves 2.1k Gas)

Proof of Code

File: src/WebAuthnSol/WebAuthn.sol
40: bytes1 private constant AUTH_DATA_FLAGS_UP = 0x01;

    /// @dev Bit 2 of the authenticator data struct, corresponding to the "User Verified" bit.
    ///      See https://www.w3.org/TR/webauthn-2/#flags.
    bytes1 private constant AUTH_DATA_FLAGS_UV = 0x04;

Optimized code:

diff --git a/src/WebAuthnSol/WebAuthn.sol b/src/WebAuthnSol/WebAuthn.sol
index a0b29e5..22860c6 100644
--- a/src/WebAuthnSol/WebAuthn.sol
+++ b/src/WebAuthnSol/WebAuthn.sol
@@ -43,13 +43,13 @@ library WebAuthn {
     ///      See https://www.w3.org/TR/webauthn-2/#flags.
     bytes1 private constant AUTH_DATA_FLAGS_UV = 0x04;
 
-    /// @dev Secp256r1 curve order / 2 used as guard to prevent signature malleabi
lity issue.
-    uint256 private constant P256_N_DIV_2 = FCL.n / 2;
-
     /// @dev The precompiled contract address to use for signature verification in
 the “secp256r1” elliptic curve.
     ///      See https://github.com/ethereum/RIPs/blob/master/RIPS/rip-7212.md.
     address private constant VERIFIER = address(0x100);
 
+    /// @dev Secp256r1 curve order / 2 used as guard to prevent signature malleabi
lity issue.
+    uint256 private constant P256_N_DIV_2 = FCL.n / 2;
+
     /// @dev The expected type (hash) in the client data JSON when verifying asser
tion signatures.
     ///      See https://www.w3.org/TR/webauthn-2/#dom-collectedclientdata-type
     bytes32 private constant EXPECTED_TYPE_HASH = keccak256('"type":"webauthn.get"
');

[G-03] Cache calculations in loop to avoid re-calculating on each iteration

Details

In CoinbaseSmartWallet.sol:executeBatch() : calls[i] we can cache once and use multiple times. Instead of repeatedly calling calls[i] in the loop, we can calculate it once and use the result.

Proof of Code

File: src/SmartWallet/CoinbaseSmartWallet.sol
205:  function executeBatch(Call[] calldata calls) public payable virtual onlyEntryPointOrOwner {
        for (uint256 i; i < calls.length;) {
            _call(calls[i].target, calls[i].value, calls[i].data); //@audit cache calls[i]
            unchecked {
                ++i;
            }
        }
    }

Optimized code:

diff --git a/src/SmartWallet/CoinbaseSmartWallet.sol b/src/SmartWallet/CoinbaseSmartWallet.sol
index 2278a5a..1d09e54 100644
--- a/src/SmartWallet/CoinbaseSmartWallet.sol
+++ b/src/SmartWallet/CoinbaseSmartWallet.sol
@@ -204,7 +204,8 @@ contract CoinbaseSmartWallet is MultiOwnable, UUPSUpgradeable, Receiver, ERC1271
     /// @param calls The list of `Call`s to execute.
     function executeBatch(Call[] calldata calls) public payable virtual onlyEntryPointOrOwner {
         for (uint256 i; i < calls.length;) {
-            _call(calls[i].target, calls[i].value, calls[i].data);
+            uint256 _calls = calls[i];
+            _call(_calls.target, _calls.value, _calls.data);
             unchecked {
                 ++i;
             }

Instances 2

In MultiOwnable.sol:_initializeOwners() : owners.length[i] we can cache once and use multiple times. Instead of repeatedly calling owners.length[i] in the loop, we can calculate it once and use the result.

Proof of Code

File: src/SmartWallet/MultiOwnable.sol
162: function _initializeOwners(bytes[] memory owners) internal virtual {
        for (uint256 i; i < owners.length; i++) {
            if (owners[i].length != 32 && owners[i].length != 64) {
                revert InvalidOwnerBytesLength(owners[i]); //@audit
            }

            if (owners[i].length == 32 && uint256(bytes32(owners[i])) > type(uint160).max) {
                revert InvalidEthereumAddressOwner(owners[i]);
            }

            _addOwnerAtIndex(owners[i], _getMultiOwnableStorage().nextOwnerIndex++);
        }
    }

Optimized code:

diff --git a/src/SmartWallet/MultiOwnable.sol b/src/SmartWallet/MultiOwnable.sol
index 64fd19a..9a46f34 100644
--- a/src/SmartWallet/MultiOwnable.sol
+++ b/src/SmartWallet/MultiOwnable.sol
@@ -161,11 +161,12 @@ contract MultiOwnable {
     /// @param owners The intiial list of owners to register.
     function _initializeOwners(bytes[] memory owners) internal virtual {
         for (uint256 i; i < owners.length; i++) {
-            if (owners[i].length != 32 && owners[i].length != 64) {
+            uint256 owners_ = owners.length;
+            if (owners_ != 32 && owners_ != 64) {
                 revert InvalidOwnerBytesLength(owners[i]);
             }
 
-            if (owners[i].length == 32 && uint256(bytes32(own
ers[i])) > type(uint160).max) {
+            if (owners_ == 32 && uint256(bytes32(owners[i])) 
> type(uint160).max) {
                 revert InvalidEthereumAddressOwner(owners[i])
;
             }

#0 - raymondfam

2024-03-22T21:45:59Z

3 well elaborate G.

#1 - c4-pre-sort

2024-03-22T21:46:03Z

raymondfam marked the issue as sufficient quality report

#2 - c4-judge

2024-03-27T13:17:46Z

3docSec marked the issue as grade-b

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax © 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter