Skip to content

Instantly share code, notes, and snippets.

@xtremetom
Created September 23, 2022 19:06
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save xtremetom/64d1c590b933826a546a5c8b0573be3a to your computer and use it in GitHub Desktop.
Save xtremetom/64d1c590b933826a546a5c8b0573be3a to your computer and use it in GitHub Desktop.
Dirty library storage example
pragma solidity ^0.8.9;
import {SSTORE2} from "sstore2/SSTORE2.sol";
import {DynamicBuffer} from "ethier/contracts/utils/DynamicBuffer.sol";
contract LibraryStorage {
struct Library {
address owner;
bytes details;
uint256 size;
address[] chunks;
}
mapping(string => Library) _libraries;
mapping(string => address[]) _libraries2;
error NotOwner();
error InvalidLength();
error LibraryExists();
error NotLibraryOwner();
constructor(){}
modifier libraryOwner(string memory name) {
if(msg.sender != _libraries[name].owner) revert NotLibraryOwner();
_;
}
modifier exists(string memory name) {
if(_libraries[name].owner != address(0)) revert LibraryExists();
_;
}
function createLibrary(string calldata name, bytes calldata details) public {
_libraries[name] = Library(msg.sender, details, 0, new address[](0));
}
function addChunkToLibrary(string calldata name, bytes calldata chunk) public libraryOwner(name) {
_libraries[name].chunks.push(SSTORE2.write(chunk));
_libraries[name].size += chunk.length;
}
function getLibrary2(string calldata name) public view returns (string memory) {
address[] memory chunks = _libraries[name].chunks;
bytes memory data = DynamicBuffer.allocate(_libraries[name].size);
for (uint256 i; i < chunks.length;) {
DynamicBuffer.appendSafe(
data,
SSTORE2.read(chunks[i])
);
unchecked {
++ i;
}
}
return string(data);
}
function getLibrary(string calldata name) public view returns (string memory o_code) {
address[] memory chunks = _libraries[name].chunks;
// address[] memory chunks = _libraries2[name];
unchecked {
assembly {
let len := mload(chunks)
let totalSize := 0x20
let size := 0
o_code := mload(0x40)
// loop through all chunk addresses
// - get address
// - get data size
// - get code and add to o_code
// - update total size
let targetChunk := 0
for { let i := 0 } lt(i, len) { i := add(i, 1) } {
targetChunk := mload(add(chunks, add(0x20, mul(i, 0x20))))
size := sub(extcodesize(targetChunk), 1)
extcodecopy(targetChunk, add(o_code, totalSize), 1, size)
totalSize := add(totalSize, size)
}
// update o_code size
mstore(o_code, sub(totalSize, 0x20))
// store o_code
mstore(0x40, add(o_code, and(add(totalSize, 0x1f), not(0x1f))))
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment