Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Eternal Storage by Decentralized DNS Example
The blog post that explains how these contracts work can be found at:
https://hackernoon.com/eternal-storage-building-dapps-for-the-future-stl3xre
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))
) ;
}
}
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)));
}
}
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;
}
}
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;
}
}
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;
}
}
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;
}
}
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;
}
}
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;
}
}
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;
}
}
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];
}
}
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)}
}
}
}
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);
}
}
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
You can’t perform that action at this time.