From 47455a56ec601417346e12787817c1470d35da1d Mon Sep 17 00:00:00 2001 From: Felipe Forbeck Date: Wed, 2 Jun 2021 09:55:23 -0300 Subject: [PATCH] Initial version of DaoArtifacts (#293) * 1st version of DaoArtifacts * reduced storage costs and using msg.sender as owner * remove struct * added logs/ folder Co-authored-by: David Roon --- .gitignore | 1 - contracts/utils/DaoArtifacts.sol | 108 ++++++++++++++++++++++++++++ logs/.gitkeep | 0 test/utils/dao-artifacts.test.js | 120 +++++++++++++++++++++++++++++++ utils/ContractUtil.js | 3 + 5 files changed, 231 insertions(+), 1 deletion(-) create mode 100644 contracts/utils/DaoArtifacts.sol create mode 100644 logs/.gitkeep create mode 100644 test/utils/dao-artifacts.test.js diff --git a/.gitignore b/.gitignore index e3cedfcd8..641249bcd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ # Logs -logs *.log npm-debug.log* yarn-debug.log* diff --git a/contracts/utils/DaoArtifacts.sol b/contracts/utils/DaoArtifacts.sol new file mode 100644 index 000000000..426a8b52a --- /dev/null +++ b/contracts/utils/DaoArtifacts.sol @@ -0,0 +1,108 @@ +pragma solidity ^0.8.0; + +// SPDX-License-Identifier: MIT + +/** +MIT License + +Copyright (c) 2020 Openlaw + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ + +contract DaoArtifacts { + enum ArtifactType {ADAPTER, EXTENSION} + + // Mapping from Artifact Name => (Owner Address => (Version => Adapters Address)) + mapping(bytes32 => mapping(address => mapping(bytes32 => address))) + public adapters; + + // Mapping from Artifact Name => (Owner Address => (Version => ExtensionsAddress)) + mapping(bytes32 => mapping(address => mapping(bytes32 => address))) + public extensionsFactories; + + event NewArtifact( + bytes32 _id, + address _owner, + bytes32 _version, + address _address, + ArtifactType _type + ); + + /** + * @notice Adds the adapter address to the storage + * @param _id The id of the adapter (sha3). + * @param _version The version of the adapter. + * @param _address The address of the adapter to be stored. + */ + function addAdapter( + bytes32 _id, + bytes32 _version, + address _address + ) external { + address _owner = msg.sender; + adapters[_id][_owner][_version] = _address; + emit NewArtifact(_id, _owner, _version, _address, ArtifactType.ADAPTER); + } + + /** + * @notice Adds the extension factory address to the storage. + * @param _id The id of the extension factory (sha3). + * @param _version The version of the extension factory. + * @param _address The address of the extension factory to be stored. + */ + function addExtensionFactory( + bytes32 _id, + bytes32 _version, + address _address + ) external { + address _owner = msg.sender; + extensionsFactories[_id][_owner][_version] = _address; + emit NewArtifact( + _id, + _owner, + _version, + _address, + ArtifactType.EXTENSION + ); + } + + /** + * @notice Retrieves the adapter/extension factory address from the storage. + * @param _id The id of the adapter/extension factory (sha3). + * @param _owner The address of the owner of the adapter/extension factory. + * @param _version The version of the adapter/extension factory. + * @param _type The type of the artifact, 0 = Adapter, 1 = Extension Factory. + * @return The address of the adapter/extension factory if any. + */ + function getArtifactAddress( + bytes32 _id, + address _owner, + bytes32 _version, + ArtifactType _type + ) external view returns (address) { + if (_type == ArtifactType.ADAPTER) { + return adapters[_id][_owner][_version]; + } + if (_type == ArtifactType.EXTENSION) { + return extensionsFactories[_id][_owner][_version]; + } + return address(0x0); + } +} diff --git a/logs/.gitkeep b/logs/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/test/utils/dao-artifacts.test.js b/test/utils/dao-artifacts.test.js new file mode 100644 index 000000000..451264daa --- /dev/null +++ b/test/utils/dao-artifacts.test.js @@ -0,0 +1,120 @@ +// Whole-script strict mode syntax +"use strict"; + +const expectEvent = require("@openzeppelin/test-helpers/src/expectEvent"); +const { toBN } = require("web3-utils"); +/** +MIT License + +Copyright (c) 2020 Openlaw + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ +const { sha3 } = require("../../utils/ContractUtil.js"); + +const { accounts, expect, DaoArtifacts } = require("../../utils/OZTestUtil.js"); + +describe("Utils - DaoArtifacts", () => { + it("should be possible to create a dao artifacts contract", async () => { + const daoArtifacts = await DaoArtifacts.new(); + expect(daoArtifacts.address).to.not.be.null; + expect(daoArtifacts.address).to.not.be.equal( + "0x0000000000000000000000000000000000000000" + ); + }); + + it("should be possible add a new adapter to the dao artifacts storage", async () => { + const daoArtifacts = await DaoArtifacts.new(); + const owner = accounts[2]; + const adapterAddress = accounts[9]; + const res = await daoArtifacts.addAdapter( + sha3("adapter1"), + sha3("v1.0.0"), + adapterAddress, + { from: owner } + ); + expectEvent(res, "NewArtifact", { + _id: sha3("adapter1"), + _owner: owner, + _version: sha3("v1.0.0"), + _address: adapterAddress, + _type: toBN("0"), + }); + }); + + it("should be possible get the adapter address from the dao artifacts storage", async () => { + const daoArtifacts = await DaoArtifacts.new(); + const owner = accounts[2]; + const adapterAddress = accounts[9]; + + await daoArtifacts.addAdapter( + sha3("adapter1"), + sha3("v1.0.0"), + adapterAddress, + { from: owner } + ); + + const address = await daoArtifacts.getArtifactAddress( + sha3("adapter1"), + owner, + sha3("v1.0.0"), + toBN("0") //Type = adapter + ); + expect(address).to.be.equal(adapterAddress); + }); + + it("should be possible add a new extension factory to the dao artifacts storage", async () => { + const daoArtifacts = await DaoArtifacts.new(); + const owner = accounts[2]; + const extensionAddress = accounts[9]; + const res = await daoArtifacts.addExtensionFactory( + sha3("extFactory1"), + sha3("v1.0.0"), + extensionAddress, + { from: owner } + ); + expectEvent(res, "NewArtifact", { + _id: sha3("extFactory1"), + _owner: owner, + _version: sha3("v1.0.0"), + _address: extensionAddress, + _type: toBN("1"), + }); + }); + + it("should be possible get the extension factory address from the dao artifacts storage", async () => { + const daoArtifacts = await DaoArtifacts.new(); + const owner = accounts[2]; + const extensionAddress = accounts[9]; + await daoArtifacts.addExtensionFactory( + sha3("extFactory1"), + sha3("v1.0.0"), + extensionAddress, + { from: owner } + ); + + const address = await daoArtifacts.getArtifactAddress( + sha3("extFactory1"), + owner, + sha3("v1.0.0"), + toBN("1") //Type = adapter + ); + expect(address).to.be.equal(extensionAddress); + }); +}); diff --git a/utils/ContractUtil.js b/utils/ContractUtil.js index 5fe21608e..8b2055274 100644 --- a/utils/ContractUtil.js +++ b/utils/ContractUtil.js @@ -95,6 +95,9 @@ const contracts = { CouponOnboardingContract: "./adapters/CouponOnboardingContract", TributeContract: "./adapters/TributeContract", TributeNFTContract: "./adapters/TributeNFTContract", + + // Utils + DaoArtifacts: "./utils/DaoArtifacts", }; module.exports = {