Last active
October 25, 2021 15:40
-
-
Save jiexi/27fb1c7e8241b78b4264f497e49efd2f to your computer and use it in GitHub Desktop.
Eternal Storage by Decentralized DNS Example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
The blog post that explains how these contracts work can be found at: | |
https://hackernoon.com/eternal-storage-building-dapps-for-the-future-stl3xre |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity >=0.5.14 <0.6.0; | |
contract Base { | |
EternalStorage internal es; | |
constructor(address _es) public { | |
es = EternalStorage(_es); | |
} | |
modifier onlyNetworkContracts() { | |
require( | |
hasRole("contract") == true, | |
"Sender is not a contract in the network" | |
); | |
_; | |
} | |
modifier onlyNetworkContract(string memory _contractName) { | |
address contractAddress = getContractAddress(_contractName); | |
require(contractAddress == msg.sender, "Incorrect or outdated contract access used"); | |
_; | |
} | |
modifier onlyRole(string memory _role) { | |
require( | |
hasRole(_role) == true, | |
"Sender doesn't have matching role" | |
); | |
_; | |
} | |
function getContractAddress(string memory _contractName) public view returns(address) { | |
address contractAddress = es.getAddress( | |
keccak256(abi.encodePacked("contracts", _contractName, "address")) | |
); | |
require(address(contractAddress) != address(0x0), "Contract not found"); | |
return contractAddress; | |
} | |
function hasRole(string memory _role) public view returns(bool) { | |
return es.getBool( | |
keccak256(abi.encodePacked("access.role", _role, msg.sender)) | |
) ; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity >=0.5.14 <0.6.0; | |
contract ContractAdmin is Base { | |
constructor(address _es) Base(_es) public {} | |
function addContract( | |
string memory _name, | |
address _contractAddress, | |
string memory _contractAbi | |
) public onlyRole("owner") { | |
require(_contractAddress != address(0x0), "Invalid contract address"); | |
address existingContractName = es.getAddress(keccak256(abi.encodePacked("contracts", _name, "address"))); | |
require(existingContractName == address(0x0), "Contract name is already in use"); | |
bool existingContractAddress = es.getBool(keccak256(abi.encodePacked("access.role", "contract", _contractAddress))); | |
require(!existingContractAddress, "Contract address is already in use"); | |
es.setAddress(keccak256(abi.encodePacked("contracts", _name, "address")), _contractAddress); | |
es.setString(keccak256(abi.encodePacked("contracts", _name, "abi")), _contractAbi); | |
es.setBool(keccak256(abi.encodePacked("access.role", "contract", _contractAddress)), true); | |
} | |
function upgradeContract( | |
string memory _name, | |
address _upgradedContractAddress, | |
string memory _upgradedContractAbi, | |
bool _forceEther | |
) public onlyRole("owner") { | |
require(_upgradedContractAddress != address(0x0), "Invalid contract address"); | |
address oldContractAddress = es.getAddress(keccak256(abi.encodePacked("contracts", _name, "address"))); | |
require(oldContractAddress != address(0x0), "Contract name does not exist"); | |
require(oldContractAddress != _upgradedContractAddress, "Upgraded contract address must not be existing contract address"); | |
if (!_forceEther) { | |
require(oldContractAddress.balance == 0, "Existing contract has an ether balance"); | |
} | |
es.setAddress(keccak256(abi.encodePacked("contracts", _name, "address")), _upgradedContractAddress); | |
es.setString(keccak256(abi.encodePacked("contracts", _name, "abi")), _upgradedContractAbi); | |
es.setBool(keccak256(abi.encodePacked("access.role", "contract", _upgradedContractAddress)), true); | |
es.deleteBool(keccak256(abi.encodePacked("access.role", "contract", oldContractAddress))); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity >=0.5.14 <0.6.0; | |
pragma experimental ABIEncoderV2; | |
contract DNS { | |
DomainsModel _domains; | |
constructor(address _es) public { | |
_domains = new DomainsModel(_es); | |
} | |
function claim(string memory name) public { | |
address domainOwner = _domains.getOwner(name); | |
if (domainOwner == address(0)) { | |
_domains.setOwner(name, msg.sender); | |
return; | |
} | |
require(domainOwner == msg.sender, "Domain has already been claimed"); | |
} | |
function updateRecords(string memory name, DomainsModel.DomainRecord[] memory records) public { | |
claim(name); | |
_domains.setRecords(name, records); | |
} | |
function release(string memory name) public { | |
address domainOwner = _domains.getOwner(name); | |
require(domainOwner == msg.sender, "Sender does not own this domain"); | |
_domains.setRecords(name, []); | |
_domains.deleteOwner(name); | |
} | |
function domains(string memory name) public view | |
returns (address owner_) | |
{ | |
address domainOwner = _domains.getOwner(name); | |
owner_ = domainOwner; | |
} | |
function recordsForName(string memory name) public view | |
returns (DomainsModel.DomainRecord[] memory recordsForName_) | |
{ | |
DomainsModel.DomainRecord[] memory records = _domains.getRecords(name); | |
recordsForName_ = records; | |
} | |
function domainNamesForOwner(address owner) public view | |
returns (string[] memory domainNamesForOwner_) | |
{ | |
string[] memory domainNames = _domains.getDomainNamesForOwner(owner); | |
domainNamesForOwner_ = domainNames; | |
} | |
function domainNamesForSender() public view | |
returns (string[] memory domainNamesForSender_) | |
{ | |
string[] memory domainNames = _domains.getDomainNamesForOwner(msg.sender); | |
domainNamesForSender_ = domainNames; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity >=0.6.4 <0.7.0; | |
pragma experimental ABIEncoderV2; | |
contract DNS { | |
struct DomainRecord { | |
string _type; // "A", "CNAME", "MX", etc... | |
string value; | |
uint ttl; | |
} | |
struct Domain { | |
address owner; | |
DomainRecord[] records; | |
} | |
mapping(string => Domain) public domains; | |
function claim(string memory name) public { | |
address domainOwner = domains[name].owner; | |
if (domainOwner == address(0)) { | |
domains[name].owner = msg.sender; | |
return; | |
} | |
require(domainOwner == msg.sender, "Domain has already been claimed"); | |
} | |
function updateRecords(string memory name, DomainRecord[] memory records) public { | |
claim(name); | |
delete domains[name].records; | |
uint size = records.length; | |
for (uint i = 0; i < size; i++) { | |
domains[name].records.push(records[i]); | |
} | |
} | |
function release(string memory name) public { | |
require(domains[name].owner == msg.sender, "Sender does not own this domain"); | |
domains[name].owner = address(0); | |
} | |
function recordsForName(string memory name) public view | |
returns (DomainRecord[] memory recordsForName_) | |
{ | |
recordsForName_ = domains[name].records; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity >=0.6.4 <0.7.0; | |
pragma experimental ABIEncoderV2; | |
contract DNS { | |
struct DomainRecord { | |
string _type; // "A", "CNAME", "MX", etc... | |
string value; | |
uint ttl; | |
} | |
struct Domain { | |
address owner; | |
DomainRecord[] records; | |
} | |
mapping(string => Domain) public domains; | |
function claim(string memory name) public { | |
address domainOwner = domains[name].owner; | |
if (domainOwner == address(0)) { | |
domains[name].owner = msg.sender; | |
return; | |
} | |
require(domainOwner == msg.sender, "Domain has already been claimed"); | |
} | |
function updateRecords(string memory name, DomainRecord[] memory records) public { | |
claim(name); | |
delete domains[name].records; | |
uint size = records.length; | |
for (uint i = 0; i < size; i++) { | |
domains[name].records.push(records[i]); | |
} | |
} | |
function release(string memory name) public { | |
require(domains[name].owner == msg.sender, "Sender does not own this domain"); | |
delete domains[name].records; // now it clears records during release | |
domains[name].owner = address(0); | |
} | |
function recordsForName(string memory name) public view | |
returns (DomainRecord[] memory recordsForName_) | |
{ | |
recordsForName_ = domains[name].records; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity >=0.5.14 <0.6.0; | |
pragma experimental ABIEncoderV2; | |
contract DNS { | |
DomainsModel _domains; | |
constructor(address _es) public { | |
_domains = new DomainsModel(_es); | |
} | |
function claim(string memory name) public { | |
address domainOwner = _domains.getOwner(name); | |
if (domainOwner == address(0)) { | |
_domains.setOwner(name, msg.sender); | |
return; | |
} | |
require(domainOwner == msg.sender, "Domain has already been claimed"); | |
} | |
function updateRecords(string memory name, DomainsModel.DomainRecord[] memory records) public { | |
claim(name); | |
_domains.setRecords(name, records); | |
} | |
function release(string memory name) public { | |
address domainOwner = _domains.getOwner(name); | |
require(domainOwner == msg.sender, "Sender does not own this domain"); | |
_domains.setRecords(name, []); | |
_domains.deleteOwner(name); | |
} | |
function domains(string memory name) public view | |
returns (address owner_) | |
{ | |
address domainOwner = _domains.getOwner(name); | |
owner_ = domainOwner; | |
} | |
function recordsForName(string memory name) public view | |
returns (DomainsModel.DomainRecord[] memory recordsForName_) | |
{ | |
DomainsModel.DomainRecord[] memory records = _domains.getRecords(name); | |
recordsForName_ = records; | |
} | |
function domainNamesForOwner(address owner) public view | |
returns (string[] memory domainNamesForOwner_) | |
{ | |
string[] memory domainNames = _domains.getDomainNamesForOwner(owner); | |
domainNamesForOwner_ = domainNames; | |
} | |
function domainNamesForSender() public view | |
returns (string[] memory domainNamesForSender_) | |
{ | |
string[] memory domainNames = _domains.getDomainNamesForOwner(msg.sender); | |
domainNamesForSender_ = domainNames; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity >=0.5.14 <0.6.0; | |
pragma experimental ABIEncoderV2; | |
contract DNS { | |
DomainsModel _domains; | |
constructor(address _es) public { | |
_domains = new DomainsModel(_es); | |
} | |
function claim(string memory name) public { | |
address domainOwner = _domains.getOwner(name); | |
if (domainOwner == address(0)) { | |
_domains.setOwner(name, msg.sender); | |
return; | |
} | |
require(domainOwner == msg.sender, "Domain has already been claimed"); | |
} | |
function updateRecords(string memory name, DomainsModel.DomainRecord[] memory records) public { | |
claim(name); | |
_domains.setRecords(name, records); | |
} | |
function release(string memory name) public { | |
address domainOwner = _domains.getOwner(name); | |
require(domainOwner == msg.sender, "Sender does not own this domain"); | |
_domains.setRecords(name, []); | |
_domains.deleteOwner(name); | |
} | |
function domains(string memory name) public view | |
returns (address owner_) | |
{ | |
address domainOwner = _domains.getOwner(name); | |
owner_ = domainOwner; | |
} | |
function recordsForName(string memory name) public view | |
returns (DomainsModel.DomainRecord[] memory recordsForName_) | |
{ | |
DomainsModel.DomainRecord[] memory records = _domains.getRecords(name); | |
recordsForName_ = records; | |
} | |
function domainNamesForOwner(address owner) public view | |
returns (string[] memory domainNamesForOwner_) | |
{ | |
string[] memory domainNames = _domains.getDomainNamesForOwner(owner); | |
domainNamesForOwner_ = domainNames; | |
} | |
function domainNamesForSender() public view | |
returns (string[] memory domainNamesForSender_) | |
{ | |
string[] memory domainNames = _domains.getDomainNamesForOwner(msg.sender); | |
domainNamesForSender_ = domainNames; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity >=0.5.14 <0.6.0; | |
pragma experimental ABIEncoderV2; | |
contract DomainModel { | |
struct DomainRecord { | |
string recordType; // "A", "CNAME", "MX", etc... | |
string value; | |
uint ttl; | |
} | |
EternalStorage es; | |
StringListStorage sls; | |
constructor(address _es) public { | |
es = EternalStorage(_es); | |
sls = new StringListStorage(_es); | |
} | |
function getOwner(string memory name) public view | |
returns (address owner_) | |
{ | |
address domainOwner = es.getAddress(keccak256(abi.encodePacked("domains", name, "owner"))); | |
owner_ = domainOwner; | |
} | |
function setOwner(string memory name, address owner) public { | |
if (owner == address(0)) { | |
return; | |
} | |
es.setAddress(keccak256(abi.encodePacked("domains", name, "owner")), owner); | |
sls.pushListItem(keccak256(abi.encodePacked("owners", owner, "domains")), name); | |
} | |
function setRecords(string memory name, DomainRecord[] memory records) public { | |
uint length = records.length; | |
es.setUint(keccak256(abi.encodePacked("domains", name, "records", "length")), length); | |
for (uint i = 0; i < length; i++) { | |
es.setString(keccak256(abi.encodePacked("domains", name, "records", i, "type")), records[i].recordType); | |
es.setString(keccak256(abi.encodePacked("domains", name, "records", i, "value")), records[i].value); | |
es.setUint(keccak256(abi.encodePacked("domains", name, "records", i, "ttl")), records[i].ttl); | |
} | |
} | |
function deleteOwner(string memory name) public { | |
address domainOwner = es.getAddress(keccak256(abi.encodePacked("domains", name, "owner"))); | |
if (domainOwner == address(0)) { | |
return; | |
} | |
es.setAddress(keccak256(abi.encodePacked("domains", name, "owner")), address(0)); | |
int index = sls.getListIndexOf(keccak256(abi.encodePacked("owners", domainOwner, "domains")), name); | |
if (index != -1) { | |
sls.removeUnorderedListItem(keccak256(abi.encodePacked("owners", domainOwner, "domains")), uint(index)); | |
} | |
} | |
function getRecords(string memory name) public view | |
returns (DomainRecord[] memory recordsForName_) | |
{ | |
uint length = es.getUint(keccak256(abi.encodePacked("domains", name, "records", "length"))); | |
DomainRecord[] memory records = new DomainRecord[](length); | |
for (uint i = 0; i < length; i++) { | |
records[i] = DomainRecord({ | |
recordType: es.getString(keccak256(abi.encodePacked("domains", name, "records", i, "type"))), | |
value: es.getString(keccak256(abi.encodePacked("domains", name, "records", i, "value"))), | |
ttl: es.getUint(keccak256(abi.encodePacked("domains", name, "records", i, "ttl"))) | |
}); | |
} | |
recordsForName_ = records; | |
} | |
function getDomainNamesForOwner(address owner) public view | |
returns (string[] memory domainNamesForOwner_) | |
{ | |
uint length = sls.getListLength(keccak256(abi.encodePacked("owners", owner, "domains"))); | |
string[] memory domainNames = new string[](length); | |
for (uint i = 0; i < length; i++) { | |
domainNames[i] = sls.getListItem(keccak256(abi.encodePacked("owners", owner, "domains")), i); | |
} | |
domainNamesForOwner_ = domainNames; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity >=0.5.14 <0.6.0; | |
pragma experimental ABIEncoderV2; | |
contract DomainModel is Base { | |
struct DomainRecord { | |
string recordType; // "A", "CNAME", "MX", etc... | |
string value; | |
uint ttl; | |
} | |
constructor(address _es) Base(_es) public {} | |
function getOwner(string memory name) public view | |
returns (address owner_) | |
{ | |
address domainOwner = es.getAddress(keccak256(abi.encodePacked("domains", name, "owner"))); | |
owner_ = domainOwner; | |
} | |
function setOwner(string memory name, address owner) onlyNetworkContract("DNS") public { | |
if (owner == address(0)) { | |
return; | |
} | |
StringListStorage sls = StringListStorage(getContractAddress("StringListStorage")); | |
es.setAddress(keccak256(abi.encodePacked("domains", name, "owner")), owner); | |
sls.pushListItem(keccak256(abi.encodePacked("owners", owner, "domains")), name); | |
} | |
function setRecords(string memory name, DomainRecord[] memory records) onlyNetworkContract("DNS") public { | |
uint length = records.length; | |
es.setUint(keccak256(abi.encodePacked("domains", name, "records", "length")), length); | |
for (uint i = 0; i < length; i++) { | |
es.setString(keccak256(abi.encodePacked("domains", name, "records", i, "type")), records[i].recordType); | |
es.setString(keccak256(abi.encodePacked("domains", name, "records", i, "value")), records[i].value); | |
es.setUint(keccak256(abi.encodePacked("domains", name, "records", i, "ttl")), records[i].ttl); | |
} | |
} | |
function deleteOwner(string memory name) onlyNetworkContract("DNS") public { | |
address domainOwner = es.getAddress(keccak256(abi.encodePacked("domains", name, "owner"))); | |
if (domainOwner == address(0)) { | |
return; | |
} | |
es.setAddress(keccak256(abi.encodePacked("domains", name, "owner")), address(0)); | |
StringListStorage sls = StringListStorage(getContractAddress("StringListStorage")); | |
int index = sls.getListIndexOf(keccak256(abi.encodePacked("owners", domainOwner, "domains")), name); | |
if (index != -1) { | |
sls.removeUnorderedListItem(keccak256(abi.encodePacked("owners", domainOwner, "domains")), uint(index)); | |
} | |
} | |
function getRecords(string memory name) public view | |
returns (DomainRecord[] memory recordsForName_) | |
{ | |
uint length = es.getUint(keccak256(abi.encodePacked("domains", name, "records", "length"))); | |
DomainRecord[] memory records = new DomainRecord[](length); | |
for (uint i = 0; i < length; i++) { | |
records[i] = DomainRecord({ | |
recordType: es.getString(keccak256(abi.encodePacked("domains", name, "records", i, "type"))), | |
value: es.getString(keccak256(abi.encodePacked("domains", name, "records", i, "value"))), | |
ttl: es.getUint(keccak256(abi.encodePacked("domains", name, "records", i, "ttl"))) | |
}); | |
} | |
recordsForName_ = records; | |
} | |
function getDomainNamesForOwner(address owner) public view | |
returns (string[] memory domainNamesForOwner_) | |
{ | |
StringListStorage sls = StringListStorage(getContractAddress("StringListStorage")); | |
uint length = sls.getListLength(keccak256(abi.encodePacked("owners", owner, "domains"))); | |
string[] memory domainNames = new string[](length); | |
for (uint i = 0; i < length; i++) { | |
domainNames[i] = sls.getListItem(keccak256(abi.encodePacked("owners", owner, "domains")), i); | |
} | |
domainNamesForOwner_ = domainNames; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity >=0.5.14 <0.6.0; | |
contract EternalStorage { | |
mapping(bytes32 => uint256) private uIntStorage; | |
mapping(bytes32 => string) private stringStorage; | |
mapping(bytes32 => address) private addressStorage; | |
mapping(bytes32 => bytes) private bytesStorage; | |
mapping(bytes32 => bool) private boolStorage; | |
mapping(bytes32 => int256) private intStorage; | |
mapping(bytes32 => bytes32) private bytes32Storage; | |
modifier onlyNetworkContract() { | |
if (boolStorage[keccak256(abi.encodePacked("contract.storage.initialized"))] == true) { | |
require(boolStorage[keccak256(abi.encodePacked("access.role", "contract", msg.sender))] == true, "Sender is not a contract in the network"); | |
} | |
_; | |
} | |
constructor() public { | |
boolStorage[keccak256(abi.encodePacked("access.role", "owner", msg.sender))] = true; | |
} | |
// Get | |
function getAddress(bytes32 _key) external view returns (address) { | |
return addressStorage[_key]; | |
} | |
function getUint(bytes32 _key) external view returns (uint) { | |
return uIntStorage[_key]; | |
} | |
function getString(bytes32 _key) external view returns (string memory) { | |
return stringStorage[_key]; | |
} | |
function getBytes(bytes32 _key) external view returns (bytes memory) { | |
return bytesStorage[_key]; | |
} | |
function getBool(bytes32 _key) external view returns (bool) { | |
return boolStorage[_key]; | |
} | |
function getInt(bytes32 _key) external view returns (int) { | |
return intStorage[_key]; | |
} | |
function getBytes32(bytes32 _key) external view returns (bytes32) { | |
return bytes32Storage[_key]; | |
} | |
// Set | |
function setAddress(bytes32 _key, address _value) external onlyNetworkContract { | |
addressStorage[_key] = _value; | |
} | |
function setUint(bytes32 _key, uint _value) external onlyNetworkContract { | |
uIntStorage[_key] = _value; | |
} | |
function setString(bytes32 _key, string memory _value) public onlyNetworkContract { | |
stringStorage[_key] = _value; | |
} | |
function setBytes(bytes32 _key, bytes memory _value) public onlyNetworkContract { | |
bytesStorage[_key] = _value; | |
} | |
function setBool(bytes32 _key, bool _value) external onlyNetworkContract { | |
boolStorage[_key] = _value; | |
} | |
function setInt(bytes32 _key, int _value) external onlyNetworkContract { | |
intStorage[_key] = _value; | |
} | |
function setBytes32(bytes32 _key, bytes32 _value) external onlyNetworkContract { | |
bytes32Storage[_key] = _value; | |
} | |
// Delete | |
function deleteAddress(bytes32 _key) external onlyNetworkContract { | |
delete addressStorage[_key]; | |
} | |
function deleteUint(bytes32 _key) external onlyNetworkContract { | |
delete uIntStorage[_key]; | |
} | |
function deleteString(bytes32 _key) external onlyNetworkContract { | |
delete stringStorage[_key]; | |
} | |
function deleteBytes(bytes32 _key) external onlyNetworkContract { | |
delete bytesStorage[_key]; | |
} | |
function deleteBool(bytes32 _key) external onlyNetworkContract { | |
delete boolStorage[_key]; | |
} | |
function deleteInt(bytes32 _key) external onlyNetworkContract { | |
delete intStorage[_key]; | |
} | |
function deleteBytes32(bytes32 _key) external onlyNetworkContract { | |
delete bytes32Storage[_key]; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity >=0.5.14 <0.6.0; | |
contract Proxy { | |
address private delegate; | |
address private owner = msg.sender; | |
// allows us to update where the proxy contract points to | |
function upgradeDelegate(address newDelegateAddress) public { | |
require(msg.sender == owner, "Sender is not owner"); | |
delegate = newDelegateAddress; | |
} | |
// fallback function | |
function() external payable { | |
assembly { | |
let _target := sload(0) | |
calldatacopy(0x0, 0x0, calldatasize) | |
let result := delegatecall(gas(), _target, 0x0, calldatasize, 0x0, 0) | |
returndatacopy(0x0, 0x0, returndatasize) | |
switch result case 0 {revert(0, 0)} default {return (0, returndatasize)} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity >=0.5.14 <0.6.0; | |
contract StringListStorage { | |
EternalStorage es; | |
constructor(address _es) public { | |
es = EternalStorage(_es); | |
} | |
// Get | |
function getListLength(bytes32 _key) external view returns (uint) { | |
return es.getUint(keccak256(abi.encodePacked(_key, "length"))); | |
} | |
function getListItem(bytes32 _key, uint _index) external view returns (string memory) { | |
return es.getString(keccak256(abi.encodePacked(_key, "item", _index))); | |
} | |
function getListIndexOf(bytes32 _key, string memory _value) public view returns (int) { | |
uint length = es.getUint(keccak256(abi.encodePacked(_key, "length"))); | |
for (uint index = 0; index < length; ++index) { | |
string memory value = es.getString(keccak256(abi.encodePacked(_key, "item", index))); | |
if (keccak256(abi.encodePacked(value)) == keccak256(abi.encodePacked(_value))) { | |
return int(index); | |
} | |
} | |
return -1; | |
} | |
// Set | |
function setListItem(bytes32 _key, uint _index, string memory _value) public { | |
require(_index < es.getUint(keccak256(abi.encodePacked(_key, "length"))), "List index out of bounds"); | |
es.setString(keccak256(abi.encodePacked(_key, "item", _index)), _value); | |
} | |
function pushListItem(bytes32 _key, string memory _value) public { | |
uint length = es.getUint(keccak256(abi.encodePacked(_key, "length"))); | |
es.setString(keccak256(abi.encodePacked(_key, "item", length)), _value); | |
es.setUint(keccak256(abi.encodePacked(_key, "length")), length + 1); | |
} | |
function removeUnorderedListItem(bytes32 _key, uint _index) external { | |
require(_index < es.getUint(keccak256(abi.encodePacked(_key, "length"))), "List index out of bounds"); | |
uint length = es.getUint(keccak256(abi.encodePacked(_key, "length"))); | |
if (_index < length - 1) { | |
string memory lastItem = es.getString(keccak256(abi.encodePacked(_key, "item", length - 1))); | |
es.setString(keccak256(abi.encodePacked(_key, "item", _index)), lastItem); | |
} | |
es.setUint(keccak256(abi.encodePacked(_key, "length")), length - 1); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity >=0.5.14 <0.6.0; | |
contract StringListStorage { | |
EternalStorage es; | |
constructor(address _es) public { | |
es = EternalStorage(_es); | |
} | |
// Get | |
function getListLength(bytes32 _key) external view returns (uint) { | |
return es.getUint(keccak256(abi.encodePacked(_key, "length"))); | |
} | |
function getListItem(bytes32 _key, uint _index) external view returns (string memory) { | |
return es.getString(keccak256(abi.encodePacked(_key, "item", _index))); | |
} | |
function getListIndexOf(bytes32 _key, string memory _value) public view returns (int) { | |
uint length = es.getUint(keccak256(abi.encodePacked(_key, "length"))); | |
for (uint index = 0; index < length; ++index) { | |
string memory value = es.getString(keccak256(abi.encodePacked(_key, "item", index))); | |
if (keccak256(abi.encodePacked(value)) == keccak256(abi.encodePacked(_value))) { | |
return int(index); | |
} | |
} | |
return -1; | |
} | |
// Set | |
function setListItem(bytes32 _key, uint _index, string memory _value) onlyNetworkContracts public { | |
require(_index < es.getUint(keccak256(abi.encodePacked(_key, "length"))), "List index out of bounds"); | |
es.setString(keccak256(abi.encodePacked(_key, "item", _index)), _value); | |
} | |
function pushListItem(bytes32 _key, string memory _value) onlyNetworkContracts public { | |
uint length = es.getUint(keccak256(abi.encodePacked(_key, "length"))); | |
es.setString(keccak256(abi.encodePacked(_key, "item", length)), _value); | |
es.setUint(keccak256(abi.encodePacked(_key, "length")), length + 1); | |
} | |
function removeUnorderedListItem(bytes32 _key, uint _index) onlyNetworkContracts external { | |
require(_index < es.getUint(keccak256(abi.encodePacked(_key, "length"))), "List index out of bounds"); | |
uint length = es.getUint(keccak256(abi.encodePacked(_key, "length"))); | |
if (_index < length - 1) { | |
string memory lastItem = es.getString(keccak256(abi.encodePacked(_key, "item", length - 1))); | |
es.setString(keccak256(abi.encodePacked(_key, "item", _index)), lastItem); | |
} | |
es.setUint(keccak256(abi.encodePacked(_key, "length")), length - 1); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment