Skip to content

Commit

Permalink
constructor in yul
Browse files Browse the repository at this point in the history
  • Loading branch information
Radek Svarz committed Oct 13, 2024
1 parent c871f04 commit 9599be6
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 21 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@

Entrypoint ERC-1967 proxy and storage contract for the UUPS based architecture. Flattened and adapted from OpenZeppelin.

Use with Foundry.
Use `src/Entrypoint.sol` with Foundry.

# Why?

- no dependencies
- small focused package
- smaller bytecode, lower gas consumption, yet still verifiable for explorers
- easier to audit
- clear steps, easier to audit
- easy to plug in to OpenZeppelin based contracts
- does not brake when OpenZeppelin restructures folders

Expand Down
53 changes: 34 additions & 19 deletions src/Entrypoint.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ contract Entrypoint {
*/
event Upgraded(address indexed implementation);

/**
* @dev `keccak256(bytes("Upgraded(address)"))`
*/
uint256 private constant _UPGRADED_EVENT_SIGNATURE =
0xbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b;

/**
* @dev The `implementation` of the proxy is invalid.
*/
Expand All @@ -34,29 +40,38 @@ contract Entrypoint {
*
*/
constructor(address implementation, bytes memory data) payable {
_setImplementation(implementation);
emit Upgraded(implementation);
assembly {
// Revert when implementation address does not contain code
if iszero(extcodesize(implementation)) {
// revert ERC1967InvalidImplementation(implementation);
mstore(0x00, 0x4c9c8ce3)
mstore(0x20, implementation)
revert(0x1c, 0x24)
}

// Store a new address in the ERC-1967 implementation slot
sstore(_IMPLEMENTATION_SLOT, implementation)

// emit {Upgraded} event
log2(0, 0, _UPGRADED_EVENT_SIGNATURE, implementation)

if (data.length > 0) {
(bool success, bytes memory returndata) = implementation.delegatecall(data);
if (!success) {
assembly ("memory-safe") {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
// Execute initialization call when function calldata are provided
let data_size := mload(data)
if data_size {
// Call the implementation.
// out and outsize are 0 because we don't know the size yet.
let result := delegatecall(gas(), implementation, add(32, data), data_size, 0, 0)

// delegatecall returns 0 on error.
if iszero(result) {
// Copy the returned error data and bubble up revert
returndatacopy(0, 0, returndatasize())
revert(0, returndatasize())
}
}
}
}

/**
* @dev Stores a new address in the ERC-1967 implementation slot.
*/
function _setImplementation(address newImplementation) internal {
if (newImplementation.code.length == 0) {
revert ERC1967InvalidImplementation(newImplementation);
}
assembly {
sstore(_IMPLEMENTATION_SLOT, newImplementation)
// @dev: No need to restore memory pointers, as the rest of the constructor just returns the runtime
// bytecode
}
}

Expand Down

0 comments on commit 9599be6

Please sign in to comment.