Last active
June 6, 2022 17:27
-
-
Save panukettu/cef39bd5f1b6d127b4b929663e43fd06 to your computer and use it in GitHub Desktop.
Diamond with free function storage
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
// SPDX-License-Identifier: MIT | |
pragma solidity 0.8.13; | |
import {s} from './Storage.sol'; | |
contract Logic { | |
function setFoo(string memory newFoo) external { | |
s()._setFoo(newFoo); | |
} | |
function foo() external view returns (string memory) { | |
return s()._getFoo(); | |
} | |
} |
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
// SPDX-License-Identifier: MIT | |
pragma solidity 0.8.13; | |
import {s} from './Storage.sol'; | |
contract Logic2 { | |
function setFoo2(string memory newFoo) external { | |
s()._setFoo(newFoo); | |
} | |
function foo2() external view returns (string memory) { | |
return s()._getFoo(); | |
} | |
} |
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
// SPDX-License-Identifier: MIT | |
pragma solidity 0.8.13; | |
import {s} from './Storage.sol'; | |
import {Logic} from './Logic.sol'; | |
import {Logic2} from './Logic2.sol'; | |
/** | |
* @title Proxy | |
* @custom:dev-run-script tests/proxy.test.js | |
*/ | |
contract Proxy { | |
constructor() payable { | |
Logic logic = new Logic(); | |
Logic2 logic2 = new Logic2(); | |
bytes4[] memory sigs = new bytes4[](2); | |
sigs[0] = logic.setFoo.selector; | |
sigs[1] = logic.foo.selector; | |
s().addRoutes(address(logic), sigs); | |
bytes4[] memory sigs2 = new bytes4[](2); | |
sigs2[0] = logic2.setFoo2.selector; | |
sigs2[1] = logic2.foo2.selector; | |
s().addRoutes(address(logic2), sigs2); | |
} | |
fallback() external payable { | |
// get facet from function selectors | |
address facet = s().target(); | |
require(facet != address(0), '0-addr'); | |
// Execute external function from facet using delegatecall and return any value. | |
assembly { | |
// copy function selector and any arguments | |
calldatacopy(0, 0, calldatasize()) | |
// execute function call using the facet | |
let result := delegatecall(gas(), facet, 0, calldatasize(), 0, 0) | |
// get any return value | |
returndatacopy(0, 0, returndatasize()) | |
// return any return value or error back to the caller | |
switch result | |
case 0 { | |
revert(0, returndatasize()) | |
} | |
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
// Right click on the script name and hit "Run" to execute | |
const { expect } = require("chai"); | |
const { ethers } = require("hardhat"); | |
describe("Proxy", function () { | |
it("should work", async function () { | |
const Proxy = await ethers.getContractFactory("Proxy"); | |
const proxy = await Proxy.deploy(); | |
await proxy.deployed(); | |
const Logic = await ethers.getContractAt('Logic', proxy.address); | |
const Logic2 = await ethers.getContractAt('Logic2', proxy.address); | |
await Logic.setFoo('FooSetFromLogic'); | |
let fooFrom1 = await Logic.foo(); | |
let fooFrom2 = await Logic2.foo2(); | |
expect(fooFrom1).to.equal('FooSetFromLogic'); | |
expect(fooFrom1).to.equal(fooFrom2); | |
await Logic2.setFoo2('FooSetFromLogic2'); | |
fooFrom1 = await Logic.foo(); | |
fooFrom2 = await Logic2.foo2(); | |
expect(fooFrom1).to.equal('FooSetFromLogic2'); | |
console.log('done'); | |
expect(fooFrom1).to.equal(fooFrom2); | |
}); | |
}); |
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
// SPDX-License-Identifier: MIT | |
pragma solidity 0.8.13; | |
struct Route { | |
address destination; | |
bytes4 selector; | |
} | |
struct State { | |
string foo; | |
mapping(bytes4 => Route) routes; | |
} | |
using {_setFoo, _getFoo, addRoutes, target} for State global; | |
function _getFoo(State storage self) view returns (string memory) { | |
return self.foo; | |
} | |
function target(State storage self) view returns (address) { | |
return self.routes[msg.sig].destination; | |
} | |
function addRoutes(State storage self, address destination, bytes4[] memory sigs) { | |
for(uint i; i < sigs.length; i++) { | |
self.routes[sigs[i]] = Route(destination, sigs[i]); | |
} | |
} | |
function _setFoo(State storage self, string memory _newFoo) { | |
self.foo = _newFoo; | |
} | |
function s() pure returns (State storage state) { | |
bytes32 position = keccak256("diamond.storage.file"); | |
assembly { | |
state.slot := position | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment