Skip to content

Commit

Permalink
Fixes during GDA mainnet rollout (#1780)
Browse files Browse the repository at this point in the history
* make superfluidPoolBeacon part of GeneralDistributionAgreementV1 logic

* fix up nft constructor

* update deploy script to latest changes

* fix gov script

* 2-phase GDA bootstrapping

* pool placeholder contract

* 2-step GDA bootstrapping, fix verification script

* more consistent naming

* token update: skip tokens we don't own (not pointing to a previous canonical logic)

* updated bsc metadata

* piggyback: added aux contracts to scroll-mainnet metadata

* please the linter

* metadata changelog

* improved verification script

* refine deploy script

* patch gas settings into truffle contract object, various small ops-script improvements

* patch gas settings into truffle contract object, various small ops-script improvements

* fix for local testing

* fix gas price for other ops scripts too

* polygon-mainnet gda and new loader in metadata

* smol fix

* fix tests

* smol fixes

* inlike function for getting gas settings in Framework.js to fix failing package building

* consider new admin override when upgrading SuperTokens

* fix test failure

* add forwarders to verification

* refactor SuperfluidFrameworkDeploymentSteps to reduce sizes

* [WORKFLOWS] make sure linting happens in more places

* [WORKFLOWS] fix the shell script

* fix typo: SuperfluidGDAv1DeployerLibrary

* fix typo: SuperfluidGDAv1DeployerLibrary

* fix build warning SuperfluidPoolPlaceholder.sol

* fixes

* fixes

* some fixes to

* fix gov.updateContracts

* already remove the deprecated overloaded method, too much fallout

* revert ugly workaround for overloaded (nomore) method

* [WORKFLOW] cleanups to root package.json

* audit changelog

---------

Co-authored-by: 0xdavinchee <0xdavinchee@gmail.com>
Co-authored-by: didi <git@d10r.net>
  • Loading branch information
3 people authored Feb 7, 2024
1 parent 2d2d66f commit 80099ac
Show file tree
Hide file tree
Showing 38 changed files with 1,017 additions and 1,049 deletions.
21 changes: 10 additions & 11 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,7 @@
"npmClient": "yarn",
"license": "MIT",
"scripts": {
"prepare": "yarn git:submodule:init",
"git:submodule:init": "git submodule update --init --recursive",
"git:submodule:update": "git submodule update --recursive",
"git:submodule:sync": "git submodule update --remote --recursive;git submodule sync --recursive",
"git:submodule:deinit": "git submodule deinit --all --force",
"postinstall": "yarn git-submodule:init && husky install",
"lint": "run-s lint:*",
"lint:shellcheck": "tasks/shellcheck-all-tasks.sh",
"lint:workspaces": "yarn workspaces run lint",
Expand All @@ -23,17 +19,20 @@
"build-for-contracts-dev": "set -ex;for i in metadata ethereum-contracts js-sdk;do yarn workspace @superfluid-finance/$i build;done",
"clean": "rm -rf node_modules; rm -rf packages/*/node_modules; yarn workspace @superfluid-finance/ethereum-contracts clean",
"test": "set -ex;for i in ethereum-contracts;do yarn workspace @superfluid-finance/$i test;done",
"manage-versions": "lerna version --exact --no-git-tag-version --preid rc",
"check-updates": "run-s check-updates:*",
"check-updates:root": "ncu --target minor --dep dev -u",
"check-updates:workspaces": "yarn workspaces run check-updates -u",
"show-versions": "lerna ls --long",
"postinstall": "husky install",
"pre-commit": "yarn lint:shellcheck && yarn workspaces run pre-commit",
"git-submodule:init": "git submodule update --init --recursive",
"git-submodule:update": "git submodule update --recursive",
"git-submodule:sync": "git submodule update --remote --recursive;git submodule sync --recursive",
"git-submodule:deinit": "git submodule deinit --all --force",
"check-updates": "run-s check-updates:*",
"check-updates:root": "ncu --target minor --dep dev",
"check-updates:workspaces": "yarn workspaces run check-updates",
"shell": "nix develop",
"shell:spec": "nix develop .#spec",
"shell:whitehat": "nix develop .#whitehat",
"shell:full": "nix develop .#full"
"shell:full": "nix develop .#full",
"manage-versions": "lerna version --exact --no-git-tag-version --preid rc"
},
"devDependencies": {
"@nomicfoundation/hardhat-chai-matchers": "^1.0.6",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,19 @@ Use `git diff 4ece1a3f4aff8b5a9cbf37118d261023960c0f0f.. packages/ethereum-contr
- `PoolConnectionUpdated` event only emitted if the connection was changed

### SuperfluidPool
The method for obtaining timestamps and checking member connections is updated to use Superfluid framework methods instead of Ethereum's native functionalities.
The method for obtaining timestamps and checking member connections is updated to use Superfluid framework methods instead of Ethereum's native functionalities.

### SuperfluidPoolPlaceholder
- A contract to be used on the first deployment (upgrade case) of the GDA to prevent circular dependency between GDA and SuperfluidPool

### SuperfluidGovernanceBase
- `updatePoolBeaconLogic` added for updating the pool beacon logic

### Superfluid
- `updatePoolBeaconLogic` added for updating the pool beacon logic (to be called via Governance)

### SafeGasLibrary
- `gasleft() <= gasLeftBefore / 63` => `gasleft() <= gasLeftBefore / 64` per the recommendation from the audit

### NFT Contracts
- Agreements passed to the constructor due to issues that we ran into during the deployment process
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
pragma solidity 0.8.19;

import { SafeCast } from "@openzeppelin/contracts/utils/math/SafeCast.sol";
import { IBeacon } from "@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol";

import { ISuperfluid, ISuperfluidGovernance } from "../../interfaces/superfluid/ISuperfluid.sol";
import {
Expand All @@ -21,6 +20,7 @@ import {
IGeneralDistributionAgreementV1,
PoolConfig
} from "../../interfaces/agreements/gdav1/IGeneralDistributionAgreementV1.sol";
import { SuperfluidUpgradeableBeacon } from "../../upgradability/SuperfluidUpgradeableBeacon.sol";
import { ISuperfluidToken } from "../../interfaces/superfluid/ISuperfluidToken.sol";
import { IConstantOutflowNFT } from "../../interfaces/superfluid/IConstantOutflowNFT.sol";
import { ISuperToken } from "../../interfaces/superfluid/ISuperToken.sol";
Expand Down Expand Up @@ -94,11 +94,9 @@ contract GeneralDistributionAgreementV1 is AgreementBase, TokenMonad, IGeneralDi
bytes32 private constant SUPERTOKEN_MINIMUM_DEPOSIT_KEY =
keccak256("org.superfluid-finance.superfluid.superTokenMinimumDeposit");

IBeacon public superfluidPoolBeacon;
SuperfluidUpgradeableBeacon public immutable superfluidPoolBeacon;

constructor(ISuperfluid host) AgreementBase(address(host)) { }

function initialize(IBeacon superfluidPoolBeacon_) external initializer {
constructor(ISuperfluid host, SuperfluidUpgradeableBeacon superfluidPoolBeacon_) AgreementBase(address(host)) {
superfluidPoolBeacon = superfluidPoolBeacon_;
}

Expand Down Expand Up @@ -335,7 +333,7 @@ contract GeneralDistributionAgreementV1 is AgreementBase, TokenMonad, IGeneralDi

_clearPoolConnectionsBitmap(token, msgSender, poolMemberData.poolID);
}

emit PoolConnectionUpdated(token, pool, msgSender, doConnect, currentContext.userData);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ pragma solidity 0.8.19;
import { IERC721Metadata } from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol";
import { IPoolAdminNFT } from "../../interfaces/agreements/gdav1/IPoolAdminNFT.sol";
import { PoolNFTBase } from "./PoolNFTBase.sol";
import { ISuperfluid } from "../../interfaces/superfluid/ISuperfluid.sol";
import { IGeneralDistributionAgreementV1, ISuperfluid } from "../../interfaces/superfluid/ISuperfluid.sol";
import { ISuperfluidPool } from "../../interfaces/agreements/gdav1/ISuperfluidPool.sol";
import { ISuperfluidToken } from "../../interfaces/superfluid/ISuperfluidToken.sol";

Expand All @@ -22,7 +22,7 @@ contract PoolAdminNFT is PoolNFTBase, IPoolAdminNFT {
/// @dev The token id is uint256(keccak256(abi.encode(pool, admin)))
mapping(uint256 => PoolAdminNFTData) internal _poolAdminDataByTokenId;

constructor(ISuperfluid host) PoolNFTBase(host) { }
constructor(ISuperfluid host, IGeneralDistributionAgreementV1 gdaV1) PoolNFTBase(host, gdaV1) { }

// note that this is used so we don't upgrade to wrong logic contract
function proxiableUUID() public pure override returns (bytes32) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ pragma solidity 0.8.19;
import { IERC721Metadata } from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol";
import { IPoolMemberNFT } from "../../interfaces/agreements/gdav1/IPoolMemberNFT.sol";
import { PoolNFTBase } from "./PoolNFTBase.sol";
import { ISuperfluid } from "../../interfaces/superfluid/ISuperfluid.sol";
import { IGeneralDistributionAgreementV1, ISuperfluid } from "../../interfaces/superfluid/ISuperfluid.sol";
import { ISuperfluidPool } from "../../interfaces/agreements/gdav1/ISuperfluidPool.sol";
import { ISuperfluidToken } from "../../interfaces/superfluid/ISuperfluidToken.sol";

Expand All @@ -22,7 +22,7 @@ contract PoolMemberNFT is PoolNFTBase, IPoolMemberNFT {
/// @dev The token id is uint256(keccak256(abi.encode(pool, member)))
mapping(uint256 => PoolMemberNFTData) internal _poolMemberDataByTokenId;

constructor(ISuperfluid host) PoolNFTBase(host) { }
constructor(ISuperfluid host, IGeneralDistributionAgreementV1 gdaV1) PoolNFTBase(host, gdaV1) { }

// note that this is used so we don't upgrade to wrong logic contract
function proxiableUUID() public pure override returns (bytes32) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,9 @@ pragma solidity 0.8.19;
// solhint-disable-next-line no-unused-import
import { IERC165, IERC721, IERC721Metadata } from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol";
import { UUPSProxiable } from "../../upgradability/UUPSProxiable.sol";
import { ISuperfluid } from "../../interfaces/superfluid/ISuperfluid.sol";
import { IGeneralDistributionAgreementV1, ISuperfluid } from "../../interfaces/superfluid/ISuperfluid.sol";
import { ISuperTokenFactory } from "../../interfaces/superfluid/ISuperTokenFactory.sol";
import { IPoolNFTBase } from "../../interfaces/agreements/gdav1/IPoolNFTBase.sol";
import { IGeneralDistributionAgreementV1 } from "../../interfaces/agreements/gdav1/IGeneralDistributionAgreementV1.sol";

abstract contract PoolNFTBase is UUPSProxiable, IPoolNFTBase {
string public constant DEFAULT_BASE_URI = "https://nft.superfluid.finance/pool/v2/getmeta";
Expand Down Expand Up @@ -68,15 +67,9 @@ abstract contract PoolNFTBase is UUPSProxiable, IPoolNFTBase {
uint256 private _reserve20;
uint256 internal _reserve21;

constructor(ISuperfluid host) {
constructor(ISuperfluid host, IGeneralDistributionAgreementV1 gdaV1) {
HOST = host;
GENERAL_DISTRIBUTION_AGREEMENT_V1 = IGeneralDistributionAgreementV1(
address(
ISuperfluid(host).getAgreementClass(
keccak256("org.superfluid-finance.agreements.GeneralDistributionAgreement.v1")
)
)
);
GENERAL_DISTRIBUTION_AGREEMENT_V1 = gdaV1;
}

function initialize(string memory nftName, string memory nftSymbol)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// SPDX-License-Identifier: AGPLv3
// solhint-disable not-rely-on-time
pragma solidity 0.8.19;

import { BeaconProxiable } from "../../upgradability/BeaconProxiable.sol";

/**
* @title used on first deployment (upgrade case) of GDA
* in order to solve the circular dependency between GDA and SuperfluidPool
*/
contract SuperfluidPoolPlaceholder is BeaconProxiable {
// don't allow to create instances of the placeholder
function initialize(address, address, bool ,bool) external pure {
// solhint-disable-next-line reason-string
revert();
}

function proxiableUUID() public pure override returns (bytes32) {
return keccak256("org.superfluid-finance.contracts.SuperfluidPool.implementation");
}
}
25 changes: 20 additions & 5 deletions packages/ethereum-contracts/contracts/mocks/CFAv1NFTMock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,13 @@
pragma solidity 0.8.19;

import { Strings } from "@openzeppelin/contracts/utils/Strings.sol";
import { ISuperfluid, IConstantInflowNFT, IConstantOutflowNFT } from "../interfaces/superfluid/ISuperfluid.sol";
import {
IConstantFlowAgreementV1,
IGeneralDistributionAgreementV1,
ISuperfluid,
IConstantInflowNFT,
IConstantOutflowNFT
} from "../interfaces/superfluid/ISuperfluid.sol";
import { ConstantOutflowNFT } from "../superfluid/ConstantOutflowNFT.sol";
import { ConstantInflowNFT } from "../superfluid/ConstantInflowNFT.sol";
import { FlowNFTBase } from "../superfluid/FlowNFTBase.sol";
Expand All @@ -17,7 +23,9 @@ contract FlowNFTBaseMock is FlowNFTBase {

mapping(uint256 => FlowNFTData) internal _flowDataByTokenId;

constructor(ISuperfluid host) FlowNFTBase(host) { }
constructor(ISuperfluid host, IConstantFlowAgreementV1 cfaV1, IGeneralDistributionAgreementV1 gdaV1)
FlowNFTBase(host, cfaV1, gdaV1)
{ }

function proxiableUUID() public pure override returns (bytes32) {
return keccak256("org.superfluid-finance.contracts.FlowNFTBaseMock.implementation");
Expand Down Expand Up @@ -57,7 +65,12 @@ contract FlowNFTBaseMock is FlowNFTBase {
}

contract ConstantOutflowNFTMock is ConstantOutflowNFT {
constructor(ISuperfluid host, IConstantInflowNFT constantInflowNFT) ConstantOutflowNFT(host, constantInflowNFT) { }
constructor(
ISuperfluid host,
IConstantFlowAgreementV1 cfaV1,
IGeneralDistributionAgreementV1 gdaV1,
IConstantInflowNFT constantInflowNFT
) ConstantOutflowNFT(host, cfaV1, gdaV1, constantInflowNFT) { }

/// @dev a mock mint function that exposes the internal _mint function
function mockMint(address _superToken, address _to, address _flowReceiver, uint256 _newTokenId) public {
Expand All @@ -83,8 +96,10 @@ contract ConstantOutflowNFTMock is ConstantOutflowNFT {
contract ConstantInflowNFTMock is ConstantInflowNFT {
constructor(
ISuperfluid host,
IConstantFlowAgreementV1 cfaV1,
IGeneralDistributionAgreementV1 gdaV1,
IConstantOutflowNFT constantOutflowNFT
) ConstantInflowNFT(host, constantOutflowNFT) { }
) ConstantInflowNFT(host, cfaV1, gdaV1, constantOutflowNFT) { }

/// @dev a mock mint function to emit the mint Transfer event
function mockMint(address _to, uint256 _newTokenId) public {
Expand All @@ -105,4 +120,4 @@ contract ConstantInflowNFTMock is ConstantInflowNFT {
function mockGetApproved(uint256 _tokenId) public view returns (address) {
return _tokenApprovals[_tokenId];
}
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
// SPDX-License-Identifier: AGPLv3
pragma solidity 0.8.19;

import { ISuperfluid } from "../interfaces/superfluid/ISuperfluid.sol";
import { IConstantFlowAgreementV1, IGeneralDistributionAgreementV1, ISuperfluid }
from "../interfaces/superfluid/ISuperfluid.sol";
import { ConstantInflowNFT, IConstantInflowNFT } from "../superfluid/ConstantInflowNFT.sol";
import { ConstantOutflowNFT, IConstantOutflowNFT } from "../superfluid/ConstantOutflowNFT.sol";
import { FlowNFTBase } from "../superfluid/FlowNFTBase.sol";
Expand All @@ -16,9 +17,10 @@ import { IStorageLayoutBase } from "./IStorageLayoutBase.sol";
/// @notice A mock FlowNFTBase contract for testing storage layout.
/// @dev This contract *MUST* have the same storage layout as FlowNFTBase.sol
contract FlowNFTBaseStorageLayoutMock is FlowNFTBase, IStorageLayoutBase {
constructor(
ISuperfluid host
) FlowNFTBase(host) {}

constructor(ISuperfluid host, IConstantFlowAgreementV1 cfaV1, IGeneralDistributionAgreementV1 gdaV1)
FlowNFTBase(host, cfaV1, gdaV1)
{ }

/// @notice Validates storage layout
/// @dev This function is used by all the FlowNFTBase mock contracts to validate the layout
Expand Down Expand Up @@ -94,8 +96,10 @@ contract ConstantInflowNFTStorageLayoutMock is ConstantInflowNFT, IStorageLayout

constructor(
ISuperfluid host,
IConstantFlowAgreementV1 cfaV1,
IGeneralDistributionAgreementV1 gdaV1,
IConstantOutflowNFT constantOutflowNFT
) ConstantInflowNFT(host, constantOutflowNFT) {}
) ConstantInflowNFT(host, cfaV1, gdaV1, constantOutflowNFT) { }

/// @notice Validates storage layout
/// @dev This function is used to validate storage layout of ConstantInflowNFT
Expand Down Expand Up @@ -145,8 +149,10 @@ contract ConstantOutflowNFTStorageLayoutMock is ConstantOutflowNFT, IStorageLayo

constructor(
ISuperfluid host,
IConstantFlowAgreementV1 cfaV1,
IGeneralDistributionAgreementV1 gdaV1,
IConstantInflowNFT constantInflowNFT
) ConstantOutflowNFT(host, constantInflowNFT) {}
) ConstantOutflowNFT(host, cfaV1, gdaV1, constantInflowNFT) { }

/// @notice Validates storage layout
/// @dev This function is used to validate storage layout of ConstantOutflowNFT
Expand Down
8 changes: 4 additions & 4 deletions packages/ethereum-contracts/contracts/mocks/PoolNFTMock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
pragma solidity 0.8.19;

import { Strings } from "@openzeppelin/contracts/utils/Strings.sol";
import { ISuperfluid } from "../interfaces/superfluid/ISuperfluid.sol";
import { IGeneralDistributionAgreementV1, ISuperfluid } from "../interfaces/superfluid/ISuperfluid.sol";
import { PoolAdminNFT } from "../agreements/gdav1/PoolAdminNFT.sol";
import { PoolMemberNFT } from "../agreements/gdav1/PoolMemberNFT.sol";
import { PoolNFTBase } from "../agreements/gdav1/PoolNFTBase.sol";
Expand All @@ -13,7 +13,7 @@ contract PoolNFTBaseMock is PoolNFTBase {

mapping(uint256 => address) private _owners;

constructor(ISuperfluid host) PoolNFTBase(host) { }
constructor(ISuperfluid host, IGeneralDistributionAgreementV1 gdaV1) PoolNFTBase(host, gdaV1) { }

function proxiableUUID() public pure override returns (bytes32) {
return keccak256("org.superfluid-finance.contracts.PoolNFTBaseMock.implementation");
Expand Down Expand Up @@ -52,7 +52,7 @@ contract PoolNFTBaseMock is PoolNFTBase {
}

contract PoolAdminNFTMock is PoolAdminNFT {
constructor(ISuperfluid host) PoolAdminNFT(host) { }
constructor(ISuperfluid host, IGeneralDistributionAgreementV1 gdaV1) PoolAdminNFT(host, gdaV1) { }

/// @dev a mock mint function that exposes the internal _mint function
function mockMint(address _pool) public {
Expand All @@ -71,7 +71,7 @@ contract PoolAdminNFTMock is PoolAdminNFT {
}

contract PoolMemberNFTMock is PoolMemberNFT {
constructor(ISuperfluid host) PoolMemberNFT(host) { }
constructor(ISuperfluid host, IGeneralDistributionAgreementV1 gdaV1) PoolMemberNFT(host, gdaV1) { }

/// @dev a mock mint function that exposes the internal _mint function
function mockMint(address _pool, address _member) public {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
pragma solidity 0.8.19;

import { PoolNFTBase } from "../agreements/gdav1/PoolNFTBase.sol";
import { ISuperfluid } from "../interfaces/superfluid/ISuperfluid.sol";
import { IGeneralDistributionAgreementV1, ISuperfluid } from "../interfaces/superfluid/ISuperfluid.sol";
import { PoolMemberNFT } from "../agreements/gdav1/PoolMemberNFT.sol";
import { PoolAdminNFT } from "../agreements/gdav1/PoolAdminNFT.sol";
import { IStorageLayoutBase } from "./IStorageLayoutBase.sol";

contract PoolNFTBaseStorageLayoutMock is PoolNFTBase, IStorageLayoutBase {
constructor(ISuperfluid host) PoolNFTBase(host) { }
constructor(ISuperfluid host, IGeneralDistributionAgreementV1 gdaV1) PoolNFTBase(host, gdaV1) { }

function validateStorageLayout() public virtual {
uint256 slot;
Expand Down Expand Up @@ -72,7 +72,7 @@ contract PoolNFTBaseStorageLayoutMock is PoolNFTBase, IStorageLayoutBase {
}

contract PoolAdminNFTStorageLayoutMock is PoolAdminNFT, IStorageLayoutBase {
constructor(ISuperfluid host) PoolAdminNFT(host) { }
constructor(ISuperfluid host, IGeneralDistributionAgreementV1 gdaV1) PoolAdminNFT(host, gdaV1) { }

function validateStorageLayout() public virtual {
uint256 slot;
Expand Down Expand Up @@ -112,7 +112,7 @@ contract PoolAdminNFTStorageLayoutMock is PoolAdminNFT, IStorageLayoutBase {
}

contract PoolMemberNFTStorageLayoutMock is PoolMemberNFT, IStorageLayoutBase {
constructor(ISuperfluid host) PoolMemberNFT(host) { }
constructor(ISuperfluid host, IGeneralDistributionAgreementV1 gdaV1) PoolMemberNFT(host, gdaV1) { }

function validateStorageLayout() public virtual {
uint256 slot;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
pragma solidity 0.8.19;

import { IERC721Metadata } from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol";
import { IGeneralDistributionAgreementV1 } from "../interfaces/agreements/gdav1/IGeneralDistributionAgreementV1.sol";
import { IConstantFlowAgreementV1 } from "../interfaces/agreements/IConstantFlowAgreementV1.sol";
import { IConstantOutflowNFT } from "../interfaces/superfluid/IConstantOutflowNFT.sol";
import { IConstantInflowNFT } from "../interfaces/superfluid/IConstantInflowNFT.sol";
import { ISuperfluid } from "../interfaces/superfluid/ISuperfluid.sol";
Expand All @@ -15,7 +17,12 @@ contract ConstantInflowNFT is FlowNFTBase, IConstantInflowNFT {
IConstantOutflowNFT public immutable CONSTANT_OUTFLOW_NFT;

// solhint-disable-next-line no-empty-blocks
constructor(ISuperfluid host, IConstantOutflowNFT constantOutflowNFT) FlowNFTBase(host) {
constructor(
ISuperfluid host,
IConstantFlowAgreementV1 cfaV1,
IGeneralDistributionAgreementV1 gdaV1,
IConstantOutflowNFT constantOutflowNFT
) FlowNFTBase(host, cfaV1, gdaV1) {
CONSTANT_OUTFLOW_NFT = constantOutflowNFT;
}

Expand Down
Loading

0 comments on commit 80099ac

Please sign in to comment.