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.

226 lines
8.8 KiB
Solidity

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./Memory.sol";
import "./StorageSlotFactory.sol";
library StorageHelperV2 {
uint256 public constant STORAGE_SLOT_CODE_V2_PREFIX_LEN = 280;
// 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;
}
}