Geode Finance
Search…
⌃K

Isolated Storage

Like off-chain infrastructures, Portal is designed to host multiple parties without them affecting each other's module under any condition.

DataStoreUtils is a storage management tool designed to create a safe and scalable storage layout with the help of ids and keys. Mainly focusing on upgradable contracts with multiple user types to create a sustainable development environment.

DataStore Library allows a base class to be constructed. This Parent Class is inherited on any other implementation when external parties are included in the logic.

For example in other Libraries, it will be used to create another Base Class named "Maintainer", which gives many functionalities.

With Isolated Storage that is implemented as DataStore, Portal achieves 3 goals:

  • A Dynamic Struct that is defined with the "TYPE" parameter, that can hold any amount of parameters, instead of 16 (max # of variables a struct can hold in Solidity).
  • Make it very easy to build new classes that has different parameters and functionalities without altering most of the codebase.
  • Separating the storage space of the contract, allowing Portal to maintain multiple parties without any friction.

Deep Dive

Storage Management library for dynamic structs based on data types

The DataStore Struct

DataStoreLib.sol
struct DataStore {
// type[0,1,2,3...] => ID list
mapping(uint256 => uint256[]) allIdsByType;
// keccak(id, key) => data
mapping(bytes32 => uint256) UintData;
mapping(bytes32 => bytes) BytesData;
mapping(bytes32 => address) AddressData;
}
In the struct, there are 4 different mapping to serve different types of storage.

Sample Write Operation

DataStoreLib.sol
function writeUintForId(
DataStore storage self,
uint256 _id,
bytes32 _key,
uint256 data
) public {
self.UintData[keccak256(abi.encodePacked(_id, _key))] = data;
}
Basically, it takes the id and key pair encoded, secures a slot in the mapping for the id&key pair and assigns the data to slot in the UintData mapping where DataStore struct is taken as a storage argument. Every write operation in the library follows the same procedure.

Sample Read Operation

DataStoreLib.sol
function readUintForId(
DataStore storage self,
uint256 _id,
bytes32 _key
) public view returns (uint256 data) {
data = self.UintData[keccak256(abi.encodePacked(_id, _key))];
}
This is also a typical read operation in the library, getting the data from the assigned slot with the given id and key pair returning the data publicly with the view restriction.