You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
225 lines
8.8 KiB
Solidity
225 lines
8.8 KiB
Solidity
2 years ago
|
// SPDX-License-Identifier: MIT
|
||
|
pragma solidity ^0.8.0;
|
||
|
|
||
|
import "./Memory.sol";
|
||
|
import "./StorageSlotFactory.sol";
|
||
|
|
||
|
library StorageHelperV2 {
|
||
|
// StorageSlotSelfDestructableV2 compiled via solc 0.8.7 optimized 200
|
||
|
bytes internal constant STORAGE_SLOT_CODE_V2 =
|
||
|
hex"6080604052348015600f57600080fd5b506004361060285760003560e01c80632b68b9c614602d575b600080fd5b60336035565b005b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161460965760405162461bcd60e51b81526020600482015260036024820152624e464f60e81b604482015260640160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316fffea2646970667358221220154417754813d1989858c876ab2ded2ba1aa380679fff7a4c8faea076ba020e664736f6c63430008070033";
|
||
|
uint256 internal constant OWNER_ADDR_OFF = 64;
|
||
|
uint256 internal constant USER_ADDR_OFF = 152;
|
||
|
|
||
|
// StorageSlotFactoryFromInput compiled via solc 0.8.7 optimized 200 + STORAGE_SLOT_CODE
|
||
|
bytes internal constant FACTORY_CODE =
|
||
|
hex"60806040526040516101113803806101118339810160408190526100229161002b565b80518060208301f35b6000602080838503121561003e57600080fd5b82516001600160401b038082111561005557600080fd5b818501915085601f83011261006957600080fd5b81518181111561007b5761007b6100fa565b604051601f8201601f19908116603f011681019083821181831017156100a3576100a36100fa565b8160405282815288868487010111156100bb57600080fd5b600093505b828410156100dd57848401860151818501870152928501926100c0565b828411156100ee5760008684830101525b98975050505050505050565b634e487b7160e01b600052604160045260246000fdfe000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000006080604052348015600f57600080fd5b506004361060325760003560e01c80632b68b9c61460375780638da5cb5b14603f575b600080fd5b603d6081565b005b60657f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200160405180910390f35b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161460ed5760405162461bcd60e51b815260206004820152600e60248201526d3737ba10333937b69037bbb732b960911b604482015260640160405180910390fd5b33fffea2646970667358221220fc66c9afb7cb2f6209ae28167cf26c6c06f86a82cbe3c56de99027979389a1be64736f6c63430008070033";
|
||
|
uint256 internal constant FACTORY_SIZE_OFF = 305;
|
||
|
uint256 internal constant FACTORY_ADDR_OFF0 = 305 + 32 + OWNER_ADDR_OFF;
|
||
|
uint256 internal constant FACTORY_ADDR_OFF1 = 305 + 32 + USER_ADDR_OFF;
|
||
|
|
||
|
function putRawFromCalldata(
|
||
|
bytes calldata data,
|
||
|
uint256 value
|
||
|
) internal returns (address) {
|
||
|
bytes memory bytecode = bytes.concat(STORAGE_SLOT_CODE_V2, data);
|
||
|
address userAddr = msg.sender;
|
||
|
{
|
||
|
// revise the owner to the contract (so that it is destructable)
|
||
|
uint256 off = OWNER_ADDR_OFF + 0x20;
|
||
|
assembly {
|
||
|
mstore(add(bytecode, off), address())
|
||
|
}
|
||
|
off = USER_ADDR_OFF + 0x20;
|
||
|
assembly {
|
||
|
mstore(add(bytecode, off), userAddr)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
StorageSlotFactoryFromInput c = new StorageSlotFactoryFromInput{
|
||
|
value: value
|
||
|
}(bytecode);
|
||
|
return address(c);
|
||
|
}
|
||
|
|
||
|
function putRaw(
|
||
|
bytes memory data,
|
||
|
uint256 value
|
||
|
) internal returns (address) {
|
||
|
// create the new contract code with the data
|
||
|
bytes memory bytecode = STORAGE_SLOT_CODE_V2;
|
||
|
uint256 bytecodeLen = bytecode.length;
|
||
|
uint256 newSize = bytecode.length + data.length;
|
||
|
assembly {
|
||
|
// in-place resize of bytecode bytes
|
||
|
// note that this must be done when bytecode is the last allocated object by solidity.
|
||
|
mstore(bytecode, newSize)
|
||
|
// notify solidity about the memory size increase, must be 32-bytes aligned
|
||
|
mstore(
|
||
|
0x40,
|
||
|
add(bytecode, and(add(add(newSize, 0x20), 0x1f), not(0x1f)))
|
||
|
)
|
||
|
}
|
||
|
// append data to self-destruct byte code
|
||
|
Memory.copy(
|
||
|
Memory.dataPtr(data),
|
||
|
Memory.dataPtr(bytecode) + bytecodeLen,
|
||
|
data.length
|
||
|
);
|
||
|
address userAddr = msg.sender;
|
||
|
{
|
||
|
// revise the owner to the contract (so that it is destructable)
|
||
|
uint256 off = OWNER_ADDR_OFF + 0x20;
|
||
|
assembly {
|
||
|
mstore(add(bytecode, off), address())
|
||
|
}
|
||
|
off = USER_ADDR_OFF + 0x20;
|
||
|
assembly {
|
||
|
mstore(add(bytecode, off), userAddr)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
StorageSlotFactoryFromInput c = new StorageSlotFactoryFromInput{
|
||
|
value: value
|
||
|
}(bytecode);
|
||
|
return address(c);
|
||
|
}
|
||
|
|
||
|
function putRaw2(
|
||
|
bytes32 key,
|
||
|
bytes memory data,
|
||
|
uint256 value
|
||
|
) internal returns (address) {
|
||
|
// create the new contract code with the data
|
||
|
bytes memory bytecode = FACTORY_CODE;
|
||
|
uint256 bytecodeLen = bytecode.length;
|
||
|
uint256 newSize = bytecode.length + data.length;
|
||
|
assembly {
|
||
|
// in-place resize of bytecode bytes
|
||
|
// note that this must be done when bytecode is the last allocated object by solidity.
|
||
|
mstore(bytecode, newSize)
|
||
|
// notify solidity about the memory size increase, must be 32-bytes aligned
|
||
|
mstore(
|
||
|
0x40,
|
||
|
add(bytecode, and(add(add(newSize, 0x20), 0x1f), not(0x1f)))
|
||
|
)
|
||
|
}
|
||
|
// append data to self-destruct byte code
|
||
|
Memory.copy(
|
||
|
Memory.dataPtr(data),
|
||
|
Memory.dataPtr(bytecode) + bytecodeLen,
|
||
|
data.length
|
||
|
);
|
||
|
{
|
||
|
// revise the size of calldata
|
||
|
uint256 calldataSize = STORAGE_SLOT_CODE_V2.length + data.length;
|
||
|
uint256 off = FACTORY_SIZE_OFF + 0x20;
|
||
|
assembly {
|
||
|
mstore(add(bytecode, off), calldataSize)
|
||
|
}
|
||
|
}
|
||
|
{
|
||
|
// revise the owner to the contract (so that it is destructable)
|
||
|
uint256 off = FACTORY_ADDR_OFF0 + 0x20;
|
||
|
assembly {
|
||
|
mstore(add(bytecode, off), address())
|
||
|
}
|
||
|
off = FACTORY_ADDR_OFF1 + 0x20;
|
||
|
assembly {
|
||
|
mstore(add(bytecode, off), address())
|
||
|
}
|
||
|
}
|
||
|
|
||
|
address addr;
|
||
|
assembly {
|
||
|
addr := create2(
|
||
|
value,
|
||
|
add(bytecode, 0x20), // data offset
|
||
|
mload(bytecode), // size
|
||
|
key
|
||
|
)
|
||
|
|
||
|
if iszero(extcodesize(addr)) {
|
||
|
revert(0, 0)
|
||
|
}
|
||
|
}
|
||
|
return addr;
|
||
|
}
|
||
|
|
||
|
function sizeRaw(address addr) internal view returns (uint256, bool) {
|
||
|
if (addr == address(0x0)) {
|
||
|
return (0, false);
|
||
|
}
|
||
|
uint256 codeSize;
|
||
|
uint256 off = STORAGE_SLOT_CODE_V2.length;
|
||
|
assembly {
|
||
|
codeSize := extcodesize(addr)
|
||
|
}
|
||
|
if (codeSize < off) {
|
||
|
return (0, false);
|
||
|
}
|
||
|
|
||
|
return (codeSize - off, true);
|
||
|
}
|
||
|
|
||
|
function getRaw(address addr) internal view returns (bytes memory, bool) {
|
||
|
(uint256 dataSize, bool found) = sizeRaw(addr);
|
||
|
|
||
|
if (!found) {
|
||
|
return (new bytes(0), false);
|
||
|
}
|
||
|
|
||
|
// copy the data without the "code"
|
||
|
bytes memory data = new bytes(dataSize);
|
||
|
uint256 off = STORAGE_SLOT_CODE_V2.length;
|
||
|
assembly {
|
||
|
// retrieve data size
|
||
|
extcodecopy(addr, add(data, 0x20), off, dataSize)
|
||
|
}
|
||
|
return (data, true);
|
||
|
}
|
||
|
|
||
|
function getRawAt(
|
||
|
address addr,
|
||
|
uint256 memoryPtr
|
||
|
) internal view returns (uint256, bool) {
|
||
|
(uint256 dataSize, bool found) = sizeRaw(addr);
|
||
|
|
||
|
if (!found) {
|
||
|
return (0, false);
|
||
|
}
|
||
|
|
||
|
uint256 off = STORAGE_SLOT_CODE_V2.length;
|
||
|
assembly {
|
||
|
// retrieve data size
|
||
|
extcodecopy(addr, memoryPtr, off, dataSize)
|
||
|
}
|
||
|
return (dataSize, true);
|
||
|
}
|
||
|
|
||
|
function returnBytesInplace(bytes memory content) internal pure {
|
||
|
// equal to return abi.encode(content)
|
||
|
uint256 size = content.length + 0x40; // pointer + size
|
||
|
size = (size + 0x20 + 0x1f) & ~uint256(0x1f);
|
||
|
assembly {
|
||
|
// (DATA CORRUPTION): the caller method must be "external returns (bytes)", cannot be public!
|
||
|
mstore(sub(content, 0x20), 0x20)
|
||
|
return(sub(content, 0x20), size)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function calculateValueForData(
|
||
|
uint256 datalen,
|
||
|
uint256 chunkSize,
|
||
|
uint256 codeStakingPerChunk
|
||
|
) internal pure returns (uint256) {
|
||
|
return
|
||
|
((datalen + STORAGE_SLOT_CODE_V2.length - 1) / chunkSize) *
|
||
|
codeStakingPerChunk;
|
||
|
}
|
||
|
|
||
|
function storageSlotCodeLength() internal pure returns (uint256) {
|
||
|
return STORAGE_SLOT_CODE_V2.length;
|
||
|
}
|
||
|
}
|