93 lines
3.3 KiB
Solidity
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))
|
||
|
}
|
||
|
}
|
||
|
}
|