DCIPs/assets/eip-3448/MetaProxyFactory.sol

93 lines
3.3 KiB
Solidity

// SPDX-License-Identifier: CC0-1.0
pragma solidity >=0.7.6;
contract MetaProxyFactory {
/// @dev Creates a new proxy for `targetContract` with metadata from calldata.
/// Copies everything from calldata except the first 4 bytes.
/// @return addr A non-zero address if successful.
function _metaProxyFromCalldata (address targetContract) internal returns (address addr) {
// the following assembly code (init code + contract code) constructs a metaproxy.
assembly {
// load free memory pointer as per solidity convention
let start := mload(64)
// copy
let ptr := start
// deploy code (11 bytes) + first part of the proxy (21 bytes)
mstore(ptr, 0x600b380380600b3d393df3363d3d373d3d3d3d60368038038091363936013d73)
ptr := add(ptr, 32)
// store the address of the contract to be called
mstore(ptr, shl(96, targetContract))
// 20 bytes
ptr := add(ptr, 20)
// the remaining proxy code...
mstore(ptr, 0x5af43d3d93803e603457fd5bf300000000000000000000000000000000000000)
// ...13 bytes
ptr := add(ptr, 13)
// now calculdate the size and copy the metadata
// - 4 bytes function signature
let size := sub(calldatasize(), 4)
// copy
calldatacopy(ptr, 4, size)
ptr := add(ptr, size)
// store the size of the metadata at the end of the bytecode
mstore(ptr, size)
ptr := add(ptr, 32)
// The size is deploy code + contract code + calldatasize - 4 + 32.
addr := create(0, start, sub(ptr, start))
}
}
/// @dev Creates a proxy for `targetContract` with metadata from `metadata`.
/// @return A non-zero address if successful.
function _metaProxyFromBytes (address targetContract, bytes memory metadata) internal returns (address) {
uint256 ptr;
assembly {
ptr := add(metadata, 32)
}
return _metaProxyFromMemory(targetContract, ptr, metadata.length);
}
/// @dev Creates a new proxy for `targetContract` with metadata from memory starting at `offset` and `length` bytes.
/// @return addr A non-zero address if successful.
function _metaProxyFromMemory (address targetContract, uint256 offset, uint256 length) internal returns (address addr) {
// the following assembly code (init code + contract code) constructs a metaproxy.
assembly {
// load free memory pointer as per solidity convention
let start := mload(64)
// keep a copy
let ptr := start
// deploy code (11 bytes) + first part of the proxy (21 bytes)
mstore(ptr, 0x600b380380600b3d393df3363d3d373d3d3d3d60368038038091363936013d73)
ptr := add(ptr, 32)
// store the address of the contract to be called
mstore(ptr, shl(96, targetContract))
// 20 bytes
ptr := add(ptr, 20)
// the remaining proxy code...
mstore(ptr, 0x5af43d3d93803e603457fd5bf300000000000000000000000000000000000000)
// ...13 bytes
ptr := add(ptr, 13)
// copy the metadata
{
for { let i := 0 } lt(i, length) { i := add(i, 32) } {
mstore(add(ptr, i), mload(add(offset, i)))
}
}
ptr := add(ptr, length)
// store the size of the metadata at the end of the bytecode
mstore(ptr, length)
ptr := add(ptr, 32)
// The size is deploy code + contract code + calldatasize - 4 + 32.
addr := create(0, start, sub(ptr, start))
}
}
}