Bird
Raised Fist0
Blockchain / Solidityprogramming~20 mins

Diamond pattern (EIP-2535) in Blockchain / Solidity - Practice Problems & Coding Challenges

Choose your learning style10 modes available

Start learning this pattern below

Jump into concepts and practice - no test required

or
Recommended
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
Challenge - 5 Problems
🎖️
Diamond Mastery
Get all challenges correct to earn this badge!
Test your skills under time pressure!
Predict Output
intermediate
2:00remaining
Output of Diamond Storage Access
Consider a Diamond contract using EIP-2535. Given the following Solidity snippet, what will be the output of the function getValue() when called after deployment?

contract DiamondStorage {
    struct DS {
        uint256 value;
    }
    bytes32 constant DIAMOND_STORAGE_POSITION = keccak256("diamond.storage.example");

    function diamondStorage() internal pure returns (DS storage ds) {
        bytes32 position = DIAMOND_STORAGE_POSITION;
        assembly {
            ds.slot := position
        }
    }

    function setValue(uint256 _value) external {
        DS storage ds = diamondStorage();
        ds.value = _value;
    }

    function getValue() external view returns (uint256) {
        DS storage ds = diamondStorage();
        return ds.value;
    }
}
Blockchain / Solidity
DiamondStorage ds = new DiamondStorage();
ds.setValue(42);
uint256 result = ds.getValue();
A42
B0
CCompilation error
DRevert error at runtime
Attempts:
2 left
💡 Hint
Think about how the diamond storage pattern uses a fixed storage slot to keep data consistent across facets.
🧠 Conceptual
intermediate
1:30remaining
Facet Function Selector Collision
In the Diamond pattern (EIP-2535), what happens if two facets added to the diamond have functions with the same selector?

Choose the correct behavior:
AThe diamond automatically merges the two functions into one.
BThe diamond will revert on deployment due to selector collision.
CBoth functions coexist and can be called by their selectors without conflict.
DThe last added facet's function selector overwrites the previous one in the diamond's selector mapping.
Attempts:
2 left
💡 Hint
Think about how the diamond manages function selectors in its mapping.
🔧 Debug
advanced
2:30remaining
Debugging Diamond Cut Failure
You try to add a new facet to your diamond contract using the diamondCut function, but the transaction reverts with an error related to function selectors.

Given this diamondCut call snippet:
diamondCut(
  [
    {
      facetAddress: newFacetAddress,
      action: FacetCutAction.Add,
      functionSelectors: [bytes4(keccak256("foo()")), bytes4(keccak256("bar()"))]
    }
  ],
  address(0),
  ""
);

What is the most likely cause of the revert?
AThe newFacetAddress does not implement one or more of the functions corresponding to the selectors.
BThe diamondCut function requires a non-zero address for the second parameter when adding facets.
CThe function selectors array is empty, causing the revert.
DThe FacetCutAction enum value is invalid.
Attempts:
2 left
💡 Hint
Check if the facet contract actually has the functions matching the selectors you want to add.
📝 Syntax
advanced
2:00remaining
Correct Solidity Syntax for Diamond Storage
Which of the following Solidity code snippets correctly implements the diamond storage pattern to access a struct stored at a fixed storage slot?
A
function diamondStorage() internal view returns (DS storage ds) {
    bytes32 position = keccak256("diamond.storage.example");
    assembly {
        ds.slot = position
    }
}
B
function diamondStorage() internal pure returns (DS storage ds) {
    bytes32 position = keccak256("diamond.storage.example");
    assembly {
        ds.slot := position
    }
}
C
function diamondStorage() internal pure returns (DS storage ds) {
    bytes32 position = keccak256("diamond.storage.example");
    assembly {
        ds := position
    }
}
D
function diamondStorage() internal pure returns (DS storage ds) {
    bytes32 position = keccak256("diamond.storage.example");
    assembly {
        ds.slot := mload(position)
    }
}
Attempts:
2 left
💡 Hint
Remember the correct assembly syntax to assign a storage slot to a variable.
🚀 Application
expert
3:00remaining
Number of Function Selectors in Diamond
You have a diamond contract with 3 facets added. Facet A has 5 functions, Facet B has 3 functions, and Facet C has 4 functions. Facet B and Facet C share 1 function selector (same function signature).

How many unique function selectors does the diamond contract have after adding all three facets?
A12
B10
C11
D9
Attempts:
2 left
💡 Hint
Count all functions, then subtract duplicates due to shared selectors.

Practice

(1/5)
1.

What is the main purpose of the Diamond pattern (EIP-2535) in blockchain smart contracts?

easy
A. To split a large contract into smaller, manageable facets
B. To increase the gas cost of contract deployment
C. To prevent any contract upgrades
D. To combine multiple unrelated contracts into one

Solution

  1. Step 1: Understand the Diamond pattern concept

    The Diamond pattern divides a big contract into smaller parts called facets to organize code better.
  2. Step 2: Identify the main benefit

    This splitting allows easier upgrades and management of smart contracts.
  3. Final Answer:

    To split a large contract into smaller, manageable facets -> Option A
  4. Quick Check:

    Diamond pattern = splitting contract into facets [OK]
Hint: Remember: Diamond pattern breaks big contracts into smaller parts [OK]
Common Mistakes:
  • Thinking it prevents upgrades
  • Assuming it increases deployment cost
  • Confusing it with contract merging
2.

Which of the following is the correct Solidity syntax to declare a facet interface in the Diamond pattern?

interface IFacet {
    function myFunction() external;
}
easy
A. contract IFacet { function myFunction() public {} }
B. interface IFacet { function myFunction() external; }
C. library IFacet { function myFunction() internal; }
D. struct IFacet { function myFunction() external; }

Solution

  1. Step 1: Identify correct Solidity declaration for interface

    Interfaces use the keyword interface and declare functions without bodies.
  2. Step 2: Match function visibility and syntax

    Function in interface must be external and end with a semicolon, no body.
  3. Final Answer:

    interface IFacet { function myFunction() external; } -> Option B
  4. Quick Check:

    Interface syntax = interface IFacet { function myFunction() external; } [OK]
Hint: Interfaces have no function bodies and use 'external' functions [OK]
Common Mistakes:
  • Using contract instead of interface
  • Adding function bodies in interface
  • Using wrong visibility like public or internal
3.

Given the following Solidity snippet using the Diamond pattern, what will be the output when calling diamond.facetFunction()?

contract FacetA {
    function facetFunction() external pure returns (string memory) {
        return "Facet A called";
    }
}

contract Diamond {
    FacetA facetA;
    constructor() {
        facetA = new FacetA();
    }
    function facetFunction() external view returns (string memory) {
        return facetA.facetFunction();
    }
}
medium
A. "Facet A called"
B. Compilation error due to missing function
C. "Diamond called"
D. Runtime error: function not found

Solution

  1. Step 1: Understand contract interaction

    The Diamond contract creates an instance of FacetA and calls its facetFunction.
  2. Step 2: Trace the function call and return value

    Calling diamond.facetFunction() returns the string from FacetA: "Facet A called".
  3. Final Answer:

    "Facet A called" -> Option A
  4. Quick Check:

    Diamond calls FacetA function = "Facet A called" [OK]
Hint: Diamond delegates calls to facets returning their outputs [OK]
Common Mistakes:
  • Assuming Diamond returns its own string
  • Expecting compilation error due to delegation
  • Confusing runtime errors with correct delegation
4.

Identify the error in this simplified Diamond pattern Solidity code snippet:

contract Diamond {
    mapping(bytes4 => address) public facets;

    function addFacet(bytes4 selector, address facetAddress) public {
        facets[selector] = facetAddress;
    }

    fallback() external {
        address facet = facets[msg.sig];
        (bool success, ) = facet.delegatecall(msg.data);
        require(success, "Delegatecall failed");
    }
}
medium
A. Using delegatecall instead of call
B. Fallback function must be external payable
C. Mapping key type should be bytes32, not bytes4
D. Missing return statement in fallback function

Solution

  1. Step 1: Analyze fallback function behavior

    The fallback uses delegatecall but does not return data to the caller.
  2. Step 2: Identify missing return data forwarding

    Delegatecall returns data that must be returned by fallback to preserve call behavior.
  3. Final Answer:

    Missing return statement in fallback function -> Option D
  4. Quick Check:

    Fallback must return delegatecall data [OK]
Hint: Fallback must return delegatecall results to caller [OK]
Common Mistakes:
  • Ignoring return data in fallback
  • Confusing delegatecall with call
  • Assuming payable is mandatory for fallback
5.

You want to upgrade a Diamond contract by adding a new facet with a function selector that already exists in another facet. What will happen if you do not remove the old selector before adding the new one?

hard
A. The Diamond will route calls to the new facet for that selector
B. The Diamond will have two facets for the same selector causing ambiguity
C. The old facet's function will still be called, ignoring the new one
D. The contract will fail to compile due to duplicate selectors

Solution

  1. Step 1: Understand selector uniqueness in Diamond pattern

    Each function selector maps to exactly one facet address in the Diamond.
  2. Step 2: Analyze what happens when adding duplicate selectors

    If you add a selector without removing the old one, the mapping still points to the old facet, so calls route there.
  3. Final Answer:

    The old facet's function will still be called, ignoring the new one -> Option C
  4. Quick Check:

    Duplicate selector without removal = old facet called [OK]
Hint: Remove old selector before adding new to update facet [OK]
Common Mistakes:
  • Assuming Diamond supports multiple facets per selector
  • Expecting compile-time errors for duplicates
  • Thinking new facet automatically overrides old without removal