From 6220f660cbf9e053aee6b49b5f3c9161ac2351be Mon Sep 17 00:00:00 2001 From: 0xdavinchee <0xdavinchee@gmail.com> Date: Mon, 13 Feb 2023 16:11:08 +0200 Subject: [PATCH] [ETHEREUM-CONTRACTS] New web3-operations path for SuperTokenFactory (#1276) * add new updateLogicContracts * add sanity check test - add mock contract - add test to ensure new code is being run * forge install: forge-std v1.3.0 * SuperTokenFactory deploy test * fix framework test * forge install: forge-std v1.3.0 * fix redundant naming * Ops flow cleanup - delete updateLogicContracts() function - delete SuperTokenFactoryHelper - delete _updateSuperTokenLogic function (future updates will no longer follow this path) - use SuperTokenDeployerLibrary.deploySuperTokenLogic to deploy non upgradeable super token - fix breaking tests - create some abstracted functions for deploy external library and linking * cleanup * fork baseline - add fork baseline tests file - rename fork super token factory upgrade test file * fork baseline wip - refactor ForkBaseline: it is responsible for loading the forked framework - add more tests in ForkBaseline - do not run fork tests in the CI * Update CHANGELOG.md * deprecate non upgradeable deploy * fix broken build * Address CI env naming comment https://github.com/superfluid-finance/protocol-monorepo/pull/1276#discussion_r1104197334 * address merge "deployers/*.sol" comment https://github.com/superfluid-finance/protocol-monorepo/pull/1276#discussion_r1104220890 * use consistent immutable var naming https://github.com/superfluid-finance/protocol-monorepo/pull/1276#discussion_r1104205341 * address documentation comment https://github.com/superfluid-finance/protocol-monorepo/pull/1276#discussion_r1104225932 * address scripts artifacts naming change from scripts -> ops-scripts as the test/ops-scripts are testing ops-scripts * address baseline comment https://github.com/superfluid-finance/protocol-monorepo/pull/1276#discussion_r1104241091 * address missing context naming comment https://github.com/superfluid-finance/protocol-monorepo/pull/1276#discussion_r1104244941 * cleanup - change hot-fuzz to match new file format - remove unused UUPSProxy import * duplicate keys makes no sense ty Miao --- .github/workflows/ci.feature.yml | 3 + .gitmodules | 1 + lib/forge-std | 2 +- packages/ethereum-contracts/CHANGELOG.md | 6 + .../gov/SuperfluidGovernanceBase.sol | 3 + .../superfluid/ISuperTokenFactory.sol | 11 +- .../contracts/mocks/SuperTokenFactoryMock.sol | 96 +-- .../superfluid/SuperTokenFactory.sol | 95 +-- .../utils/SuperfluidFrameworkDeployer.sol | 160 ++++- .../SuperfluidCFAv1DeployerLibrary.sol | 28 - .../SuperfluidGovDeployerLibrary.sol | 28 - .../SuperfluidHostDeployerLibrary.sol | 26 - .../SuperfluidIDAv1DeployerLibrary.sol | 22 - .../SuperfluidPeripheryDeployerLibrary.sol | 36 - ...SuperTokenFactoryHelperDeployerLibrary.sol | 25 - .../dev-scripts/deploy-test-framework.js | 48 +- packages/ethereum-contracts/foundry.toml | 1 - .../ops-scripts/deploy-framework.js | 80 ++- packages/ethereum-contracts/package.json | 9 +- .../test/TestEnvironment.ts | 36 +- .../superfluid/SuperTokenFactory.test.ts | 109 +-- .../contracts/superfluid/Superfluid.test.ts | 67 +- .../ForkPolygonSuperTokenFactoryUpgrade.t.sol | 171 +++++ .../test/foundry/deployments/ForkSmoke.t.sol | 632 ++++++++++++++++++ .../deployment.test.js | 0 .../deployment.test.sh | 0 packages/ethereum-contracts/tsconfig.json | 2 +- packages/hot-fuzz/echidna.yaml | 2 +- packages/hot-fuzz/index.js | 14 +- packages/hot-fuzz/truffle-config.js | 2 +- 30 files changed, 1290 insertions(+), 425 deletions(-) delete mode 100644 packages/ethereum-contracts/contracts/utils/deployers/SuperfluidCFAv1DeployerLibrary.sol delete mode 100644 packages/ethereum-contracts/contracts/utils/deployers/SuperfluidGovDeployerLibrary.sol delete mode 100644 packages/ethereum-contracts/contracts/utils/deployers/SuperfluidHostDeployerLibrary.sol delete mode 100644 packages/ethereum-contracts/contracts/utils/deployers/SuperfluidIDAv1DeployerLibrary.sol delete mode 100644 packages/ethereum-contracts/contracts/utils/deployers/SuperfluidPeripheryDeployerLibrary.sol delete mode 100644 packages/ethereum-contracts/contracts/utils/deployers/SuperfluidSuperTokenFactoryHelperDeployerLibrary.sol create mode 100644 packages/ethereum-contracts/test/foundry/deployments/ForkPolygonSuperTokenFactoryUpgrade.t.sol create mode 100644 packages/ethereum-contracts/test/foundry/deployments/ForkSmoke.t.sol rename packages/ethereum-contracts/test/{scripts => ops-scripts}/deployment.test.js (100%) rename packages/ethereum-contracts/test/{scripts => ops-scripts}/deployment.test.sh (100%) diff --git a/.github/workflows/ci.feature.yml b/.github/workflows/ci.feature.yml index 0ac33ba771..36b0f60fe0 100644 --- a/.github/workflows/ci.feature.yml +++ b/.github/workflows/ci.feature.yml @@ -79,6 +79,9 @@ jobs: - name: Test ethereum-contracts run: | yarn workspace @superfluid-finance/ethereum-contracts test + env: + # NOTE: This is currently unset and fork tests are not being run + POLYGON_MAINNET_ARCHIVE_PROVIDER_URL: ${{ secrets.POLYGON_MAINNET_ARCHIVE_PROVIDER_URL }} coverage-ethereum-contracts: name: Build and test coverage of ethereum-contracts (Feature Branch) diff --git a/.gitmodules b/.gitmodules index 888d42dcd9..b2061c77b0 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,4 @@ [submodule "lib/forge-std"] path = lib/forge-std url = https://github.com/foundry-rs/forge-std + branch = v1.3.0 diff --git a/lib/forge-std b/lib/forge-std index 5927f70bd4..066ff16c5c 160000 --- a/lib/forge-std +++ b/lib/forge-std @@ -1 +1 @@ -Subproject commit 5927f70bd40e0967d1e4e2c18f0c982ba9a02957 +Subproject commit 066ff16c5c03e6f931cd041fd366bc4be1fae82a diff --git a/packages/ethereum-contracts/CHANGELOG.md b/packages/ethereum-contracts/CHANGELOG.md index 5c33d3791f..48a7a6c6e2 100644 --- a/packages/ethereum-contracts/CHANGELOG.md +++ b/packages/ethereum-contracts/CHANGELOG.md @@ -7,6 +7,12 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm ### Added - bump solc to 0.8.18 +### Breaking +- `SuperTokenFactory` contract no longer takes `SuperTokenHelper` contract in its constructor + - Migration: Pass in a deployed `SuperToken` (logic) contract address to `SuperTokenFactory` constructor instead + +### Changed +- `_superTokenLogic` field in `SuperTokenFactory` contract is now a public immutable field and the previous storage variable is removed ### [v1.5.0] - 2022-12-19 ### Added diff --git a/packages/ethereum-contracts/contracts/gov/SuperfluidGovernanceBase.sol b/packages/ethereum-contracts/contracts/gov/SuperfluidGovernanceBase.sol index 2e4e20291e..83395d1618 100644 --- a/packages/ethereum-contracts/contracts/gov/SuperfluidGovernanceBase.sol +++ b/packages/ethereum-contracts/contracts/gov/SuperfluidGovernanceBase.sol @@ -547,6 +547,9 @@ abstract contract SuperfluidGovernanceBase is ISuperfluidGovernance emit AppFactoryAuthorizationChanged(host, factory, false); } + // NOTE: we currently don't check anything with host in + // SuperfluidGovernanceII and only assert that the host passed + // is the correct host in TestGovernance modifier onlyAuthorized(ISuperfluid host) { _requireAuthorised(host); _; diff --git a/packages/ethereum-contracts/contracts/interfaces/superfluid/ISuperTokenFactory.sol b/packages/ethereum-contracts/contracts/interfaces/superfluid/ISuperTokenFactory.sol index aa72ff601f..f0400baedd 100644 --- a/packages/ethereum-contracts/contracts/interfaces/superfluid/ISuperTokenFactory.sol +++ b/packages/ethereum-contracts/contracts/interfaces/superfluid/ISuperTokenFactory.sol @@ -17,11 +17,12 @@ interface ISuperTokenFactory { /************************************************************************** * Errors *************************************************************************/ - error SUPER_TOKEN_FACTORY_ALREADY_EXISTS(); // 0x91d67972 - error SUPER_TOKEN_FACTORY_DOES_NOT_EXIST(); // 0x872cac48 - error SUPER_TOKEN_FACTORY_UNINITIALIZED(); // 0x1b39b9b4 - error SUPER_TOKEN_FACTORY_ONLY_HOST(); // 0x478b8e83 - error SUPER_TOKEN_FACTORY_ZERO_ADDRESS(); // 0x305c9e82 + error SUPER_TOKEN_FACTORY_ALREADY_EXISTS(); // 0x91d67972 + error SUPER_TOKEN_FACTORY_DOES_NOT_EXIST(); // 0x872cac48 + error SUPER_TOKEN_FACTORY_UNINITIALIZED(); // 0x1b39b9b4 + error SUPER_TOKEN_FACTORY_ONLY_HOST(); // 0x478b8e83 + error SUPER_TOKEN_FACTORY_NON_UPGRADEABLE_IS_DEPRECATED(); // 0x478b8e83 + error SUPER_TOKEN_FACTORY_ZERO_ADDRESS(); // 0x305c9e82 /** * @dev Get superfluid host contract address diff --git a/packages/ethereum-contracts/contracts/mocks/SuperTokenFactoryMock.sol b/packages/ethereum-contracts/contracts/mocks/SuperTokenFactoryMock.sol index 146d876c13..ecd5ca79e0 100644 --- a/packages/ethereum-contracts/contracts/mocks/SuperTokenFactoryMock.sol +++ b/packages/ethereum-contracts/contracts/mocks/SuperTokenFactoryMock.sol @@ -3,18 +3,21 @@ pragma solidity 0.8.18; import { SuperTokenMock } from "./SuperTokenMock.sol"; import { - SuperTokenFactoryBase, - ISuperfluid + ISuperfluid, + ISuperToken, + SuperToken, + SuperTokenFactoryBase } from "../superfluid/SuperTokenFactory.sol"; contract SuperTokenFactoryStorageLayoutTester is SuperTokenFactoryBase { - constructor( - ISuperfluid host + ISuperfluid host, + ISuperToken superTokenLogic ) - SuperTokenFactoryBase(host) - // solhint-disable-next-line no-empty-blocks + SuperTokenFactoryBase(host, superTokenLogic) + // solhint-disable-next-line no-empty-blocks { + } // @dev Make sure the storage layout never change over the course of the development @@ -24,73 +27,72 @@ contract SuperTokenFactoryStorageLayoutTester is SuperTokenFactoryBase { // Initializable bool _initialized and bool _initialized - assembly { slot:= _superTokenLogic.slot offset := _superTokenLogic.offset } - require (slot == 0 && offset == 2, "_superTokenLogic changed location"); + assembly { slot:= _superTokenLogicDeprecated.slot offset := _superTokenLogicDeprecated.offset } + require (slot == 0 && offset == 2, "_superTokenLogicDeprecated changed location"); assembly { slot := _canonicalWrapperSuperTokens.slot offset := _canonicalWrapperSuperTokens.offset } require(slot == 1 && offset == 0, "_canonicalWrapperSuperTokens changed location"); } - // dummy impl - function createSuperTokenLogic(ISuperfluid) - external pure override - returns (address) - { - return address(0); + function createSuperTokenLogic( + ISuperfluid // host + ) external override returns (address) { + return address(_SUPER_TOKEN_LOGIC); } } -// spliting this off because the contract is getting bigger -contract SuperTokenFactoryMockHelper { - function create(ISuperfluid host, uint256 waterMark) - external - returns (address logic) +contract SuperTokenFactoryUpdateLogicContractsTester is SuperTokenFactoryBase { + uint256 public newVariable; + + constructor( + ISuperfluid host, + ISuperToken superTokenLogic + ) + SuperTokenFactoryBase(host, superTokenLogic) + // solhint-disable-next-line no-empty-blocks { - SuperTokenMock superToken = new SuperTokenMock(host, waterMark); - return address(superToken); + } -} -contract SuperTokenFactoryMock is SuperTokenFactoryBase -{ - SuperTokenFactoryMockHelper immutable private _helper; + function createSuperTokenLogic( + ISuperfluid // host + ) external override returns (address) { + return address(_SUPER_TOKEN_LOGIC); + } +} +contract SuperTokenFactoryMock is SuperTokenFactoryBase { constructor( ISuperfluid host, - SuperTokenFactoryMockHelper helper + ISuperToken superTokenLogic ) - SuperTokenFactoryBase(host) + SuperTokenFactoryBase(host, superTokenLogic) + // solhint-disable-next-line no-empty-blocks { - _helper = helper; + } - function createSuperTokenLogic(ISuperfluid host) - external override - returns (address logic) - { - return _helper.create(host, 0); + function createSuperTokenLogic( + ISuperfluid // host + ) external override returns (address) { + return address(_SUPER_TOKEN_LOGIC); } } -contract SuperTokenFactoryMock42 is SuperTokenFactoryBase -{ - - SuperTokenFactoryMockHelper immutable private _helper; - +contract SuperTokenFactoryMock42 is SuperTokenFactoryBase { constructor( ISuperfluid host, - SuperTokenFactoryMockHelper helper + ISuperToken superTokenLogic ) - SuperTokenFactoryBase(host) + SuperTokenFactoryBase(host, superTokenLogic) + // solhint-disable-next-line no-empty-blocks { - _helper = helper; - } - function createSuperTokenLogic(ISuperfluid host) - external override - returns (address logic) - { - return _helper.create(host, 42); } + function createSuperTokenLogic( + ISuperfluid // host + ) external override returns (address) { + return address(_SUPER_TOKEN_LOGIC); + } } diff --git a/packages/ethereum-contracts/contracts/superfluid/SuperTokenFactory.sol b/packages/ethereum-contracts/contracts/superfluid/SuperTokenFactory.sol index 806917c728..ca867c88be 100644 --- a/packages/ethereum-contracts/contracts/superfluid/SuperTokenFactory.sol +++ b/packages/ethereum-contracts/contracts/superfluid/SuperTokenFactory.sol @@ -1,21 +1,17 @@ // SPDX-License-Identifier: AGPLv3 pragma solidity 0.8.18; +import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; import { ISuperTokenFactory, ISuperToken, IERC20, ERC20WithTokenInfo } from "../interfaces/superfluid/ISuperTokenFactory.sol"; - import { ISuperfluid } from "../interfaces/superfluid/ISuperfluid.sol"; -import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; - import { UUPSProxy } from "../upgradability/UUPSProxy.sol"; import { UUPSProxiable } from "../upgradability/UUPSProxiable.sol"; - import { SuperToken } from "../superfluid/SuperToken.sol"; - import { FullUpgradableSuperTokenProxy } from "./FullUpgradableSuperTokenProxy.sol"; abstract contract SuperTokenFactoryBase is @@ -27,14 +23,28 @@ abstract contract SuperTokenFactoryBase is address superToken; } + /************************************************************************** + * Immutable Variables + **************************************************************************/ + + // solhint-disable-next-line var-name-mixedcase + ISuperToken immutable public _SUPER_TOKEN_LOGIC; + + ISuperfluid immutable internal _host; + + /************************************************************************** + * Storage Variables + **************************************************************************/ + /* WARNING: NEVER RE-ORDER VARIABLES! Including the base contracts. Always double-check that new variables are added APPEND-ONLY. Re-ordering variables can permanently BREAK the deployed proxy contract. */ - ISuperfluid immutable internal _host; - - ISuperToken internal _superTokenLogic; + // @dev This is the old SuperToken logic contract that is no longer used + // It is kept here for backwards compatibility due to the fact that we cannot + // change the storage layout of the contract + ISuperToken internal _superTokenLogicDeprecated; /// @notice A mapping from underlying token addresses to canonical wrapper super token addresses /// @dev Reasoning: (1) provide backwards compatibility for existing listed wrapper super tokens @@ -49,9 +59,24 @@ abstract contract SuperTokenFactoryBase is error SUPER_TOKEN_FACTORY_ONLY_GOVERNANCE_OWNER(); constructor( - ISuperfluid host + ISuperfluid host, + ISuperToken superTokenLogic ) { _host = host; + + // SuperToken logic is now deployed prior to new factory logic deployment + // and passed in as a parameter to SuperTokenFactory constructor + _SUPER_TOKEN_LOGIC = superTokenLogic; + + // @note this function call is commented out on the first upgrade + // https://polygonscan.com/address/0x092462ef87bdd081a6346102b0be134ff63da01b#code + // the logic contract has _updateSuperTokenLogic and uses: this.createSuperTokenLogic + // which calls .castrate() on the logic contract, so if we call it here again, + // it will revert the first time, however we MUST uncomment it after subsequent + // updates to the logic contract so that the super token logic contract is initialized + // here + // UUPSProxiable(address(_SUPER_TOKEN_LOGIC)).castrate(); + emit SuperTokenLogicCreated(_SUPER_TOKEN_LOGIC); } /// @inheritdoc ISuperTokenFactory @@ -68,10 +93,12 @@ abstract contract SuperTokenFactoryBase is **************************************************************************/ /// @inheritdoc ISuperTokenFactory function initialize() - external override + external + override initializer // OpenZeppelin Initializable + // solhint-disable-next-line no-empty-blocks { - _updateSuperTokenLogic(); + } function proxiableUUID() public pure override returns (bytes32) { @@ -83,14 +110,6 @@ abstract contract SuperTokenFactoryBase is revert SUPER_TOKEN_FACTORY_ONLY_HOST(); } _updateCodeAddress(newAddress); - _updateSuperTokenLogic(); - } - - function _updateSuperTokenLogic() private { - // use external call to trigger the new code to update the super token logic contract - _superTokenLogic = SuperToken(this.createSuperTokenLogic(_host)); - UUPSProxiable(address(_superTokenLogic)).castrate(); - emit SuperTokenLogicCreated(_superTokenLogic); } /************************************************************************** @@ -101,7 +120,7 @@ abstract contract SuperTokenFactoryBase is external view override returns (ISuperToken) { - return _superTokenLogic; + return _SUPER_TOKEN_LOGIC; } function createSuperTokenLogic(ISuperfluid host) external virtual returns (address logic); @@ -137,7 +156,7 @@ abstract contract SuperTokenFactoryBase is ); // set the implementation/logic contract address for the newly deployed proxy - proxy.initializeProxy(address(_superTokenLogic)); + proxy.initializeProxy(address(_SUPER_TOKEN_LOGIC)); // cast it as the same type as the logic contract ISuperToken superToken = ISuperToken(address(proxy)); @@ -175,11 +194,11 @@ abstract contract SuperTokenFactoryBase is } if (upgradability == Upgradability.NON_UPGRADABLE) { - superToken = ISuperToken(this.createSuperTokenLogic(_host)); + revert SUPER_TOKEN_FACTORY_NON_UPGRADEABLE_IS_DEPRECATED(); } else if (upgradability == Upgradability.SEMI_UPGRADABLE) { UUPSProxy proxy = new UUPSProxy(); // initialize the wrapper - proxy.initializeProxy(address(_superTokenLogic)); + proxy.initializeProxy(address(_SUPER_TOKEN_LOGIC)); superToken = ISuperToken(address(proxy)); } else /* if (type == Upgradability.FULL_UPGRADABLE) */ { FullUpgradableSuperTokenProxy proxy = new FullUpgradableSuperTokenProxy(); @@ -226,7 +245,7 @@ abstract contract SuperTokenFactoryBase is // odd solidity stuff.. // NOTE payable necessary because UUPSProxy has a payable fallback function address payable a = payable(address(uint160(customSuperTokenProxy))); - UUPSProxy(a).initializeProxy(address(_superTokenLogic)); + UUPSProxy(a).initializeProxy(address(_SUPER_TOKEN_LOGIC)); emit CustomSuperTokenCreated(ISuperToken(customSuperTokenProxy)); } @@ -298,15 +317,6 @@ abstract contract SuperTokenFactoryBase is } } -// splitting this off because the contract is getting bigger -contract SuperTokenFactoryHelper { - function create(ISuperfluid host) - external - returns (address logic) - { - return address(new SuperToken(host)); - } -} contract SuperTokenFactory is SuperTokenFactoryBase { @@ -315,22 +325,25 @@ contract SuperTokenFactory is SuperTokenFactoryBase variables are added APPEND-ONLY. Re-ordering variables can permanently BREAK the deployed proxy contract. */ - SuperTokenFactoryHelper immutable private _helper; - constructor( ISuperfluid host, - SuperTokenFactoryHelper helper + ISuperToken superTokenLogic ) - SuperTokenFactoryBase(host) + SuperTokenFactoryBase(host, superTokenLogic) // solhint-disable-next-line no-empty-blocks { - _helper = helper; } - function createSuperTokenLogic(ISuperfluid host) + /// DEPRECATED + /// This function will return the super token logic + /// that was set in the constructor + /// TO BE DELETED IN THE NEXT UPGRADE + function createSuperTokenLogic( + ISuperfluid // host + ) external override - returns (address logic) + returns (address) { - return _helper.create(host); + return address(_SUPER_TOKEN_LOGIC); } } diff --git a/packages/ethereum-contracts/contracts/utils/SuperfluidFrameworkDeployer.sol b/packages/ethereum-contracts/contracts/utils/SuperfluidFrameworkDeployer.sol index f530b0c8b5..aebd3baad5 100644 --- a/packages/ethereum-contracts/contracts/utils/SuperfluidFrameworkDeployer.sol +++ b/packages/ethereum-contracts/contracts/utils/SuperfluidFrameworkDeployer.sol @@ -1,34 +1,13 @@ // SPDX-License-Identifier: AGPLv3 pragma solidity ^0.8.0; -import { - SuperfluidGovDeployerLibrary -} from "./deployers/SuperfluidGovDeployerLibrary.sol"; - -import { - SuperfluidHostDeployerLibrary -} from "./deployers/SuperfluidHostDeployerLibrary.sol"; -import { - SuperfluidCFAv1DeployerLibrary -} from "./deployers/SuperfluidCFAv1DeployerLibrary.sol"; -import { - SuperfluidIDAv1DeployerLibrary -} from "./deployers/SuperfluidIDAv1DeployerLibrary.sol"; -import { - SuperfluidSuperTokenFactoryHelperDeployerLibrary -} from "./deployers/SuperfluidSuperTokenFactoryHelperDeployerLibrary.sol"; -import { - SuperfluidPeripheryDeployerLibrary -} from "./deployers/SuperfluidPeripheryDeployerLibrary.sol"; import { CFAv1Forwarder } from "./CFAv1Forwarder.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; - -import { UUPSProxy } from "../upgradability/UUPSProxy.sol"; - -import { Superfluid } from "../superfluid/Superfluid.sol"; import { - ISuperfluidToken -} from "../interfaces/superfluid/ISuperfluidToken.sol"; + ISuperfluid, + ISuperfluidToken, + Superfluid +} from "../superfluid/Superfluid.sol"; import { TestGovernance } from "./TestGovernance.sol"; import { ConstantFlowAgreementV1 @@ -39,13 +18,11 @@ import { import { ISuperTokenFactory, SuperTokenFactory, - SuperTokenFactoryHelper, ERC20WithTokenInfo } from "../superfluid/SuperTokenFactory.sol"; -import { SuperToken } from "../superfluid/SuperToken.sol"; +import { ISuperToken, SuperToken } from "../superfluid/SuperToken.sol"; import { TestResolver } from "./TestResolver.sol"; import { SuperfluidLoader } from "./SuperfluidLoader.sol"; - import { SETHProxy } from "../tokens/SETH.sol"; import { PureSuperToken } from "../tokens/PureSuperToken.sol"; import { @@ -55,7 +32,6 @@ import { IPureSuperToken } from "../interfaces/tokens/IPureSuperToken.sol"; import { ISETH } from "../interfaces/tokens/ISETH.sol"; import { CFAv1Library } from "../apps/CFAv1Library.sol"; import { IDAv1Library } from "../apps/IDAv1Library.sol"; - import { TestToken } from "./TestToken.sol"; /// @title Superfluid Framework Deployer @@ -143,13 +119,14 @@ contract SuperfluidFrameworkDeployer { // Register InstantDistributionAgreementV1 with Governance testGovernance.registerAgreementClass(host, address(idaV1)); - // Deploy SuperTokenFactoryHelper - SuperTokenFactoryHelper superTokenFactoryHelper = SuperfluidSuperTokenFactoryHelperDeployerLibrary - .deploySuperTokenFactoryHelper(); + // Deploy canonical SuperToken logic contract + SuperToken superTokenLogic = SuperToken( + SuperTokenDeployerLibrary.deploySuperTokenLogic(host) + ); // Deploy SuperTokenFactory superTokenFactory = SuperfluidPeripheryDeployerLibrary - .deploySuperTokenFactory(host, superTokenFactoryHelper); + .deploySuperTokenFactory(host, superTokenLogic); // 'Update' code with Governance and register SuperTokenFactory with Superfluid testGovernance.updateContracts( @@ -303,4 +280,119 @@ contract SuperfluidFrameworkDeployer { testResolver.set(_resolverKey, address(_superTokenAddress)); } } -} \ No newline at end of file +} + +/************************************************************************** + * External Libraries + **************************************************************************/ + +/// @title SuperfluidGovDeployerLibrary +/// @author Superfluid +/// @notice An external library that deploys the Superfluid TestGovernance contract with additional functions +/// @dev This library is used for testing purposes only, not deployments to test OR production networks +library SuperfluidGovDeployerLibrary { + /// @notice deploys the Superfluid TestGovernance Contract + /// @return newly deployed TestGovernance contract + function deployTestGovernance() external returns (TestGovernance) { + return new TestGovernance(); + } + + /// @notice transfers ownership of _gov to _newOwner + /// @dev _gov must be deployed from this contract + /// @param _gov address of the TestGovernance contract + /// @param _newOwner the new owner of the governance contract + function transferOwnership( + TestGovernance _gov, + address _newOwner + ) external { + _gov.transferOwnership(_newOwner); + } +} + +/// @title SuperfluidHostDeployerLibrary +/// @author Superfluid +/// @notice An external library that deploys the Superfluid Host contract with additional functions. +/// @dev This library is used for testing purposes only, not deployments to test OR production networks +library SuperfluidHostDeployerLibrary { + /// @notice Deploys the Superfluid Host Contract + /// @param _nonUpgradable whether the hsot contract is upgradeable or not + /// @param _appWhiteListingEnabled whether app white listing is enabled + /// @return Superfluid newly deployed Superfluid Host contract + function deploySuperfluidHost( + bool _nonUpgradable, + bool _appWhiteListingEnabled + ) external returns (Superfluid) { + return new Superfluid(_nonUpgradable, _appWhiteListingEnabled); + } +} + +/// @title SuperfluidIDAv1DeployerLibrary +/// @author Superfluid +/// @notice An external library that deploys the Superfluid InstantDistributionAgreementV1 contract. +/// @dev This library is used for testing purposes only, not deployments to test OR production networks +library SuperfluidIDAv1DeployerLibrary { + /// @notice deploys the Superfluid InstantDistributionAgreementV1 Contract + /// @param _host Superfluid host address + /// @return newly deployed InstantDistributionAgreementV1 contract + function deployInstantDistributionAgreementV1( + ISuperfluid _host + ) external returns (InstantDistributionAgreementV1) { + return new InstantDistributionAgreementV1(_host); + } +} + +/// @title SuperfluidCFAv1DeployerLibrary +/// @author Superfluid +/// @notice An external library that deploys Superfluid ConstantFlowAgreementV1 contract +/// @dev This library is used for testing purposes only, not deployments to test OR production networks +library SuperfluidCFAv1DeployerLibrary { + /// @notice deploys ConstantFlowAgreementV1 contract + /// @param _host address of the Superfluid contract + /// @param _cfaHook address of the IConstantFlowAgreementHook contract + /// @return newly deployed ConstantFlowAgreementV1 contract + function deployConstantFlowAgreementV1( + ISuperfluid _host, + IConstantFlowAgreementHook _cfaHook + ) external returns (ConstantFlowAgreementV1) { + return new ConstantFlowAgreementV1(_host, _cfaHook); + } +} + +/// @title SuperToken deployer library +/// @author Superfluid +/// @notice This is an external library used to deploy SuperToken logic contracts +library SuperTokenDeployerLibrary { + /// @notice Deploy a SuperToken logic contract + /// @param host the address of the host contract + function deploySuperTokenLogic( + ISuperfluid host + ) external returns (address) { + return address(new SuperToken(host)); + } +} + +/// @title SuperfluidPeripheryDeployerLibrary +/// @author Superfluid +/// @notice An external library that deploys Superfluid periphery contracts (Super Token Factory and Test Resolver) +/// @dev This library is used for testing purposes only, not deployments to test OR production networks +library SuperfluidPeripheryDeployerLibrary { + /// @dev deploys Super Token Factory contract + /// @param _host address of the Superfluid contract + /// @param _superTokenLogic address of the Super Token logic contract + /// @return newly deployed SuperTokenFactory contract + function deploySuperTokenFactory( + ISuperfluid _host, + ISuperToken _superTokenLogic + ) external returns (SuperTokenFactory) { + return new SuperTokenFactory(_host, _superTokenLogic); + } + + /// @dev deploys Test Resolver contract + /// @param _additionalAdmin address of the additional administrator of the Test Resolver contract + /// @return newly deployed Test Resolver contract + function deployTestResolver( + address _additionalAdmin + ) external returns (TestResolver) { + return new TestResolver(_additionalAdmin); + } +} diff --git a/packages/ethereum-contracts/contracts/utils/deployers/SuperfluidCFAv1DeployerLibrary.sol b/packages/ethereum-contracts/contracts/utils/deployers/SuperfluidCFAv1DeployerLibrary.sol deleted file mode 100644 index efbf11a188..0000000000 --- a/packages/ethereum-contracts/contracts/utils/deployers/SuperfluidCFAv1DeployerLibrary.sol +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-License-Identifier: AGPLv3 -pragma solidity ^0.8.0; - -import { - ConstantFlowAgreementV1 -} from "../../agreements/ConstantFlowAgreementV1.sol"; -import { - IConstantFlowAgreementHook -} from "../../interfaces/agreements/IConstantFlowAgreementHook.sol"; -import { ISuperfluid, Superfluid } from "../../superfluid/Superfluid.sol"; -import { TestGovernance } from "../TestGovernance.sol"; - -/// @title SuperfluidCFAv1DeployerLibrary -/// @author Superfluid -/// @notice An external library that deploys Superfluid ConstantFlowAgreementV1 contract -/// @dev This library is used for testing purposes only, not deployments to test OR production networks -library SuperfluidCFAv1DeployerLibrary { - /// @notice deploys ConstantFlowAgreementV1 contract - /// @param _host address of the Superfluid contract - /// @param _cfaHook address of the IConstantFlowAgreementHook contract - /// @return newly deployed ConstantFlowAgreementV1 contract - function deployConstantFlowAgreementV1( - ISuperfluid _host, - IConstantFlowAgreementHook _cfaHook - ) external returns (ConstantFlowAgreementV1) { - return new ConstantFlowAgreementV1(_host, _cfaHook); - } -} diff --git a/packages/ethereum-contracts/contracts/utils/deployers/SuperfluidGovDeployerLibrary.sol b/packages/ethereum-contracts/contracts/utils/deployers/SuperfluidGovDeployerLibrary.sol deleted file mode 100644 index be8422f726..0000000000 --- a/packages/ethereum-contracts/contracts/utils/deployers/SuperfluidGovDeployerLibrary.sol +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-License-Identifier: AGPLv3 -pragma solidity ^0.8.0; - -import { ISuperfluid, ISuperfluidToken } from "../../superfluid/Superfluid.sol"; -import { TestGovernance } from "../TestGovernance.sol"; - -/// @title SuperfluidGovDeployerLibrary -/// @author Superfluid -/// @notice An external library that deploys the Superfluid TestGovernance contract with additional functions -/// @dev This library is used for testing purposes only, not deployments to test OR production networks -library SuperfluidGovDeployerLibrary { - /// @notice deploys the Superfluid TestGovernance Contract - /// @return newly deployed TestGovernance contract - function deployTestGovernance() external returns (TestGovernance) { - return new TestGovernance(); - } - - /// @notice transfers ownership of _gov to _newOwner - /// @dev _gov must be deployed from this contract - /// @param _gov address of the TestGovernance contract - /// @param _newOwner the new owner of the governance contract - function transferOwnership( - TestGovernance _gov, - address _newOwner - ) external { - _gov.transferOwnership(_newOwner); - } -} diff --git a/packages/ethereum-contracts/contracts/utils/deployers/SuperfluidHostDeployerLibrary.sol b/packages/ethereum-contracts/contracts/utils/deployers/SuperfluidHostDeployerLibrary.sol deleted file mode 100644 index 0328b32e72..0000000000 --- a/packages/ethereum-contracts/contracts/utils/deployers/SuperfluidHostDeployerLibrary.sol +++ /dev/null @@ -1,26 +0,0 @@ -// SPDX-License-Identifier: AGPLv3 -pragma solidity ^0.8.0; - -import { - ISuperfluid, - ISuperfluidToken, - Superfluid -} from "../../superfluid/Superfluid.sol"; -import { TestGovernance } from "../TestGovernance.sol"; - -/// @title SuperfluidHostDeployerLibrary -/// @author Superfluid -/// @notice An external library that deploys the Superfluid Host contract with additional functions. -/// @dev This library is used for testing purposes only, not deployments to test OR production networks -library SuperfluidHostDeployerLibrary { - /// @notice Deploys the Superfluid Host Contract - /// @param _nonUpgradable whether the hsot contract is upgradeable or not - /// @param _appWhiteListingEnabled whether app white listing is enabled - /// @return Superfluid newly deployed Superfluid Host contract - function deploySuperfluidHost( - bool _nonUpgradable, - bool _appWhiteListingEnabled - ) external returns (Superfluid) { - return new Superfluid(_nonUpgradable, _appWhiteListingEnabled); - } -} diff --git a/packages/ethereum-contracts/contracts/utils/deployers/SuperfluidIDAv1DeployerLibrary.sol b/packages/ethereum-contracts/contracts/utils/deployers/SuperfluidIDAv1DeployerLibrary.sol deleted file mode 100644 index a89a32c856..0000000000 --- a/packages/ethereum-contracts/contracts/utils/deployers/SuperfluidIDAv1DeployerLibrary.sol +++ /dev/null @@ -1,22 +0,0 @@ -// SPDX-License-Identifier: AGPLv3 -pragma solidity ^0.8.0; - -import { - InstantDistributionAgreementV1 -} from "../../agreements/InstantDistributionAgreementV1.sol"; -import { ISuperfluid } from "../../superfluid/Superfluid.sol"; - -/// @title SuperfluidIDAv1DeployerLibrary -/// @author Superfluid -/// @notice An external library that deploys the Superfluid InstantDistributionAgreementV1 contract. -/// @dev This library is used for testing purposes only, not deployments to test OR production networks -library SuperfluidIDAv1DeployerLibrary { - /// @notice deploys the Superfluid InstantDistributionAgreementV1 Contract - /// @param _host Superfluid host address - /// @return newly deployed InstantDistributionAgreementV1 contract - function deployInstantDistributionAgreementV1( - ISuperfluid _host - ) external returns (InstantDistributionAgreementV1) { - return new InstantDistributionAgreementV1(_host); - } -} diff --git a/packages/ethereum-contracts/contracts/utils/deployers/SuperfluidPeripheryDeployerLibrary.sol b/packages/ethereum-contracts/contracts/utils/deployers/SuperfluidPeripheryDeployerLibrary.sol deleted file mode 100644 index 68a3a7410e..0000000000 --- a/packages/ethereum-contracts/contracts/utils/deployers/SuperfluidPeripheryDeployerLibrary.sol +++ /dev/null @@ -1,36 +0,0 @@ -// SPDX-License-Identifier: AGPLv3 -pragma solidity ^0.8.0; - -import { ISuperfluid, ISuperfluidToken } from "../../superfluid/Superfluid.sol"; -import { - ISuperTokenFactory, - SuperTokenFactory, - SuperTokenFactoryHelper -} from "../../superfluid/SuperTokenFactory.sol"; -import { TestResolver } from "../TestResolver.sol"; - -/// @title SuperfluidPeripheryDeployerLibrary -/// @author Superfluid -/// @notice An external library that deploys Superfluid periphery contracts (Super Token Factory and Test Resolver) -/// @dev This library is used for testing purposes only, not deployments to test OR production networks -library SuperfluidPeripheryDeployerLibrary { - /// @dev deploys Super Token Factory contract - /// @param _host address of the Superfluid contract - /// @param _superTokenFactoryHelper address of the SuperTokenFactoryHelper contract - /// @return newly deployed SuperTokenFactory contract - function deploySuperTokenFactory( - ISuperfluid _host, - SuperTokenFactoryHelper _superTokenFactoryHelper - ) external returns (SuperTokenFactory) { - return new SuperTokenFactory(_host, _superTokenFactoryHelper); - } - - /// @dev deploys Test Resolver contract - /// @param _additionalAdmin address of the additional administrator of the Test Resolver contract - /// @return newly deployed Test Resolver contract - function deployTestResolver( - address _additionalAdmin - ) external returns (TestResolver) { - return new TestResolver(_additionalAdmin); - } -} diff --git a/packages/ethereum-contracts/contracts/utils/deployers/SuperfluidSuperTokenFactoryHelperDeployerLibrary.sol b/packages/ethereum-contracts/contracts/utils/deployers/SuperfluidSuperTokenFactoryHelperDeployerLibrary.sol deleted file mode 100644 index 0453c81154..0000000000 --- a/packages/ethereum-contracts/contracts/utils/deployers/SuperfluidSuperTokenFactoryHelperDeployerLibrary.sol +++ /dev/null @@ -1,25 +0,0 @@ -// SPDX-License-Identifier: AGPLv3 -pragma solidity ^0.8.0; - -import { ISuperfluid, ISuperfluidToken } from "../../superfluid/Superfluid.sol"; -import { - ISuperTokenFactory, - SuperTokenFactory, - SuperTokenFactoryHelper -} from "../../superfluid/SuperTokenFactory.sol"; -import { TestResolver } from "../TestResolver.sol"; - -/// @title SuperfluidSuperTokenFactoryHelperDeployerLibrary -/// @author Superfluid -/// @notice An external library that deploys the Superfluid Super Token Factory Helper contract. -/// @dev This library is used for testing purposes only, not deployments to test OR production networks -library SuperfluidSuperTokenFactoryHelperDeployerLibrary { - /// @dev deploys Super Token Factory Helper contract - /// @return newly deployed Super Token Factory Helper contract - function deploySuperTokenFactoryHelper() - external - returns (SuperTokenFactoryHelper) - { - return new SuperTokenFactoryHelper(); - } -} diff --git a/packages/ethereum-contracts/dev-scripts/deploy-test-framework.js b/packages/ethereum-contracts/dev-scripts/deploy-test-framework.js index 0a7b67a5e3..e8f57ba962 100644 --- a/packages/ethereum-contracts/dev-scripts/deploy-test-framework.js +++ b/packages/ethereum-contracts/dev-scripts/deploy-test-framework.js @@ -1,11 +1,11 @@ const {ethers} = require("hardhat"); -const SuperfluidGovDeployerLibraryArtifact = require("@superfluid-finance/ethereum-contracts/artifacts/contracts/utils/deployers/SuperfluidGovDeployerLibrary.sol/SuperfluidGovDeployerLibrary.json"); -const SuperfluidHostDeployerLibraryArtifact = require("@superfluid-finance/ethereum-contracts/artifacts/contracts/utils/deployers/SuperfluidHostDeployerLibrary.sol/SuperfluidHostDeployerLibrary.json"); -const SuperfluidCFAv1DeployerLibraryArtifact = require("@superfluid-finance/ethereum-contracts/artifacts/contracts/utils/deployers/SuperfluidCFAv1DeployerLibrary.sol/SuperfluidCFAv1DeployerLibrary.json"); -const SuperfluidIDAv1DeployerLibraryArtifact = require("@superfluid-finance/ethereum-contracts/artifacts/contracts/utils/deployers/SuperfluidIDAv1DeployerLibrary.sol/SuperfluidIDAv1DeployerLibrary.json"); -const SuperfluidPeripheryDeployerLibraryArtifact = require("@superfluid-finance/ethereum-contracts/artifacts/contracts/utils/deployers/SuperfluidPeripheryDeployerLibrary.sol/SuperfluidPeripheryDeployerLibrary.json"); -const SuperfluidSuperTokenFactoryHelperDeployerLibraryArtifact = require("@superfluid-finance/ethereum-contracts/artifacts/contracts/utils/deployers/SuperfluidSuperTokenFactoryHelperDeployerLibrary.sol/SuperfluidSuperTokenFactoryHelperDeployerLibrary.json"); +const SuperfluidGovDeployerLibraryArtifact = require("@superfluid-finance/ethereum-contracts/artifacts/contracts/utils/SuperfluidFrameworkDeployer.sol/SuperfluidGovDeployerLibrary.json"); +const SuperfluidHostDeployerLibraryArtifact = require("@superfluid-finance/ethereum-contracts/artifacts/contracts/utils/SuperfluidFrameworkDeployer.sol/SuperfluidHostDeployerLibrary.json"); +const SuperfluidCFAv1DeployerLibraryArtifact = require("@superfluid-finance/ethereum-contracts/artifacts/contracts/utils/SuperfluidFrameworkDeployer.sol/SuperfluidCFAv1DeployerLibrary.json"); +const SuperfluidIDAv1DeployerLibraryArtifact = require("@superfluid-finance/ethereum-contracts/artifacts/contracts/utils/SuperfluidFrameworkDeployer.sol/SuperfluidIDAv1DeployerLibrary.json"); +const SuperTokenDeployerLibraryArtifact = require("@superfluid-finance/ethereum-contracts/artifacts/contracts/utils/SuperfluidFrameworkDeployer.sol/SuperTokenDeployerLibrary.json"); +const SuperfluidPeripheryDeployerLibraryArtifact = require("@superfluid-finance/ethereum-contracts/artifacts/contracts/utils/SuperfluidFrameworkDeployer.sol/SuperfluidPeripheryDeployerLibrary.json"); const SuperfluidFrameworkDeployerArtifact = require("@superfluid-finance/ethereum-contracts/artifacts/contracts/utils/SuperfluidFrameworkDeployer.sol/SuperfluidFrameworkDeployer.json"); const SlotsBitmapLibraryArtifact = require("@superfluid-finance/ethereum-contracts/artifacts/contracts/libs/SlotsBitmapLibrary.sol/SlotsBitmapLibrary.json"); @@ -61,7 +61,7 @@ const _getFactoryAndReturnDeployedContract = async ( /** * Deploys Superfluid Framework in local testing environments. * NOTE: This only works with Hardhat. - * @returns + * @returns */ const deployTestFramework = async () => { const signer = (await ethers.getSigners())[0]; @@ -93,10 +93,18 @@ const deployTestFramework = async () => { await _getFactoryAndReturnDeployedContract( "SuperfluidIDAv1DeployerLibrary", SuperfluidIDAv1DeployerLibraryArtifact, - {signer, + { + signer, libraries: { SlotsBitmapLibrary: SlotsBitmapLibrary.address, - },} + }, + } + ); + const SuperTokenDeployerLibrary = + await _getFactoryAndReturnDeployedContract( + "SuperTokenDeployerLibrary", + SuperTokenDeployerLibraryArtifact, + signer ); const SuperfluidPeripheryDeployerLibrary = await _getFactoryAndReturnDeployedContract( @@ -104,23 +112,23 @@ const deployTestFramework = async () => { SuperfluidPeripheryDeployerLibraryArtifact, signer ); - const SuperfluidSuperTokenFactoryHelperDeployerLibrary = - await _getFactoryAndReturnDeployedContract( - "SuperfluidSuperTokenFactoryHelperDeployerLibrary", - SuperfluidSuperTokenFactoryHelperDeployerLibraryArtifact, - ); const frameworkDeployer = await _getFactoryAndReturnDeployedContract( "SuperfluidFrameworkDeployer", SuperfluidFrameworkDeployerArtifact, { signer, libraries: { - SuperfluidGovDeployerLibrary: SuperfluidGovDeployerLibrary.address, - SuperfluidHostDeployerLibrary: SuperfluidHostDeployerLibrary.address, - SuperfluidCFAv1DeployerLibrary: SuperfluidCFAv1DeployerLibrary.address, - SuperfluidIDAv1DeployerLibrary: SuperfluidIDAv1DeployerLibrary.address, - SuperfluidPeripheryDeployerLibrary: SuperfluidPeripheryDeployerLibrary.address, - SuperfluidSuperTokenFactoryHelperDeployerLibrary: SuperfluidSuperTokenFactoryHelperDeployerLibrary.address + SuperfluidGovDeployerLibrary: + SuperfluidGovDeployerLibrary.address, + SuperfluidHostDeployerLibrary: + SuperfluidHostDeployerLibrary.address, + SuperfluidCFAv1DeployerLibrary: + SuperfluidCFAv1DeployerLibrary.address, + SuperfluidIDAv1DeployerLibrary: + SuperfluidIDAv1DeployerLibrary.address, + SuperfluidPeripheryDeployerLibrary: + SuperfluidPeripheryDeployerLibrary.address, + SuperTokenDeployerLibrary: SuperTokenDeployerLibrary.address, }, } ); diff --git a/packages/ethereum-contracts/foundry.toml b/packages/ethereum-contracts/foundry.toml index 7b9cb3181d..89167bca73 100644 --- a/packages/ethereum-contracts/foundry.toml +++ b/packages/ethereum-contracts/foundry.toml @@ -1,6 +1,5 @@ [profile.default] root = '../..' -libs = ['lib'] src = 'packages/ethereum-contracts' remappings = [ '@superfluid-finance/ethereum-contracts/contracts/=packages/ethereum-contracts/contracts/', diff --git a/packages/ethereum-contracts/ops-scripts/deploy-framework.js b/packages/ethereum-contracts/ops-scripts/deploy-framework.js index fdf0b9c168..6b3962af5b 100644 --- a/packages/ethereum-contracts/ops-scripts/deploy-framework.js +++ b/packages/ethereum-contracts/ops-scripts/deploy-framework.js @@ -2,7 +2,6 @@ const fs = require("fs"); const util = require("util"); const getConfig = require("./libs/getConfig"); const SuperfluidSDK = require("@superfluid-finance/js-sdk"); -const ethers = require("ethers"); const {web3tx} = require("@decentral.ee/web3-helpers"); const deployERC1820 = require("../ops-scripts/deploy-erc1820"); @@ -117,7 +116,7 @@ module.exports = eval(`(${S.toString()})({skipArgv: true})`)(async function ( appWhiteListing, protocolReleaseVersion, outputFile, - cfaHookContract + cfaHookContract, } = options; resetSuperfluidFramework = options.resetSuperfluidFramework; @@ -183,7 +182,6 @@ module.exports = eval(`(${S.toString()})({skipArgv: true})`)(async function ( "SuperfluidLoader", "Superfluid", "SuperTokenFactory", - "SuperTokenFactoryHelper", "SuperToken", "TestGovernance", "ISuperfluidGovernance", @@ -196,7 +194,6 @@ module.exports = eval(`(${S.toString()})({skipArgv: true})`)(async function ( const mockContracts = [ "SuperfluidMock", "SuperTokenFactoryMock", - "SuperTokenFactoryMockHelper", "SuperTokenMock", ]; const { @@ -209,9 +206,7 @@ module.exports = eval(`(${S.toString()})({skipArgv: true})`)(async function ( Superfluid, SuperfluidMock, SuperTokenFactory, - SuperTokenFactoryHelper, SuperTokenFactoryMock, - SuperTokenFactoryMockHelper, SuperToken, SuperTokenMock, TestGovernance, @@ -386,26 +381,46 @@ module.exports = eval(`(${S.toString()})({skipArgv: true})`)(async function ( )(superfluid.address, cfa.address); } + /** + * This function: + * deploys an external library + * links a contract artifact to the deployed external library (in two ways depending on if hardhat or truffle env) + * returns the deployed external library + * @param {*} externalLibraryArtifact artifact of the external library + * @param {*} externalLibraryName name of the external library + * @param {*} outputName the output name + * @param {*} contract the contract artifact to link to the external library + * @returns + */ + const deployExternalLibraryAndLink = async ( + externalLibraryArtifact, + externalLibraryName, + outputName, + contract + ) => { + const externalLibrary = await web3tx( + externalLibraryArtifact.new, + `${externalLibraryName}.new` + )(); + output += `${outputName}=${externalLibrary.address}\n`; + if (process.env.IS_HARDHAT) { + contract.link(externalLibrary); + } else { + contract.link(externalLibraryName, externalLibrary.address); + } + return externalLibrary; + }; + // list IDA v1 const deployIDAv1 = async () => { - const deploySlotsBitmapLibrary = async () => { - const slotsBmpLib = await web3tx( - SlotsBitmapLibrary.new, - "SlotsBitmapLibrary.new" - )(); - output += `SLOTS_BITMAP_LIBRARY_ADDRESS=${slotsBmpLib.address}\n`; - if (process.env.IS_HARDHAT) { - InstantDistributionAgreementV1.link(slotsBmpLib); - } else { - InstantDistributionAgreementV1.link( - "SlotsBitmapLibrary", - slotsBmpLib.address - ); - } - return slotsBmpLib; - }; // small inefficiency: this may be re-deployed even if not changed - await deploySlotsBitmapLibrary(); + // deploySlotsBitmapLibrary + await deployExternalLibraryAndLink( + SlotsBitmapLibrary, + "SlotsBitmapLibrary", + "SLOTS_BITMAP_LIBRARY_ADDRESS", + InstantDistributionAgreementV1 + ); const agreement = await web3tx( InstantDistributionAgreementV1.new, "InstantDistributionAgreementV1.new" @@ -533,12 +548,10 @@ module.exports = eval(`(${S.toString()})({skipArgv: true})`)(async function ( } // deploy new super token factory logic - const SuperTokenFactoryHelperLogic = useMocks - ? SuperTokenFactoryMockHelper - : SuperTokenFactoryHelper; const SuperTokenFactoryLogic = useMocks ? SuperTokenFactoryMock : SuperTokenFactory; + const SuperTokenLogic = useMocks ? SuperTokenMock : SuperToken; const superTokenFactoryNewLogicAddress = await deployContractIf( web3, @@ -578,14 +591,19 @@ module.exports = eval(`(${S.toString()})({skipArgv: true})`)(async function ( }, async () => { let superTokenFactoryLogic; - const helper = await web3tx( - SuperTokenFactoryHelperLogic.new, - "SuperTokenFactoryHelperLogic.new" - )(); + const superTokenLogic = useMocks + ? await web3tx(SuperTokenLogic.new, "SuperTokenLogic.new")( + superfluid.address, + 0 + ) + : await web3tx( + SuperTokenLogic.new, + "SuperTokenLogic.new" + )(superfluid.address); superTokenFactoryLogic = await web3tx( SuperTokenFactoryLogic.new, "SuperTokenFactoryLogic.new" - )(superfluid.address, helper.address); + )(superfluid.address, superTokenLogic.address); output += `SUPERFLUID_SUPER_TOKEN_FACTORY_LOGIC=${superTokenFactoryLogic.address}\n`; return superTokenFactoryLogic.address; } diff --git a/packages/ethereum-contracts/package.json b/packages/ethereum-contracts/package.json index 9c8b751935..0718c925af 100644 --- a/packages/ethereum-contracts/package.json +++ b/packages/ethereum-contracts/package.json @@ -31,6 +31,7 @@ "typings": "./types/index.d.ts", "scripts": { "dev": "tasks/dev.sh", + "dev-forge": "nodemon -e sol -x yarn run-forge test --hardhat", "clean": "rm -rf node_modules; rm -rf cache; rm -rf build; rm -rf artifacts; rm -rf typechain-types; rm -rf scripts/*.d.ts scripts/*.d.ts.map", "run-hardhat": "IS_HARDHAT=true hardhat", "run-truffle": "IS_TRUFFLE=true truffle", @@ -48,11 +49,11 @@ "pretest": "{ yarn testenv:start > /dev/null& } && sleep 5", "test": "run-s test:*:*", "test:contracts:hardhat": "yarn run-hardhat test testsuites/all-contracts.ts", - "test:contracts:foundry": "yarn run-forge test --hardhat", + "test:contracts:foundry": "yarn run-forge test --hardhat --no-match-contract Fork", "test:contracts:solc-compatibility": "test/test-solc-compatibility.sh", - "test:deployment:scripts-js-hardhat": "yarn run-hardhat test test/scripts/deployment.test.js", - "test:deployment:scripts-js-truffle": "yarn run-truffle test test/scripts/deployment.test.js", - "test:deployment:scripts-bash": "test/scripts/deployment.test.sh", + "test:deployment:scripts-js-hardhat": "yarn run-hardhat test test/ops-scripts/deployment.test.js", + "test:deployment:scripts-js-truffle": "yarn run-truffle test test/ops-scripts/deployment.test.js", + "test:deployment:scripts-bash": "test/ops-scripts/deployment.test.sh", "test-coverage": "yarn run-hardhat coverage --testfiles testsuites/all-contracts.js --solcoverjs ./.solcover.js", "posttest": "yarn testenv:stop", "lint": "run-s lint:*", diff --git a/packages/ethereum-contracts/test/TestEnvironment.ts b/packages/ethereum-contracts/test/TestEnvironment.ts index 93e0b6efd1..712562ed1f 100644 --- a/packages/ethereum-contracts/test/TestEnvironment.ts +++ b/packages/ethereum-contracts/test/TestEnvironment.ts @@ -1,7 +1,7 @@ import fs from "fs"; import {createObjectCsvWriter as createCsvWriter} from "csv-writer"; -import {BigNumber} from "ethers"; +import {BigNumber, Contract} from "ethers"; import {artifacts, assert, ethers, expect, network, web3} from "hardhat"; import _ from "lodash"; import Web3 from "web3"; @@ -542,6 +542,40 @@ export default class TestEnvironment { ); } + deployContract = async (contractName: string, ...args: any) => { + const contractFactory = await ethers.getContractFactory(contractName); + const contract = await contractFactory.deploy(...args); + + return contract as T; + }; + + /** + * Deploys an external library with name: externLibraryName and links it to + * with the contract factory for the contract with name: contractName + * @param externalLibraryName + * @param contractName + * @param contractArgs + * @returns deployed contract + */ + deployExternalLibraryAndLink = async ( + externalLibraryName: string, + contractName: string, + ...contractArgs: any + ): Promise => { + const externalLibrary = await this.deployContract( + externalLibraryName + ); + const contractFactory = await ethers.getContractFactory(contractName, { + libraries: { + [externalLibraryName]: externalLibrary.address, + }, + }); + + const contract = await contractFactory.deploy(...contractArgs); + + return contract as T; + }; + /************************************************************************** * Test data functions *************************************************************************/ diff --git a/packages/ethereum-contracts/test/contracts/superfluid/SuperTokenFactory.test.ts b/packages/ethereum-contracts/test/contracts/superfluid/SuperTokenFactory.test.ts index 0cf0a42558..dae91550f4 100644 --- a/packages/ethereum-contracts/test/contracts/superfluid/SuperTokenFactory.test.ts +++ b/packages/ethereum-contracts/test/contracts/superfluid/SuperTokenFactory.test.ts @@ -1,8 +1,13 @@ -import {artifacts, assert, ethers, expect, web3} from "hardhat"; +import {assert, ethers, expect, web3} from "hardhat"; import { SuperfluidMock, + SuperToken, SuperTokenFactory, + SuperTokenFactoryMock42, + SuperTokenFactoryStorageLayoutTester, + SuperTokenFactoryUpdateLogicContractsTester, + SuperTokenMock, TestGovernance, TestToken, TestToken__factory, @@ -56,8 +61,17 @@ describe("SuperTokenFactory Contract", function () { describe("#1 upgradability", () => { it("#1.1 storage layout", async () => { - const T = artifacts.require("SuperTokenFactoryStorageLayoutTester"); - const tester = await T.new(superfluid.address); + const superTokenLogic = await t.deployContract( + "SuperTokenMock", + superfluid.address, + "0" + ); + const tester = + await t.deployContract( + "SuperTokenFactoryStorageLayoutTester", + superfluid.address, + superTokenLogic.address + ); await tester.validateStorageLayout(); }); @@ -95,6 +109,7 @@ describe("SuperTokenFactory Contract", function () { "SuperTokenFactory", await factory.getCodeAddress() ); + await expectRevertedWith( factoryLogic.initialize(), "Initializable: contract is already initialized" @@ -104,6 +119,12 @@ describe("SuperTokenFactory Contract", function () { "SuperTokenMock", await factory.getSuperTokenLogic() ); + + // we need to call this here because we are not castrating the super token + // logic contract after upgrades anymore. + // we do it in the SuperTokenFactory constructor now + await superTokenLogic.initialize(ZERO_ADDRESS, 0, "", ""); + await expectRevertedWith( superTokenLogic.initialize(ZERO_ADDRESS, 0, "", ""), "Initializable: contract is already initialized" @@ -114,18 +135,17 @@ describe("SuperTokenFactory Contract", function () { describe("#2 createERC20Wrapper", () => { context("#2.a Mock factory", () => { async function updateSuperTokenFactory() { - const SuperTokenFactoryMock42 = await ethers.getContractFactory( - "SuperTokenFactoryMock42" - ); - const SuperTokenFactoryMockHelper = - await ethers.getContractFactory( - "SuperTokenFactoryMockHelper" - ); - const helper = await SuperTokenFactoryMockHelper.deploy(); - const factory2Logic = await SuperTokenFactoryMock42.deploy( + const superTokenLogic = await t.deployContract( + "SuperTokenMock", superfluid.address, - helper.address + 42 ); + const factory2Logic = + await t.deployContract( + "SuperTokenFactoryMock42", + superfluid.address, + superTokenLogic.address + ); await governance.updateContracts( superfluid.address, ZERO_ADDRESS, @@ -135,26 +155,17 @@ describe("SuperTokenFactory Contract", function () { await superfluid.getSuperTokenFactoryLogic(); } - it("#2.a.1 non upgradable", async () => { - let superToken1 = await t.sf.createERC20Wrapper(token1, { - upgradability: 0, - }); - await expectEvent(superToken1.tx.receipt, "SuperTokenCreated", { - token: superToken1.address, - }); - superToken1 = await ethers.getContractAt( - "SuperTokenMock", - superToken1.address - ); - await updateSuperTokenFactory(); - assert.equal((await superToken1.waterMark()).toString(), "0"); - await expectRevertedWith( - governance.batchUpdateSuperTokenLogic(superfluid.address, [ - superToken1.address, - ]), - "UUPSProxiable: not upgradable" + it("#2.a.1 non upgradable super token creation is deprecated", async () => { + await expectCustomError( + factory["createERC20Wrapper(address,uint8,string,string)"]( + token1.address, + 0, + "", + "" + ), + factory, + "SUPER_TOKEN_FACTORY_NON_UPGRADEABLE_IS_DEPRECATED" ); - assert.equal((await superToken1.waterMark()).toString(), "0"); }); it("#2.a.2 semi upgradable", async () => { @@ -230,12 +241,16 @@ describe("SuperTokenFactory Contract", function () { context("#2.b Production Factory", () => { it("#2.b.1 use production factory to create different super tokens", async () => { - const helper = await ( - await ethers.getContractFactory("SuperTokenFactoryHelper") - ).deploy(); - const factory2Logic = await ( - await ethers.getContractFactory("SuperTokenFactory") - ).deploy(superfluid.address, helper.address); + const superTokenLogic = await t.deployContract( + "SuperToken", + superfluid.address + ); + const factory2Logic = + await t.deployContract( + "SuperTokenFactoryUpdateLogicContractsTester", + superfluid.address, + superTokenLogic.address + ); await governance.updateContracts( superfluid.address, ZERO_ADDRESS, @@ -243,15 +258,15 @@ describe("SuperTokenFactory Contract", function () { factory2Logic.address ); - const superToken0 = await t.sf.createERC20Wrapper(token1, { - upgradability: 0, - }); - await expectEvent(superToken0.tx.receipt, "SuperTokenCreated", { - token: superToken0.address, - }); - assert.equal( - await superToken0.getUnderlyingToken(), - token1.address + await expectCustomError( + factory["createERC20Wrapper(address,uint8,string,string)"]( + token1.address, + 0, + "", + "" + ), + factory, + "SUPER_TOKEN_FACTORY_NON_UPGRADEABLE_IS_DEPRECATED" ); const superToken1 = await t.sf.createERC20Wrapper(token1, { diff --git a/packages/ethereum-contracts/test/contracts/superfluid/Superfluid.test.ts b/packages/ethereum-contracts/test/contracts/superfluid/Superfluid.test.ts index c835af8e48..2308910dde 100644 --- a/packages/ethereum-contracts/test/contracts/superfluid/Superfluid.test.ts +++ b/packages/ethereum-contracts/test/contracts/superfluid/Superfluid.test.ts @@ -12,6 +12,9 @@ import { SuperAppMock__factory, SuperAppMockWithRegistrationKey__factory, SuperfluidMock, + SuperToken, + SuperTokenFactory, + SuperTokenFactoryUpdateLogicContractsTester, SuperTokenMock, TestGovernance, } from "../../../typechain-types"; @@ -431,17 +434,49 @@ describe("Superfluid Host Contract", function () { it("#3.2 update super token factory", async () => { const factory = await superfluid.getSuperTokenFactory(); - const SuperTokenFactoryHelperFactory = - await ethers.getContractFactory("SuperTokenFactoryHelper"); - const superTokenFactoryHelper = - await SuperTokenFactoryHelperFactory.deploy(); + const superTokenLogicFactory = await ethers.getContractFactory( + "SuperToken" + ); + const superTokenLogic = await superTokenLogicFactory.deploy( + superfluid.address + ); const factory2LogicFactory = await ethers.getContractFactory( "SuperTokenFactory" ); const factory2Logic = await factory2LogicFactory.deploy( superfluid.address, - superTokenFactoryHelper.address + superTokenLogic.address + ); + await governance.updateContracts( + superfluid.address, + ZERO_ADDRESS, + [], + factory2Logic.address + ); + assert.equal( + await superfluid.getSuperTokenFactory(), + factory, + "Upgradable factory address does not change" + ); + assert.equal( + await superfluid.getSuperTokenFactoryLogic(), + factory2Logic.address, + "Upgradable factory logic address should change to the new one" + ); + }); + + it("#3.3 update super token factory double check if new code is called", async () => { + const factory = await superfluid.getSuperTokenFactory(); + const superTokenLogic = await t.deployContract( + "SuperToken", + superfluid.address ); + const factory2Logic = + await t.deployContract( + "SuperTokenFactoryUpdateLogicContractsTester", + superfluid.address, + superTokenLogic.address + ); await governance.updateContracts( superfluid.address, ZERO_ADDRESS, @@ -458,6 +493,14 @@ describe("Superfluid Host Contract", function () { factory2Logic.address, "Upgradable factory logic address should change to the new one" ); + const factoryProxy = await ethers.getContractAt( + "SuperTokenFactoryUpdateLogicContractsTester", + factory + ); + assert.equal( + (await factoryProxy.newVariable()).toString(), + ethers.BigNumber.from(0).toString() + ); }); }); @@ -2599,16 +2642,14 @@ describe("Superfluid Host Contract", function () { await superfluid.getSuperTokenFactory(), await superfluid.getSuperTokenFactoryLogic() ); - const SuperTokenFactoryHelperFactory = - await ethers.getContractFactory("SuperTokenFactoryHelper"); - const SuperTokenFactoryHelper = - await SuperTokenFactoryHelperFactory.deploy(); - const factory2LogicFactory = await ethers.getContractFactory( - "SuperTokenFactory" + const superTokenLogic = await t.deployContract( + "SuperToken", + superfluid.address ); - const factory2Logic = await factory2LogicFactory.deploy( + const factory2Logic = await t.deployContract( + "SuperTokenFactory", superfluid.address, - SuperTokenFactoryHelper.address + superTokenLogic.address ); await expectCustomError( governance.updateContracts( diff --git a/packages/ethereum-contracts/test/foundry/deployments/ForkPolygonSuperTokenFactoryUpgrade.t.sol b/packages/ethereum-contracts/test/foundry/deployments/ForkPolygonSuperTokenFactoryUpgrade.t.sol new file mode 100644 index 0000000000..1f2d0840a8 --- /dev/null +++ b/packages/ethereum-contracts/test/foundry/deployments/ForkPolygonSuperTokenFactoryUpgrade.t.sol @@ -0,0 +1,171 @@ +// SPDX-License-Identifier: AGPLv3 +pragma solidity 0.8.18; + +import { console, Test } from "forge-std/Test.sol"; +import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; +import { + IConstantFlowAgreementV1, + ConstantFlowAgreementV1, + IConstantFlowAgreementHook +} from "../../../contracts/agreements/ConstantFlowAgreementV1.sol"; +import { + IInstantDistributionAgreementV1 +} from "../../../contracts/interfaces/agreements/IInstantDistributionAgreementV1.sol"; +import { IResolver } from "../../../contracts/interfaces/utils/IResolver.sol"; +import { + ISuperfluidGovernance +} from "../../../contracts/interfaces/superfluid/ISuperfluidGovernance.sol"; +import { + SuperfluidLoader +} from "../../../contracts/utils/SuperfluidLoader.sol"; +import { + ISuperfluid +} from "../../../contracts/interfaces/superfluid/ISuperfluid.sol"; +import { + IERC20, + ISuperToken, + SuperToken +} from "../../../contracts/superfluid/SuperToken.sol"; +import { + ISuperTokenFactory, + SuperTokenFactory +} from "../../../contracts/superfluid/SuperTokenFactory.sol"; +import { + SuperTokenFactoryUpdateLogicContractsTester +} from "../../../contracts/mocks/SuperTokenFactoryMock.sol"; +import { + SuperTokenV1Library +} from "../../../contracts/apps/SuperTokenV1Library.sol"; +import { ForkSmokeTest } from "./ForkSmoke.t.sol"; + +/// @title ForkPolygonSuperTokenFactoryUpgradeTest +/// @author Superfluid +/// @notice Tests the SuperTokenFactory upgrade flow on Polygon mainnet fork +/// @dev Note that this test file is likely dynamic and will change over time +/// due to the possibility that the upgrade flow may also change over time +/// This is also only running tests for Polygon +contract ForkPolygonSuperTokenFactoryUpgradeTest is ForkSmokeTest { + using SuperTokenV1Library for ISuperToken; + string public PROVIDER_URL; + + IResolver public constant resolver = + IResolver(0xE0cc76334405EE8b39213E620587d815967af39C); + + ISuperfluid public host; + IConstantFlowAgreementV1 public cfaV1; + SuperfluidLoader public superfluidLoader; + ISuperTokenFactory public superTokenFactory; + ISuperfluidGovernance public governance; + + IERC20 public constant weth = + IERC20(0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619); + ISuperToken public constant ethX = + ISuperToken(0x27e1e4E6BC79D93032abef01025811B7E4727e85); + + // arbitrary test account with a good amount of ETHx + address public constant TEST_ACCOUNT = + 0x0154d25120Ed20A516fE43991702e7463c5A6F6e; + address public constant ALICE = address(1); + address public constant BOB = address(2); + address public constant DEFAULT_FLOW_OPERATOR = address(69); + + constructor() + ForkSmokeTest( + ethX, + TEST_ACCOUNT, + resolver, + "POLYGON_MAINNET_PROVIDER_URL" + ) + {} + + function setUp() public { + superfluidLoader = sfFramework.superfluidLoader; + cfaV1 = sfFramework.cfaV1; + host = sfFramework.host; + governance = sfFramework.governance; + superTokenFactory = sfFramework.superTokenFactory; + + // execute super token factory upgrade + helper_Execute_Super_Token_Factory_Upgrade(); + } + + function helper_Execute_Super_Token_Factory_Upgrade() public { + address superTokenFactoryLogicPre = host.getSuperTokenFactoryLogic(); + address superTokenLogicPre = address( + superTokenFactory.getSuperTokenLogic() + ); + + address governanceOwner = Ownable(address(governance)).owner(); + + // Prank as governance owner + vm.startPrank(governanceOwner); + + // As part of the new ops flow, we deploy a new SuperToken logic contract + SuperToken newSuperTokenLogic = new SuperToken(host); + + // Deploy the new super token factory logic contract, note that we pass in + // the new super token logic contract, this is set as an immutable field in + // the constructor + SuperTokenFactoryUpdateLogicContractsTester newLogic = new SuperTokenFactoryUpdateLogicContractsTester( + host, + newSuperTokenLogic + ); + + // update the super token factory logic via goverance->host + governance.updateContracts( + host, + address(0), + new address[](0), + address(newLogic) + ); + + // get the addresses of the super token factory logic and super token logic post update + address superTokenFactoryLogicPost = host.getSuperTokenFactoryLogic(); + address superTokenLogicPost = address( + superTokenFactory.getSuperTokenLogic() + ); + + // validate that the logic contracts have been updated and are no longer the same + // as prior to deployment + assertFalse(superTokenFactoryLogicPre == superTokenFactoryLogicPost); + assertFalse(superTokenLogicPre == superTokenLogicPost); + + // validate that the super token logic is the new one + // we deprecate the previous _superTokenLogic in slot 2 and replace it + // with an immutable variable - this is a sanity check that the new + // immutable variable is properly set and referenced + assertEq(address(newSuperTokenLogic), superTokenLogicPost); + + // expect revert when trying to initialize the logic contracts + vm.expectRevert("Initializable: contract is already initialized"); + SuperTokenFactory(superTokenFactoryLogicPost).initialize(); + + vm.stopPrank(); + + // the mock contract adds a new storage variable and sets it to 69 + assertEq( + SuperTokenFactoryUpdateLogicContractsTester( + address(superTokenFactory) + ).newVariable(), + 0 + ); + + vm.stopPrank(); + + // create update and delete flows after updating SuperTokenFactory logic + // after deploying and setting new SuperToken logic in SuperTokenFactory + helper_Create_Update_Delete_Flow_One_To_One(ethX, TEST_ACCOUNT); + + // LOGGING + console.log("Chain ID: ", block.chainid); + console.log("Governance Owner Address: ", governanceOwner); + console.log("SuperfluidLoader Address: ", address(superfluidLoader)); + console.log("Superfluid Host Address: ", address(host)); + console.log("Superfluid Governance Address: ", address(governance)); + console.log("SuperTokenFactory Address: ", address(superTokenFactory)); + console.log("SuperTokenFactoryLogic Pre Migration: ", superTokenFactoryLogicPre); + console.log("SuperTokenFactoryLogic Post Migration: ", superTokenFactoryLogicPost); + console.log("SuperTokenLogic Pre Migration: ", superTokenLogicPre); + console.log("SuperTokenLogic Post Migration: ", superTokenLogicPost); + } +} diff --git a/packages/ethereum-contracts/test/foundry/deployments/ForkSmoke.t.sol b/packages/ethereum-contracts/test/foundry/deployments/ForkSmoke.t.sol new file mode 100644 index 0000000000..5834f5872c --- /dev/null +++ b/packages/ethereum-contracts/test/foundry/deployments/ForkSmoke.t.sol @@ -0,0 +1,632 @@ +// SPDX-License-Identifier: AGPLv3 +pragma solidity 0.8.18; + +import { console, Test } from "forge-std/Test.sol"; +import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import { + IConstantFlowAgreementV1 +} from "../../../contracts/agreements/ConstantFlowAgreementV1.sol"; +import { + IInstantDistributionAgreementV1 +} from "../../../contracts/interfaces/agreements/IInstantDistributionAgreementV1.sol"; +import { IResolver } from "../../../contracts/interfaces/utils/IResolver.sol"; +import { + ISuperfluidGovernance +} from "../../../contracts/interfaces/superfluid/ISuperfluidGovernance.sol"; +import { + SuperfluidLoader +} from "../../../contracts/utils/SuperfluidLoader.sol"; +import { + ISuperfluid +} from "../../../contracts/interfaces/superfluid/ISuperfluid.sol"; +import { + IERC20, + ISuperToken, + SafeERC20 +} from "../../../contracts/superfluid/SuperToken.sol"; +import { + ISuperTokenFactory +} from "../../../contracts/superfluid/SuperTokenFactory.sol"; +import { + SuperTokenV1Library +} from "../../../contracts/apps/SuperTokenV1Library.sol"; + +/// @title ForkSmokeTest +/// @author Superfluid +/// @notice A contract containing a set of smoke tests to be used in forked mainnet tests +/// @dev This contract contains a smoke test function which will run the standard Superfluid +/// operations on a forked mainnet. It will also make public some of the smoke test functions +/// so that they can be used between stages of the upgrade process. +contract ForkSmokeTest is Test { + using SuperTokenV1Library for ISuperToken; + + struct SuperfluidFramework { + ISuperfluid host; + IInstantDistributionAgreementV1 idaV1; + IConstantFlowAgreementV1 cfaV1; + SuperfluidLoader superfluidLoader; + ISuperTokenFactory superTokenFactory; + ISuperfluidGovernance governance; + ISuperToken token; + } + + struct ExpectedIndexData { + address publisher; + uint32 indexId; + bool exist; + uint128 indexValue; + uint128 totalUnitsApproved; + uint128 totalUnitsPending; + } + + struct ExpectedSubscriptionData { + address publisher; + uint32 indexId; + address subscriber; + bool approved; + bool exist; + uint128 units; + uint256 unitsPendingDistribution; + } + + address public adminPrankAccount; + ISuperToken public superToken; + SuperfluidFramework public sfFramework; + uint256 public snapshot; + + constructor( + ISuperToken _superToken, + address _adminPrankAccount, + IResolver resolver, + string memory providerURLKey + ) { + string memory providerURL = vm.envString(providerURLKey); + vm.createSelectFork(providerURL); + + adminPrankAccount = _adminPrankAccount; + superToken = _superToken; + SuperfluidLoader superfluidLoader = SuperfluidLoader( + resolver.get("SuperfluidLoader-v1") + ); + SuperfluidLoader.Framework memory framework = superfluidLoader + .loadFramework("v1"); + + sfFramework = SuperfluidFramework({ + host: framework.superfluid, + idaV1: IInstantDistributionAgreementV1( + address(framework.agreementIDAv1) + ), + cfaV1: IConstantFlowAgreementV1(address(framework.agreementCFAv1)), + superfluidLoader: superfluidLoader, + superTokenFactory: framework.superTokenFactory, + governance: framework.superfluid.getGovernance(), + token: _superToken + }); + snapshot = vm.snapshot(); + } + + function assert_Expected_Flow_Rate( + ISuperToken _superToken, + address sender, + address receiver, + int96 expectedFlowRate + ) public { + (, int96 flowRate, , ) = _superToken.getFlowInfo(sender, receiver); + assertEq(flowRate, expectedFlowRate, "flow rate not equal"); + } + + function assert_Balance_Is_Expected( + IERC20 _token, + address account, + uint256 expectedBalance + ) public { + assertEq(_token.balanceOf(account), expectedBalance, "token balance not equal"); + } + + function assert_Flow_Permissions( + ISuperToken token, + address sender, + address flowOperator, + bool expectedAllowCreate, + bool expectedAllowUpdate, + bool expectedAllowDelete, + int96 expectedFlowRateAllowance + ) public { + ( + bool allowCreate, + bool allowUpdate, + bool allowDelete, + int96 flowRateAllowance + ) = token.getFlowPermissions(sender, flowOperator); + (, int96 flowRate, , ) = token.getFlowInfo(sender, flowOperator); + assertEq(allowCreate, expectedAllowCreate); + assertEq(allowUpdate, expectedAllowUpdate); + assertEq(allowDelete, expectedAllowDelete); + } + + function assert_Expected_Index_Data( + ISuperToken _superToken, + ExpectedIndexData memory expectedIndexData + ) public { + ( + bool exist, + uint128 indexValue, + uint128 totalUnitsApproved, + uint128 totalUnitsPending + ) = _superToken.getIndex( + expectedIndexData.publisher, + expectedIndexData.indexId + ); + + assertEq(exist, expectedIndexData.exist, "index data: exist not equal"); + assertEq(indexValue, expectedIndexData.indexValue, "index data: indexValue not equal"); + assertEq(totalUnitsApproved, expectedIndexData.totalUnitsApproved, "index data: totalUnitsApproved not equal"); + assertEq(totalUnitsPending, expectedIndexData.totalUnitsPending, "index data: totalUnitsPending not equal"); + } + + function assert_Expected_Subscription_Data( + ISuperToken _superToken, + ExpectedSubscriptionData memory expectedSubscriptionData + ) public { + ( + bool exist, + bool approved, + uint128 units, + uint256 pendingDistribution + ) = _superToken.getSubscription( + expectedSubscriptionData.publisher, + expectedSubscriptionData.indexId, + expectedSubscriptionData.subscriber + ); + + assertEq(expectedSubscriptionData.exist, exist, "subscription data: exist not equal"); + assertEq(expectedSubscriptionData.units, units, "subscription data: units not equal"); + assertEq(expectedSubscriptionData.unitsPendingDistribution, approved ? 0 : pendingDistribution, "subscription data: pending distribution not equal"); + } + + function helper_Create_Update_Delete_Flow_One_To_One( + ISuperToken _superToken, + address prankedAccount + ) public { + // test that flows can still be created with SuperTokenFactory updated + vm.startPrank(prankedAccount); + + _superToken.createFlow(address(1), 42069); + assert_Expected_Flow_Rate(_superToken, prankedAccount, address(1), 42069); + + _superToken.updateFlow(address(1), 4206933); + assert_Expected_Flow_Rate(_superToken, prankedAccount, address(1), 4206933); + + _superToken.deleteFlow(prankedAccount, address(1)); + assert_Expected_Flow_Rate(_superToken, prankedAccount, address(1), 0); + + vm.stopPrank(); + } + + function helper_Wrap_Unwrap( + ISuperToken _superToken, + address prankedAccount + ) public { + // test that flows can still be created with SuperTokenFactory updated + vm.startPrank(prankedAccount); + IERC20 underlyingToken = IERC20(_superToken.getUnderlyingToken()); + uint256 underlyingTokenBalanceBefore = underlyingToken.balanceOf( + prankedAccount + ); + uint256 superTokenBalanceBefore = _superToken.balanceOf(prankedAccount); + _superToken.upgrade(42069); + assert_Balance_Is_Expected( + underlyingToken, + prankedAccount, + underlyingTokenBalanceBefore - 42069 + ); + assert_Balance_Is_Expected( + _superToken, + prankedAccount, + superTokenBalanceBefore + 42069 + ); + + _superToken.downgrade(420691); + assert_Balance_Is_Expected( + underlyingToken, + prankedAccount, + underlyingTokenBalanceBefore - 42069 + 420691 + ); + assert_Balance_Is_Expected( + _superToken, + prankedAccount, + superTokenBalanceBefore + 42069 - 420691 + ); + + vm.stopPrank(); + } + + function helper_Set_Flow_Permissions( + ISuperToken _superToken, + address prankedAccount + ) public { + vm.startPrank(prankedAccount); + _superToken.setFlowPermissions(address(1), true, true, true, 42069); + assert_Flow_Permissions( + _superToken, + prankedAccount, + address(1), + true, + true, + true, + 42069 + ); + vm.stopPrank(); + } + + function helper_Set_Max_Flow_Permissions( + ISuperToken _superToken, + address prankedAccount + ) public { + vm.startPrank(prankedAccount); + _superToken.setMaxFlowPermissions(address(1)); + assert_Flow_Permissions( + _superToken, + prankedAccount, + address(1), + true, + true, + true, + type(int96).max + ); + vm.stopPrank(); + } + + function helper_Set_Revoke_Flow_Permissions( + ISuperToken _superToken, + address prankedAccount + ) public { + vm.startPrank(prankedAccount); + + _superToken.revokeFlowPermissions(address(1)); + assert_Flow_Permissions( + _superToken, + prankedAccount, + address(1), + false, + false, + false, + 0 + ); + + vm.stopPrank(); + } + + function helper_ACL_Create_Update_Delete_Flow_One_To_One( + ISuperToken _superToken, + address prankedAccount + ) public { + helper_Set_Max_Flow_Permissions(_superToken, prankedAccount); + vm.startPrank(address(1)); + _superToken.createFlowFrom(prankedAccount, address(1), 42069); + assert_Expected_Flow_Rate(_superToken, prankedAccount, address(1), 42069); + _superToken.updateFlowFrom(prankedAccount, address(1), 4206933); + assert_Expected_Flow_Rate(_superToken, prankedAccount, address(1), 4206933); + _superToken.deleteFlowFrom(prankedAccount, address(1)); + assert_Expected_Flow_Rate(_superToken, prankedAccount, address(1), 0); + vm.stopPrank(); + } + + function helper_Create_Non_Upgradeable_Super_Token( + ISuperTokenFactory superTokenFactory, + IERC20 underlyingToken, + address prankedAccount + ) public { + vm.startPrank(prankedAccount); + vm.expectRevert(ISuperTokenFactory.SUPER_TOKEN_FACTORY_NON_UPGRADEABLE_IS_DEPRECATED.selector); + superTokenFactory.createERC20Wrapper( + underlyingToken, + 18, + ISuperTokenFactory.Upgradability.NON_UPGRADABLE, + "Super Mr.", + "MRx" + ); + vm.stopPrank(); + } + + function helper_Create_Semi_Upgradeable_Super_Token( + ISuperTokenFactory superTokenFactory, + IERC20 underlyingToken, + address prankedAccount + ) public { + vm.startPrank(prankedAccount); + superTokenFactory.createERC20Wrapper( + underlyingToken, + 18, + ISuperTokenFactory.Upgradability.SEMI_UPGRADABLE, + "Super Mr.", + "MRx" + ); + vm.stopPrank(); + } + + function helper_Create_Fully_Upgradeable_Super_Token( + ISuperTokenFactory superTokenFactory, + IERC20 underlyingToken, + address prankedAccount + ) public { + vm.startPrank(prankedAccount); + + superTokenFactory.createERC20Wrapper( + underlyingToken, + 18, + ISuperTokenFactory.Upgradability.FULL_UPGRADABLE, + "Super Mr.", + "MRx" + ); + vm.stopPrank(); + } + + function helper_Create_Index( + ISuperToken _superToken, + address publisher + ) public { + vm.startPrank(publisher); + _superToken.createIndex(1); + assert_Expected_Index_Data( + _superToken, + ExpectedIndexData({ + publisher: publisher, + indexId: 1, + exist: true, + indexValue: 0, + totalUnitsApproved: 0, + totalUnitsPending: 0 + }) + ); + vm.stopPrank(); + } + + function helper_Update_Index_Value( + ISuperToken _superToken, + address publisher, + uint128 newIndexValue + ) public { + ( + bool exist, + uint128 indexValue, + uint128 totalUnitsApproved, + uint128 totalUnitsPending + ) = _superToken.getIndex( + publisher, + 1 + ); + vm.startPrank(publisher); + _superToken.updateIndexValue(1, newIndexValue); + assert_Expected_Index_Data( + _superToken, + ExpectedIndexData({ + publisher: publisher, + indexId: 1, + exist: true, + indexValue: newIndexValue, + totalUnitsApproved: totalUnitsApproved, + totalUnitsPending: totalUnitsPending + }) + ); + + vm.stopPrank(); + } + + function helper_Distribute( + ISuperToken _superToken, + address publisher, + uint256 distributionAmount + ) public { + vm.startPrank(publisher); + _superToken.distribute(1, distributionAmount); + vm.stopPrank(); + } + + function helper_Approve_Subscription( + ISuperToken _superToken, + address publisher, + address subscriber + ) public { + (, , uint128 units, uint256 pendingDistribution) = _superToken + .getSubscription(publisher, 1, subscriber); + vm.startPrank(subscriber); + _superToken.approveSubscription(publisher, 1); + assert_Expected_Subscription_Data( + _superToken, + ExpectedSubscriptionData({ + publisher: publisher, + subscriber: subscriber, + indexId: 1, + exist: true, + units: units, + approved: true, + unitsPendingDistribution: pendingDistribution + }) + ); + vm.stopPrank(); + } + + function helper_Revoke_Subscription( + ISuperToken _superToken, + address publisher, + address subscriber + ) public { + (, bool approved, uint128 units, uint256 pendingDistribution) = _superToken + .getSubscription(publisher, 1, subscriber); + vm.startPrank(subscriber); + _superToken.revokeSubscription(publisher, 1); + assert_Expected_Subscription_Data( + _superToken, + ExpectedSubscriptionData({ + publisher: publisher, + subscriber: subscriber, + indexId: 1, + exist: true, + units: units, + approved: false, + unitsPendingDistribution: pendingDistribution + }) + ); + vm.stopPrank(); + } + + function helper_Update_Subscription_Units( + ISuperToken _superToken, + address publisher, + address subscriber, + uint128 newSubscriptionUnits + ) public { + ( + , + bool approved, + uint128 units, + uint256 pendingDistribution + ) = _superToken.getSubscription(publisher, 1, subscriber); + vm.startPrank(publisher); + _superToken.updateSubscriptionUnits( + 1, + subscriber, + newSubscriptionUnits + ); + assert_Expected_Subscription_Data( + _superToken, + ExpectedSubscriptionData({ + publisher: publisher, + subscriber: subscriber, + indexId: 1, + exist: true, + units: newSubscriptionUnits, + approved: approved, + unitsPendingDistribution: 0 + }) + ); + + vm.stopPrank(); + } + + function helper_Delete_Subscription( + ISuperToken _superToken, + address publisher, + address subscriber + ) public { + vm.startPrank(publisher); + _superToken.deleteSubscription(publisher, 1, subscriber); + assert_Expected_Subscription_Data( + _superToken, + ExpectedSubscriptionData({ + publisher: publisher, + subscriber: subscriber, + indexId: 1, + exist: false, + units: 0, + approved: false, + unitsPendingDistribution: 0 + }) + ); + vm.stopPrank(); + } + + function helper_Claim( + ISuperToken _superToken, + address publisher, + address subscriber + ) public { + (bool exist, bool approved, uint128 units, uint256 pendingDistribution) = _superToken + .getSubscription(publisher, 1, subscriber); + vm.startPrank(subscriber); + _superToken.claim(publisher, 1, subscriber); + assert_Expected_Subscription_Data( + _superToken, + ExpectedSubscriptionData({ + publisher: publisher, + subscriber: subscriber, + indexId: 1, + exist: exist, + units: units, + approved: approved, + unitsPendingDistribution: 0 + }) + ); + vm.stopPrank(); + } + + function helper_Run_Full_Smoke_Tests() public { + // SuperToken Smoke Tests + helper_Wrap_Unwrap(superToken, adminPrankAccount); + + // SuperTokenFactory Smoke Tests + ERC20 mrToken = new ERC20("Mr. Token", "MR"); + helper_Create_Non_Upgradeable_Super_Token( + sfFramework.superTokenFactory, + mrToken, + adminPrankAccount + ); + + helper_Create_Semi_Upgradeable_Super_Token( + sfFramework.superTokenFactory, + mrToken, + adminPrankAccount + ); + + helper_Create_Fully_Upgradeable_Super_Token( + sfFramework.superTokenFactory, + mrToken, + adminPrankAccount + ); + + // ConstantFlowAgreementV1 Smoke Tests + helper_Create_Update_Delete_Flow_One_To_One( + superToken, + adminPrankAccount + ); + + helper_Set_Flow_Permissions(superToken, adminPrankAccount); + + helper_Set_Max_Flow_Permissions(superToken, adminPrankAccount); + + helper_Set_Revoke_Flow_Permissions(superToken, adminPrankAccount); + + helper_ACL_Create_Update_Delete_Flow_One_To_One( + superToken, + adminPrankAccount + ); + + // InstantDistributionAgreementV1 Smoke Tests + // create index + helper_Create_Index(superToken, adminPrankAccount); + + // update subscription units to three addresses + helper_Update_Subscription_Units(superToken, adminPrankAccount, address(1), 1); + helper_Update_Subscription_Units(superToken, adminPrankAccount, address(2), 1); + helper_Update_Subscription_Units(superToken, adminPrankAccount, address(3), 1); + + // approve two subscriptions + helper_Approve_Subscription(superToken, adminPrankAccount, address(1)); + helper_Approve_Subscription(superToken, adminPrankAccount, address(3)); + + // revoke one subscription of the approved + helper_Revoke_Subscription(superToken, adminPrankAccount, address(3)); + + // delete the revoked subscription + helper_Delete_Subscription(superToken, adminPrankAccount, address(3)); + + // update the index value + helper_Update_Index_Value(superToken, adminPrankAccount, 420); + + // claim a subscription + helper_Claim(superToken, adminPrankAccount, address(2)); + + // // execute a distribution + helper_Distribute(superToken, adminPrankAccount, 420); + + // // claim a subscription + helper_Claim(superToken, adminPrankAccount, address(2)); + } + + /// @notice A suite of smoke tests to be run after an upgrade + /// @dev This is run after constructor and setUp is run + function test_Passing_Run_Full_Smoke_Tests_Post_Upgrade() public { + helper_Run_Full_Smoke_Tests(); + } +} diff --git a/packages/ethereum-contracts/test/scripts/deployment.test.js b/packages/ethereum-contracts/test/ops-scripts/deployment.test.js similarity index 100% rename from packages/ethereum-contracts/test/scripts/deployment.test.js rename to packages/ethereum-contracts/test/ops-scripts/deployment.test.js diff --git a/packages/ethereum-contracts/test/scripts/deployment.test.sh b/packages/ethereum-contracts/test/ops-scripts/deployment.test.sh similarity index 100% rename from packages/ethereum-contracts/test/scripts/deployment.test.sh rename to packages/ethereum-contracts/test/ops-scripts/deployment.test.sh diff --git a/packages/ethereum-contracts/tsconfig.json b/packages/ethereum-contracts/tsconfig.json index 1767969c8b..4d6ee3e61c 100644 --- a/packages/ethereum-contracts/tsconfig.json +++ b/packages/ethereum-contracts/tsconfig.json @@ -101,5 +101,5 @@ // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ "skipLibCheck": true /* Skip type checking all .d.ts files. */ }, - "include": ["testsuites", "test", "./typechain-types", "scripts"] + "include": ["testsuites", "test", "./typechain-types", "scripts", "hardhat.config.ts"] } diff --git a/packages/hot-fuzz/echidna.yaml b/packages/hot-fuzz/echidna.yaml index 99bf98a3fd..f04c5d546b 100644 --- a/packages/hot-fuzz/echidna.yaml +++ b/packages/hot-fuzz/echidna.yaml @@ -7,7 +7,7 @@ deployContracts: [ ["0x00000000000000000000000000000000000000f4", "SuperfluidHostDeployerLibrary"], ["0x00000000000000000000000000000000000000f5", "SuperfluidIDAv1DeployerLibrary"], ["0x00000000000000000000000000000000000000f6", "SuperfluidPeripheryDeployerLibrary"], - ["0x00000000000000000000000000000000000000f7", "SuperfluidSuperTokenFactoryHelperDeployerLibrary"], + ["0x00000000000000000000000000000000000000f7", "SuperTokenDeployerLibrary"], ] deployBytecodes: [ ["0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24", "608060405234801561001057600080fd5b506109c5806100206000396000f3fe608060405234801561001057600080fd5b50600436106100a5576000357c010000000000000000000000000000000000000000000000000000000090048063a41e7d5111610078578063a41e7d51146101d4578063aabbb8ca1461020a578063b705676514610236578063f712f3e814610280576100a5565b806329965a1d146100aa5780633d584063146100e25780635df8122f1461012457806365ba36c114610152575b600080fd5b6100e0600480360360608110156100c057600080fd5b50600160a060020a038135811691602081013591604090910135166102b6565b005b610108600480360360208110156100f857600080fd5b5035600160a060020a0316610570565b60408051600160a060020a039092168252519081900360200190f35b6100e06004803603604081101561013a57600080fd5b50600160a060020a03813581169160200135166105bc565b6101c26004803603602081101561016857600080fd5b81019060208101813564010000000081111561018357600080fd5b82018360208201111561019557600080fd5b803590602001918460018302840111640100000000831117156101b757600080fd5b5090925090506106b3565b60408051918252519081900360200190f35b6100e0600480360360408110156101ea57600080fd5b508035600160a060020a03169060200135600160e060020a0319166106ee565b6101086004803603604081101561022057600080fd5b50600160a060020a038135169060200135610778565b61026c6004803603604081101561024c57600080fd5b508035600160a060020a03169060200135600160e060020a0319166107ef565b604080519115158252519081900360200190f35b61026c6004803603604081101561029657600080fd5b508035600160a060020a03169060200135600160e060020a0319166108aa565b6000600160a060020a038416156102cd57836102cf565b335b9050336102db82610570565b600160a060020a031614610339576040805160e560020a62461bcd02815260206004820152600f60248201527f4e6f7420746865206d616e616765720000000000000000000000000000000000604482015290519081900360640190fd5b6103428361092a565b15610397576040805160e560020a62461bcd02815260206004820152601a60248201527f4d757374206e6f7420626520616e204552433136352068617368000000000000604482015290519081900360640190fd5b600160a060020a038216158015906103b85750600160a060020a0382163314155b156104ff5760405160200180807f455243313832305f4143434550545f4d4147494300000000000000000000000081525060140190506040516020818303038152906040528051906020012082600160a060020a031663249cb3fa85846040518363ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004018083815260200182600160a060020a0316600160a060020a031681526020019250505060206040518083038186803b15801561047e57600080fd5b505afa158015610492573d6000803e3d6000fd5b505050506040513d60208110156104a857600080fd5b5051146104ff576040805160e560020a62461bcd02815260206004820181905260248201527f446f6573206e6f7420696d706c656d656e742074686520696e74657266616365604482015290519081900360640190fd5b600160a060020a03818116600081815260208181526040808320888452909152808220805473ffffffffffffffffffffffffffffffffffffffff19169487169485179055518692917f93baa6efbd2244243bfee6ce4cfdd1d04fc4c0e9a786abd3a41313bd352db15391a450505050565b600160a060020a03818116600090815260016020526040812054909116151561059a5750806105b7565b50600160a060020a03808216600090815260016020526040902054165b919050565b336105c683610570565b600160a060020a031614610624576040805160e560020a62461bcd02815260206004820152600f60248201527f4e6f7420746865206d616e616765720000000000000000000000000000000000604482015290519081900360640190fd5b81600160a060020a031681600160a060020a0316146106435780610646565b60005b600160a060020a03838116600081815260016020526040808220805473ffffffffffffffffffffffffffffffffffffffff19169585169590951790945592519184169290917f605c2dbf762e5f7d60a546d42e7205dcb1b011ebc62a61736a57c9089d3a43509190a35050565b600082826040516020018083838082843780830192505050925050506040516020818303038152906040528051906020012090505b92915050565b6106f882826107ef565b610703576000610705565b815b600160a060020a03928316600081815260208181526040808320600160e060020a031996909616808452958252808320805473ffffffffffffffffffffffffffffffffffffffff19169590971694909417909555908152600284528181209281529190925220805460ff19166001179055565b600080600160a060020a038416156107905783610792565b335b905061079d8361092a565b156107c357826107ad82826108aa565b6107b85760006107ba565b815b925050506106e8565b600160a060020a0390811660009081526020818152604080832086845290915290205416905092915050565b6000808061081d857f01ffc9a70000000000000000000000000000000000000000000000000000000061094c565b909250905081158061082d575080155b1561083d576000925050506106e8565b61084f85600160e060020a031961094c565b909250905081158061086057508015155b15610870576000925050506106e8565b61087a858561094c565b909250905060018214801561088f5750806001145b1561089f576001925050506106e8565b506000949350505050565b600160a060020a0382166000908152600260209081526040808320600160e060020a03198516845290915281205460ff1615156108f2576108eb83836107ef565b90506106e8565b50600160a060020a03808316600081815260208181526040808320600160e060020a0319871684529091529020549091161492915050565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff161590565b6040517f01ffc9a7000000000000000000000000000000000000000000000000000000008082526004820183905260009182919060208160248189617530fa90519096909550935050505056fea165627a7a72305820377f4a2d4301ede9949f163f319021a6e9c687c292a5e2b2c4734c126b524e6c0029"], diff --git a/packages/hot-fuzz/index.js b/packages/hot-fuzz/index.js index 8b51114986..b6ebb54706 100644 --- a/packages/hot-fuzz/index.js +++ b/packages/hot-fuzz/index.js @@ -14,23 +14,13 @@ function hotfuzzPatchTruffleConfig(c) { "@superfluid-finance/ethereum-contracts/contracts/libs/SlotsBitmapLibrary.sol": { SlotsBitmapLibrary: "0x" + "0".repeat(38) + "f1", }, - "@superfluid-finance/ethereum-contracts/contracts/utils/deployers/SuperfluidCFAv1DeployerLibrary.sol": { + "@superfluid-finance/ethereum-contracts/contracts/utils/SuperfluidFrameworkDeployer.sol": { SuperfluidCFAv1DeployerLibrary: "0x" + "0".repeat(38) + "f2", - }, - "@superfluid-finance/ethereum-contracts/contracts/utils/deployers/SuperfluidGovDeployerLibrary.sol": { SuperfluidGovDeployerLibrary: "0x" + "0".repeat(38) + "f3", - }, - "@superfluid-finance/ethereum-contracts/contracts/utils/deployers/SuperfluidHostDeployerLibrary.sol": { SuperfluidHostDeployerLibrary: "0x" + "0".repeat(38) + "f4", - }, - "@superfluid-finance/ethereum-contracts/contracts/utils/deployers/SuperfluidIDAv1DeployerLibrary.sol": { SuperfluidIDAv1DeployerLibrary: "0x" + "0".repeat(38) + "f5", - }, - "@superfluid-finance/ethereum-contracts/contracts/utils/deployers/SuperfluidPeripheryDeployerLibrary.sol": { SuperfluidPeripheryDeployerLibrary: "0x" + "0".repeat(38) + "f6", - }, - "@superfluid-finance/ethereum-contracts/contracts/utils/deployers/SuperfluidSuperTokenFactoryHelperDeployerLibrary.sol": { - SuperfluidSuperTokenFactoryHelperDeployerLibrary: "0x" + "0".repeat(38) + "f7", + SuperTokenDeployerLibrary: "0x" + "0".repeat(38) + "f7", }, }; diff --git a/packages/hot-fuzz/truffle-config.js b/packages/hot-fuzz/truffle-config.js index 6744b2be09..456a40726e 100644 --- a/packages/hot-fuzz/truffle-config.js +++ b/packages/hot-fuzz/truffle-config.js @@ -81,7 +81,7 @@ const M = (module.exports = { // Configure your compilers compilers: { solc: { - version: "0.8.16", // Fetch exact version from solc-bin (default: truffle's version) + version: "0.8.18", // Fetch exact version from solc-bin (default: truffle's version) // docker: true, // Use "0.5.1" you've installed locally with docker (default: false) settings: { // See the solidity docs for advice about optimization and evmVersion