From 69c58565819cd8e69dfe3e2f50bab869706568e3 Mon Sep 17 00:00:00 2001 From: Didi Date: Mon, 5 Aug 2024 16:50:17 +0200 Subject: [PATCH] [ETHEREUM-CONTRACTS] Disable flownfts (#1991) * gov-upgrade-super-token-logic: auto-include tokens using the previous canonical logic * fix multisig detection * disable FlowNFT hooks * remove unused imports * ? * don't update IDA, don't update FlowNFTs, remove bad test code * remove obsolete tests * fix deploy script for tests * updated CHANGELOG * not in this PR * flowNFT purging * more removal, changing subgraph too. WIP * fix tests & devcontainer * fetch newest schema and fix sdk-core build * bump sdk-redux version * remove from verification script * appease linter * remove ApprovalForAllEvent * one more * github runner switched to docker compose v2 * removed MetadataUpdate event, bumped versions, updated metadata, updated CHANGELOG files * fix deploy script * fix code path with pre-existing DMZForwarder * more removal --------- Co-authored-by: Kaspar Kallas --- .devcontainer/devcontainer.json | 4 +- .../workflows/call.test-local-subgraph.yml | 2 +- .github/workflows/call.test-sdk-core.yml | 4 +- ...subgraph-on-previous-sdk-core-versions.yml | 2 +- .../handler.publish-release-packages.yml | 4 +- .../autowrap/package.json | 4 +- .../scheduler/package.json | 4 +- packages/ethereum-contracts/CHANGELOG.md | 6 + .../agreements/ConstantFlowAgreementV1.sol | 75 +-- .../gdav1/GeneralDistributionAgreementV1.sol | 51 -- .../apps/SuperfluidLoaderLibrary.sol | 6 + .../superfluid/IConstantInflowNFT.sol | 28 - .../superfluid/IConstantOutflowNFT.sol | 41 -- .../interfaces/superfluid/IFlowNFTBase.sol | 78 --- .../interfaces/superfluid/ISuperToken.sol | 23 - .../interfaces/superfluid/ISuperfluid.sol | 3 - .../mocks/SuperTokenFactoryMock.t.sol | 6 +- .../contracts/mocks/SuperTokenMock.t.sol | 4 +- .../superfluid/ConstantInflowNFT.sol | 99 --- .../superfluid/ConstantOutflowNFT.sol | 177 ------ .../contracts/superfluid/FlowNFTBase.sol | 362 ----------- .../contracts/superfluid/SuperToken.sol | 24 +- .../superfluid/SuperTokenFactory.sol | 13 +- .../SuperfluidFrameworkDeploymentSteps.sol | 73 +-- .../dev-scripts/deploy-test-framework.js | 12 - .../run-deploy-contracts-and-token.js | 2 - .../ops-scripts/deploy-framework.js | 179 +----- .../gov-transfer-framework-ownership.js | 9 +- .../gov-upgrade-super-token-logic.js | 56 +- .../info-print-contract-addresses.js | 26 - .../ops-scripts/validate-deployment.ts | 41 +- packages/ethereum-contracts/package.json | 4 +- .../tasks/bundled-abi-contracts-list.json | 3 - .../tasks/etherscan-verify-framework.sh | 16 - .../test/TestEnvironment.ts | 139 +---- .../apps/SuperTokenV1Library.CFA.test.ts | 12 +- .../superfluid/SuperToken.NonStandard.test.ts | 24 +- .../superfluid/SuperTokenFactory.test.ts | 48 +- .../contracts/superfluid/Superfluid.test.ts | 36 +- .../test/foundry/FoundrySuperfluidTester.sol | 49 +- .../foundry/SuperfluidFrameworkDeployer.t.sol | 2 - .../agreements/ConstantFlowAgreementV1.t.sol | 24 - .../gdav1/GeneralDistributionAgreement.t.sol | 3 - .../foundry/superfluid/CFAv1NFTMock.t.sol | 124 ---- .../CFAv1NFTUpgradabilityMock.t.sol | 198 ------ .../superfluid/ConstantInflowNFT.t.sol | 141 ----- .../superfluid/ConstantOutflowNFT.t.sol | 300 --------- .../test/foundry/superfluid/ERC721.t.sol | 49 +- .../foundry/superfluid/FlowNFTBase.prop.t.sol | 24 - .../test/foundry/superfluid/FlowNFTBase.t.sol | 396 ------------ .../test/foundry/superfluid/PoolNFTBase.t.sol | 3 - .../test/foundry/superfluid/SuperToken.t.sol | 70 +-- .../superfluid/SuperTokenFactory.t.sol | 32 +- packages/hot-fuzz/hot-fuzz | 3 +- packages/hot-fuzz/package.json | 2 +- packages/js-sdk/package.json | 4 +- packages/metadata/CHANGELOG.md | 10 + packages/metadata/main/networks/list.cjs | 28 - packages/metadata/module/networks/list.d.ts | 2 - packages/metadata/module/networks/list.js | 28 - packages/metadata/networks.json | 28 - packages/metadata/package.json | 2 +- packages/sdk-core/CHANGELOG.md | 6 + packages/sdk-core/package.json | 15 +- packages/sdk-core/src/ConstantInflowNFT.ts | 18 - packages/sdk-core/src/ConstantOutflowNFT.ts | 18 - packages/sdk-core/src/ERC721Token.ts | 24 +- packages/sdk-core/src/FlowNFTBase.ts | 85 --- packages/sdk-core/src/SuperToken.ts | 112 +--- packages/sdk-core/src/events.ts | 10 - .../src/mapGetAllEventsQueryEvents.ts | 24 - .../src/subgraph/events/events.graphql | 16 +- .../src/subgraph/queries/getAllEvents.graphql | 8 - packages/sdk-core/src/subgraph/schema.graphql | 581 +----------------- .../sdk-core/test/1.4_supertoken_nft.test.ts | 348 ----------- packages/sdk-redux/CHANGELOG.md | 6 + packages/sdk-redux/package.json | 4 +- packages/subgraph/CHANGELOG.md | 6 + packages/subgraph/README.md | 4 +- packages/subgraph/config/mock.json | 4 +- packages/subgraph/package.json | 6 +- packages/subgraph/schema.graphql | 83 +-- .../subgraph/scripts/buildNetworkConfig.ts | 6 +- packages/subgraph/scripts/getAbi.js | 1 - packages/subgraph/src/mappings/flowNFT.ts | 67 -- packages/subgraph/src/mappings/superToken.ts | 3 - packages/subgraph/subgraph.template.yaml | 70 --- packages/subgraph/tasks/setup-graph-node.sh | 10 +- .../superToken/event/superToken.event.test.ts | 14 +- 89 files changed, 275 insertions(+), 4496 deletions(-) delete mode 100644 packages/ethereum-contracts/contracts/interfaces/superfluid/IConstantInflowNFT.sol delete mode 100644 packages/ethereum-contracts/contracts/interfaces/superfluid/IConstantOutflowNFT.sol delete mode 100644 packages/ethereum-contracts/contracts/interfaces/superfluid/IFlowNFTBase.sol delete mode 100644 packages/ethereum-contracts/contracts/superfluid/ConstantInflowNFT.sol delete mode 100644 packages/ethereum-contracts/contracts/superfluid/ConstantOutflowNFT.sol delete mode 100644 packages/ethereum-contracts/contracts/superfluid/FlowNFTBase.sol delete mode 100644 packages/ethereum-contracts/test/foundry/superfluid/CFAv1NFTMock.t.sol delete mode 100644 packages/ethereum-contracts/test/foundry/superfluid/CFAv1NFTUpgradabilityMock.t.sol delete mode 100644 packages/ethereum-contracts/test/foundry/superfluid/ConstantInflowNFT.t.sol delete mode 100644 packages/ethereum-contracts/test/foundry/superfluid/ConstantOutflowNFT.t.sol delete mode 100644 packages/ethereum-contracts/test/foundry/superfluid/FlowNFTBase.prop.t.sol delete mode 100644 packages/ethereum-contracts/test/foundry/superfluid/FlowNFTBase.t.sol delete mode 100644 packages/sdk-core/src/ConstantInflowNFT.ts delete mode 100644 packages/sdk-core/src/ConstantOutflowNFT.ts delete mode 100644 packages/sdk-core/src/FlowNFTBase.ts delete mode 100644 packages/sdk-core/test/1.4_supertoken_nft.test.ts delete mode 100644 packages/subgraph/src/mappings/flowNFT.ts diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index dcfd2038eb..ee2b5c9cd6 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -31,11 +31,11 @@ // 3. if you want to use nix further, do "nix develop" "postCreateCommand": [ "curl -L https://foundry.paradigm.xyz | bash", - "source /home/node/.bashrc && foundryup", + "source /home/vscode/.bashrc && foundryup", "yarn global add npm-run-all", "yarn install && yarn build", "sudo apt-get install libpq5", // for subgraph's matchstick - "./tasks/fix-devcontainer.sh && nix develop . -c bash <(echo \"yarn install && yarn build\")" + "./tasks/fix-devcontainer.sh && yarn shell . -c bash <(echo \"yarn install && yarn build\")" ] // Configure tool-specific properties. // "customizations": {}, diff --git a/.github/workflows/call.test-local-subgraph.yml b/.github/workflows/call.test-local-subgraph.yml index cf6c30a5c9..0fb84d40f5 100644 --- a/.github/workflows/call.test-local-subgraph.yml +++ b/.github/workflows/call.test-local-subgraph.yml @@ -102,7 +102,7 @@ jobs: - name: "Docker compose" run: | docker rm subgraph_graph-node_1 || true - docker-compose up & + docker compose up & working-directory: ${{ env.subgraph-working-directory }} - name: "Run subgraph integration test suite" diff --git a/.github/workflows/call.test-sdk-core.yml b/.github/workflows/call.test-sdk-core.yml index d24e3e09e4..0c77edadd2 100644 --- a/.github/workflows/call.test-sdk-core.yml +++ b/.github/workflows/call.test-sdk-core.yml @@ -73,7 +73,7 @@ jobs: - name: "Docker compose" run: | docker rm subgraph_graph-node_1 || true - docker-compose up & + docker compose up & working-directory: ${{ env.subgraph-working-directory }} - name: "Build and deploy local subgraph" @@ -86,7 +86,7 @@ jobs: - name: "Run test suite" if: inputs.run-coverage-tests == false run: | - yarn generate-graphql-schema:${{ inputs.subgraph-release }} + yarn get-graphql-schema:${{ inputs.subgraph-release }} ./tasks/setupTestEnvironment.sh npx hardhat test --network localhost working-directory: ${{ env.sdk-core-working-directory }} diff --git a/.github/workflows/call.test-subgraph-on-previous-sdk-core-versions.yml b/.github/workflows/call.test-subgraph-on-previous-sdk-core-versions.yml index 05f4c83c4d..bd74a576ea 100644 --- a/.github/workflows/call.test-subgraph-on-previous-sdk-core-versions.yml +++ b/.github/workflows/call.test-subgraph-on-previous-sdk-core-versions.yml @@ -73,7 +73,7 @@ jobs: - name: "Docker compose" run: | docker rm subgraph_graph-node_1 || true - docker-compose up & + docker compose up & working-directory: ./packages/subgraph - name: "Prepare and Deploy Local Subgraph" diff --git a/.github/workflows/handler.publish-release-packages.yml b/.github/workflows/handler.publish-release-packages.yml index 556a241dc7..b6d82f8a1d 100644 --- a/.github/workflows/handler.publish-release-packages.yml +++ b/.github/workflows/handler.publish-release-packages.yml @@ -58,7 +58,7 @@ jobs: id: publish-sdk-core if: env.PUBLISH_SDK_CORE == 1 run: | - yarn --cwd packages/sdk-core generate-graphql-schema:v1 + yarn --cwd packages/sdk-core get-graphql-schema:v1 yarn --cwd packages/ethereum-contracts build yarn --cwd packages/sdk-core build tasks/npm-publish.sh packages/sdk-core/ latest @@ -103,7 +103,7 @@ jobs: if: env.PUBLISH_SDK_REDUX == 1 run: | yarn --cwd packages/ethereum-contracts build - yarn --cwd packages/sdk-core generate-graphql-schema:v1 + yarn --cwd packages/sdk-core get-graphql-schema:v1 yarn --cwd packages/sdk-core build yarn --cwd packages/sdk-redux build tasks/npm-publish.sh packages/sdk-redux/ latest diff --git a/packages/automation-contracts/autowrap/package.json b/packages/automation-contracts/autowrap/package.json index ec0852e5f0..ccbb894182 100644 --- a/packages/automation-contracts/autowrap/package.json +++ b/packages/automation-contracts/autowrap/package.json @@ -15,7 +15,7 @@ }, "devDependencies": { "@openzeppelin/contracts": "4.9.6", - "@superfluid-finance/ethereum-contracts": "^1.10.0", - "@superfluid-finance/metadata": "^1.3.1" + "@superfluid-finance/ethereum-contracts": "^1.11.0", + "@superfluid-finance/metadata": "^1.4.0" } } diff --git a/packages/automation-contracts/scheduler/package.json b/packages/automation-contracts/scheduler/package.json index 1f9ecca1ef..72ebc8a154 100644 --- a/packages/automation-contracts/scheduler/package.json +++ b/packages/automation-contracts/scheduler/package.json @@ -15,7 +15,7 @@ }, "devDependencies": { "@openzeppelin/contracts": "4.9.6", - "@superfluid-finance/ethereum-contracts": "^1.10.0", - "@superfluid-finance/metadata": "^1.3.1" + "@superfluid-finance/ethereum-contracts": "^1.11.0", + "@superfluid-finance/metadata": "^1.4.0" } } diff --git a/packages/ethereum-contracts/CHANGELOG.md b/packages/ethereum-contracts/CHANGELOG.md index 2c5b8c8d50..d9e6aa95b0 100644 --- a/packages/ethereum-contracts/CHANGELOG.md +++ b/packages/ethereum-contracts/CHANGELOG.md @@ -3,6 +3,12 @@ All notable changes to the ethereum-contracts will be documented in this file. This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [v1.11.0] + +### Breaking + +- FlowNFTs are being deprecated. The hooks aren't invoked anymore by CFA and GDA. + ## [v1.10.0] ### Breaking diff --git a/packages/ethereum-contracts/contracts/agreements/ConstantFlowAgreementV1.sol b/packages/ethereum-contracts/contracts/agreements/ConstantFlowAgreementV1.sol index d4e0edc98d..bf225b729b 100644 --- a/packages/ethereum-contracts/contracts/agreements/ConstantFlowAgreementV1.sol +++ b/packages/ethereum-contracts/contracts/agreements/ConstantFlowAgreementV1.sol @@ -5,14 +5,12 @@ import { ISuperfluid, ISuperfluidGovernance, ISuperApp, - ISuperToken, ISuperfluidToken, IConstantFlowAgreementV1, FlowOperatorDefinitions, SuperAppDefinitions, ContextDefinitions, - SuperfluidGovernanceConfigs, - IConstantOutflowNFT + SuperfluidGovernanceConfigs } from "../interfaces/superfluid/ISuperfluid.sol"; import { AgreementBase } from "./AgreementBase.sol"; import { SafeCast } from "@openzeppelin/contracts/utils/math/SafeCast.sol"; @@ -431,71 +429,6 @@ contract ConstantFlowAgreementV1 is if (flowParams.flowRate <= 0) revert CFA_INVALID_FLOW_RATE(); } - - /** - * @notice Checks whether or not the NFT hook can be called. - * @dev A staticcall, so `CONSTANT_OUTFLOW_NFT` must be a view otherwise the assumption is that it reverts - * @param token the super token that is being streamed - * @return constantOutflowNFTAddress the address returned by low level call - */ - function _canCallNFTHook( - ISuperfluidToken token - ) internal view returns (address constantOutflowNFTAddress) { - // solhint-disable-next-line avoid-low-level-calls - (bool success, bytes memory data) = address(token).staticcall( - abi.encodeWithSelector(ISuperToken.CONSTANT_OUTFLOW_NFT.selector) - ); - - if (success) { - // @note We are aware this may revert if a Custom SuperToken's - // CONSTANT_OUTFLOW_NFT does not return data that can be - // decoded to an address. This would mean it was intentionally - // done by the creator of the Custom SuperToken logic and is - // fully expected to revert in that case as the author desired. - constantOutflowNFTAddress = abi.decode(data, (address)); - } - } - - function _handleOnCreateHook( - _StackVars_createOrUpdateFlow memory flowVars - ) internal { - address constantOutflowNFTAddress = _canCallNFTHook(flowVars.token); - - if (constantOutflowNFTAddress != address(0)) { - IConstantOutflowNFT(constantOutflowNFTAddress).onCreate( - flowVars.token, - flowVars.sender, - flowVars.receiver - ); - } - } - - function _handleOnUpdateHook( - _StackVars_createOrUpdateFlow memory flowVars - ) internal { - address constantOutflowNFTAddress = _canCallNFTHook(flowVars.token); - if (constantOutflowNFTAddress != address(0)) { - IConstantOutflowNFT(constantOutflowNFTAddress).onUpdate( - flowVars.token, - flowVars.sender, - flowVars.receiver - ); - } - } - - function _handleOnDeleteHook( - _StackVars_createOrUpdateFlow memory flowVars - ) internal { - address constantOutflowNFTAddress = _canCallNFTHook(flowVars.token); - if (constantOutflowNFTAddress != address(0)) { - IConstantOutflowNFT(constantOutflowNFTAddress).onDelete( - flowVars.token, - flowVars.sender, - flowVars.receiver - ); - } - } - function _createFlow( _StackVars_createOrUpdateFlow memory flowVars, bytes calldata ctx, @@ -521,8 +454,6 @@ contract ConstantFlowAgreementV1 is } _requireAvailableBalance(flowVars.token, flowVars.sender, currentContext); - - _handleOnCreateHook(flowVars); } function _updateFlow( @@ -551,8 +482,6 @@ contract ConstantFlowAgreementV1 is } _requireAvailableBalance(flowVars.token, flowVars.sender, currentContext); - - _handleOnUpdateHook(flowVars); } function _deleteFlow( @@ -663,8 +592,6 @@ contract ConstantFlowAgreementV1 is newCtx, currentContext); } } - - _handleOnDeleteHook(flowVars); } /************************************************************************** diff --git a/packages/ethereum-contracts/contracts/agreements/gdav1/GeneralDistributionAgreementV1.sol b/packages/ethereum-contracts/contracts/agreements/gdav1/GeneralDistributionAgreementV1.sol index 3876ca7177..846967aec7 100644 --- a/packages/ethereum-contracts/contracts/agreements/gdav1/GeneralDistributionAgreementV1.sol +++ b/packages/ethereum-contracts/contracts/agreements/gdav1/GeneralDistributionAgreementV1.sol @@ -22,7 +22,6 @@ import { } 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"; import { IPoolAdminNFT } from "../../interfaces/agreements/gdav1/IPoolAdminNFT.sol"; import { ISuperfluidPool } from "../../interfaces/agreements/gdav1/ISuperfluidPool.sol"; @@ -565,31 +564,6 @@ contract GeneralDistributionAgreementV1 is AgreementBase, TokenMonad, IGeneralDi } } - // handleFlowNFT() - mint/burn FlowNFT to flow distributor - { - address constantOutflowNFTAddress = _getConstantOutflowNFTAddress(token); - - if (constantOutflowNFTAddress != address(0)) { - // create flow (mint) - if (requestedFlowRate > 0 && FlowRate.unwrap(flowVars.oldFlowRate) == 0) { - // solhint-disable-next-line no-empty-blocks - IConstantOutflowNFT(constantOutflowNFTAddress).onCreate(token, from, address(pool)); - } - - // update flow (update metadata) - if (requestedFlowRate > 0 && FlowRate.unwrap(flowVars.oldFlowRate) > 0) { - // solhint-disable-next-line no-empty-blocks - IConstantOutflowNFT(constantOutflowNFTAddress).onUpdate(token, from, address(pool)); - } - - // delete flow (burn) - if (requestedFlowRate == 0) { - // solhint-disable-next-line no-empty-blocks - IConstantOutflowNFT(constantOutflowNFTAddress).onDelete(token, from, address(pool)); - } - } - } - { (address adjustmentFlowRecipient,, int96 adjustmentFlowRate) = _getPoolAdjustmentFlowInfo(abi.encode(token), address(pool)); @@ -609,31 +583,6 @@ contract GeneralDistributionAgreementV1 is AgreementBase, TokenMonad, IGeneralDi } } - /** - * @notice Checks whether or not the NFT hook can be called. - * @dev A staticcall, so `CONSTANT_OUTFLOW_NFT` must be a view otherwise the assumption is that it reverts - * @param token the super token that is being streamed - * @return constantOutflowNFTAddress the address returned by low level call - */ - function _getConstantOutflowNFTAddress(ISuperfluidToken token) - internal - view - returns (address constantOutflowNFTAddress) - { - // solhint-disable-next-line avoid-low-level-calls - (bool success, bytes memory data) = - address(token).staticcall(abi.encodeWithSelector(ISuperToken.CONSTANT_OUTFLOW_NFT.selector)); - - if (success) { - // @note We are aware this may revert if a Custom SuperToken's - // CONSTANT_OUTFLOW_NFT does not return data that can be - // decoded to an address. This would mean it was intentionally - // done by the creator of the Custom SuperToken logic and is - // fully expected to revert in that case as the author desired. - constantOutflowNFTAddress = abi.decode(data, (address)); - } - } - function _getPoolAdminNFTAddress(ISuperfluidToken token) internal view returns (address poolAdminNFTAddress) { // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory data) = diff --git a/packages/ethereum-contracts/contracts/apps/SuperfluidLoaderLibrary.sol b/packages/ethereum-contracts/contracts/apps/SuperfluidLoaderLibrary.sol index 859795406a..4d09832e2c 100644 --- a/packages/ethereum-contracts/contracts/apps/SuperfluidLoaderLibrary.sol +++ b/packages/ethereum-contracts/contracts/apps/SuperfluidLoaderLibrary.sol @@ -15,6 +15,7 @@ library SuperfluidLoaderLibrary { uint256 private constant CELO_MAINNET = 42220; uint256 private constant AVALANCHE_C = 43114; uint256 private constant SCROLL_MAINNET = 534352; + uint256 private constant DEGENCHAIN = 666666666; // testnets @@ -22,6 +23,7 @@ library SuperfluidLoaderLibrary { uint256 private constant SCROLL_SEPOLIA = 534351; uint256 private constant ETH_SEPOLIA = 11155111; uint256 private constant OPTIMISM_SEPOLIA = 11155420; + uint256 private constant BASE_SEPOLIA = 84532; function getHost() public view returns (address) { @@ -46,6 +48,8 @@ library SuperfluidLoaderLibrary { return 0x60377C7016E4cdB03C87EF474896C11cB560752C; } else if (block.chainid == SCROLL_MAINNET) { return 0x0F86a21F6216c061B222c224e315d9FC34520bb7; + } else if (block.chainid == DEGENCHAIN) { + return 0xc1314EdcD7e478C831a7a24169F7dEADB2646eD2; // testnets } else if (block.chainid == AVALANCHE_FUJI) { return 0x85Fe79b998509B77BF10A8BD4001D58475D29386; @@ -55,6 +59,8 @@ library SuperfluidLoaderLibrary { return 0x109412E3C84f0539b43d39dB691B08c90f58dC7c; } else if (block.chainid == OPTIMISM_SEPOLIA) { return 0xd399e2Fb5f4cf3722a11F65b88FAB6B2B8621005; + } else if (block.chainid == BASE_SEPOLIA) { + return 0x109412E3C84f0539b43d39dB691B08c90f58dC7c; } else { revert UnsupportedNetwork(); } diff --git a/packages/ethereum-contracts/contracts/interfaces/superfluid/IConstantInflowNFT.sol b/packages/ethereum-contracts/contracts/interfaces/superfluid/IConstantInflowNFT.sol deleted file mode 100644 index c0c89879ad..0000000000 --- a/packages/ethereum-contracts/contracts/interfaces/superfluid/IConstantInflowNFT.sol +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.11; - -import { IFlowNFTBase } from "./IFlowNFTBase.sol"; - -interface IConstantInflowNFT is IFlowNFTBase { - /************************************************************************** - * Custom Errors - *************************************************************************/ - error CIF_NFT_ONLY_CONSTANT_OUTFLOW(); // 0xe81ef57a - - /************************************************************************** - * Write Functions - *************************************************************************/ - - /// @notice The mint function emits the "mint" `Transfer` event. - /// @dev We don't modify storage as this is handled in ConstantOutflowNFT.sol and this function's sole purpose - /// is to inform clients that search for events. - /// @param to the flow receiver (inflow NFT receiver) - /// @param newTokenId the new token id - function mint(address to, uint256 newTokenId) external; - - /// @notice This burn function emits the "burn" `Transfer` event. - /// @dev We don't modify storage as this is handled in ConstantOutflowNFT.sol and this function's sole purpose - /// is to inform clients that search for events. - /// @param tokenId desired token id to burn - function burn(uint256 tokenId) external; -} diff --git a/packages/ethereum-contracts/contracts/interfaces/superfluid/IConstantOutflowNFT.sol b/packages/ethereum-contracts/contracts/interfaces/superfluid/IConstantOutflowNFT.sol deleted file mode 100644 index 76dc52c8f3..0000000000 --- a/packages/ethereum-contracts/contracts/interfaces/superfluid/IConstantOutflowNFT.sol +++ /dev/null @@ -1,41 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.11; - -import { ISuperfluidToken } from "./ISuperfluidToken.sol"; -import { IFlowNFTBase } from "./IFlowNFTBase.sol"; - -interface IConstantOutflowNFT is IFlowNFTBase { - /************************************************************************** - * Custom Errors - *************************************************************************/ - - error COF_NFT_INVALID_SUPER_TOKEN(); // 0x6de98774 - error COF_NFT_MINT_TO_AND_FLOW_RECEIVER_SAME(); // 0x0d1d1161 - error COF_NFT_MINT_TO_ZERO_ADDRESS(); // 0x43d05e51 - error COF_NFT_ONLY_CONSTANT_INFLOW(); // 0xa495a718 - error COF_NFT_ONLY_FLOW_AGREEMENTS(); // 0xd367b64f - error COF_NFT_TOKEN_ALREADY_EXISTS(); // 0xe2480183 - - - /************************************************************************** - * Write Functions - *************************************************************************/ - - /// @notice The onCreate function is called when a new flow is created. - /// @param token the super token passed from the CFA (flowVars) - /// @param flowSender the flow sender - /// @param flowReceiver the flow receiver - function onCreate(ISuperfluidToken token, address flowSender, address flowReceiver) external; - - /// @notice The onUpdate function is called when a flow is updated. - /// @param token the super token passed from the CFA (flowVars) - /// @param flowSender the flow sender - /// @param flowReceiver the flow receiver - function onUpdate(ISuperfluidToken token, address flowSender, address flowReceiver) external; - - /// @notice The onDelete function is called when a flow is deleted. - /// @param token the super token passed from the CFA (flowVars) - /// @param flowSender the flow sender - /// @param flowReceiver the flow receiver - function onDelete(ISuperfluidToken token, address flowSender, address flowReceiver) external; -} diff --git a/packages/ethereum-contracts/contracts/interfaces/superfluid/IFlowNFTBase.sol b/packages/ethereum-contracts/contracts/interfaces/superfluid/IFlowNFTBase.sol deleted file mode 100644 index 3ca847e6ad..0000000000 --- a/packages/ethereum-contracts/contracts/interfaces/superfluid/IFlowNFTBase.sol +++ /dev/null @@ -1,78 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.11; - -import { IERC721Metadata } from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol"; - -interface IFlowNFTBase is IERC721Metadata { - // FlowNFTData struct storage packing: - // b = bits - // WORD 1: | superToken | FREE - // | 160b | 96b - // WORD 2: | flowSender | FREE - // | 160b | 96b - // WORD 3: | flowReceiver | flowStartDate | FREE - // | 160b | 32b | 64b - struct FlowNFTData { - address superToken; - address flowSender; - address flowReceiver; - uint32 flowStartDate; - } - - /************************************************************************** - * Custom Errors - *************************************************************************/ - - error CFA_NFT_APPROVE_CALLER_NOT_OWNER_OR_APPROVED_FOR_ALL(); // 0xa3352582 - error CFA_NFT_APPROVE_TO_CALLER(); // 0xd3c77329 - error CFA_NFT_APPROVE_TO_CURRENT_OWNER(); // 0xe4790b25 - error CFA_NFT_INVALID_TOKEN_ID(); // 0xeab95e3b - error CFA_NFT_ONLY_SUPER_TOKEN_FACTORY(); // 0xebb7505b - error CFA_NFT_TRANSFER_CALLER_NOT_OWNER_OR_APPROVED_FOR_ALL(); // 0x2551d606 - error CFA_NFT_TRANSFER_FROM_INCORRECT_OWNER(); // 0x5a26c744 - error CFA_NFT_TRANSFER_IS_NOT_ALLOWED(); // 0xaa747eca - error CFA_NFT_TRANSFER_TO_ZERO_ADDRESS(); // 0xde06d21e - - /************************************************************************** - * Events - *************************************************************************/ - - /// @notice Informs third-party platforms that NFT metadata should be updated - /// @dev This event comes from https://eips.ethereum.org/EIPS/eip-4906 - /// @param tokenId the id of the token that should have its metadata updated - event MetadataUpdate(uint256 tokenId); - - /************************************************************************** - * View - *************************************************************************/ - - /// @notice An external function for querying flow data by `tokenId`` - /// @param tokenId the token id - /// @return flowData the flow data associated with `tokenId` - function flowDataByTokenId( - uint256 tokenId - ) external view returns (FlowNFTData memory flowData); - - /// @notice An external function for computing the deterministic tokenId - /// @dev tokenId = uint256(keccak256(abi.encode(block.chainId, superToken, flowSender, flowReceiver))) - /// @param superToken the super token - /// @param flowSender the flow sender - /// @param flowReceiver the flow receiver - /// @return tokenId the tokenId - function getTokenId( - address superToken, - address flowSender, - address flowReceiver - ) external view returns (uint256); - - /************************************************************************** - * Write - *************************************************************************/ - - function initialize( - string memory nftName, - string memory nftSymbol - ) external; // initializer; - - function triggerMetadataUpdate(uint256 tokenId) external; -} diff --git a/packages/ethereum-contracts/contracts/interfaces/superfluid/ISuperToken.sol b/packages/ethereum-contracts/contracts/interfaces/superfluid/ISuperToken.sol index 30d7e95084..c1a468f631 100644 --- a/packages/ethereum-contracts/contracts/interfaces/superfluid/ISuperToken.sol +++ b/packages/ethereum-contracts/contracts/interfaces/superfluid/ISuperToken.sol @@ -4,8 +4,6 @@ pragma solidity >= 0.8.11; import { ISuperfluidToken } from "./ISuperfluidToken.sol"; import { IERC20, IERC20Metadata } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import { IERC777 } from "@openzeppelin/contracts/token/ERC777/IERC777.sol"; -import { IConstantOutflowNFT } from "./IConstantOutflowNFT.sol"; -import { IConstantInflowNFT } from "./IConstantInflowNFT.sol"; import { IPoolAdminNFT } from "../agreements/gdav1/IPoolAdminNFT.sol"; import { IPoolMemberNFT } from "../agreements/gdav1/IPoolMemberNFT.sol"; @@ -73,10 +71,6 @@ interface ISuperToken is ISuperfluidToken, IERC20Metadata, IERC777 { * Immutable variables *************************************************************************/ - // solhint-disable-next-line func-name-mixedcase - function CONSTANT_OUTFLOW_NFT() external view returns (IConstantOutflowNFT); - // solhint-disable-next-line func-name-mixedcase - function CONSTANT_INFLOW_NFT() external view returns (IConstantInflowNFT); // solhint-disable-next-line func-name-mixedcase function POOL_ADMIN_NFT() external view returns (IPoolAdminNFT); // solhint-disable-next-line func-name-mixedcase @@ -600,23 +594,6 @@ interface ISuperToken is ISuperfluidToken, IERC20Metadata, IERC777 { */ function operationDowngradeTo(address account, address to, uint256 amount) external; - // Flow NFT events - /** - * @dev Constant Outflow NFT proxy created event - * @param constantOutflowNFT constant outflow nft address - */ - event ConstantOutflowNFTCreated( - IConstantOutflowNFT indexed constantOutflowNFT - ); - - /** - * @dev Constant Inflow NFT proxy created event - * @param constantInflowNFT constant inflow nft address - */ - event ConstantInflowNFTCreated( - IConstantInflowNFT indexed constantInflowNFT - ); - /** * @dev Pool Admin NFT proxy created event * @param poolAdminNFT pool admin nft address diff --git a/packages/ethereum-contracts/contracts/interfaces/superfluid/ISuperfluid.sol b/packages/ethereum-contracts/contracts/interfaces/superfluid/ISuperfluid.sol index cf660e9a10..b698648111 100644 --- a/packages/ethereum-contracts/contracts/interfaces/superfluid/ISuperfluid.sol +++ b/packages/ethereum-contracts/contracts/interfaces/superfluid/ISuperfluid.sol @@ -23,9 +23,6 @@ import { ISuperToken } from "./ISuperToken.sol"; import { ISuperTokenFactory } from "./ISuperTokenFactory.sol"; import { ISETH } from "../tokens/ISETH.sol"; /// Superfluid/ERC20x NFTs -import { IFlowNFTBase } from "./IFlowNFTBase.sol"; -import { IConstantOutflowNFT } from "./IConstantOutflowNFT.sol"; -import { IConstantInflowNFT } from "./IConstantInflowNFT.sol"; import { IPoolAdminNFT } from "../agreements/gdav1/IPoolAdminNFT.sol"; import { IPoolMemberNFT } from "../agreements/gdav1/IPoolMemberNFT.sol"; /// Superfluid agreement interfaces: diff --git a/packages/ethereum-contracts/contracts/mocks/SuperTokenFactoryMock.t.sol b/packages/ethereum-contracts/contracts/mocks/SuperTokenFactoryMock.t.sol index 824d006bd6..bb1ad92282 100644 --- a/packages/ethereum-contracts/contracts/mocks/SuperTokenFactoryMock.t.sol +++ b/packages/ethereum-contracts/contracts/mocks/SuperTokenFactoryMock.t.sol @@ -1,15 +1,13 @@ // SPDX-License-Identifier: AGPLv3 pragma solidity ^0.8.23; -import { +import { ISuperfluid, ISuperToken, - IConstantInflowNFT, - IConstantOutflowNFT, IPoolAdminNFT, IPoolMemberNFT } from "../interfaces/superfluid/ISuperfluid.sol"; -import { SuperTokenFactoryBase } from "../superfluid/SuperTokenFactory.sol"; +import { SuperTokenFactoryBase, IConstantOutflowNFT, IConstantInflowNFT } from "../superfluid/SuperTokenFactory.sol"; contract SuperTokenFactoryStorageLayoutTester is SuperTokenFactoryBase { constructor( diff --git a/packages/ethereum-contracts/contracts/mocks/SuperTokenMock.t.sol b/packages/ethereum-contracts/contracts/mocks/SuperTokenMock.t.sol index 5863890cdb..402c753631 100644 --- a/packages/ethereum-contracts/contracts/mocks/SuperTokenMock.t.sol +++ b/packages/ethereum-contracts/contracts/mocks/SuperTokenMock.t.sol @@ -4,11 +4,11 @@ pragma solidity ^0.8.23; import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import { - ISuperfluid, IERC20, IConstantInflowNFT, IConstantOutflowNFT, IPoolAdminNFT, IPoolMemberNFT + ISuperfluid, IERC20, IPoolAdminNFT, IPoolMemberNFT } from "../interfaces/superfluid/ISuperfluid.sol"; import { UUPSProxiable } from "../upgradability/UUPSProxiable.sol"; import { ERC777Helper } from "../libs/ERC777Helper.sol"; -import { SuperToken } from "../superfluid/SuperToken.sol"; +import { SuperToken, IConstantOutflowNFT, IConstantInflowNFT } from "../superfluid/SuperToken.sol"; import { SuperfluidToken } from "../superfluid/SuperfluidToken.sol"; contract SuperTokenStorageLayoutTester is SuperToken { diff --git a/packages/ethereum-contracts/contracts/superfluid/ConstantInflowNFT.sol b/packages/ethereum-contracts/contracts/superfluid/ConstantInflowNFT.sol deleted file mode 100644 index 44bbd35627..0000000000 --- a/packages/ethereum-contracts/contracts/superfluid/ConstantInflowNFT.sol +++ /dev/null @@ -1,99 +0,0 @@ -// SPDX-License-Identifier: AGPLv3 -pragma solidity ^0.8.23; - -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"; -import { FlowNFTBase, IFlowNFTBase } from "./FlowNFTBase.sol"; - -/// @title ConstantInflowNFT Contract (CIF NFT) -/// @author Superfluid -/// @notice The ConstantInflowNFT contract to be minted to the flow sender on flow creation. -/// @dev This contract does not hold any storage, but references the ConstantOutflowNFT contract storage. -contract ConstantInflowNFT is FlowNFTBase, IConstantInflowNFT { - IConstantOutflowNFT public immutable CONSTANT_OUTFLOW_NFT; - - // solhint-disable-next-line no-empty-blocks - constructor( - ISuperfluid host, - IConstantFlowAgreementV1 cfaV1, - IGeneralDistributionAgreementV1 gdaV1, - IConstantOutflowNFT constantOutflowNFT - ) FlowNFTBase(host, cfaV1, gdaV1) { - CONSTANT_OUTFLOW_NFT = constantOutflowNFT; - } - - function proxiableUUID() public pure override returns (bytes32) { - return keccak256("org.superfluid-finance.contracts.ConstantInflowNFT.implementation"); - } - - /// @notice The mint function emits the "mint" `Transfer` event. - /// @dev We don't modify storage as this is handled in ConstantOutflowNFT.sol and this function's sole purpose - /// is to inform clients that search for events. - /// Only callable by ConstantOutflowNFT - /// @param to the receiver of the inflow nft and desired flow receiver - /// @param newTokenId the new token id - function mint(address to, uint256 newTokenId) external onlyConstantOutflowNFT { - _mint(to, newTokenId); - } - - /// @notice This burn function emits the "burn" `Transfer` event. - /// @dev We don't modify storage as this is handled in ConstantOutflowNFT.sol and this function's sole purpose - /// is to inform clients that search for events. - /// Only callable by ConstantOutflowNFT - /// @param tokenId desired token id to burn - function burn(uint256 tokenId) external onlyConstantOutflowNFT { - _burn(tokenId); - } - - function flowDataByTokenId(uint256 tokenId) - public - view - override(FlowNFTBase, IFlowNFTBase) - returns (FlowNFTData memory flowData) - { - flowData = CONSTANT_OUTFLOW_NFT.flowDataByTokenId(tokenId); - } - - function tokenURI(uint256 tokenId) external view override(FlowNFTBase, IERC721Metadata) returns (string memory) { - return _tokenURI(tokenId, true); - } - - /// @inheritdoc FlowNFTBase - function _ownerOf(uint256 tokenId) internal view override returns (address) { - FlowNFTData memory flowData = flowDataByTokenId(tokenId); - return flowData.flowReceiver; - } - - /// @notice Transfer is currently not allowed. - /// @dev Will revert currently. - function _transfer( - address, // from, - address, // to, - uint256 // tokenId - ) internal pure override { - revert CFA_NFT_TRANSFER_IS_NOT_ALLOWED(); - } - - function _mint(address to, uint256 newTokenId) internal { - emit Transfer(address(0), to, newTokenId); - } - - function _burn(uint256 tokenId) internal override { - FlowNFTData memory flowData = flowDataByTokenId(tokenId); - - super._burn(tokenId); - - emit Transfer(flowData.flowReceiver, address(0), tokenId); - } - - modifier onlyConstantOutflowNFT() { - if (msg.sender != address(CONSTANT_OUTFLOW_NFT)) { - revert CIF_NFT_ONLY_CONSTANT_OUTFLOW(); - } - _; - } -} diff --git a/packages/ethereum-contracts/contracts/superfluid/ConstantOutflowNFT.sol b/packages/ethereum-contracts/contracts/superfluid/ConstantOutflowNFT.sol deleted file mode 100644 index 98c5592dff..0000000000 --- a/packages/ethereum-contracts/contracts/superfluid/ConstantOutflowNFT.sol +++ /dev/null @@ -1,177 +0,0 @@ -// SPDX-License-Identifier: AGPLv3 -// solhint-disable not-rely-on-time -pragma solidity ^0.8.23; - -import { IERC721Metadata } from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol"; -import { ISuperfluidToken } from "../interfaces/superfluid/ISuperfluidToken.sol"; -import { IGeneralDistributionAgreementV1 } from "../interfaces/agreements/gdav1/IGeneralDistributionAgreementV1.sol"; -import { IConstantFlowAgreementV1 } from "../interfaces/agreements/IConstantFlowAgreementV1.sol"; -import { IConstantInflowNFT } from "../interfaces/superfluid/IConstantInflowNFT.sol"; -import { IConstantOutflowNFT } from "../interfaces/superfluid/IConstantOutflowNFT.sol"; -import { ISuperfluid } from "../interfaces/superfluid/ISuperfluid.sol"; -import { FlowNFTBase, IFlowNFTBase } from "./FlowNFTBase.sol"; - -/// @title ConstantOutflowNFT contract (COF NFT) -/// @author Superfluid -/// @notice The ConstantOutflowNFT contract to be minted to the flow sender on flow creation. -/// @dev This contract uses mint/burn interface for flow creation/deletion and holds the actual storage for both NFTs. -contract ConstantOutflowNFT is FlowNFTBase, IConstantOutflowNFT { - IConstantInflowNFT public immutable CONSTANT_INFLOW_NFT; - - /// @notice A mapping from token id to FlowNFTData - /// FlowNFTData: { address flowSender, uint32 flowStartDate, address flowReceiver, address superToken } - /// @dev The token id is uint256(keccak256(abi.encode(flowSender, flowReceiver))) - mapping(uint256 => FlowNFTData) internal _flowDataByTokenId; - - // solhint-disable-next-line no-empty-blocks - constructor( - ISuperfluid host, - IConstantFlowAgreementV1 cfaV1, - IGeneralDistributionAgreementV1 gdaV1, - IConstantInflowNFT constantInflowNFT - ) FlowNFTBase(host, cfaV1, gdaV1) { - CONSTANT_INFLOW_NFT = constantInflowNFT; - } - - // note that this is used so we don't upgrade to wrong logic contract - function proxiableUUID() public pure override returns (bytes32) { - return keccak256("org.superfluid-finance.contracts.ConstantOutflowNFT.implementation"); - } - - /// @notice An external function for querying flow data by `tokenId`` - /// @param tokenId the token id - /// @return flowData the flow data associated with `tokenId` - function flowDataByTokenId(uint256 tokenId) - public - view - override(FlowNFTBase, IFlowNFTBase) - returns (FlowNFTData memory flowData) - { - flowData = _flowDataByTokenId[tokenId]; - } - - function tokenURI(uint256 tokenId) external view override(FlowNFTBase, IERC721Metadata) returns (string memory) { - return _tokenURI(tokenId, false); - } - - /// @notice Hook called by CFA contract on flow creation - /// @dev This function mints the COF NFT to the flow sender and mints the CIF NFT to the flow receiver - /// @param superToken the SuperToken contract address - /// @param flowSender the flow sender - /// @param flowReceiver the flow receiver - /// NOTE: We do an existence check in here to determine whether or not to execute the hook - function onCreate(ISuperfluidToken superToken, address flowSender, address flowReceiver) - external - onlyFlowAgreements - { - // we don't check matching super token because the nft token id - // is generated based on the superToken - uint256 newTokenId = _getTokenId(address(superToken), flowSender, flowReceiver); - if (_flowDataByTokenId[newTokenId].flowSender == address(0)) { - _mint(address(superToken), flowSender, flowReceiver, newTokenId); - - CONSTANT_INFLOW_NFT.mint(flowReceiver, newTokenId); - } - } - - /// @notice Hook called by CFA contract on flow update - /// @dev This function triggers the metadata update of both COF and CIF NFTs - /// @param superToken the SuperToken contract address - /// @param flowSender the flow sender - /// @param flowReceiver the flow receiver - /// NOTE: We do an existence check in here to determine whether or not to execute the hook - function onUpdate(ISuperfluidToken superToken, address flowSender, address flowReceiver) - external - onlyFlowAgreements - { - uint256 tokenId = _getTokenId(address(superToken), flowSender, flowReceiver); - if (_flowDataByTokenId[tokenId].flowSender != address(0)) { - _triggerMetadataUpdate(tokenId); - - CONSTANT_INFLOW_NFT.triggerMetadataUpdate(tokenId); - } - } - - /// @notice Hook called by CFA contract on flow deletion - /// @dev This function burns the COF NFT and burns the CIF NFT - /// @param superToken the SuperToken contract address - /// @param flowSender the flow sender - /// @param flowReceiver the flow receiver - /// NOTE: We do an existence check in here to determine whether or not to execute the hook - function onDelete(ISuperfluidToken superToken, address flowSender, address flowReceiver) - external - onlyFlowAgreements - { - uint256 tokenId = _getTokenId(address(superToken), flowSender, flowReceiver); - if (_flowDataByTokenId[tokenId].flowSender != address(0)) { - // must "burn" inflow NFT first because we clear storage when burning outflow NFT - - CONSTANT_INFLOW_NFT.burn(tokenId); - - _burn(tokenId); - } - } - - /// @inheritdoc FlowNFTBase - function _ownerOf(uint256 tokenId) internal view override returns (address) { - return _flowDataByTokenId[tokenId].flowSender; - } - - /// @notice Reverts - Transfer of outflow NFT is not allowed. - /// @dev We revert when users attempt to transfer outflow NFTs. - function _transfer( - address, // from, - address, // to, - uint256 // tokenId - ) internal pure override { - revert CFA_NFT_TRANSFER_IS_NOT_ALLOWED(); - } - - /// @notice Mints `newTokenId` and transfers it to `flowSender` - /// @dev `newTokenId` must not exist `flowSender` cannot be `address(0)` and we emit a {Transfer} event. - /// `flowSender` cannot be equal to `flowReceiver`. - /// @param superToken the SuperToken contract address - /// @param flowSender the receiver of the newly minted outflow nft (to) - /// @param flowReceiver the flow receiver (owner of the InflowNFT) - /// @param newTokenId the new token id to be minted - function _mint(address superToken, address flowSender, address flowReceiver, uint256 newTokenId) internal { - assert(flowSender != address(0)); - assert(flowSender != flowReceiver); - - // update mapping for new NFT to be minted - _flowDataByTokenId[newTokenId] = FlowNFTData( - superToken, - flowSender, - flowReceiver, - uint32(block.timestamp) // flowStartDate - ); - - // emit mint of new outflow token with newTokenId - emit Transfer(address(0), flowSender, newTokenId); - } - - /// @notice Destroys token with `tokenId` and clears approvals from previous owner. - /// @dev `tokenId` must exist AND we emit a {Transfer} event - /// @param tokenId the id of the token we are destroying - function _burn(uint256 tokenId) internal override { - address owner = _ownerOf(tokenId); - - super._burn(tokenId); - - // remove previous tokenId flow data mapping - delete _flowDataByTokenId[tokenId]; - - // emit burn of outflow token with tokenId - emit Transfer(owner, address(0), tokenId); - } - - modifier onlyFlowAgreements() { - if ( - msg.sender != address(CONSTANT_FLOW_AGREEMENT_V1) - && msg.sender != address(GENERAL_DISTRIBUTION_AGREEMENT_V1) - ) { - revert COF_NFT_ONLY_FLOW_AGREEMENTS(); - } - _; - } -} diff --git a/packages/ethereum-contracts/contracts/superfluid/FlowNFTBase.sol b/packages/ethereum-contracts/contracts/superfluid/FlowNFTBase.sol deleted file mode 100644 index 3629dfa7f1..0000000000 --- a/packages/ethereum-contracts/contracts/superfluid/FlowNFTBase.sol +++ /dev/null @@ -1,362 +0,0 @@ -// SPDX-License-Identifier: AGPLv3 -pragma solidity ^0.8.23; - -// solhint-disable max-states-count -// Notes: We use reserved slots for upgradable contracts. - -// They are used in solidity docs. -import { - // solhint-disable-next-line no-unused-import - IERC165, IERC721, IERC721Metadata -} from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol"; - -import { UUPSProxiable } from "../upgradability/UUPSProxiable.sol"; -import { Strings } from "@openzeppelin/contracts/utils/Strings.sol"; -import { - ISuperfluid, ISuperToken, ISuperTokenFactory, IFlowNFTBase, - IConstantFlowAgreementV1, IGeneralDistributionAgreementV1 -} from "../interfaces/superfluid/ISuperfluid.sol"; - -/// @title FlowNFTBase abstract contract -/// @author Superfluid -/// @notice The abstract contract to be inherited by the Flow NFTs. -/// @dev This contract inherits from IFlowNFTBase which inherits from -/// IERC721Metadata and holds shared storage and functions for the two NFT contracts. -/// This contract is upgradeable and it inherits from our own ad-hoc UUPSProxiable contract which allows. -/// NOTE: the storage gap allows us to add an additional 16 storage variables to this contract without breaking child -/// COFNFT or CIFNFT storage. -abstract contract FlowNFTBase is UUPSProxiable, IFlowNFTBase { - using Strings for uint256; - - string public constant DEFAULT_BASE_URI = "https://nft.superfluid.finance/cfa/v2/getmeta"; - - function baseURI() public pure returns (string memory) { return DEFAULT_BASE_URI; } - - /// @notice ConstantFlowAgreementV1 contract address - /// @dev This is the address of the CFAv1 contract cached so we don't have to - /// do an external call for every flow created. - // solhint-disable-next-line var-name-mixedcase - IConstantFlowAgreementV1 public immutable CONSTANT_FLOW_AGREEMENT_V1; - - /// @notice GeneralDistributionAgreementV1 contract address - /// @dev This is the address of the GDAv1 contract cached so we don't have to - /// do an external call for every flow created. - // solhint-disable-next-line var-name-mixedcase - IGeneralDistributionAgreementV1 public immutable GENERAL_DISTRIBUTION_AGREEMENT_V1; - - /// @notice Superfluid host contract address - ISuperfluid public immutable HOST; - - /************************************************************************** - * Storage variables - *************************************************************************/ - /// NOTE: The storage variables in this contract MUST NOT: - /// - change the ordering of the existing variables - /// - change any of the variable types - /// - rename any of the existing variables - /// - remove any of the existing variables - /// - add any new variables after _gap - /// - add any new variables before _gap and NOT decrement the length of the _gap array - /// Go to CFAv1NFTUpgradability.t.sol for the tests and make sure to add new tests for upgrades. - - string internal _name; - string internal _symbol; - - /// @notice Mapping for token approvals - /// @dev tokenID => approved address mapping - mapping(uint256 => address) internal _tokenApprovals; - - /// @notice Mapping for operator approvals - mapping(address => mapping(address => bool)) internal _operatorApprovals; - - /// @notice This allows us to add new storage variables in the base contract - /// without having to worry about messing up the storage layout that exists in COFNFT or CIFNFT. - /// @dev This empty reserved space is put in place to allow future versions to add new - /// variables without shifting down storage in the inheritance chain. - /// Slots 5-21 are reserved for future use. - /// We use this pattern in SuperToken.sol and favor this over the OpenZeppelin pattern - /// as this prevents silly footgunning. - /// See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps - uint256 internal _reserve5; - uint256 private _reserve6; - uint256 private _reserve7; - uint256 private _reserve8; - uint256 private _reserve9; - uint256 private _reserve10; - uint256 private _reserve11; - uint256 private _reserve12; - uint256 private _reserve13; - uint256 private _reserve14; - uint256 private _reserve15; - uint256 private _reserve16; - uint256 private _reserve17; - uint256 private _reserve18; - uint256 private _reserve19; - uint256 private _reserve20; - uint256 internal _reserve21; - - constructor(ISuperfluid host, IConstantFlowAgreementV1 cfaV1, IGeneralDistributionAgreementV1 gdaV1) { - HOST = host; - CONSTANT_FLOW_AGREEMENT_V1 = cfaV1; - GENERAL_DISTRIBUTION_AGREEMENT_V1 = gdaV1; - } - - function initialize(string memory nftName, string memory nftSymbol) - external - override - initializer // OpenZeppelin Initializable - { - _name = nftName; - _symbol = nftSymbol; - } - - function updateCode(address newAddress) external override { - ISuperTokenFactory superTokenFactory = HOST.getSuperTokenFactory(); - if (msg.sender != address(superTokenFactory)) { - revert CFA_NFT_ONLY_SUPER_TOKEN_FACTORY(); - } - - UUPSProxiable._updateCodeAddress(newAddress); - } - - /// @notice Emits the MetadataUpdate event with `tokenId` as the argument. - /// @dev Callable by anyone. - /// @param tokenId the token id to trigger a metaupdate for - function triggerMetadataUpdate(uint256 tokenId) external { - _triggerMetadataUpdate(tokenId); - } - - /// @notice This contract supports IERC165, IERC721 and IERC721Metadata - /// @dev This is part of the Standard Interface Detection EIP: https://eips.ethereum.org/EIPS/eip-165 - /// @param interfaceId the XOR of all function selectors in the interface - /// @return boolean true if the interface is supported - /// @inheritdoc IERC165 - function supportsInterface(bytes4 interfaceId) external pure virtual override returns (bool) { - return interfaceId == 0x01ffc9a7 // ERC165 Interface ID for ERC165 - || interfaceId == 0x80ac58cd // ERC165 Interface ID for ERC721 - || interfaceId == 0x5b5e139f; // ERC165 Interface ID for ERC721Metadata - } - - /// @inheritdoc IERC721 - function ownerOf(uint256 tokenId) public view virtual override returns (address) { - address owner = _ownerOf(tokenId); - if (owner == address(0)) { - revert CFA_NFT_INVALID_TOKEN_ID(); - } - return owner; - } - - /// @notice Returns a hardcoded balance of 1 - /// @dev We always return 1 to avoid the need for additional mapping - /// @return balance = 1 - function balanceOf( - address // owner - ) external pure returns (uint256 balance) { - balance = 1; - } - - /// @notice Returns the name of the NFT - /// @dev Should follow the naming convention: TOKENx Constant Outflow/Inflow NFT - /// @return name of the NFT - function name() external view virtual override returns (string memory) { - return _name; - } - - /// @notice Returns the symbol of the NFT - /// @dev Should follow the naming convention: TOKENx(COF/CIF) - /// @return symbol of the NFT - function symbol() external view virtual override returns (string memory) { - return _symbol; - } - - /// @notice This returns the Uniform Resource Identifier (URI), where the metadata for the NFT lives. - /// @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. - /// @return the token URI - function tokenURI(uint256 tokenId) external view virtual returns (string memory); - - function _tokenURI(uint256 tokenId, bool isInflow) internal view virtual returns (string memory) { - FlowNFTData memory flowData = flowDataByTokenId(tokenId); - - ISuperToken token = ISuperToken(flowData.superToken); - - (, int96 flowRate,,) = CONSTANT_FLOW_AGREEMENT_V1.getFlow(token, flowData.flowSender, flowData.flowReceiver); - - return - string( - abi.encodePacked( - baseURI(), - "?flowRate=", - uint256(uint96(flowRate)).toString(), - "&outgoing=", - isInflow ? "false" : "true", - _flowDataString(tokenId) - ) - ); - } - - function _flowDataString(uint256 tokenId) internal view returns (string memory) { - FlowNFTData memory flowData = flowDataByTokenId(tokenId); - - // @note taking this out to deal with the stack too deep issue - // which occurs when you are attempting to abi.encodePacked - // too many elements - return string( - abi.encodePacked( - "&token_address=", - Strings.toHexString(uint256(uint160(flowData.superToken)), 20), - "&chain_id=", - block.chainid.toString(), - "&token_symbol=", - ISuperToken(flowData.superToken).symbol(), - "&sender=", - Strings.toHexString(uint256(uint160(flowData.flowSender)), 20), - "&receiver=", - Strings.toHexString(uint256(uint160(flowData.flowReceiver)), 20), - "&token_decimals=", - uint256(ISuperToken(flowData.superToken).decimals()).toString(), - "&start_date=", - // @note upcasting is safe - uint256(flowData.flowStartDate).toString() - ) - ); - } - - /// @inheritdoc IERC721 - function approve(address to, uint256 tokenId) public virtual override { - address owner = FlowNFTBase.ownerOf(tokenId); - if (to == owner) { - revert CFA_NFT_APPROVE_TO_CURRENT_OWNER(); - } - - if (msg.sender != owner && !isApprovedForAll(owner, msg.sender)) { - revert CFA_NFT_APPROVE_CALLER_NOT_OWNER_OR_APPROVED_FOR_ALL(); - } - - _approve(to, tokenId); - } - - /// @inheritdoc IFlowNFTBase - function getTokenId(address superToken, address sender, address receiver) external view returns (uint256 tokenId) { - tokenId = _getTokenId(superToken, sender, receiver); - } - - function _getTokenId(address superToken, address sender, address receiver) - internal - view - returns (uint256 tokenId) - { - tokenId = uint256(keccak256(abi.encode(block.chainid, superToken, sender, receiver))); - } - - /// @inheritdoc IERC721 - function getApproved(uint256 tokenId) public view virtual override returns (address) { - _requireMinted(tokenId); - - return _tokenApprovals[tokenId]; - } - - /// @inheritdoc IERC721 - function setApprovalForAll(address operator, bool approved) external virtual override { - _setApprovalForAll(msg.sender, operator, approved); - } - - /// @inheritdoc IERC721 - function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) { - return _operatorApprovals[owner][operator]; - } - - /// @inheritdoc IERC721 - function transferFrom(address from, address to, uint256 tokenId) external virtual override { - if (!_isApprovedOrOwner(msg.sender, tokenId)) { - revert CFA_NFT_TRANSFER_CALLER_NOT_OWNER_OR_APPROVED_FOR_ALL(); - } - - _transfer(from, to, tokenId); - } - - /// @inheritdoc IERC721 - function safeTransferFrom(address from, address to, uint256 tokenId) external virtual override { - safeTransferFrom(from, to, tokenId, ""); - } - - /// @inheritdoc IERC721 - function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) public virtual override { - if (!_isApprovedOrOwner(msg.sender, tokenId)) { - revert CFA_NFT_TRANSFER_CALLER_NOT_OWNER_OR_APPROVED_FOR_ALL(); - } - - _safeTransfer(from, to, tokenId, data); - } - - /// @notice Returns whether `spender` is allowed to manage `tokenId`. - /// @dev Will revert if `tokenId` doesn't exist. - /// @param spender the spender of the token - /// @param tokenId the id of the token to be spent - /// @return whether `tokenId` can be spent by `spender` - function _isApprovedOrOwner(address spender, uint256 tokenId) internal view returns (bool) { - address owner = FlowNFTBase.ownerOf(tokenId); - return (spender == owner || isApprovedForAll(owner, spender) || getApproved(tokenId) == spender); - } - - /// @notice Reverts if `tokenId` doesn't exist - /// @param tokenId the token id whose existence we are checking - function _requireMinted(uint256 tokenId) internal view { - if (!_exists(tokenId)) revert CFA_NFT_INVALID_TOKEN_ID(); - } - - /// @notice Returns whether `tokenId` exists - /// @dev Tokens can be managed by their owner or approved accounts via `approve` or `setApprovalForAll`. - /// Tokens start existing when they are minted (`_mint`), - /// and stop existing when they are burned (`_burn`). - /// @param tokenId the token id we're interested in seeing if exists - /// @return bool whether ot not the token exists - function _exists(uint256 tokenId) internal view returns (bool) { - return _ownerOf(tokenId) != address(0); - } - - function _triggerMetadataUpdate(uint256 tokenId) internal { - emit MetadataUpdate(tokenId); - } - - function _approve(address to, uint256 tokenId) internal { - _tokenApprovals[tokenId] = to; - - emit Approval(_ownerOf(tokenId), to, tokenId); - } - - function _setApprovalForAll(address owner, address operator, bool approved) internal { - if (owner == operator) revert CFA_NFT_APPROVE_TO_CALLER(); - - _operatorApprovals[owner][operator] = approved; - - emit ApprovalForAll(owner, operator, approved); - } - - /// @dev Returns the flow data of the `tokenId`. Does NOT revert if token doesn't exist. - /// @param tokenId the token id whose existence we're checking - /// @return flowData the FlowNFTData struct for `tokenId` - function flowDataByTokenId(uint256 tokenId) public view virtual returns (FlowNFTData memory flowData); - - /// @dev Returns the owner of the `tokenId`. Does NOT revert if token doesn't exist. - /// @param tokenId the token id whose existence we're checking - /// @return address the address of the owner of `tokenId` - function _ownerOf(uint256 tokenId) internal view virtual returns (address); - - function _transfer(address from, address to, uint256 tokenId) internal virtual; - - function _safeTransfer( - address from, - address to, - uint256 tokenId, - bytes memory // data - ) internal virtual { - _transfer(from, to, tokenId); - } - - /// @dev Deletes the tokenApprovals for `tokenId` - /// @param tokenId the token id whose approvals we're clearing - function _burn(uint256 tokenId) internal virtual { - // clear approvals from the previous owner - delete _tokenApprovals[tokenId]; - } -} diff --git a/packages/ethereum-contracts/contracts/superfluid/SuperToken.sol b/packages/ethereum-contracts/contracts/superfluid/SuperToken.sol index f6ac26f51f..dbb0db043f 100644 --- a/packages/ethereum-contracts/contracts/superfluid/SuperToken.sol +++ b/packages/ethereum-contracts/contracts/superfluid/SuperToken.sol @@ -9,8 +9,6 @@ import { ISuperfluid, ISuperToken, IERC20, - IConstantOutflowNFT, - IConstantInflowNFT, IPoolAdminNFT, IPoolMemberNFT } from "../interfaces/superfluid/ISuperfluid.sol"; @@ -23,6 +21,12 @@ import { IERC777Recipient } from "@openzeppelin/contracts/token/ERC777/IERC777Re import { IERC777Sender } from "@openzeppelin/contracts/token/ERC777/IERC777Sender.sol"; import { Address } from "@openzeppelin/contracts/utils/Address.sol"; +// placeholder types needed as an intermediate step before complete removal of FlowNFTs +// solhint-disable-next-line no-empty-blocks +interface IConstantOutflowNFT {} +// solhint-disable-next-line no-empty-blocks +interface IConstantInflowNFT {} + /** * @title Superfluid's super token implementation * @@ -117,12 +121,10 @@ contract SuperToken is // set the immutable canonical NFT proxy addresses CONSTANT_OUTFLOW_NFT = constantOutflowNFT; CONSTANT_INFLOW_NFT = constantInflowNFT; + POOL_ADMIN_NFT = poolAdminNFT; POOL_MEMBER_NFT = poolMemberNFT; - emit ConstantOutflowNFTCreated(constantOutflowNFT); - emit ConstantInflowNFTCreated(constantInflowNFT); - emit PoolAdminNFTCreated(poolAdminNFT); emit PoolMemberNFTCreated(poolMemberNFT); } @@ -177,18 +179,6 @@ contract SuperToken is */ function updateCode(address newAddress) external virtual override onlyAdmin { UUPSProxiable._updateCodeAddress(newAddress); - - // @note This is another check to ensure that when updating to a new SuperToken logic contract - // that we have passed the correct NFT proxy contracts in the construction of the new SuperToken - // logic contract - if ( - CONSTANT_OUTFLOW_NFT != - SuperToken(newAddress).CONSTANT_OUTFLOW_NFT() || - CONSTANT_INFLOW_NFT != - SuperToken(newAddress).CONSTANT_INFLOW_NFT() - ) { - revert SUPER_TOKEN_NFT_PROXY_ADDRESS_CHANGED(); - } } function changeAdmin(address newAdmin) external override onlyAdmin { diff --git a/packages/ethereum-contracts/contracts/superfluid/SuperTokenFactory.sol b/packages/ethereum-contracts/contracts/superfluid/SuperTokenFactory.sol index fe9db038e0..55823bf0e4 100644 --- a/packages/ethereum-contracts/contracts/superfluid/SuperTokenFactory.sol +++ b/packages/ethereum-contracts/contracts/superfluid/SuperTokenFactory.sol @@ -8,11 +8,12 @@ import { ISuperToken } from "../interfaces/superfluid/ISuperTokenFactory.sol"; import { - ISuperfluid, IConstantOutflowNFT, IConstantInflowNFT, IPoolAdminNFT, IPoolMemberNFT + ISuperfluid, IPoolAdminNFT, IPoolMemberNFT } from "../interfaces/superfluid/ISuperfluid.sol"; import { UUPSProxy } from "../upgradability/UUPSProxy.sol"; import { UUPSProxiable } from "../upgradability/UUPSProxiable.sol"; import { FullUpgradableSuperTokenProxy } from "./FullUpgradableSuperTokenProxy.sol"; +import { IConstantOutflowNFT, IConstantInflowNFT } from "./SuperToken.sol"; abstract contract SuperTokenFactoryBase is UUPSProxiable, @@ -144,16 +145,6 @@ abstract contract SuperTokenFactoryBase is // We only do this if the new logic contracts passed in updating the SuperTokenFactory // are different from the current logic contracts SuperTokenFactory newFactory = SuperTokenFactory(newAddress); - address newConstantOutflowLogic = address(newFactory.CONSTANT_OUTFLOW_NFT_LOGIC()); - address newConstantInflowLogic = address(newFactory.CONSTANT_INFLOW_NFT_LOGIC()); - - if (address(CONSTANT_OUTFLOW_NFT_LOGIC) != newConstantOutflowLogic) { - UUPSProxiable(address(_SUPER_TOKEN_LOGIC.CONSTANT_OUTFLOW_NFT())).updateCode(newConstantOutflowLogic); - } - - if (address(CONSTANT_INFLOW_NFT_LOGIC) != newConstantInflowLogic) { - UUPSProxiable(address(_SUPER_TOKEN_LOGIC.CONSTANT_INFLOW_NFT())).updateCode(newConstantInflowLogic); - } if (address(POOL_ADMIN_NFT_LOGIC) != address(newFactory.POOL_ADMIN_NFT_LOGIC())) { UUPSProxiable(address(_SUPER_TOKEN_LOGIC.POOL_ADMIN_NFT())).updateCode( diff --git a/packages/ethereum-contracts/contracts/utils/SuperfluidFrameworkDeploymentSteps.sol b/packages/ethereum-contracts/contracts/utils/SuperfluidFrameworkDeploymentSteps.sol index bef16401a6..7d15408dd4 100644 --- a/packages/ethereum-contracts/contracts/utils/SuperfluidFrameworkDeploymentSteps.sol +++ b/packages/ethereum-contracts/contracts/utils/SuperfluidFrameworkDeploymentSteps.sol @@ -9,9 +9,7 @@ import { IDAv1Forwarder } from "./IDAv1Forwarder.sol"; import { GDAv1Forwarder } from "./GDAv1Forwarder.sol"; import { ISuperfluid, ISuperfluidToken, Superfluid } from "../superfluid/Superfluid.sol"; import { TestGovernance } from "./TestGovernance.sol"; -import { IConstantFlowAgreementV1, ConstantFlowAgreementV1 } from "../agreements/ConstantFlowAgreementV1.sol"; -import { ConstantOutflowNFT, IConstantOutflowNFT } from "../superfluid/ConstantOutflowNFT.sol"; -import { ConstantInflowNFT, IConstantInflowNFT } from "../superfluid/ConstantInflowNFT.sol"; +import { ConstantFlowAgreementV1 } from "../agreements/ConstantFlowAgreementV1.sol"; import { PoolAdminNFT, IPoolAdminNFT } from "../agreements/gdav1/PoolAdminNFT.sol"; import { PoolMemberNFT, IPoolMemberNFT } from "../agreements/gdav1/PoolMemberNFT.sol"; import { InstantDistributionAgreementV1 } from "../agreements/InstantDistributionAgreementV1.sol"; @@ -23,7 +21,7 @@ import { SuperTokenFactory } from "../superfluid/SuperTokenFactory.sol"; import { TestToken } from "./TestToken.sol"; import { PureSuperToken } from "../tokens/PureSuperToken.sol"; import { SETHProxy } from "../tokens/SETH.sol"; -import { ISuperToken, SuperToken } from "../superfluid/SuperToken.sol"; +import { ISuperToken, SuperToken, IConstantOutflowNFT, IConstantInflowNFT } from "../superfluid/SuperToken.sol"; import { TestResolver } from "./TestResolver.sol"; import { SuperfluidLoader } from "./SuperfluidLoader.sol"; import { SuperfluidPool } from "../agreements/gdav1/SuperfluidPool.sol"; @@ -63,8 +61,6 @@ contract SuperfluidFrameworkDeploymentSteps { IDAv1Library.InitData idaLib; SuperTokenFactory superTokenFactory; ISuperToken superTokenLogic; - ConstantOutflowNFT constantOutflowNFT; - ConstantInflowNFT constantInflowNFT; TestResolver resolver; SuperfluidLoader superfluidLoader; CFAv1Forwarder cfaV1Forwarder; @@ -86,8 +82,6 @@ contract SuperfluidFrameworkDeploymentSteps { GeneralDistributionAgreementV1 internal gdaV1; // SuperToken-related Contracts - ConstantOutflowNFT internal constantOutflowNFT; - ConstantInflowNFT internal constantInflowNFT; PoolAdminNFT internal poolAdminNFT; PoolMemberNFT internal poolMemberNFT; @@ -122,8 +116,6 @@ contract SuperfluidFrameworkDeploymentSteps { gda: gdaV1, superTokenFactory: superTokenFactory, superTokenLogic: superTokenLogic, - constantOutflowNFT: constantOutflowNFT, - constantInflowNFT: constantInflowNFT, resolver: testResolver, superfluidLoader: superfluidLoader, cfaV1Forwarder: cfaV1Forwarder, @@ -204,27 +196,6 @@ contract SuperfluidFrameworkDeploymentSteps { gdaV1Logic.superfluidPoolBeacon().transferOwnership(address(host)); } } else if (step == 3) {// PERIPHERAL CONTRACTS: NFT Proxy and Logic - { - constantOutflowNFT = ConstantOutflowNFT(address(ProxyDeployerLibrary.deployUUPSProxy())); - constantInflowNFT = ConstantInflowNFT(address(ProxyDeployerLibrary.deployUUPSProxy())); - - ConstantOutflowNFT constantOutflowNFTLogic = SuperfluidFlowNFTLogicDeployerLibrary - .deployConstantOutflowNFT(host, cfaV1, gdaV1, constantInflowNFT); - constantOutflowNFTLogic.castrate(); - - ConstantInflowNFT constantInflowNFTLogic = SuperfluidFlowNFTLogicDeployerLibrary - .deployConstantInflowNFT(host, cfaV1, gdaV1, constantOutflowNFT); - constantInflowNFTLogic.castrate(); - - UUPSProxy(payable(address(constantOutflowNFT))).initializeProxy(address(constantOutflowNFTLogic)); - - UUPSProxy(payable(address(constantInflowNFT))).initializeProxy(address(constantInflowNFTLogic)); - - constantOutflowNFT.initialize("Constant Outflow NFT", "COF"); - - constantInflowNFT.initialize("Constant Inflow NFT", "CIF"); - } - { poolAdminNFT = PoolAdminNFT(address(ProxyDeployerLibrary.deployUUPSProxy())); PoolAdminNFT poolAdminNFTLogic = @@ -257,8 +228,6 @@ contract SuperfluidFrameworkDeploymentSteps { // Deploy canonical SuperToken logic contract superTokenLogic = SuperToken(SuperTokenDeployerLibrary.deploy( host, - constantOutflowNFT, - constantInflowNFT, poolAdminNFT, poolMemberNFT )); @@ -270,8 +239,6 @@ contract SuperfluidFrameworkDeploymentSteps { SuperTokenFactory superTokenFactoryLogic = SuperTokenFactoryDeployerLibrary.deploy( host, superTokenLogic, - IConstantOutflowNFT(constantOutflowNFT.getCodeAddress()), - IConstantInflowNFT(constantInflowNFT.getCodeAddress()), IPoolAdminNFT(poolAdminNFT.getCodeAddress()), IPoolMemberNFT(poolMemberNFT.getCodeAddress()) ); @@ -420,32 +387,16 @@ library GDAv1ForwarderDeployerLibrary { library SuperTokenDeployerLibrary { function deploy( ISuperfluid host, - IConstantOutflowNFT constantOutflowNFT, - IConstantInflowNFT constantInflowNFT, IPoolAdminNFT poolAdminNFT, IPoolMemberNFT poolMemberNFT ) external returns (address) { - return address(new SuperToken(host, constantOutflowNFT, constantInflowNFT, poolAdminNFT, poolMemberNFT)); - } -} - -library SuperfluidFlowNFTLogicDeployerLibrary { - function deployConstantOutflowNFT( - ISuperfluid host, - IConstantFlowAgreementV1 cfa, - IGeneralDistributionAgreementV1 gda, - IConstantInflowNFT constantInflowNFTProxy - ) external returns (ConstantOutflowNFT) { - return new ConstantOutflowNFT(host, cfa, gda, constantInflowNFTProxy); - } - - function deployConstantInflowNFT( - ISuperfluid host, - IConstantFlowAgreementV1 cfa, - IGeneralDistributionAgreementV1 gda, - IConstantOutflowNFT constantOutflowNFTProxy - ) external returns (ConstantInflowNFT) { - return new ConstantInflowNFT(host, cfa, gda, constantOutflowNFTProxy); + return address(new SuperToken( + host, + IConstantOutflowNFT(address(0)), + IConstantInflowNFT(address(0)), + poolAdminNFT, + poolMemberNFT + )); } } @@ -498,16 +449,14 @@ library SuperTokenFactoryDeployerLibrary { function deploy( ISuperfluid host, ISuperToken superTokenLogic, - IConstantOutflowNFT constantOutflowNFTLogic, - IConstantInflowNFT constantInflowNFTLogic, IPoolAdminNFT poolAdminNFTLogic, IPoolMemberNFT poolMemberNFTLogic ) external returns (SuperTokenFactory) { return new SuperTokenFactory( host, superTokenLogic, - constantOutflowNFTLogic, - constantInflowNFTLogic, + IConstantOutflowNFT(address(0)), + IConstantInflowNFT(address(0)), poolAdminNFTLogic, poolMemberNFTLogic ); diff --git a/packages/ethereum-contracts/dev-scripts/deploy-test-framework.js b/packages/ethereum-contracts/dev-scripts/deploy-test-framework.js index 41d12ae832..3425d88afb 100644 --- a/packages/ethereum-contracts/dev-scripts/deploy-test-framework.js +++ b/packages/ethereum-contracts/dev-scripts/deploy-test-framework.js @@ -10,7 +10,6 @@ const SuperfluidGDAv1DeployerLibraryArtifact = require("@superfluid-finance/ethe const SuperTokenDeployerLibraryArtifact = require("@superfluid-finance/ethereum-contracts/build/hardhat/contracts/utils/SuperfluidFrameworkDeploymentSteps.sol/SuperTokenDeployerLibrary.json"); const SuperfluidPeripheryDeployerLibraryArtifact = require("@superfluid-finance/ethereum-contracts/build/hardhat/contracts/utils/SuperfluidFrameworkDeploymentSteps.sol/SuperfluidPeripheryDeployerLibrary.json"); const SuperfluidPoolLogicDeployerLibraryArtifact = require("@superfluid-finance/ethereum-contracts/build/hardhat/contracts/utils/SuperfluidFrameworkDeploymentSteps.sol/SuperfluidPoolLogicDeployerLibrary.json"); -const SuperfluidFlowNFTLogicDeployerLibraryArtifact = require("@superfluid-finance/ethereum-contracts/build/hardhat/contracts/utils/SuperfluidFrameworkDeploymentSteps.sol/SuperfluidFlowNFTLogicDeployerLibrary.json"); const SuperfluidPoolNFTLogicDeployerLibraryArtifact = require("@superfluid-finance/ethereum-contracts/build/hardhat/contracts/utils/SuperfluidFrameworkDeploymentSteps.sol/SuperfluidPoolNFTLogicDeployerLibrary.json"); const ProxyDeployerLibraryArtifact = require("@superfluid-finance/ethereum-contracts/build/hardhat/contracts/utils/SuperfluidFrameworkDeploymentSteps.sol/ProxyDeployerLibrary.json"); const CFAv1ForwarderDeployerLibraryArtifact = require("@superfluid-finance/ethereum-contracts/build/hardhat/contracts/utils/SuperfluidFrameworkDeploymentSteps.sol/CFAv1ForwarderDeployerLibrary.json"); @@ -193,12 +192,6 @@ const _deployTestFramework = async (provider, signer) => { SuperfluidPoolLogicDeployerLibraryArtifact, signer ); - const SuperfluidFlowNFTLogicDeployerLibrary = - await _getFactoryAndReturnDeployedContract( - "SuperfluidFlowNFTLogicDeployerLibrary", - SuperfluidFlowNFTLogicDeployerLibraryArtifact, - signer - ); const SuperfluidPoolNFTLogicDeployerLibrary = await _getFactoryAndReturnDeployedContract( "SuperfluidPoolNFTLogicDeployerLibrary", @@ -276,9 +269,6 @@ const _deployTestFramework = async (provider, signer) => { SuperfluidPoolLogicDeployerLibrary: getContractAddress( SuperfluidPoolLogicDeployerLibrary ), - SuperfluidFlowNFTLogicDeployerLibrary: getContractAddress( - SuperfluidFlowNFTLogicDeployerLibrary - ), SuperfluidPoolNFTLogicDeployerLibrary: getContractAddress( SuperfluidPoolNFTLogicDeployerLibrary ), @@ -316,8 +306,6 @@ const printProtocolFrameworkAddresses = (framework) => { IDAv1: framework.ida, SuperTokenFactory: framework.superTokenFactory, SuperTokenLogic: framework.superTokenLogic, - ConstantOutflowNFT: framework.constantOutflowNFT, - ConstantInflowNFT: framework.constantInflowNFT, Resolver: framework.resolver, SuperfluidLoader: framework.superfluidLoader, CFAv1Forwarder: framework.cfaV1Forwarder, diff --git a/packages/ethereum-contracts/dev-scripts/run-deploy-contracts-and-token.js b/packages/ethereum-contracts/dev-scripts/run-deploy-contracts-and-token.js index e81ebc157e..6b033f737f 100644 --- a/packages/ethereum-contracts/dev-scripts/run-deploy-contracts-and-token.js +++ b/packages/ethereum-contracts/dev-scripts/run-deploy-contracts-and-token.js @@ -18,8 +18,6 @@ deployContractsAndToken() nativeAssetSuperTokenAddress: tokenDeploymentOutput.nativeAssetSuperTokenData .nativeAssetSuperTokenAddress, - constantOutflowNFTAddress: frameworkAddresses.constantOutflowNFT, - constantInflowNFTAddress: frameworkAddresses.constantInflowNFT, }; // create json output diff --git a/packages/ethereum-contracts/ops-scripts/deploy-framework.js b/packages/ethereum-contracts/ops-scripts/deploy-framework.js index e758e07f7d..3e28ba35db 100644 --- a/packages/ethereum-contracts/ops-scripts/deploy-framework.js +++ b/packages/ethereum-contracts/ops-scripts/deploy-framework.js @@ -229,8 +229,6 @@ module.exports = eval(`(${S.toString()})({skipArgv: true})`)(async function ( "SuperfluidPoolPlaceholder", "SuperfluidPoolDeployerLibrary", "BeaconProxy", - "ConstantOutflowNFT", - "ConstantInflowNFT", "PoolAdminNFT", "PoolMemberNFT", "IAccessControlEnumerable", @@ -270,8 +268,6 @@ module.exports = eval(`(${S.toString()})({skipArgv: true})`)(async function ( SuperfluidPoolPlaceholder, SuperfluidPoolDeployerLibrary, BeaconProxy, - ConstantOutflowNFT, - ConstantInflowNFT, PoolAdminNFT, PoolMemberNFT, IAccessControlEnumerable, @@ -812,18 +808,19 @@ module.exports = eval(`(${S.toString()})({skipArgv: true})`)(async function ( } async function getPrevDMZForwarderAddr() { - console.log("Getting DMZForwarder address..."); try { return await superfluid.DMZ_FORWARDER(); } catch (err) { + console.error("### Error getting DMZForwarder address", err); return ZERO_ADDRESS; // fallback } } + const prevDMZForwarderAddr = await getPrevDMZForwarderAddr(); - const dmzForwarderAddress = await deployContractIfCodeChanged( + const dmzForwarderNewAddress = await deployContractIfCodeChanged( web3, DMZForwarder, - await getPrevDMZForwarderAddr(), + prevDMZForwarderAddr, async () => { const dmzForwarder = await web3tx(DMZForwarder.new, "DMZForwarder.new")(); await web3tx( @@ -834,6 +831,9 @@ module.exports = eval(`(${S.toString()})({skipArgv: true})`)(async function ( return dmzForwarder.address; } ); + const dmzForwarderAddress = dmzForwarderNewAddress !== ZERO_ADDRESS + ? dmzForwarderNewAddress + : prevDMZForwarderAddr; // get previous callback gas limit, make sure we don't decrease it const prevCallbackGasLimit = await superfluid.CALLBACK_GAS_LIMIT(); @@ -921,8 +921,6 @@ module.exports = eval(`(${S.toString()})({skipArgv: true})`)(async function ( const factoryAddress = await superfluid.getSuperTokenFactory.call(); - let constantOutflowNFTLogicChanged = false; - let constantInflowNFTLogicChanged = false; let poolAdminNFTLogicChanged = false; let poolMemberNFTLogicChanged = false; @@ -951,37 +949,22 @@ module.exports = eval(`(${S.toString()})({skipArgv: true})`)(async function ( const superTokenLogicAddress = await factory.getSuperTokenLogic.call(); const superTokenLogic = await SuperTokenLogic.at(superTokenLogicAddress); - const cfaPAddr = await superfluid.getAgreementClass.call(CFAv1_TYPE); const gdaPAddr = await superfluid.getAgreementClass.call(GDAv1_TYPE); const cofNFTPAddr = await superTokenLogic.CONSTANT_OUTFLOW_NFT(); const cifNFTPAddr = await superTokenLogic.CONSTANT_INFLOW_NFT(); - let cofNFTLAddr; - let cifNFTLAddr; + let cofNFTLAddr = ZERO_ADDRESS; + let cifNFTLAddr = ZERO_ADDRESS; if (cofNFTPAddr !== ZERO_ADDRESS) { - const cofNFTContract = await ConstantOutflowNFT.at(cofNFTPAddr); + const cofNFTContract = await UUPSProxiable.at(cofNFTPAddr); cofNFTLAddr = await cofNFTContract.getCodeAddress(); - constantOutflowNFTLogicChanged = await codeChanged( - web3, - ConstantOutflowNFT, - cofNFTLAddr, - [superfluidConstructorParam, ap(cifNFTPAddr), ap(cfaPAddr), ap(gdaPAddr)] - ); - console.log(" constantOutflowNFTLogicChanged:", constantOutflowNFTLogicChanged); } if (cifNFTPAddr !== ZERO_ADDRESS) { - const cifNFTContract = await ConstantInflowNFT.at(cifNFTPAddr); + const cifNFTContract = await UUPSProxiable.at(cifNFTPAddr); cifNFTLAddr = await cifNFTContract.getCodeAddress(); - constantInflowNFTLogicChanged = await codeChanged( - web3, - ConstantInflowNFT, - cifNFTLAddr, - [superfluidConstructorParam, ap(cofNFTPAddr), ap(cfaPAddr), ap(gdaPAddr)] - ); - console.log(" constantInflowNFTLogicChanged:", constantInflowNFTLogicChanged); } // TODO: remove from try block once all networks have a PoolNFT aware supertoken logic deployed @@ -1037,12 +1020,9 @@ module.exports = eval(`(${S.toString()})({skipArgv: true})`)(async function ( return ( // check if super token factory logic has changed // or super token logic has changed - // or constant outflow nft logic has changed - // or constant inflow nft logic has changed + // or pool nft logic has changed superTokenFactoryCodeChanged || superTokenLogicCodeChanged || - constantOutflowNFTLogicChanged || - constantInflowNFTLogicChanged || poolAdminNFTLogicChanged || poolMemberNFTLogicChanged ); @@ -1061,8 +1041,8 @@ module.exports = eval(`(${S.toString()})({skipArgv: true})`)(async function ( // @note this will either be freshly created proxies on the very first bootstrapping per network // OR it will be the canonical proxy set on the SuperToken - let cofNFTProxyAddress = ZERO_ADDRESS; - let cifNFTProxyAddress = ZERO_ADDRESS; + let cofNFTProxyAddress; + let cifNFTProxyAddress; let cofNFTLogicAddress = ZERO_ADDRESS; let cifNFTLogicAddress = ZERO_ADDRESS; let poolAdminNFTProxyAddress = ZERO_ADDRESS; @@ -1088,10 +1068,10 @@ module.exports = eval(`(${S.toString()})({skipArgv: true})`)(async function ( await superTokenLogic.CONSTANT_OUTFLOW_NFT.call(); cifNFTProxyAddress = await superTokenLogic.CONSTANT_INFLOW_NFT.call(); - cofNFTLogicAddress = await ( + cofNFTLogicAddress = cofNFTProxyAddress === ZERO_ADDRESS ? ZERO_ADDRESS : await ( await UUPSProxiable.at(cofNFTProxyAddress) ).getCodeAddress(); - cifNFTLogicAddress = await ( + cifNFTLogicAddress = cofNFTProxyAddress === ZERO_ADDRESS ? ZERO_ADDRESS : await ( await UUPSProxiable.at(cifNFTProxyAddress) ).getCodeAddress(); @@ -1121,118 +1101,23 @@ module.exports = eval(`(${S.toString()})({skipArgv: true})`)(async function ( const cfaAddr = await superfluid.getAgreementClass.call(CFAv1_TYPE); const gdaAddr = await superfluid.getAgreementClass.call(GDAv1_TYPE); - // TODO: we may not want it deployed if address is zero (eth-mainnet) - - if ( - cofNFTProxyAddress === ZERO_ADDRESS || - cifNFTProxyAddress === ZERO_ADDRESS - ) { - console.log("BOOTSTRAPPING: Deploying Flow NFT Proxies..."); - const constantOutflowNFTProxy = await web3tx( - UUPSProxy.new, - `Create ConstantOutflowNFT proxy` - )(); - console.log( - "ConstantOutflowNFT Proxy address", - constantOutflowNFTProxy.address - ); - output += `CONSTANT_OUTFLOW_NFT_PROXY=${constantOutflowNFTProxy.address}\n`; - - const constantInflowNFTProxy = await web3tx( - UUPSProxy.new, - `Create ConstantInflowNFT proxy` - )(); - console.log( - "ConstantInflowNFT Proxy address", - constantInflowNFTProxy.address - ); - output += `CONSTANT_INFLOW_NFT_PROXY=${constantInflowNFTProxy.address}\n`; - - const constantOutflowNFTLogic = await deployNFTContract( - ConstantOutflowNFT, - "ConstantOutflowNFT", - "CONSTANT_OUTFLOW_NFT_LOGIC", - [superfluid.address, cfaAddr, gdaAddr, constantInflowNFTProxy.address] - ); - const constantInflowNFTLogic = await deployNFTContract( - ConstantInflowNFT, - "ConstantInflowNFT", - "CONSTANT_INFLOW_NFT_LOGIC", - [superfluid.address, cfaAddr, gdaAddr, constantOutflowNFTProxy.address] - ); - - // set the nft logic addresses (to be consumed by the super token factory logic constructor) - cofNFTLogicAddress = constantOutflowNFTLogic.address; - cifNFTLogicAddress = constantInflowNFTLogic.address; - - // initialize the nft proxy with the nft logic - await constantOutflowNFTProxy.initializeProxy( - constantOutflowNFTLogic.address - ); - await constantInflowNFTProxy.initializeProxy( - constantInflowNFTLogic.address - ); - const constantOutflowNFT = await ConstantOutflowNFT.at( - constantOutflowNFTProxy.address - ); - const constantInflowNFT = await ConstantInflowNFT.at( - constantInflowNFTProxy.address - ); - - // initialize the proxy contracts with the nft names - await constantOutflowNFT.initialize( - "Constant Outflow NFT", - "COF" - ); - await constantInflowNFT.initialize( - "Constant Inflow NFT", - "CIF" - ); - - // set the nft proxy addresses (to be consumed by the super token logic constructor) - cofNFTProxyAddress = constantOutflowNFTProxy.address; - cifNFTProxyAddress = constantInflowNFTProxy.address; - } else { - // FlowNFT proxies already exist - console.log("Check-upgrading Flow NFTs..."); - await deployContractIf( - web3, - ConstantOutflowNFT, - async () => { - return constantOutflowNFTLogicChanged; - }, - async () => { - const cofNFTLogic = await deployNFTContract( - ConstantOutflowNFT, - "ConstantOutflowNFT", - "CONSTANT_OUTFLOW_NFT_LOGIC", - [superfluid.address, cfaAddr, gdaAddr, cifNFTProxyAddress] - ); - // @note we set the cofNFTLogicAddress to be passed to SuperTokenFactoryLogic here - cofNFTLogicAddress = cofNFTLogic.address; + // We used to deploy a proxy if none existed. But FlowNFTs are now deprecated, so we don't. + if (cofNFTProxyAddress === undefined) { + console.log("COFNFT proxy doesn't exist, skipping deployment"); + cofNFTProxyAddress = ZERO_ADDRESS; + } + if (cifNFTProxyAddress === undefined) { + console.log("CIFNFT proxy doesn't exist, skipping deployment"); + cifNFTProxyAddress = ZERO_ADDRESS; + } - return cofNFTLogic.address; - } - ); - await deployContractIf( - web3, - ConstantInflowNFT, - async () => { - return constantInflowNFTLogicChanged; - }, - async () => { - const cifNFTLogic = await deployNFTContract( - ConstantInflowNFT, - "ConstantInflowNFT", - "CONSTANT_INFLOW_NFT_LOGIC", - [superfluid.address, cfaAddr, gdaAddr, cofNFTProxyAddress] - ); - // @note we set the cifNFTLogicAddress to be passed to SuperTokenFactoryLogic here - cifNFTLogicAddress = cifNFTLogic.address; - return cifNFTLogic.address; - } - ); - }; + // For existing proxies, we used to check-update the logic. But we don't anymore. + if (cofNFTProxyAddress !== ZERO_ADDRESS) { + console.log("skipping COFNFT logic update") + } + if (cifNFTProxyAddress !== ZERO_ADDRESS) { + console.log("skipping CIFNFT logic update") + } if ( diff --git a/packages/ethereum-contracts/ops-scripts/gov-transfer-framework-ownership.js b/packages/ethereum-contracts/ops-scripts/gov-transfer-framework-ownership.js index b66286c95f..1b5ef9924f 100644 --- a/packages/ethereum-contracts/ops-scripts/gov-transfer-framework-ownership.js +++ b/packages/ethereum-contracts/ops-scripts/gov-transfer-framework-ownership.js @@ -5,6 +5,7 @@ const { extractWeb3Options, hasCode, sendGovernanceAction, + builtTruffleContractLoader, } = require("./libs/common"); /** @@ -47,7 +48,13 @@ module.exports = eval(`(${S.toString()})()`)(async function ( const sf = new SuperfluidSDK.Framework({ ...extractWeb3Options(options), version: protocolReleaseVersion, - additionalContracts: ["AccessControl", "Ownable"], + additionalContracts: [ + "AccessControl", + "Ownable", + "IMultiSigWallet", + "ISafe" + ], + contractLoader: builtTruffleContractLoader, }); await sf.initialize(); diff --git a/packages/ethereum-contracts/ops-scripts/gov-upgrade-super-token-logic.js b/packages/ethereum-contracts/ops-scripts/gov-upgrade-super-token-logic.js index 2393da2e01..a40e979ec1 100644 --- a/packages/ethereum-contracts/ops-scripts/gov-upgrade-super-token-logic.js +++ b/packages/ethereum-contracts/ops-scripts/gov-upgrade-super-token-logic.js @@ -92,8 +92,27 @@ module.exports = eval(`(${S.toString()})()`)(async function ( console.log("SuperToken logic to update to:", newSuperTokenLogic); + const pastSuperTokenLogics = (await sf.subgraphQuery(`{ + superTokenLogicCreatedEvents { + name + tokenLogic + } + }`)).superTokenLogicCreatedEvents.map((i) => i.tokenLogic); + + const extraPastSuperTokenLogics = (process.env.EXTRA_PAST_SUPER_TOKEN_LOGICS || "").split(",") + .map((i) => i.trim()) + .filter((i) => i !== ""); + + // workaround for the subgraph query not returning all past canonical super token logics + if (canonicalSuperTokenLogic !== newSuperTokenLogic) { + pastSuperTokenLogics.push(canonicalSuperTokenLogic); + } + + console.log(`Extra past SuperToken logic contracts: ${JSON.stringify(extraPastSuperTokenLogics, null, 2)}`); + pastSuperTokenLogics.push(...extraPastSuperTokenLogics); + let tokensToBeUpgraded = (args.length === 1 && args[0] === "ALL") ? - await getTokensToBeUpgraded(sf, newSuperTokenLogic, skipTokens) : + await getTokensToBeUpgraded(sf, newSuperTokenLogic, skipTokens, pastSuperTokenLogics) : Array.from(args); console.log(`${tokensToBeUpgraded.length} tokens to be upgraded`); @@ -123,24 +142,6 @@ module.exports = eval(`(${S.toString()})()`)(async function ( (gov) => gov.batchUpdateSuperTokenLogic(sf.host.address, batch) await sendGovernanceAction(sf, govAction); - - // When first updating to the version adding native flow NFTs, this needs to be run twice - console.log("checking if 2nd run needed..."); - try { - const beaconST = await sf.contracts.ISuperToken.at(batch[0]); - const cofAddr = await beaconST.CONSTANT_OUTFLOW_NFT(); - if (cofAddr === ZERO_ADDRESS) { - console.log("...running upgrade again for NFT initialization..."); - // the first time it is to get the code to initialize the NFT proxies there - // the second time is to actually execute that code in updateCode - await sendGovernanceAction(sf, govAction); - } else { - console.log("...not needed"); - } - } catch (e) { - console.log(`failed to read constantOutflowNFT addr: ${e.toString()}`); - console.log("this is expected if running against a pre-1.6.0 deployment"); - } } } } @@ -161,25 +162,10 @@ async function getCanonicalSuperTokenLogic(sf) { // - not being a proxy or not having a logic address // - already pointing to the latest logic // - in the skip list (e.g. because not managed by SF gov) -async function getTokensToBeUpgraded(sf, newSuperTokenLogic, skipList) { +async function getTokensToBeUpgraded(sf, newSuperTokenLogic, skipList, pastSuperTokenLogics) { const maxItems = parseInt(process.env.MAX_ITEMS) || 1000; const skipItems = parseInt(process.env.SKIP_ITEMS) || 0; - const pastSuperTokenLogics = (await sf.subgraphQuery(`{ - superTokenLogicCreatedEvents { - name - tokenLogic - } - }`)).superTokenLogicCreatedEvents.map((i) => i.tokenLogic); - - const extraPastSuperTokenLogics = (process.env.EXTRA_PAST_SUPER_TOKEN_LOGICS || "").split(",") - .map((i) => i.trim()) - .filter((i) => i !== ""); - - console.log(`Extra past SuperToken logic contracts: ${JSON.stringify(extraPastSuperTokenLogics, null, 2)}`); - pastSuperTokenLogics.push(...extraPastSuperTokenLogics); - - console.log(`Past SuperToken logic contracts we take into account: ${JSON.stringify(pastSuperTokenLogics, null, 2)}`); const candidateTokens = (await sf.subgraphQuery(`{ diff --git a/packages/ethereum-contracts/ops-scripts/info-print-contract-addresses.js b/packages/ethereum-contracts/ops-scripts/info-print-contract-addresses.js index ec20fd41f8..aca089f4e0 100644 --- a/packages/ethereum-contracts/ops-scripts/info-print-contract-addresses.js +++ b/packages/ethereum-contracts/ops-scripts/info-print-contract-addresses.js @@ -141,32 +141,6 @@ module.exports = eval(`(${S.toString()})()`)(async function ( const superTokenLogicContract = await SuperToken.at(superTokenLogicAddress); - const constantOutflowNFTProxyAddress = - await superTokenLogicContract.CONSTANT_OUTFLOW_NFT(); - - // FlowNFTs are optional, zero address means not deployed - if (constantOutflowNFTProxyAddress !== ZERO_ADDRESS) { - output += `CONSTANT_OUTFLOW_NFT_PROXY=${constantOutflowNFTProxyAddress}\n`; - - const constantOutflowNFTLogicAddress = await ( - await UUPSProxiable.at(constantOutflowNFTProxyAddress) - ).getCodeAddress(); - output += `CONSTANT_OUTFLOW_NFT_LOGIC=${constantOutflowNFTLogicAddress}\n`; - } - - const constantInflowNFTProxyAddress = - await superTokenLogicContract.CONSTANT_INFLOW_NFT(); - - // FlowNFTs are optional, zero address means not deployed - if (constantInflowNFTProxyAddress !== ZERO_ADDRESS) { - output += `CONSTANT_INFLOW_NFT_PROXY=${constantInflowNFTProxyAddress}\n`; - - const constantInflowNFTLogicAddress = await ( - await UUPSProxiable.at(constantInflowNFTProxyAddress) - ).getCodeAddress(); - output += `CONSTANT_INFLOW_NFT_LOGIC=${constantInflowNFTLogicAddress}\n`; - } - // not yet deployed on all networks // TODO: remove try after rollout try { diff --git a/packages/ethereum-contracts/ops-scripts/validate-deployment.ts b/packages/ethereum-contracts/ops-scripts/validate-deployment.ts index 0495f223b7..907c083c27 100644 --- a/packages/ethereum-contracts/ops-scripts/validate-deployment.ts +++ b/packages/ethereum-contracts/ops-scripts/validate-deployment.ts @@ -7,8 +7,6 @@ const gdaAgreementType = ethers.utils.solidityKeccak256(["string"], ["org.superf const superTokenFactoryUuid = ethers.utils.solidityKeccak256(["string"], ["org.superfluid-finance.contracts.SuperTokenFactory.implementation"]); const superTokenUUID = ethers.utils.solidityKeccak256(["string"], ["org.superfluid-finance.contracts.SuperToken.implementation"]); -const constantOutflowNftUuid = ethers.utils.solidityKeccak256(["string"], ["org.superfluid-finance.contracts.ConstantOutflowNFT.implementation"]); -const constantInflowNftUuid = ethers.utils.solidityKeccak256(["string"], ["org.superfluid-finance.contracts.ConstantInflowNFT.implementation"]); const superfluidPoolUUID = ethers.utils.solidityKeccak256(["string"], ["org.superfluid-finance.contracts.SuperfluidPool.implementation"]); function assertLog(condition: boolean, message: string) { @@ -45,7 +43,7 @@ async function main() { console.log("SuperTokenFactory Logic Address:", superTokenFactoryLogicAddress, "\n"); assertLog(superTokenFactoryLogicAddress === await superTokenFactoryContract.getCodeAddress(), "Canonical Factory Logic Address matches Factory Proxy Logic Address"); - + const superTokenLogicAddress = await superTokenFactoryContract.getSuperTokenLogic(); console.log("SuperToken Logic Address:", superTokenLogicAddress, "\n"); @@ -53,37 +51,6 @@ async function main() { const superTokenLiveUUID = await superTokenLogicContract.proxiableUUID(); assertLog(superTokenUUID === superTokenLiveUUID, "SuperTokenFactory Deployed UUID matches live UUID"); - // validate flow NFTs - const constantOutflowNFTCanonicalLogic = await superTokenFactoryContract.CONSTANT_OUTFLOW_NFT_LOGIC(); - console.log("ConstantOutflowNFT Canonical Logic (on Factory):", constantOutflowNFTCanonicalLogic); - const constantInflowNFTCanonicalLogic = await superTokenFactoryContract.CONSTANT_INFLOW_NFT_LOGIC(); - console.log("ConstantInflowNFT Canonical Logic (on Factory):", constantInflowNFTCanonicalLogic, "\n"); - - const constantOutflowNFProxy = await superTokenLogicContract.CONSTANT_OUTFLOW_NFT(); - const cofNFTContract = await ethers.getContractAt("ConstantOutflowNFT", constantOutflowNFProxy); - const cofNFTContractLiveUUID = await cofNFTContract.proxiableUUID(); - assertLog(constantOutflowNftUuid === cofNFTContractLiveUUID, "ConstantOutflowNFT Deployed UUID matches live UUID"); - console.log("ConstantOutflowNFT:", constantOutflowNFProxy); - - const outflowProxyLogic = await cofNFTContract.getCodeAddress(); - console.log("ConstantOutflow NFT Logic (on Proxy):", outflowProxyLogic, "\n"); - assertLog(await cofNFTContract.baseURI() === "https://nft.superfluid.finance/cfa/v2/getmeta", "ConstantOutflowNFT baseURI is equal to https://nft.superfluid.finance/cfa/v2/getmeta"); - - const constantInflowNFProxy = await superTokenLogicContract.CONSTANT_INFLOW_NFT(); - const cifNFTContract = await ethers.getContractAt("ConstantInflowNFT", constantInflowNFProxy); - const cifNFTContractLiveUUID = await cifNFTContract.proxiableUUID(); - assertLog(constantInflowNftUuid === cifNFTContractLiveUUID, "ConstantInflowNFT Deployed UUID matches live UUID"); - console.log("ConstantInflowNFT:", constantInflowNFProxy); - assertLog(await cifNFTContract.baseURI() === "https://nft.superfluid.finance/cfa/v2/getmeta", "ConstantInflowNFT baseURI is equal to https://nft.superfluid.finance/cfa/v2/getmeta"); - - const inflowProxyLogic = await cifNFTContract.getCodeAddress(); - console.log("ConstantInflow NFT Logic (on Proxy):", inflowProxyLogic); - - assertLog(await cofNFTContract.proxiableUUID() !== await cifNFTContract.proxiableUUID(), "NFT proxies have different implementation."); - - assertLog(outflowProxyLogic === constantOutflowNFTCanonicalLogic, "Outflow proxy logic is equal to canonical outflow logic"); - assertLog(inflowProxyLogic === constantInflowNFTCanonicalLogic, "Inflow proxy logic is equal to canonical inflow logic"); - // validate pool NFTs const poolAdminNFTCanonicalLogic = await superTokenFactoryContract.POOL_ADMIN_NFT_LOGIC(); console.log("PoolAdminNFT Canonical Logic (on Factory):", poolAdminNFTCanonicalLogic); @@ -101,7 +68,7 @@ async function main() { console.log("PoolMemberNFT:", poolMemberNFProxy); const pmNFTContract = await ethers.getContractAt("PoolMemberNFT", poolMemberNFProxy); assertLog(await pmNFTContract.baseURI() === "https://nft.superfluid.finance/pool/v2/getmeta", "PoolMemberNFT baseURI is equal to https://nft.superfluid.finance/pool/v2/getmeta"); - + const poolMemberProxyLogic = await pmNFTContract.getCodeAddress(); console.log("ConstantInflow NFT Logic (on Proxy):", poolMemberProxyLogic); @@ -129,11 +96,11 @@ async function main() { // GDA specific validation const superfluidPoolBeaconAddress = await gdaContract.superfluidPoolBeacon(); assertLog(superfluidPoolBeaconAddress !== ethers.constants.AddressZero, "SuperfluidPoolBeaconAddress is not zero address") - + const beaconContract = await ethers.getContractAt("IBeacon", superfluidPoolBeaconAddress); const sfPoolBeaconImplementationAddress = await beaconContract.implementation(); assertLog(sfPoolBeaconImplementationAddress !== ethers.constants.AddressZero, "SFPool beacon implementation is not zero address"); - + const superfluidPoolContract = await ethers.getContractAt("SuperfluidPool", sfPoolBeaconImplementationAddress); const sfPoolLiveUUID = await superfluidPoolContract.proxiableUUID(); diff --git a/packages/ethereum-contracts/package.json b/packages/ethereum-contracts/package.json index 6f38908b9d..f9f8d6ee64 100644 --- a/packages/ethereum-contracts/package.json +++ b/packages/ethereum-contracts/package.json @@ -1,6 +1,6 @@ { "name": "@superfluid-finance/ethereum-contracts", - "version": "1.10.0", + "version": "1.11.0", "description": " Ethereum contracts implementation for the Superfluid Protocol", "homepage": "https://github.com/superfluid-finance/protocol-monorepo/tree/dev/packages/ethereum-contracts#readme", "repository": { @@ -93,7 +93,7 @@ "@safe-global/safe-service-client": "^2.0.3", "@safe-global/safe-web3-lib": "^1.9.4", "@superfluid-finance/js-sdk": "^0.6.3", - "@superfluid-finance/metadata": "^1.3.1", + "@superfluid-finance/metadata": "^1.4.0", "async": "^3.2.5", "csv-writer": "^1.6.0", "ethers": "^5.7.2", diff --git a/packages/ethereum-contracts/tasks/bundled-abi-contracts-list.json b/packages/ethereum-contracts/tasks/bundled-abi-contracts-list.json index d99757e764..dcb99646a4 100644 --- a/packages/ethereum-contracts/tasks/bundled-abi-contracts-list.json +++ b/packages/ethereum-contracts/tasks/bundled-abi-contracts-list.json @@ -10,9 +10,6 @@ "ISuperToken", "SuperToken", "ISuperTokenFactory", "SuperTokenFactory", "ISETH", "SETHProxy", - "IFlowNFTBase", "FlowNFTBase", - "IConstantInflowNFT", "ConstantInflowNFT", - "IConstantOutflowNFT", "ConstantOutflowNFT", "IPoolAdminNFT", "PoolAdminNFT", "IPoolMemberNFT", "PoolMemberNFT", "ISuperAgreement", diff --git a/packages/ethereum-contracts/tasks/etherscan-verify-framework.sh b/packages/ethereum-contracts/tasks/etherscan-verify-framework.sh index 6631786d4d..63bfcf9cdb 100755 --- a/packages/ethereum-contracts/tasks/etherscan-verify-framework.sh +++ b/packages/ethereum-contracts/tasks/etherscan-verify-framework.sh @@ -102,22 +102,6 @@ if [ -n "$SUPER_TOKEN_FACTORY_PROXY" ]; then try_verify SuperTokenFactory@"${SUPER_TOKEN_FACTORY_PROXY}" --custom-proxy UUPSProxy fi -if [ -n "$CONSTANT_OUTFLOW_NFT_LOGIC" ]; then - try_verify ConstantOutflowNFT@"${CONSTANT_OUTFLOW_NFT_LOGIC}" -fi - -if [ -n "$CONSTANT_INFLOW_NFT_LOGIC" ]; then - try_verify ConstantInflowNFT@"${CONSTANT_INFLOW_NFT_LOGIC}" -fi - -if [ -n "$CONSTANT_OUTFLOW_NFT_PROXY" ]; then - try_verify ConstantOutflowNFT@"${CONSTANT_OUTFLOW_NFT_PROXY}" --custom-proxy UUPSProxy -fi - -if [ -n "$CONSTANT_INFLOW_NFT_PROXY" ]; then - try_verify ConstantInflowNFT@"${CONSTANT_INFLOW_NFT_PROXY}" --custom-proxy UUPSProxy -fi - if [ -n "$POOL_ADMIN_NFT_PROXY" ]; then try_verify PoolAdminNFT@"${POOL_ADMIN_NFT_PROXY}" --custom-proxy UUPSProxy fi diff --git a/packages/ethereum-contracts/test/TestEnvironment.ts b/packages/ethereum-contracts/test/TestEnvironment.ts index 1985ef56c3..2474e042eb 100644 --- a/packages/ethereum-contracts/test/TestEnvironment.ts +++ b/packages/ethereum-contracts/test/TestEnvironment.ts @@ -7,20 +7,12 @@ import _ from "lodash"; import Web3 from "web3"; import { - ConstantInflowNFT, - ConstantInflowNFT__factory, - ConstantOutflowNFT, - ConstantOutflowNFT__factory, ISuperToken, ISuperToken__factory, - PoolAdminNFT, PoolAdminNFT__factory, - PoolMemberNFT, PoolMemberNFT__factory, SuperTokenMock, TestToken, - UUPSProxiableMock__factory, - UUPSProxy, } from "../typechain-types"; import {VerifyOptions} from "./contracts/agreements/Agreement.types"; @@ -585,15 +577,6 @@ export default class TestEnvironment { } deployNFTContracts = async () => { - let constantOutflowNFT; - let constantInflowNFT; - let cofNFTLogicAddress; - let cifNFTLogicAddress; - let paNFTLogicAddress; - let poolAdminNFT; - let pmNFTLogicAddress; - let poolMemberNFT; - const superTokenFactoryLogicAddress = await this.contracts.superfluid.getSuperTokenFactoryLogic(); const superTokenFactory = await ethers.getContractAt( @@ -606,125 +589,23 @@ export default class TestEnvironment { "SuperToken", superTokenLogicAddress ); - const constantOutflowNFTProxyAddress = - await superTokenLogic.CONSTANT_OUTFLOW_NFT(); - const constantInflowNFTProxyAddress = - await superTokenLogic.CONSTANT_INFLOW_NFT(); const poolAdminNFTProxyAddress = await superTokenLogic.POOL_ADMIN_NFT(); const poolMemberNFTProxyAddress = await superTokenLogic.POOL_MEMBER_NFT(); - if ( - constantOutflowNFTProxyAddress === ethers.constants.AddressZero || - constantInflowNFTProxyAddress === ethers.constants.AddressZero || - poolAdminNFTProxyAddress === ethers.constants.AddressZero || - poolMemberNFTProxyAddress === ethers.constants.AddressZero - ) { - const cofProxy = await this.deployContract("UUPSProxy"); - const cifProxy = await this.deployContract("UUPSProxy"); - - const paProxy = await this.deployContract("UUPSProxy"); - const pmProxy = await this.deployContract("UUPSProxy"); - - const constantOutflowNFTLogic = - await this.deployContract( - "ConstantOutflowNFT", - this.contracts.superfluid.address, - cifProxy.address - ); - cofNFTLogicAddress = constantOutflowNFTLogic.address; - - const constantInflowNFTLogic = - await this.deployContract( - "ConstantInflowNFT", - this.contracts.superfluid.address, - cofProxy.address - ); - cifNFTLogicAddress = constantInflowNFTLogic.address; - - const poolAdminNFTLogic = await this.deployContract( - "PoolAdminNFT", - this.contracts.superfluid.address - ); - paNFTLogicAddress = poolAdminNFTLogic.address; - - const poolMemberNFTLogic = await this.deployContract( - "PoolMemberNFT", - this.contracts.superfluid.address - ); - pmNFTLogicAddress = poolMemberNFTLogic.address; - - const signer = await ethers.getSigner(this.aliases.admin); - const proxiableCofLogic = UUPSProxiableMock__factory.connect( - constantOutflowNFTLogic.address, - signer - ); - const proxiableCifLogic = UUPSProxiableMock__factory.connect( - constantInflowNFTLogic.address, - signer - ); - const proxiablePaLogic = UUPSProxiableMock__factory.connect( - poolAdminNFTLogic.address, - signer - ); - const proxiablePmLogic = UUPSProxiableMock__factory.connect( - poolMemberNFTLogic.address, - signer - ); - await proxiableCofLogic.castrate(); - await proxiableCifLogic.castrate(); - await proxiablePaLogic.castrate(); - await proxiablePmLogic.castrate(); - - await cofProxy.initializeProxy(constantOutflowNFTLogic.address); - await cifProxy.initializeProxy(constantInflowNFTLogic.address); - await paProxy.initializeProxy(poolAdminNFTLogic.address); - await pmProxy.initializeProxy(poolMemberNFTLogic.address); - constantOutflowNFT = ConstantOutflowNFT__factory.connect( - cofProxy.address, - signer - ); - constantInflowNFT = ConstantInflowNFT__factory.connect( - cifProxy.address, - signer - ); - poolAdminNFT = PoolAdminNFT__factory.connect( - paProxy.address, - signer - ); - poolMemberNFT = PoolMemberNFT__factory.connect( - pmProxy.address, - signer - ); - } else { - constantOutflowNFT = ConstantOutflowNFT__factory.connect( - constantOutflowNFTProxyAddress, - await ethers.getSigner(this.aliases.admin) - ); - constantInflowNFT = ConstantInflowNFT__factory.connect( - constantInflowNFTProxyAddress, - await ethers.getSigner(this.aliases.admin) - ); - poolAdminNFT = PoolAdminNFT__factory.connect( - poolAdminNFTProxyAddress, - await ethers.getSigner(this.aliases.admin) - ); - poolMemberNFT = PoolMemberNFT__factory.connect( - poolMemberNFTProxyAddress, - await ethers.getSigner(this.aliases.admin) - ); - cofNFTLogicAddress = await constantOutflowNFT.getCodeAddress(); - cifNFTLogicAddress = await constantInflowNFT.getCodeAddress(); - paNFTLogicAddress = await poolAdminNFT.getCodeAddress(); - pmNFTLogicAddress = await poolMemberNFT.getCodeAddress(); - } + const poolAdminNFT = PoolAdminNFT__factory.connect( + poolAdminNFTProxyAddress, + await ethers.getSigner(this.aliases.admin) + ); + const poolMemberNFT = PoolMemberNFT__factory.connect( + poolMemberNFTProxyAddress, + await ethers.getSigner(this.aliases.admin) + ); + const paNFTLogicAddress = await poolAdminNFT.getCodeAddress(); + const pmNFTLogicAddress = await poolMemberNFT.getCodeAddress(); return { - constantOutflowNFTProxy: constantOutflowNFT, - constantInflowNFTProxy: constantInflowNFT, - cofNFTLogicAddress, - cifNFTLogicAddress, poolAdminNFTProxy: poolAdminNFT, poolMemberNFTProxy: poolMemberNFT, paNFTLogicAddress, diff --git a/packages/ethereum-contracts/test/contracts/apps/SuperTokenV1Library.CFA.test.ts b/packages/ethereum-contracts/test/contracts/apps/SuperTokenV1Library.CFA.test.ts index 2d34e6a453..4022e3c1bd 100644 --- a/packages/ethereum-contracts/test/contracts/apps/SuperTokenV1Library.CFA.test.ts +++ b/packages/ethereum-contracts/test/contracts/apps/SuperTokenV1Library.CFA.test.ts @@ -41,18 +41,14 @@ const callbackFunctionIndex = { export const deploySuperTokenAndNFTContractsAndInitialize = async ( t: TestEnvironment ) => { - const { - constantOutflowNFTProxy, - constantInflowNFTProxy, - poolAdminNFTProxy, - poolMemberNFTProxy, - } = await t.deployNFTContracts(); + const {poolAdminNFTProxy, poolMemberNFTProxy} = + await t.deployNFTContracts(); const superToken = await t.deployContract( "SuperTokenMock", t.contracts.superfluid.address, "69", - constantOutflowNFTProxy.address, - constantInflowNFTProxy.address, + t.constants.ZERO_ADDRESS, + t.constants.ZERO_ADDRESS, poolAdminNFTProxy.address, poolMemberNFTProxy.address ); diff --git a/packages/ethereum-contracts/test/contracts/superfluid/SuperToken.NonStandard.test.ts b/packages/ethereum-contracts/test/contracts/superfluid/SuperToken.NonStandard.test.ts index bbbeb74be4..1c7ce0b917 100644 --- a/packages/ethereum-contracts/test/contracts/superfluid/SuperToken.NonStandard.test.ts +++ b/packages/ethereum-contracts/test/contracts/superfluid/SuperToken.NonStandard.test.ts @@ -67,18 +67,14 @@ describe("SuperToken's Non Standard Functions", function () { describe("#1 upgradability", () => { it("#1.1 storage layout", async () => { - const { - constantOutflowNFTProxy, - constantInflowNFTProxy, - poolAdminNFTProxy, - poolMemberNFTProxy, - } = await t.deployNFTContracts(); + const {poolAdminNFTProxy, poolMemberNFTProxy} = + await t.deployNFTContracts(); const superTokenLogic = await t.deployContract( "SuperTokenStorageLayoutTester", superfluid.address, - constantOutflowNFTProxy.address, - constantInflowNFTProxy.address, + t.constants.ZERO_ADDRESS, + t.constants.ZERO_ADDRESS, poolAdminNFTProxy.address, poolMemberNFTProxy.address ); @@ -710,18 +706,14 @@ describe("SuperToken's Non Standard Functions", function () { }); it("#3.1 Custom token storage should not overlap with super token", async () => { - const { - constantOutflowNFTProxy, - constantInflowNFTProxy, - poolAdminNFTProxy, - poolMemberNFTProxy, - } = await t.deployNFTContracts(); + const {poolAdminNFTProxy, poolMemberNFTProxy} = + await t.deployNFTContracts(); const superTokenLogic = await t.deployContract( "SuperTokenStorageLayoutTester", superfluid.address, - constantOutflowNFTProxy.address, - constantInflowNFTProxy.address, + t.constants.ZERO_ADDRESS, + t.constants.ZERO_ADDRESS, poolAdminNFTProxy.address, poolMemberNFTProxy.address ); diff --git a/packages/ethereum-contracts/test/contracts/superfluid/SuperTokenFactory.test.ts b/packages/ethereum-contracts/test/contracts/superfluid/SuperTokenFactory.test.ts index 0e19b464c4..9e708aee40 100644 --- a/packages/ethereum-contracts/test/contracts/superfluid/SuperTokenFactory.test.ts +++ b/packages/ethereum-contracts/test/contracts/superfluid/SuperTokenFactory.test.ts @@ -66,10 +66,6 @@ describe("SuperTokenFactory Contract", function () { describe("#1 upgradability", () => { it("#1.1 storage layout", async () => { const { - constantOutflowNFTProxy, - constantInflowNFTProxy, - cofNFTLogicAddress, - cifNFTLogicAddress, poolAdminNFTProxy, poolMemberNFTProxy, paNFTLogicAddress, @@ -79,8 +75,8 @@ describe("SuperTokenFactory Contract", function () { "SuperTokenMock", superfluid.address, "0", - constantOutflowNFTProxy.address, - constantInflowNFTProxy.address, + t.constants.ZERO_ADDRESS, + t.constants.ZERO_ADDRESS, poolAdminNFTProxy.address, poolMemberNFTProxy.address ); @@ -89,8 +85,8 @@ describe("SuperTokenFactory Contract", function () { "SuperTokenFactoryStorageLayoutTester", superfluid.address, superTokenLogic.address, - cofNFTLogicAddress, - cifNFTLogicAddress, + t.constants.ZERO_ADDRESS, + t.constants.ZERO_ADDRESS, paNFTLogicAddress, pmNFTLogicAddress ); @@ -153,10 +149,6 @@ describe("SuperTokenFactory Contract", function () { context("#2.a Mock factory", () => { async function updateSuperTokenFactory() { const { - constantOutflowNFTProxy, - constantInflowNFTProxy, - cofNFTLogicAddress, - cifNFTLogicAddress, poolAdminNFTProxy, poolMemberNFTProxy, paNFTLogicAddress, @@ -166,8 +158,8 @@ describe("SuperTokenFactory Contract", function () { "SuperTokenMock", superfluid.address, 42, - constantOutflowNFTProxy.address, - constantInflowNFTProxy.address, + t.constants.ZERO_ADDRESS, + t.constants.ZERO_ADDRESS, poolAdminNFTProxy.address, poolMemberNFTProxy.address ); @@ -176,8 +168,8 @@ describe("SuperTokenFactory Contract", function () { "SuperTokenFactoryMock42", superfluid.address, superTokenLogic.address, - cofNFTLogicAddress, - cifNFTLogicAddress, + t.constants.ZERO_ADDRESS, + t.constants.ZERO_ADDRESS, paNFTLogicAddress, pmNFTLogicAddress ); @@ -287,18 +279,14 @@ describe("SuperTokenFactory Contract", function () { await updateSuperTokenFactory(); assert.equal((await superToken1.waterMark()).toString(), "0"); - const { - constantOutflowNFTProxy, - constantInflowNFTProxy, - poolAdminNFTProxy, - poolMemberNFTProxy, - } = await t.deployNFTContracts(); + const {poolAdminNFTProxy, poolMemberNFTProxy} = + await t.deployNFTContracts(); const superTokenLogic = await t.deployContract( "SuperTokenMock", superfluid.address, 69, - constantOutflowNFTProxy.address, - constantInflowNFTProxy.address, + t.constants.ZERO_ADDRESS, + t.constants.ZERO_ADDRESS, poolAdminNFTProxy.address, poolMemberNFTProxy.address ); @@ -317,10 +305,6 @@ describe("SuperTokenFactory Contract", function () { context("#2.b Production Factory", () => { it("#2.b.1 use production factory to create different super tokens", async () => { const { - constantOutflowNFTProxy, - constantInflowNFTProxy, - cofNFTLogicAddress, - cifNFTLogicAddress, poolAdminNFTProxy, poolMemberNFTProxy, paNFTLogicAddress, @@ -329,8 +313,8 @@ describe("SuperTokenFactory Contract", function () { const superTokenLogic = await t.deployContract( "SuperToken", superfluid.address, - constantOutflowNFTProxy.address, - constantInflowNFTProxy.address, + t.constants.ZERO_ADDRESS, + t.constants.ZERO_ADDRESS, poolAdminNFTProxy.address, poolMemberNFTProxy.address ); @@ -339,8 +323,8 @@ describe("SuperTokenFactory Contract", function () { "SuperTokenFactoryMock42", superfluid.address, superTokenLogic.address, - cofNFTLogicAddress, - cifNFTLogicAddress, + t.constants.ZERO_ADDRESS, + t.constants.ZERO_ADDRESS, paNFTLogicAddress, pmNFTLogicAddress ); diff --git a/packages/ethereum-contracts/test/contracts/superfluid/Superfluid.test.ts b/packages/ethereum-contracts/test/contracts/superfluid/Superfluid.test.ts index 2573dd827e..7556c16e02 100644 --- a/packages/ethereum-contracts/test/contracts/superfluid/Superfluid.test.ts +++ b/packages/ethereum-contracts/test/contracts/superfluid/Superfluid.test.ts @@ -407,10 +407,6 @@ describe("Superfluid Host Contract", function () { it("#3.2 update super token factory", async () => { const factory = await superfluid.getSuperTokenFactory(); const { - constantOutflowNFTProxy, - constantInflowNFTProxy, - cofNFTLogicAddress, - cifNFTLogicAddress, poolAdminNFTProxy, poolMemberNFTProxy, paNFTLogicAddress, @@ -419,8 +415,8 @@ describe("Superfluid Host Contract", function () { const superTokenLogic = await t.deployContract( "SuperToken", superfluid.address, - constantOutflowNFTProxy.address, - constantInflowNFTProxy.address, + t.constants.ZERO_ADDRESS, + t.constants.ZERO_ADDRESS, poolAdminNFTProxy.address, poolMemberNFTProxy.address ); @@ -429,8 +425,8 @@ describe("Superfluid Host Contract", function () { const factory2Logic = await factory2LogicFactory.deploy( superfluid.address, superTokenLogic.address, - cofNFTLogicAddress, - cifNFTLogicAddress, + t.constants.ZERO_ADDRESS, + t.constants.ZERO_ADDRESS, paNFTLogicAddress, pmNFTLogicAddress ); @@ -456,10 +452,6 @@ describe("Superfluid Host Contract", function () { it("#3.3 update super token factory double check if new code is called", async () => { const factory = await superfluid.getSuperTokenFactory(); const { - constantOutflowNFTProxy, - constantInflowNFTProxy, - cofNFTLogicAddress, - cifNFTLogicAddress, poolAdminNFTProxy, poolMemberNFTProxy, paNFTLogicAddress, @@ -468,8 +460,8 @@ describe("Superfluid Host Contract", function () { const superTokenLogic = await t.deployContract( "SuperToken", superfluid.address, - constantOutflowNFTProxy.address, - constantInflowNFTProxy.address, + t.constants.ZERO_ADDRESS, + t.constants.ZERO_ADDRESS, poolAdminNFTProxy.address, poolMemberNFTProxy.address ); @@ -479,8 +471,8 @@ describe("Superfluid Host Contract", function () { const factory2Logic = await factory2LogicFactory.deploy( superfluid.address, superTokenLogic.address, - cofNFTLogicAddress, - cifNFTLogicAddress, + t.constants.ZERO_ADDRESS, + t.constants.ZERO_ADDRESS, paNFTLogicAddress, pmNFTLogicAddress ); @@ -2659,10 +2651,6 @@ describe("Superfluid Host Contract", function () { await superfluid.getSuperTokenFactoryLogic() ); const { - constantOutflowNFTProxy, - constantInflowNFTProxy, - cofNFTLogicAddress, - cifNFTLogicAddress, poolAdminNFTProxy, poolMemberNFTProxy, paNFTLogicAddress, @@ -2671,8 +2659,8 @@ describe("Superfluid Host Contract", function () { const superTokenLogic = await t.deployContract( "SuperToken", superfluid.address, - constantOutflowNFTProxy.address, - constantInflowNFTProxy.address, + t.constants.ZERO_ADDRESS, + t.constants.ZERO_ADDRESS, poolAdminNFTProxy.address, poolMemberNFTProxy.address ); @@ -2680,8 +2668,8 @@ describe("Superfluid Host Contract", function () { "SuperTokenFactory", superfluid.address, superTokenLogic.address, - cofNFTLogicAddress, - cifNFTLogicAddress, + t.constants.ZERO_ADDRESS, + t.constants.ZERO_ADDRESS, paNFTLogicAddress, pmNFTLogicAddress ); diff --git a/packages/ethereum-contracts/test/foundry/FoundrySuperfluidTester.sol b/packages/ethereum-contracts/test/foundry/FoundrySuperfluidTester.sol index b626f85a62..7412fe2234 100644 --- a/packages/ethereum-contracts/test/foundry/FoundrySuperfluidTester.sol +++ b/packages/ethereum-contracts/test/foundry/FoundrySuperfluidTester.sol @@ -9,7 +9,6 @@ import { ERC1820RegistryCompiled } from "../../contracts/libs/ERC1820RegistryCom import { SuperfluidFrameworkDeployer } from "../../contracts/utils/SuperfluidFrameworkDeployer.sol"; import { Superfluid } from "../../contracts/superfluid/Superfluid.sol"; import { ISuperfluidPool, SuperfluidPool } from "../../contracts/agreements/gdav1/SuperfluidPool.sol"; -import { IFlowNFTBase } from "../../contracts/interfaces/superfluid/IFlowNFTBase.sol"; import { IGeneralDistributionAgreementV1, PoolConfig @@ -17,14 +16,13 @@ import { import { IPoolNFTBase } from "../../contracts/interfaces/agreements/gdav1/IPoolNFTBase.sol"; import { IPoolAdminNFT } from "../../contracts/interfaces/agreements/gdav1/IPoolAdminNFT.sol"; import { IPoolMemberNFT } from "../../contracts/interfaces/agreements/gdav1/IPoolMemberNFT.sol"; -import { IConstantOutflowNFT } from "../../contracts/interfaces/superfluid/IConstantOutflowNFT.sol"; -import { IConstantInflowNFT } from "../../contracts/interfaces/superfluid/IConstantInflowNFT.sol"; import { ISuperfluidToken } from "../../contracts/interfaces/superfluid/ISuperfluidToken.sol"; import { ISETH } from "../../contracts/interfaces/tokens/ISETH.sol"; import { UUPSProxy } from "../../contracts/upgradability/UUPSProxy.sol"; import { ConstantFlowAgreementV1 } from "../../contracts/agreements/ConstantFlowAgreementV1.sol"; import { SuperTokenV1Library } from "../../contracts/apps/SuperTokenV1Library.sol"; -import { IERC20, ISuperToken, SuperToken } from "../../contracts/superfluid/SuperToken.sol"; +import { IERC20, ISuperToken, SuperToken, IConstantOutflowNFT, IConstantInflowNFT } + from "../../contracts/superfluid/SuperToken.sol"; import { SuperfluidLoader } from "../../contracts/utils/SuperfluidLoader.sol"; import { TestResolver } from "../../contracts/utils/TestResolver.sol"; import { TestToken } from "../../contracts/utils/TestToken.sol"; @@ -180,8 +178,6 @@ contract FoundrySuperfluidTester is Test { // - Host // - CFA // - IDA - // - ConstantOutflowNFT logic - // - ConstantInflowNFT logic // - SuperToken logic // - SuperTokenFactory // - Resolver @@ -692,8 +688,8 @@ contract FoundrySuperfluidTester is Test { ) internal returns (SuperToken localSuperToken) { localSuperToken = new SuperToken( sf.host, - previousSuperToken.CONSTANT_OUTFLOW_NFT(), - previousSuperToken.CONSTANT_INFLOW_NFT(), + IConstantOutflowNFT(address(0)), + IConstantInflowNFT(address(0)), previousSuperToken.POOL_ADMIN_NFT(), previousSuperToken.POOL_MEMBER_NFT() ); @@ -742,8 +738,6 @@ contract FoundrySuperfluidTester is Test { _assertAccountFlowInfo(receiver, flowRateDelta, receiverFlowInfoBefore, false); } - _assertFlowNftState(superToken_, sender, receiver, flowRate); - // Assert RTB for all users _assertRealTimeBalances(superToken_); _assertGlobalInvariants(); @@ -1946,10 +1940,6 @@ contract FoundrySuperfluidTester is Test { ); } - // Assert Outflow NFT is minted to distributor - // Assert Inflow NFT is minted to pool - _assertFlowNftState(superToken_, from, address(pool_), requestedFlowRate); - { if (members.length == 0) return; uint128 poolTotalUnitsAfter = pool_.getTotalUnits(); @@ -2295,35 +2285,4 @@ contract FoundrySuperfluidTester is Test { poolMemberNFT.ownerOf(tokenId); } } - - function _assertFlowNftState( - ISuperfluidToken _superToken, - address _senderOrDistributor, - address _receiverOrPool, - int96 _newFlowRate - ) internal { - IConstantOutflowNFT constantOutflowNFT = SuperToken(address(_superToken)).CONSTANT_OUTFLOW_NFT(); - IConstantInflowNFT constantInflowNFT = SuperToken(address(_superToken)).CONSTANT_INFLOW_NFT(); - uint256 tokenId = constantOutflowNFT.getTokenId(address(_superToken), address(_senderOrDistributor), address(_receiverOrPool)); - if (_newFlowRate > 0) { - // positive flowrate: NFT exists and is owned by sender/distributor and receiver/pool - assertEq( - constantOutflowNFT.ownerOf(tokenId), - _senderOrDistributor, - "_assertFlowNftState: sender/distributor doesn't own outflow NFT" - ); - assertEq( - constantInflowNFT.ownerOf(tokenId), - address(_receiverOrPool), - "_assertFlowNftState: receiver/pool doesn't own inflow NFT" - ); - } else { - // zero flowrate: NFT doesn't exist (never minted or already burned) - vm.expectRevert(IFlowNFTBase.CFA_NFT_INVALID_TOKEN_ID.selector); - constantOutflowNFT.ownerOf(tokenId); - - vm.expectRevert(IFlowNFTBase.CFA_NFT_INVALID_TOKEN_ID.selector); - constantInflowNFT.ownerOf(tokenId); - } - } } diff --git a/packages/ethereum-contracts/test/foundry/SuperfluidFrameworkDeployer.t.sol b/packages/ethereum-contracts/test/foundry/SuperfluidFrameworkDeployer.t.sol index c8b62eeb5a..250b0367f8 100644 --- a/packages/ethereum-contracts/test/foundry/SuperfluidFrameworkDeployer.t.sol +++ b/packages/ethereum-contracts/test/foundry/SuperfluidFrameworkDeployer.t.sol @@ -16,8 +16,6 @@ contract SuperfluidFrameworkDeployerTest is FoundrySuperfluidTester { assertTrue(address(sf.gda) != address(0), "SFDeployer: gda not deployed"); assertTrue(address(sf.superTokenFactory) != address(0), "SFDeployer: superTokenFactory not deployed"); assertTrue(address(sf.superTokenLogic) != address(0), "SFDeployer: superTokenLogic not deployed"); - assertTrue(address(sf.constantOutflowNFT) != address(0), "SFDeployer: constantOutflowNFT not deployed"); - assertTrue(address(sf.constantInflowNFT) != address(0), "SFDeployer: constantInflowNFT not deployed"); assertTrue(address(sf.resolver) != address(0), "SFDeployer: resolver not deployed"); assertTrue(address(sf.superfluidLoader) != address(0), "SFDeployer: superfluidLoader not deployed"); assertTrue(address(sf.cfaV1Forwarder) != address(0), "SFDeployer: cfaV1Forwarder not deployed"); diff --git a/packages/ethereum-contracts/test/foundry/agreements/ConstantFlowAgreementV1.t.sol b/packages/ethereum-contracts/test/foundry/agreements/ConstantFlowAgreementV1.t.sol index 4221a66583..556f96955f 100644 --- a/packages/ethereum-contracts/test/foundry/agreements/ConstantFlowAgreementV1.t.sol +++ b/packages/ethereum-contracts/test/foundry/agreements/ConstantFlowAgreementV1.t.sol @@ -26,30 +26,6 @@ contract ConstantFlowAgreementV1IntegrationTest is FoundrySuperfluidTester { _warpAndAssertAll(superToken); } - // there should be no gas limit which causes the NFT hook to fail with the tx succeeding - function testNFTHookOutOfGasRevertsWholeTx(uint256 gasLimit) public { - gasLimit = bound(gasLimit, 350000, 550000); - - console.log("trying createFlow..."); - int96 fr = 1; - try this.__external_createFlow{gas: gasLimit}(superToken, alice, bob, fr) { - // if the tx does not revert, the NFT hook isn't allowed to revert with outofgas, - // which we can check by verifying the FlowNFT state - _assertFlowNftState(superToken, alice, bob, fr); - } catch { } // revert of the tx is ok - - console.log("trying updateFlow..."); - fr = 2; - try this.__external_updateFlow{gas: gasLimit}(superToken, alice, bob, fr) { - _assertFlowNftState(superToken, alice, bob, fr); - } catch { } - - console.log("trying deleteFlow..."); - try this.__external_deleteFlow{gas: gasLimit}(superToken, alice, bob) { - _assertFlowNftState(superToken, alice, bob, 0); - } catch { } - } - // helper functions wrapping internal calls into external calls (needed for try/catch) function __external_createFlow(ISuperToken superToken, address sender, address receiver, int96 fr) external { diff --git a/packages/ethereum-contracts/test/foundry/agreements/gdav1/GeneralDistributionAgreement.t.sol b/packages/ethereum-contracts/test/foundry/agreements/gdav1/GeneralDistributionAgreement.t.sol index c7e96329bb..122414dd95 100644 --- a/packages/ethereum-contracts/test/foundry/agreements/gdav1/GeneralDistributionAgreement.t.sol +++ b/packages/ethereum-contracts/test/foundry/agreements/gdav1/GeneralDistributionAgreement.t.sol @@ -17,9 +17,6 @@ import { ISuperfluidPool, SuperfluidPool } from "../../../../contracts/agreement import { IPoolNFTBase } from "../../../../contracts/interfaces/agreements/gdav1/IPoolNFTBase.sol"; import { IPoolAdminNFT } from "../../../../contracts/interfaces/agreements/gdav1/IPoolAdminNFT.sol"; import { IPoolMemberNFT } from "../../../../contracts/interfaces/agreements/gdav1/IPoolMemberNFT.sol"; -import { IFlowNFTBase } from "../../../../contracts/interfaces/superfluid/IFlowNFTBase.sol"; -import { IConstantOutflowNFT } from "../../../../contracts/interfaces/superfluid/IConstantOutflowNFT.sol"; -import { IConstantInflowNFT } from "../../../../contracts/interfaces/superfluid/IConstantInflowNFT.sol"; import { SuperfluidPoolStorageLayoutMock } from "./SuperfluidPoolUpgradabilityMock.t.sol"; /// @title GeneralDistributionAgreementV1 Integration Tests diff --git a/packages/ethereum-contracts/test/foundry/superfluid/CFAv1NFTMock.t.sol b/packages/ethereum-contracts/test/foundry/superfluid/CFAv1NFTMock.t.sol deleted file mode 100644 index 439d6e881c..0000000000 --- a/packages/ethereum-contracts/test/foundry/superfluid/CFAv1NFTMock.t.sol +++ /dev/null @@ -1,124 +0,0 @@ -// SPDX-License-Identifier: AGPLv3 -// solhint-disable reason-string -// solhint-disable not-rely-on-time -pragma solidity ^0.8.23; - -import { Strings } from "@openzeppelin/contracts/utils/Strings.sol"; - -import { - IConstantFlowAgreementV1, - IGeneralDistributionAgreementV1, - ISuperfluid, - IConstantInflowNFT, - IConstantOutflowNFT -} from "../../../contracts/interfaces/superfluid/ISuperfluid.sol"; -import { ConstantOutflowNFT } from "../../../contracts/superfluid/ConstantOutflowNFT.sol"; -import { ConstantInflowNFT } from "../../../contracts/superfluid/ConstantInflowNFT.sol"; -import { FlowNFTBase } from "../../../contracts/superfluid/FlowNFTBase.sol"; - -/// @title FlowNFTBaseMock -/// @author Superfluid -/// @dev A mock contract for testing the functionality on FlowNFTBase -contract FlowNFTBaseMock is FlowNFTBase { - using Strings for uint256; - - mapping(uint256 => FlowNFTData) internal _flowDataByTokenId; - - 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"); - } - - /// @dev The owner of here is always the flow sender - function _ownerOf(uint256 tokenId) internal view override returns (address) { - return _flowDataByTokenId[tokenId].flowSender; - } - - /// @dev a mock mint function that sets the FlowNFTData - function mockMint(address _superToken, address _flowSender, address _flowReceiver) public { - uint256 tokenId = _getTokenId(_superToken, _flowSender, _flowReceiver); - _flowDataByTokenId[tokenId] = FlowNFTData({ - flowSender: _flowSender, - flowStartDate: uint32(block.timestamp), - flowReceiver: _flowReceiver, - superToken: _superToken - }); - } - - function _transfer( - address, //from, - address, //to, - uint256 //tokenId - ) internal pure override { - revert CFA_NFT_TRANSFER_IS_NOT_ALLOWED(); - } - - function flowDataByTokenId(uint256 tokenId) public view override returns (FlowNFTData memory flowData) { - return _flowDataByTokenId[tokenId]; - } - - function tokenURI(uint256 tokenId) external pure override returns (string memory) { - return string(abi.encodePacked("tokenId=", tokenId.toString())); - } -} - -contract ConstantOutflowNFTMock is ConstantOutflowNFT { - 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 { - _mint(_superToken, _to, _flowReceiver, _newTokenId); - } - - /// @dev a mock burn function that exposes the internal _burn function - function mockBurn(uint256 _tokenId) public { - _burn(_tokenId); - } - - /// @dev this ownerOf doesn't revert if _tokenId doesn't exist - function mockOwnerOf(uint256 _tokenId) public view returns (address) { - return _ownerOf(_tokenId); - } - - /// @dev This exposes the _tokenApprovals storage without the requireMinted call - function mockGetApproved(uint256 _tokenId) public view returns (address) { - return _tokenApprovals[_tokenId]; - } -} - -contract ConstantInflowNFTMock is ConstantInflowNFT { - constructor( - ISuperfluid host, - IConstantFlowAgreementV1 cfaV1, - IGeneralDistributionAgreementV1 gdaV1, - IConstantOutflowNFT constantOutflowNFT - ) ConstantInflowNFT(host, cfaV1, gdaV1, constantOutflowNFT) { } - - /// @dev a mock mint function to emit the mint Transfer event - function mockMint(address _to, uint256 _newTokenId) public { - _mint(_to, _newTokenId); - } - - /// @dev a mock burn function to emit the burn Transfer event - function mockBurn(uint256 _tokenId) public { - _burn(_tokenId); - } - - // @dev this ownerOf doesn't revert if _tokenId doesn't exist - function mockOwnerOf(uint256 _tokenId) public view returns (address) { - return _ownerOf(_tokenId); - } - - /// @dev This exposes the _tokenApprovals storage without the requireMinted call - function mockGetApproved(uint256 _tokenId) public view returns (address) { - return _tokenApprovals[_tokenId]; - } -} diff --git a/packages/ethereum-contracts/test/foundry/superfluid/CFAv1NFTUpgradabilityMock.t.sol b/packages/ethereum-contracts/test/foundry/superfluid/CFAv1NFTUpgradabilityMock.t.sol deleted file mode 100644 index 2d0ca77cd5..0000000000 --- a/packages/ethereum-contracts/test/foundry/superfluid/CFAv1NFTUpgradabilityMock.t.sol +++ /dev/null @@ -1,198 +0,0 @@ -// SPDX-License-Identifier: AGPLv3 -pragma solidity ^0.8.23; - -import { IConstantFlowAgreementV1, IGeneralDistributionAgreementV1, ISuperfluid } - from "../../../contracts/interfaces/superfluid/ISuperfluid.sol"; -import { ConstantInflowNFT, IConstantInflowNFT } from "../../../contracts/superfluid/ConstantInflowNFT.sol"; -import { ConstantOutflowNFT, IConstantOutflowNFT } from "../../../contracts/superfluid/ConstantOutflowNFT.sol"; -import { FlowNFTBase } from "../../../contracts/superfluid/FlowNFTBase.sol"; -import { StorageLayoutTestBase } from "../StorageLayoutTestBase.t.sol"; - -/*////////////////////////////////////////////////////////////////////////// - FlowNFTBase Mocks -//////////////////////////////////////////////////////////////////////////*/ - -/// @title FlowNFTBaseStorageLayoutMock -/// @author Superfluid -/// @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, StorageLayoutTestBase { - - 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 - function validateStorageLayout() public virtual { - uint256 slot; - uint256 offset; // in bytes - - // slot 0 taken is occupied by these variables: - // Initializable._initialized (uint8) 1byte - // Initializable._initializing (bool) 1byte - - assembly { slot := _name.slot offset := _name.offset } - if (slot != 1 || offset != 0) revert STORAGE_LOCATION_CHANGED("_name"); - - assembly { slot := _symbol.slot offset := _symbol.offset } - if (slot != 2 || offset != 0) revert STORAGE_LOCATION_CHANGED("_symbol"); - - assembly { slot := _tokenApprovals.slot offset := _tokenApprovals.offset } - if (slot != 3 || offset != 0) revert STORAGE_LOCATION_CHANGED("_tokenApprovals"); - - assembly { slot := _operatorApprovals.slot offset := _operatorApprovals.offset } - if (slot != 4 || offset != 0) revert STORAGE_LOCATION_CHANGED("_operatorApprovals"); - - assembly { slot := _reserve5.slot offset := _reserve5.offset } - if (slot != 5 || offset != 0) revert STORAGE_LOCATION_CHANGED("_reserve5"); - - assembly { slot := _reserve21.slot offset := _reserve21.offset } - if (slot != 21 || offset != 0) revert STORAGE_LOCATION_CHANGED("_reserve21"); - } - - // Dummy implementations for abstract functions - function flowDataByTokenId( - uint256 //tokenId - ) public pure override returns (FlowNFTData memory flowData) { - return flowData; - } - // Dummy implementations for abstract functions - function _ownerOf( - uint256 //tokenId - ) internal pure override returns (address) { - return address(0); - } - function _transfer( - address, //from, - address, //to, - uint256 //tokenId - ) internal pure override { - return; - } - function _safeTransfer( - address from, - address to, - uint256 tokenId, - bytes memory // data - ) internal pure override { - _transfer(from, to, tokenId); - } - function proxiableUUID() public pure override returns (bytes32) { - return keccak256(""); - } - - function tokenURI(uint256 /* tokenId */) external pure override returns (string memory) { - return ""; - } -} - - -/// @title ConstantInflowNFTStorageLayoutMock -/// @author Superfluid -/// @notice A mock ConstantOutflowNFT contract for testing storage layout. -/// @dev This contract *MUST* have the same storage layout as ConstantOutflowNFT.sol -contract ConstantInflowNFTStorageLayoutMock is ConstantInflowNFT, StorageLayoutTestBase { - - constructor( - ISuperfluid host, - IConstantFlowAgreementV1 cfaV1, - IGeneralDistributionAgreementV1 gdaV1, - IConstantOutflowNFT constantOutflowNFT - ) ConstantInflowNFT(host, cfaV1, gdaV1, constantOutflowNFT) { } - - /// @notice Validates storage layout - /// @dev This function is used to validate storage layout of ConstantInflowNFT - function validateStorageLayout() public virtual { - uint256 slot; - uint256 offset; // in bytes - - // slot 0 taken is occupied by these variables: - // Initializable._initialized (uint8) 1byte - // Initializable._initializing (bool) 1byte - - assembly { slot := _name.slot offset := _name.offset } - if (slot != 1 || offset != 0) revert STORAGE_LOCATION_CHANGED("_name"); - - assembly { slot := _symbol.slot offset := _symbol.offset } - if (slot != 2 || offset != 0) revert STORAGE_LOCATION_CHANGED("_symbol"); - - assembly { slot := _tokenApprovals.slot offset := _tokenApprovals.offset } - if (slot != 3 || offset != 0) revert STORAGE_LOCATION_CHANGED("_tokenApprovals"); - - assembly { slot := _operatorApprovals.slot offset := _operatorApprovals.offset } - if (slot != 4 || offset != 0) revert STORAGE_LOCATION_CHANGED("_operatorApprovals"); - - assembly { slot := _reserve5.slot offset := _reserve5.offset } - if (slot != 5 || offset != 0) revert STORAGE_LOCATION_CHANGED("_reserve5"); - - assembly { slot := _reserve21.slot offset := _reserve21.offset } - if (slot != 21 || offset != 0) revert STORAGE_LOCATION_CHANGED("_reserve21"); - } - - // Dummy implementations for abstract functions - function _safeTransfer( - address from, - address to, - uint256 tokenId, - bytes memory // data - ) internal override pure { - _transfer(from, to, tokenId); - } -} - -/// @title ConstantOutflowNFTStorageLayoutMock -/// @author Superfluid -/// @notice A mock ConstantOutflowNFT contract for testing storage layout. -/// @dev This contract *MUST* have the same storage layout as ConstantOutflowNFT.sol -contract ConstantOutflowNFTStorageLayoutMock is ConstantOutflowNFT, StorageLayoutTestBase { - - constructor( - ISuperfluid host, - IConstantFlowAgreementV1 cfaV1, - IGeneralDistributionAgreementV1 gdaV1, - IConstantInflowNFT constantInflowNFT - ) ConstantOutflowNFT(host, cfaV1, gdaV1, constantInflowNFT) { } - - /// @notice Validates storage layout - /// @dev This function is used to validate storage layout of ConstantOutflowNFT - function validateStorageLayout() public virtual { - uint256 slot; - uint256 offset; // in bytes - - // slot 0 taken is occupied by these variables: - // Initializable._initialized (uint8) 1byte - // Initializable._initializing (bool) 1byte - - assembly { slot := _name.slot offset := _name.offset } - if (slot != 1 || offset != 0) revert STORAGE_LOCATION_CHANGED("_name"); - - assembly { slot := _symbol.slot offset := _symbol.offset } - if (slot != 2 || offset != 0) revert STORAGE_LOCATION_CHANGED("_symbol"); - - assembly { slot := _tokenApprovals.slot offset := _tokenApprovals.offset } - if (slot != 3 || offset != 0) revert STORAGE_LOCATION_CHANGED("_tokenApprovals"); - - assembly { slot := _operatorApprovals.slot offset := _operatorApprovals.offset } - if (slot != 4 || offset != 0) revert STORAGE_LOCATION_CHANGED("_operatorApprovals"); - - assembly { slot := _reserve5.slot offset := _reserve5.offset } - if (slot != 5 || offset != 0) revert STORAGE_LOCATION_CHANGED("_reserve5"); - - assembly { slot := _reserve21.slot offset := _reserve21.offset } - if (slot != 21 || offset != 0) revert STORAGE_LOCATION_CHANGED("_reserve21"); - - assembly { slot := _flowDataByTokenId.slot offset := _flowDataByTokenId.offset } - if (slot != 22 || offset != 0) revert STORAGE_LOCATION_CHANGED("_flowDataByTokenId"); - } - - // Dummy implementations for abstract functions - function _safeTransfer( - address from, - address to, - uint256 tokenId, - bytes memory // data - ) internal pure override { - _transfer(from, to, tokenId); - } -} diff --git a/packages/ethereum-contracts/test/foundry/superfluid/ConstantInflowNFT.t.sol b/packages/ethereum-contracts/test/foundry/superfluid/ConstantInflowNFT.t.sol deleted file mode 100644 index ee26eade89..0000000000 --- a/packages/ethereum-contracts/test/foundry/superfluid/ConstantInflowNFT.t.sol +++ /dev/null @@ -1,141 +0,0 @@ -// SPDX-License-Identifier: AGPLv3 -pragma solidity ^0.8.23; - -import { IERC165, IERC721, IERC721Metadata } from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol"; -import { ConstantOutflowNFT } from "../../../contracts/superfluid/ConstantOutflowNFT.sol"; -import { IFlowNFTBase } from "../../../contracts/interfaces/superfluid/IFlowNFTBase.sol"; -import { FlowNFTBase, ConstantInflowNFT, IConstantInflowNFT } from "../../../contracts/superfluid/ConstantInflowNFT.sol"; -import { FlowNFTBaseTest } from "./FlowNFTBase.t.sol"; - -contract ConstantInflowNFTTest is FlowNFTBaseTest { - /*////////////////////////////////////////////////////////////////////////// - Revert Tests - //////////////////////////////////////////////////////////////////////////*/ - - function testRevertIfMintIsNotCalledByOutflowNFT(address caller) public { - _assumeCallerIsNotOtherAddress(caller, address(constantOutflowNFT)); - vm.expectRevert(IConstantInflowNFT.CIF_NFT_ONLY_CONSTANT_OUTFLOW.selector); - constantInflowNFT.mint(address(0), 69); - } - - function testRevertIfBurnIsNotCalledByOutflowNFT(address caller) public { - _assumeCallerIsNotOtherAddress(caller, address(constantOutflowNFT)); - vm.expectRevert(IConstantInflowNFT.CIF_NFT_ONLY_CONSTANT_OUTFLOW.selector); - constantInflowNFT.burn(69); - } - - function testRevertIfYouTryToTransferInflowNFT(address _flowSender, address _flowReceiver) public { - _assumeSenderNEQReceiverAndNeitherAreZeroAddress(_flowSender, _flowReceiver); - - uint256 nftId = _helperGetNFTID(address(superTokenMock), _flowSender, _flowReceiver); - constantOutflowNFT.mockMint(address(superTokenMock), _flowSender, _flowReceiver, nftId); - - vm.startPrank(_flowReceiver); - vm.expectRevert(IFlowNFTBase.CFA_NFT_TRANSFER_IS_NOT_ALLOWED.selector); - constantInflowNFT.transferFrom(_flowReceiver, _flowSender, nftId); - vm.stopPrank(); - } - - /*////////////////////////////////////////////////////////////////////////// - Passing Tests - //////////////////////////////////////////////////////////////////////////*/ - - function testProxiableUUIDIsExpectedValue() public view { - assertEq( - constantInflowNFT.proxiableUUID(), - keccak256("org.superfluid-finance.contracts.ConstantInflowNFT.implementation") - ); - } - - function testConstantInflowNFTIsProperlyInitialized() public view { - assertEq(constantInflowNFT.name(), INFLOW_NFT_NAME_TEMPLATE); - assertEq(constantInflowNFT.symbol(), INFLOW_NFT_SYMBOL_TEMPLATE); - } - - function testFlowDataByTokenIdMint(address _flowSender, address _flowReceiver) public { - _assumeSenderNEQReceiverAndNeitherAreZeroAddress(_flowSender, _flowReceiver); - - uint256 nftId = _helperGetNFTID(address(superTokenMock), _flowSender, _flowReceiver); - - constantOutflowNFT.mockMint(address(superTokenMock), _flowSender, _flowReceiver, nftId); - _assertNFTFlowDataStateIsExpected( - nftId, address(superTokenMock), _flowSender, uint32(block.timestamp), _flowReceiver - ); - - IFlowNFTBase.FlowNFTData memory flowData = constantInflowNFT.flowDataByTokenId(nftId); - assertEq(flowData.flowSender, _flowSender); - assertEq(flowData.flowReceiver, _flowReceiver); - } - - function testInternalMintToken(address _flowSender, address _flowReceiver) public { - _assumeSenderNEQReceiverAndNeitherAreZeroAddress(_flowSender, _flowReceiver); - - uint256 nftId = _helperGetNFTID(address(superTokenMock), _flowSender, _flowReceiver); - - _assertEventTransfer(address(constantInflowNFT), address(0), _flowReceiver, nftId); - - constantInflowNFT.mockMint(_flowReceiver, nftId); - - _assertNFTFlowDataStateIsEmpty(nftId); - } - - function testInternalBurnToken(address _flowSender, address _flowReceiver) public { - _assumeSenderNEQReceiverAndNeitherAreZeroAddress(_flowSender, _flowReceiver); - - uint256 nftId = _helperGetNFTID(address(superTokenMock), _flowSender, _flowReceiver); - constantOutflowNFT.mockMint(address(superTokenMock), _flowSender, _flowReceiver, nftId); - _assertNFTFlowDataStateIsExpected( - nftId, address(superTokenMock), _flowSender, uint32(block.timestamp), _flowReceiver - ); - - _assertEventTransfer(address(constantInflowNFT), _flowReceiver, address(0), nftId); - - constantInflowNFT.mockBurn(nftId); - - _assertNFTFlowDataStateIsExpected( - nftId, address(superTokenMock), _flowSender, uint32(block.timestamp), _flowReceiver - ); - } - - function testApprove(address _flowSender, address _flowReceiver, address _approvedAccount) - public - override - returns (uint256 nftId) - { - _assumeSenderNEQReceiverAndNeitherAreZeroAddress(_flowSender, _flowReceiver); - vm.assume(_flowReceiver != _approvedAccount); - - nftId = _helperGetNFTID(address(superTokenMock), _flowSender, _flowReceiver); - constantOutflowNFT.mockMint(address(superTokenMock), _flowSender, _flowReceiver, nftId); - _assertNFTFlowDataStateIsExpected( - nftId, address(superTokenMock), _flowSender, uint32(block.timestamp), _flowReceiver - ); - - _assertEventApproval(address(constantInflowNFT), _flowReceiver, _approvedAccount, nftId); - - vm.startPrank(_flowReceiver); - constantInflowNFT.approve(_approvedAccount, nftId); - vm.stopPrank(); - - _assertApprovalIsExpected(constantInflowNFT, nftId, _approvedAccount); - } - - function testApproveThenBurn(address _flowSender, address _flowReceiver, address _approvedAccount) public { - uint256 nftId = testApprove(_flowSender, _flowReceiver, _approvedAccount); - constantInflowNFT.mockBurn(nftId); - - assertEq(constantInflowNFT.mockGetApproved(nftId), address(0)); - } - - function testSetApprovalForAll(address _tokenOwner, address _operator, bool _approved) public { - vm.assume(_tokenOwner != address(0)); - vm.assume(_tokenOwner != _operator); - - vm.startPrank(_tokenOwner); - _assertEventApprovalForAll(address(constantInflowNFT), _tokenOwner, _operator, _approved); - constantInflowNFT.setApprovalForAll(_operator, _approved); - vm.stopPrank(); - - _assertOperatorApprovalIsExpected(constantInflowNFT, _tokenOwner, _operator, _approved); - } -} diff --git a/packages/ethereum-contracts/test/foundry/superfluid/ConstantOutflowNFT.t.sol b/packages/ethereum-contracts/test/foundry/superfluid/ConstantOutflowNFT.t.sol deleted file mode 100644 index e06dff36b9..0000000000 --- a/packages/ethereum-contracts/test/foundry/superfluid/ConstantOutflowNFT.t.sol +++ /dev/null @@ -1,300 +0,0 @@ -// SPDX-License-Identifier: AGPLv3 -pragma solidity ^0.8.23; - -import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { IERC165, IERC721, IERC721Metadata } from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol"; -import { Strings } from "@openzeppelin/contracts/utils/Strings.sol"; -import { UUPSProxy } from "../../../contracts/upgradability/UUPSProxy.sol"; -import { - FlowNFTBase, ConstantOutflowNFT, IConstantOutflowNFT -} from "../../../contracts/superfluid/ConstantOutflowNFT.sol"; -import { ConstantInflowNFT } from "../../../contracts/superfluid/ConstantInflowNFT.sol"; -import { FoundrySuperfluidTester, SuperTokenV1Library } from "../FoundrySuperfluidTester.sol"; -import { IFlowNFTBase } from "../../../contracts/interfaces/superfluid/IFlowNFTBase.sol"; -import { TestToken } from "../../../contracts/utils/TestToken.sol"; -import { SuperTokenV1Library } from "../../../contracts/apps/SuperTokenV1Library.sol"; -import { ISuperToken } from "../../../contracts/superfluid/SuperToken.sol"; -import { SuperToken, SuperTokenMock, NoNFTSuperTokenMock } from "../../../contracts/mocks/SuperTokenMock.t.sol"; -import { FlowNFTBaseTest } from "./FlowNFTBase.t.sol"; -import { ConstantOutflowNFTMock } from "./CFAv1NFTMock.t.sol"; - - -library StringExtra { - function concat(string memory a, string memory b) internal pure returns (string memory) { - return string(abi.encodePacked(a, b)); - } -} -using StringExtra for string; - -contract ConstantOutflowNFTTest is FlowNFTBaseTest { - using Strings for uint256; - using SuperTokenV1Library for ISuperToken; - using SuperTokenV1Library for SuperTokenMock; - - /*////////////////////////////////////////////////////////////////////////// - Revert Tests - //////////////////////////////////////////////////////////////////////////*/ - - function testRevertIfInternalMintToZeroAddress(address _flowReceiver) public { - uint256 nftId = _helperGetNFTID(address(superTokenMock), address(0), _flowReceiver); - vm.expectRevert(); - constantOutflowNFT.mockMint(address(superTokenMock), address(0), _flowReceiver, nftId); - } - - // test disabled -we do now explicitly allow this in order to not revert - // if previous onDelete hooks failed to execute - function noTestRevertIfInternalMintTokenThatExists(address _flowSender, address _flowReceiver) public { - _assumeSenderNEQReceiverAndNeitherAreZeroAddress(_flowSender, _flowReceiver); - - uint256 nftId = _helperGetNFTID(address(superTokenMock), _flowSender, _flowReceiver); - constantOutflowNFT.mockMint(address(superTokenMock), _flowSender, _flowReceiver, nftId); - vm.expectRevert(); - constantOutflowNFT.mockMint(address(superTokenMock), _flowSender, _flowReceiver, nftId); - } - - function testRevertIfInternalMintSameToAndFlowReceiver(address _flowSender) public { - vm.assume(_flowSender != address(0)); - - uint256 nftId = _helperGetNFTID(address(superTokenMock), _flowSender, _flowSender); - vm.expectRevert(); - constantOutflowNFT.mockMint(address(superTokenMock), _flowSender, _flowSender, nftId); - } - - function testRevertIfOnCreateIsNotCalledByFlowAgreement(address caller) public { - _assumeCallerIsNotOtherAddress(caller, address(sf.cfa)); - _assumeCallerIsNotOtherAddress(caller, address(sf.gda)); - - vm.expectRevert(IConstantOutflowNFT.COF_NFT_ONLY_FLOW_AGREEMENTS.selector); - vm.prank(caller); - constantOutflowNFT.onCreate(superToken, address(1), address(2)); - } - - function testRevertIfOnUpdateIsNotCalledByFlowAgreement(address caller) public { - _assumeCallerIsNotOtherAddress(caller, address(sf.cfa)); - _assumeCallerIsNotOtherAddress(caller, address(sf.gda)); - - vm.startPrank(caller); - vm.expectRevert(IConstantOutflowNFT.COF_NFT_ONLY_FLOW_AGREEMENTS.selector); - constantOutflowNFT.onUpdate(superToken, address(1), address(2)); - vm.stopPrank(); - } - - function testRevertIfOnDeleteIsNotCalledByFlowAgreement(address caller) public { - _assumeCallerIsNotOtherAddress(caller, address(sf.cfa)); - _assumeCallerIsNotOtherAddress(caller, address(sf.gda)); - vm.prank(caller); - vm.expectRevert(IConstantOutflowNFT.COF_NFT_ONLY_FLOW_AGREEMENTS.selector); - constantOutflowNFT.onDelete(superToken, address(1), address(2)); - } - - function testRevertIfGetNoFlowTokenURI() public { - uint256 nftId = _helperGetNFTID(address(superTokenMock), alice, bob); - vm.expectRevert(); - constantOutflowNFT.tokenURI(nftId); - vm.expectRevert(); - constantInflowNFT.tokenURI(nftId); - } - - function testRevertIfYouTryToTransferOutflowNFT(address _flowSender, address _flowReceiver) public { - _assumeSenderNEQReceiverAndNeitherAreZeroAddress(_flowSender, _flowReceiver); - - uint256 nftId = _helperGetNFTID(address(superTokenMock), _flowSender, _flowReceiver); - constantOutflowNFT.mockMint(address(superTokenMock), _flowSender, _flowReceiver, nftId); - - vm.startPrank(_flowSender); - vm.expectRevert(IFlowNFTBase.CFA_NFT_TRANSFER_IS_NOT_ALLOWED.selector); - constantOutflowNFT.transferFrom(_flowSender, _flowReceiver, nftId); - vm.stopPrank(); - } - - /*////////////////////////////////////////////////////////////////////////// - Passing Tests - //////////////////////////////////////////////////////////////////////////*/ - - function testProxiableUUIDIsExpectedValue() public view { - assertEq( - constantOutflowNFT.proxiableUUID(), - keccak256("org.superfluid-finance.contracts.ConstantOutflowNFT.implementation") - ); - } - - function testConstantOutflowNFTIsProperlyInitialized() public view { - assertEq(constantOutflowNFT.name(), OUTFLOW_NFT_NAME_TEMPLATE); - assertEq(constantOutflowNFT.symbol(), OUTFLOW_NFT_SYMBOL_TEMPLATE); - } - - function testInternalMintToken(address _flowSender, address _flowReceiver) public { - _assumeSenderNEQReceiverAndNeitherAreZeroAddress(_flowSender, _flowReceiver); - - uint256 nftId = _helperGetNFTID(address(superTokenMock), _flowSender, _flowReceiver); - - _assertEventTransfer(address(constantOutflowNFT), address(0), _flowSender, nftId); - - constantOutflowNFT.mockMint(address(superTokenMock), _flowSender, _flowReceiver, nftId); - _assertNFTFlowDataStateIsExpected( - nftId, address(superTokenMock), _flowSender, uint32(block.timestamp), _flowReceiver - ); - } - - function testInternalBurnToken(address _flowSender, address _flowReceiver) public { - _assumeSenderNEQReceiverAndNeitherAreZeroAddress(_flowSender, _flowReceiver); - - uint256 nftId = _helperGetNFTID(address(superTokenMock), _flowSender, _flowReceiver); - constantOutflowNFT.mockMint(address(superTokenMock), _flowSender, _flowReceiver, nftId); - _assertNFTFlowDataStateIsExpected( - nftId, address(superTokenMock), _flowSender, uint32(block.timestamp), _flowReceiver - ); - - _assertEventTransfer(address(constantOutflowNFT), _flowSender, address(0), nftId); - - constantOutflowNFT.mockBurn(nftId); - _assertNFTFlowDataStateIsEmpty(nftId); - } - - function testApprove(address _flowSender, address _flowReceiver, address _approvedAccount) - public - override - returns (uint256 nftId) - { - _assumeSenderNEQReceiverAndNeitherAreZeroAddress(_flowSender, _flowReceiver); - vm.assume(_flowSender != _approvedAccount); - - nftId = _helperGetNFTID(address(superTokenMock), _flowSender, _flowReceiver); - constantOutflowNFT.mockMint(address(superTokenMock), _flowSender, _flowReceiver, nftId); - - _assertEventApproval(address(constantOutflowNFT), _flowSender, _approvedAccount, nftId); - - vm.startPrank(_flowSender); - constantOutflowNFT.approve(_approvedAccount, nftId); - vm.stopPrank(); - - _assertApprovalIsExpected(constantOutflowNFT, nftId, _approvedAccount); - } - - function testApproveThenBurn(address _flowSender, address _flowReceiver, address _approvedAccount) public { - uint256 nftId = testApprove(_flowSender, _flowReceiver, _approvedAccount); - constantOutflowNFT.mockBurn(nftId); - - assertEq(constantOutflowNFT.mockGetApproved(nftId), address(0)); - } - - function testSetApprovalForAll(address _tokenOwner, address _operator, bool _approved) public { - vm.assume(_tokenOwner != address(0)); - vm.assume(_tokenOwner != _operator); - - - vm.startPrank(_tokenOwner); - _assertEventApprovalForAll(address(constantOutflowNFT), _tokenOwner, _operator, _approved); - constantOutflowNFT.setApprovalForAll(_operator, _approved); - vm.stopPrank(); - - _assertOperatorApprovalIsExpected(constantOutflowNFT, _tokenOwner, _operator, _approved); - } - - function testCreateFlowMintsOutflowAndInflowNFTsAndEmitsTransferEvents() public { - int96 flowRate = 42069; - address flowSender = alice; - address flowReceiver = bob; - _helperCreateFlowAndAssertNFTInvariants(flowSender, flowReceiver, flowRate); - } - - function testUpdateFlowDoesNotImpactStorageAndEmitsMetadataUpdateEvents() public { - int96 flowRate = 42069; - address flowSender = alice; - address flowReceiver = bob; - _helperCreateFlowAndAssertNFTInvariants(flowSender, flowReceiver, flowRate); - - uint256 nftId = _helperGetNFTID(address(superTokenMock), flowSender, flowReceiver); - _assertEventMetadataUpdate(address(constantOutflowNFT), nftId); - _assertEventMetadataUpdate(address(constantInflowNFT), nftId); - - vm.prank(flowSender); - superTokenMock.updateFlow(flowReceiver, flowRate + 333); - - _assertNFTFlowDataStateIsExpected( - nftId, address(superTokenMock), flowSender, uint32(block.timestamp), flowReceiver - ); - } - - function testDeleteFlowClearsStorageAndEmitsTransferEvents() public { - int96 flowRate = 42069; - address flowSender = alice; - address flowReceiver = bob; - _helperCreateFlowAndAssertNFTInvariants(flowSender, flowReceiver, flowRate); - - uint256 nftId = _helperGetNFTID(address(superTokenMock), flowSender, flowReceiver); - - _assertEventTransfer(address(constantInflowNFT), flowReceiver, address(0), nftId); - - _assertEventTransfer(address(constantOutflowNFT), flowSender, address(0), nftId); - - vm.prank(flowSender); - superTokenMock.deleteFlow(flowSender, flowReceiver); - - _assertNFTFlowDataStateIsEmpty(nftId); - } - - function testTokenURIIsExpected(uint32 startDate, uint32 flowRate) public { - vm.assume(flowRate > 0); - address flowSender = alice; - address flowReceiver = bob; - - vm.warp(startDate); - _helperCreateFlowAndAssertNFTInvariants(flowSender, flowReceiver, int96(int256(uint256(flowRate)))); - - string memory tokenURI; - { - uint256 nftId = _helperGetNFTID(address(superTokenMock), flowSender, flowReceiver); - tokenURI = constantOutflowNFT.tokenURI(nftId); - } - - string memory expectedTokenURI; - { - expectedTokenURI = string("https://nft.superfluid.finance/cfa/v2/getmeta?flowRate=") - .concat(uint256(flowRate).toString()); - expectedTokenURI = expectedTokenURI.concat("&outgoing=true"); - expectedTokenURI = expectedTokenURI.concat("&token_address=") - .concat(Strings.toHexString(uint256(uint160(address(superTokenMock))), 20)); - expectedTokenURI = expectedTokenURI.concat("&chain_id=") - .concat(block.chainid.toString()); - expectedTokenURI = expectedTokenURI.concat("&token_symbol=") - .concat(superTokenMock.symbol()); - expectedTokenURI = expectedTokenURI.concat("&sender=") - .concat(Strings.toHexString(uint256(uint160(flowSender)), 20)); - expectedTokenURI = expectedTokenURI.concat("&receiver=") - .concat(Strings.toHexString(uint256(uint160(flowReceiver)), 20)); - expectedTokenURI = expectedTokenURI.concat("&token_decimals=") - .concat(uint256(superTokenMock.decimals()).toString()); - expectedTokenURI = expectedTokenURI.concat("&start_date=") - .concat(uint256(startDate).toString()); - } - - assertEq(tokenURI, expectedTokenURI); - } - - function testCreateUpdateDeleteFlowNoNFTToken() public { - uint256 initialAmount = 10000 ether; - TestToken testToken = new TestToken("Test", "TS", 18, initialAmount); - NoNFTSuperTokenMock noNFTSuperTokenMock = new NoNFTSuperTokenMock( - sf.host - ); - noNFTSuperTokenMock.initialize(testToken, 18, "Super Test", "TSx"); - vm.startPrank(alice); - testToken.mint(alice, initialAmount); - testToken.approve(address(noNFTSuperTokenMock), initialAmount); - noNFTSuperTokenMock.upgrade(initialAmount); - ISuperToken(address(noNFTSuperTokenMock)).createFlow(bob, 100); - (, int96 flowRate,,) = sf.cfa.getFlow(noNFTSuperTokenMock, alice, bob); - assertEq(flowRate, 100); - ISuperToken(address(noNFTSuperTokenMock)).updateFlow(bob, 150); - (, flowRate,,) = sf.cfa.getFlow(noNFTSuperTokenMock, alice, bob); - assertEq(flowRate, 150); - ISuperToken(address(noNFTSuperTokenMock)).updateFlow(bob, 90); - (, flowRate,,) = sf.cfa.getFlow(noNFTSuperTokenMock, alice, bob); - assertEq(flowRate, 90); - ISuperToken(address(noNFTSuperTokenMock)).deleteFlow(alice, bob); - (, flowRate,,) = sf.cfa.getFlow(noNFTSuperTokenMock, alice, bob); - assertEq(flowRate, 0); - vm.stopPrank(); - } -} diff --git a/packages/ethereum-contracts/test/foundry/superfluid/ERC721.t.sol b/packages/ethereum-contracts/test/foundry/superfluid/ERC721.t.sol index 5c72ede53e..befdcadd4d 100644 --- a/packages/ethereum-contracts/test/foundry/superfluid/ERC721.t.sol +++ b/packages/ethereum-contracts/test/foundry/superfluid/ERC721.t.sol @@ -3,35 +3,22 @@ pragma solidity ^0.8.23; import { IERC721Metadata } from "@openzeppelin/contracts/interfaces/IERC721Metadata.sol"; import { FoundrySuperfluidTester } from "../FoundrySuperfluidTester.sol"; -import { ConstantOutflowNFTMock, ConstantInflowNFTMock } from "./CFAv1NFTMock.t.sol"; import { PoolAdminNFTMock, PoolMemberNFTMock } from "./PoolNFTMock.t.sol"; -import { ConstantOutflowNFT, IConstantOutflowNFT } from "../../../contracts/superfluid/ConstantOutflowNFT.sol"; -import { ConstantInflowNFT, IConstantInflowNFT } from "../../../contracts/superfluid/ConstantInflowNFT.sol"; import { TestToken } from "../../../contracts/utils/TestToken.sol"; import { PoolAdminNFT, IPoolAdminNFT } from "../../../contracts/agreements/gdav1/PoolAdminNFT.sol"; import { PoolMemberNFT, IPoolMemberNFT } from "../../../contracts/agreements/gdav1/PoolMemberNFT.sol"; import { UUPSProxy } from "../../../contracts/upgradability/UUPSProxy.sol"; import { UUPSProxiable } from "../../../contracts/upgradability/UUPSProxiable.sol"; -import { SuperToken, SuperTokenMock } from "../../../contracts/mocks/SuperTokenMock.t.sol"; +import { SuperToken, SuperTokenMock, IConstantOutflowNFT, IConstantInflowNFT } from "../../../contracts/mocks/SuperTokenMock.t.sol"; contract ERC721IntegrationTest is FoundrySuperfluidTester { string internal constant POOL_MEMBER_NFT_NAME_TEMPLATE = "Pool Member NFT"; string internal constant POOL_MEMBER_NFT_SYMBOL_TEMPLATE = "PMF"; string internal constant POOL_ADMIN_NFT_NAME_TEMPLATE = "Pool Admin NFT"; string internal constant POOL_ADMIN_NFT_SYMBOL_TEMPLATE = "PAF"; - string internal constant OUTFLOW_NFT_NAME_TEMPLATE = "Constant Outflow NFT"; - string internal constant OUTFLOW_NFT_SYMBOL_TEMPLATE = "COF"; - string internal constant INFLOW_NFT_NAME_TEMPLATE = "Constant Inflow NFT"; - string internal constant INFLOW_NFT_SYMBOL_TEMPLATE = "CIF"; SuperTokenMock public superTokenMock; - ConstantOutflowNFTMock public constantOutflowNFTLogic; - ConstantInflowNFTMock public constantInflowNFTLogic; - - ConstantOutflowNFTMock public constantOutflowNFT; - ConstantInflowNFTMock public constantInflowNFT; - PoolMemberNFTMock public poolMemberNFTLogic; PoolAdminNFTMock public poolAdminNFTLogic; @@ -51,36 +38,6 @@ contract ERC721IntegrationTest is FoundrySuperfluidTester { function setUp() public virtual override { super.setUp(); - // Deploy Flow NFTs - - // deploy outflow NFT contract - UUPSProxy outflowProxy = new UUPSProxy(); - - // deploy inflow NFT contract - UUPSProxy inflowProxy = new UUPSProxy(); - - // we deploy mock NFT contracts for the tests to access internal functions - constantOutflowNFTLogic = - new ConstantOutflowNFTMock(sf.host, sf.cfa, sf.gda, IConstantInflowNFT(address(inflowProxy))); - constantInflowNFTLogic = - new ConstantInflowNFTMock(sf.host, sf.cfa, sf.gda, IConstantOutflowNFT(address(outflowProxy))); - - constantOutflowNFTLogic.castrate(); - constantInflowNFTLogic.castrate(); - - // initialize proxy to point at logic - outflowProxy.initializeProxy(address(constantOutflowNFTLogic)); - - // initialize proxy to point at logic - inflowProxy.initializeProxy(address(constantInflowNFTLogic)); - - constantOutflowNFT = ConstantOutflowNFTMock(address(outflowProxy)); - constantInflowNFT = ConstantInflowNFTMock(address(inflowProxy)); - - constantOutflowNFT.initialize(OUTFLOW_NFT_NAME_TEMPLATE, OUTFLOW_NFT_SYMBOL_TEMPLATE); - - constantInflowNFT.initialize(INFLOW_NFT_NAME_TEMPLATE, INFLOW_NFT_SYMBOL_TEMPLATE); - // Deploy Pool NFTs // deploy pool member NFT contract @@ -119,8 +76,8 @@ contract ERC721IntegrationTest is FoundrySuperfluidTester { SuperTokenMock superTokenMockLogic = new SuperTokenMock( sf.host, 0, - IConstantOutflowNFT(address(constantOutflowNFT)), - IConstantInflowNFT(address(constantInflowNFT)), + IConstantOutflowNFT(address(0)), + IConstantInflowNFT(address(0)), IPoolAdminNFT(address(poolAdminNFT)), IPoolMemberNFT(address(poolMemberNFT)) ); diff --git a/packages/ethereum-contracts/test/foundry/superfluid/FlowNFTBase.prop.t.sol b/packages/ethereum-contracts/test/foundry/superfluid/FlowNFTBase.prop.t.sol deleted file mode 100644 index 339de5d93d..0000000000 --- a/packages/ethereum-contracts/test/foundry/superfluid/FlowNFTBase.prop.t.sol +++ /dev/null @@ -1,24 +0,0 @@ -// SPDX-License-Identifier: AGPLv3 -pragma solidity ^0.8.23; - -import { FoundrySuperfluidTester } from "../FoundrySuperfluidTester.sol"; - -contract FlowNFTBasePropertyTest is FoundrySuperfluidTester { - constructor() FoundrySuperfluidTester(0) { } - - function setUp() public override { - super.setUp(); - } - - function testNoTokenIdCollisionDifferentTokenSameSenderReceiver(address tokenA, address tokenB) public view { - vm.assume(tokenA != tokenB); - uint256 tokenIdA = superToken.CONSTANT_OUTFLOW_NFT().getTokenId(tokenA, alice, bob); - uint256 tokenIdB = superToken.CONSTANT_OUTFLOW_NFT().getTokenId(tokenB, alice, bob); - assertNotEq(tokenIdA, tokenIdB, "FlowNFTBaseProperties: Token Ids should differ"); - } - - function testBalanceOfIsAlwaysEqualToOne(address account) public view { - uint256 balance = superToken.CONSTANT_OUTFLOW_NFT().balanceOf(account); - assertEq(balance, 1, "FlowNFTBaseProperties: Balance of should always be equal to one"); - } -} diff --git a/packages/ethereum-contracts/test/foundry/superfluid/FlowNFTBase.t.sol b/packages/ethereum-contracts/test/foundry/superfluid/FlowNFTBase.t.sol deleted file mode 100644 index 423b2eac1b..0000000000 --- a/packages/ethereum-contracts/test/foundry/superfluid/FlowNFTBase.t.sol +++ /dev/null @@ -1,396 +0,0 @@ -// SPDX-License-Identifier: AGPLv3 -pragma solidity ^0.8.23; - -import { IERC165, IERC721, IERC721Metadata } from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol"; -import { Strings } from "@openzeppelin/contracts/utils/Strings.sol"; -import { UUPSProxy } from "../../../contracts/upgradability/UUPSProxy.sol"; -import { UUPSProxiable } from "../../../contracts/upgradability/UUPSProxiable.sol"; -import { - FlowNFTBase, - IFlowNFTBase, - ConstantOutflowNFT, - IConstantOutflowNFT -} from "../../../contracts/superfluid/ConstantOutflowNFT.sol"; -import { ConstantInflowNFT, IConstantInflowNFT } from "../../../contracts/superfluid/ConstantInflowNFT.sol"; -import { IPoolAdminNFT } from "../../../contracts/agreements/gdav1/PoolAdminNFT.sol"; -import { IPoolMemberNFT } from "../../../contracts/agreements/gdav1/PoolMemberNFT.sol"; -import { SuperTokenV1Library } from "../../../contracts/apps/SuperTokenV1Library.sol"; -import { ConstantOutflowNFTMock, ConstantInflowNFTMock } from "./CFAv1NFTMock.t.sol"; -import { SuperToken, SuperTokenMock } from "../../../contracts/mocks/SuperTokenMock.t.sol"; -import { TestToken } from "../../../contracts/utils/TestToken.sol"; -import { FlowNFTBaseMock } from "./CFAv1NFTMock.t.sol"; -import { FoundrySuperfluidTester } from "../FoundrySuperfluidTester.sol"; -import { - FlowNFTBaseStorageLayoutMock, - ConstantInflowNFTStorageLayoutMock, - ConstantOutflowNFTStorageLayoutMock -} from "./CFAv1NFTUpgradabilityMock.t.sol"; -import { ERC721IntegrationTest } from "./ERC721.t.sol"; - -abstract contract FlowNFTBaseTest is ERC721IntegrationTest { - using Strings for uint256; - using SuperTokenV1Library for SuperTokenMock; - using SuperTokenV1Library for SuperToken; - - string public constant NAME = "Flow NFT Base"; - string public constant SYMBOL = "FNFTB"; - - FlowNFTBaseMock public flowNFTBaseMock; - - function setUp() public virtual override { - super.setUp(); - flowNFTBaseMock = new FlowNFTBaseMock(sf.host, sf.cfa, sf.gda); - flowNFTBaseMock.initialize(NAME, SYMBOL); - } - - /*////////////////////////////////////////////////////////////////////////// - Revert Tests - //////////////////////////////////////////////////////////////////////////*/ - - function testRevertIfContractAlreadyInitialized() public { - vm.expectRevert("Initializable: contract is already initialized"); - - flowNFTBaseMock.initialize(NAME, SYMBOL); - } - - function testRevertIfOwnerOfCalledForNonExistentToken(uint256 tokenId) public { - _helperRevertIfOwnerOf(flowNFTBaseMock, tokenId, IFlowNFTBase.CFA_NFT_INVALID_TOKEN_ID.selector); - } - - function testRevertIfGetApprovedCalledForNonExistentToken(uint256 tokenId) public { - _helperRevertIfGetApproved(flowNFTBaseMock, tokenId, IFlowNFTBase.CFA_NFT_INVALID_TOKEN_ID.selector); - } - - function testRevertIfSetApprovalForAllOperatorApproveToCaller(address _flowSender) public { - vm.assume(_flowSender != address(0)); - - vm.startPrank(_flowSender); - vm.expectRevert(IFlowNFTBase.CFA_NFT_APPROVE_TO_CALLER.selector); - flowNFTBaseMock.setApprovalForAll(_flowSender, true); - vm.stopPrank(); - } - - function testRevertIfApproveToCurrentOwner(address _flowSender, address _flowReceiver) public { - _assumeSenderNEQReceiverAndNeitherAreZeroAddress(_flowSender, _flowReceiver); - - uint256 nftId = _helperGetNFTID(address(superTokenMock), _flowSender, _flowReceiver); - flowNFTBaseMock.mockMint(address(superTokenMock), _flowSender, _flowReceiver); - - vm.startPrank(_flowSender); - vm.expectRevert(IFlowNFTBase.CFA_NFT_APPROVE_TO_CURRENT_OWNER.selector); - flowNFTBaseMock.approve(_flowSender, nftId); - vm.stopPrank(); - } - - function testRevertIfApproveAsNonOwner( - address _flowSender, - address _flowReceiver, - address _approver, - address _approvedAccount - ) public { - _assumeSenderNEQReceiverAndNeitherAreZeroAddress(_flowSender, _flowReceiver); - /// @dev _flowSender is owner of outflow NFT - vm.assume(_approver != _flowSender); - vm.assume(_approvedAccount != _flowSender); - - uint256 nftId = _helperGetNFTID(address(superTokenMock), _flowSender, _flowReceiver); - flowNFTBaseMock.mockMint(address(superTokenMock), _flowSender, _flowReceiver); - vm.expectRevert(IFlowNFTBase.CFA_NFT_APPROVE_CALLER_NOT_OWNER_OR_APPROVED_FOR_ALL.selector); - vm.startPrank(_approver); - flowNFTBaseMock.approve(_approvedAccount, nftId); - vm.stopPrank(); - } - - function testRevertIfTransferFrom(address _flowSender, address _flowReceiver) public { - _assumeSenderNEQReceiverAndNeitherAreZeroAddress(_flowSender, _flowReceiver); - uint256 nftId = _helperGetNFTID(address(superTokenMock), _flowSender, _flowReceiver); - flowNFTBaseMock.mockMint(address(superTokenMock), _flowSender, _flowReceiver); - - _helperRevertIfTransferFrom( - flowNFTBaseMock, - _flowSender, - _flowSender, - _flowReceiver, - nftId, - IFlowNFTBase.CFA_NFT_TRANSFER_IS_NOT_ALLOWED.selector - ); - } - - function testRevertIfSafeTransferFrom(address _flowSender, address _flowReceiver) public { - _assumeSenderNEQReceiverAndNeitherAreZeroAddress(_flowSender, _flowReceiver); - uint256 nftId = _helperGetNFTID(address(superTokenMock), _flowSender, _flowReceiver); - flowNFTBaseMock.mockMint(address(superTokenMock), _flowSender, _flowReceiver); - - _helperRevertIfSafeTransferFrom( - flowNFTBaseMock, - _flowSender, - _flowSender, - _flowReceiver, - nftId, - IFlowNFTBase.CFA_NFT_TRANSFER_IS_NOT_ALLOWED.selector - ); - } - - function testRevertIfTransferFromWithData(address _flowSender, address _flowReceiver) public { - _assumeSenderNEQReceiverAndNeitherAreZeroAddress(_flowSender, _flowReceiver); - uint256 nftId = _helperGetNFTID(address(superTokenMock), _flowSender, _flowReceiver); - flowNFTBaseMock.mockMint(address(superTokenMock), _flowSender, _flowReceiver); - - _helperRevertIfSafeTransferFrom( - flowNFTBaseMock, - _flowSender, - _flowSender, - _flowReceiver, - nftId, - "0x", - IFlowNFTBase.CFA_NFT_TRANSFER_IS_NOT_ALLOWED.selector - ); - } - - function testRevertIfTransferFromAsNonOwner(address _flowSender, address _flowReceiver) public { - _assumeSenderNEQReceiverAndNeitherAreZeroAddress(_flowSender, _flowReceiver); - uint256 nftId = _helperGetNFTID(address(superTokenMock), _flowSender, _flowReceiver); - flowNFTBaseMock.mockMint(address(superTokenMock), _flowSender, _flowReceiver); - - _helperRevertIfTransferFrom( - flowNFTBaseMock, - _flowReceiver, - _flowSender, - _flowReceiver, - nftId, - IFlowNFTBase.CFA_NFT_TRANSFER_CALLER_NOT_OWNER_OR_APPROVED_FOR_ALL.selector - ); - } - - function testRevertIfSafeTransferFromAsNonOwner(address _flowSender, address _flowReceiver) public { - _assumeSenderNEQReceiverAndNeitherAreZeroAddress(_flowSender, _flowReceiver); - uint256 nftId = _helperGetNFTID(address(superTokenMock), _flowSender, _flowReceiver); - flowNFTBaseMock.mockMint(address(superTokenMock), _flowSender, _flowReceiver); - - _helperRevertIfSafeTransferFrom( - flowNFTBaseMock, - _flowReceiver, - _flowSender, - _flowReceiver, - nftId, - IFlowNFTBase.CFA_NFT_TRANSFER_CALLER_NOT_OWNER_OR_APPROVED_FOR_ALL.selector - ); - } - - function testRevertIfTransferFromWithDataAsNonOwner(address _flowSender, address _flowReceiver) public { - _assumeSenderNEQReceiverAndNeitherAreZeroAddress(_flowSender, _flowReceiver); - uint256 nftId = _helperGetNFTID(address(superTokenMock), _flowSender, _flowReceiver); - flowNFTBaseMock.mockMint(address(superTokenMock), _flowSender, _flowReceiver); - - _helperRevertIfSafeTransferFrom( - flowNFTBaseMock, - _flowReceiver, - _flowSender, - _flowReceiver, - nftId, - "0x", - IFlowNFTBase.CFA_NFT_TRANSFER_CALLER_NOT_OWNER_OR_APPROVED_FOR_ALL.selector - ); - } - - /*////////////////////////////////////////////////////////////////////////// - Passing Tests - //////////////////////////////////////////////////////////////////////////*/ - function testContractSupportsExpectedInterfaces() public view { - assertEq(flowNFTBaseMock.supportsInterface(type(IERC165).interfaceId), true); - assertEq(flowNFTBaseMock.supportsInterface(type(IERC721).interfaceId), true); - assertEq(flowNFTBaseMock.supportsInterface(type(IERC721Metadata).interfaceId), true); - } - - function testNFTBalanceOfIsAlwaysOne(address _owner) public view { - assertEq(flowNFTBaseMock.balanceOf(_owner), 1); - } - - function testHostIsProperlySetInConstructor() public view { - assertEq(address(flowNFTBaseMock.HOST()), address(sf.host)); - } - - function testCFAv1IsProperlySetInConstructor() public view { - assertEq(address(flowNFTBaseMock.CONSTANT_FLOW_AGREEMENT_V1()), address(sf.cfa)); - } - - function testGDAv1IsProperlySetInConstructor() public view { - assertEq(address(flowNFTBaseMock.GENERAL_DISTRIBUTION_AGREEMENT_V1()), address(sf.gda)); - } - - function testNFTMetadataIsProperlyInitialized() public view { - assertEq(flowNFTBaseMock.name(), NAME); - assertEq(flowNFTBaseMock.symbol(), SYMBOL); - } - - function testTriggerMetadataUpdate(uint256 tokenId) public { - _assertEventMetadataUpdate(address(flowNFTBaseMock), tokenId); - flowNFTBaseMock.triggerMetadataUpdate(tokenId); - } - - function testTokenURI(uint256 tokenId) public view { - assertEq(flowNFTBaseMock.tokenURI(tokenId), string(abi.encodePacked("tokenId=", tokenId.toString()))); - } - - function testApprove(address _flowSender, address _flowReceiver, address _approvedAccount) - public - virtual - returns (uint256 nftId) - { - _assumeSenderNEQReceiverAndNeitherAreZeroAddress(_flowSender, _flowReceiver); - vm.assume(_flowSender != _approvedAccount); - - nftId = _helperGetNFTID(address(superTokenMock), _flowSender, _flowReceiver); - flowNFTBaseMock.mockMint(address(superTokenMock), _flowSender, _flowReceiver); - - _assertEventApproval(address(flowNFTBaseMock), _flowSender, _approvedAccount, nftId); - - vm.startPrank(_flowSender); - flowNFTBaseMock.approve(_approvedAccount, nftId); - vm.stopPrank(); - - _assertApprovalIsExpected(flowNFTBaseMock, nftId, _approvedAccount); - } - - /*////////////////////////////////////////////////////////////////////////// - Assertion Helpers - //////////////////////////////////////////////////////////////////////////*/ - function _assertNFTFlowDataStateIsExpected( - uint256 _tokenId, - address _expectedSuperToken, - address _expectedFlowSender, - uint32 _expectedFlowStartDate, - address _expectedFlowReceiver - ) public view { - FlowNFTBase.FlowNFTData memory flowData = constantOutflowNFT.flowDataByTokenId(_tokenId); - - assertEq(flowData.superToken, _expectedSuperToken); - - // assert flow sender is equal to expected flow sender - assertEq(flowData.flowSender, _expectedFlowSender); - - // assert flow start date is equal to expected flow start date - assertEq(flowData.flowStartDate, _expectedFlowStartDate); - - // assert flow sender is equal to expected flow sender - assertEq(flowData.flowReceiver, _expectedFlowReceiver); - - // assert owner of outflow nft equal to expected flow sender - _assertOwnerOfIsExpected( - constantOutflowNFT, _tokenId, _expectedFlowSender, "ConstantOutflowNFT: owner of COF nft not as expected" - ); - - // assert owner of inflow nft equal to expected flow receiver - _assertOwnerOfIsExpected( - constantInflowNFT, _tokenId, _expectedFlowReceiver, "ConstantInflowNFT: owner of COF nft not as expected" - ); - } - - function _assertNFTFlowDataStateIsEmpty(uint256 _tokenId) public view { - _assertNFTFlowDataStateIsExpected(_tokenId, address(0), address(0), 0, address(0)); - } - - /*////////////////////////////////////////////////////////////////////////// - Helper Functions - //////////////////////////////////////////////////////////////////////////*/ - function _helperGetNFTID(address _superToken, address _flowSender, address _flowReceiver) - public - view - returns (uint256) - { - return constantOutflowNFT.getTokenId(_superToken, _flowSender, _flowReceiver); - } - - function _helperCreateFlowAndAssertNFTInvariants(address _flowSender, address _flowReceiver, int96 _flowRate) - public - { - uint256 nftId = _helperGetNFTID(address(superTokenMock), _flowSender, _flowReceiver); - - _assertEventTransfer(address(constantOutflowNFT), address(0), _flowSender, nftId); - - _assertEventTransfer(address(constantInflowNFT), address(0), _flowReceiver, nftId); - - vm.startPrank(_flowSender); - superTokenMock.createFlow(_flowReceiver, _flowRate); - vm.stopPrank(); - _assertNFTFlowDataStateIsExpected( - nftId, address(superTokenMock), _flowSender, uint32(block.timestamp), _flowReceiver - ); - - (uint256 timestamp, int96 flowRate,,) = sf.cfa.getFlow(superTokenMock, _flowSender, _flowReceiver); - assertEq(timestamp, block.timestamp); - assertEq(flowRate, _flowRate); - } - - /*////////////////////////////////////////////////////////////////////////// - Assume Helpers - //////////////////////////////////////////////////////////////////////////*/ - function _assumeSenderNEQReceiverAndNeitherAreZeroAddress(address _flowSender, address _flowReceiver) public pure { - vm.assume(_flowSender != address(0)); - vm.assume(_flowReceiver != address(0)); - vm.assume(_flowSender != _flowReceiver); - } - - function _assumeCallerIsNotOtherAddress(address caller, address otherAddress) public pure { - vm.assume(caller != otherAddress); - } -} - -/// @title CFAv1NFTUpgradabilityTest -/// @author Superfluid -/// @notice Used for testing storage layout and upgradability of CFAv1 NFT contracts -contract CFAv1NFTUpgradabilityTest is FlowNFTBaseTest { - function setUp() public override { - super.setUp(); - } - - /*////////////////////////////////////////////////////////////////////////// - Storage Layout Tests - //////////////////////////////////////////////////////////////////////////*/ - function testFlowNFTBaseStorageLayout() public { - FlowNFTBaseStorageLayoutMock flowNFTBaseStorageLayoutMock = - new FlowNFTBaseStorageLayoutMock(sf.host, sf.cfa, sf.gda); - flowNFTBaseStorageLayoutMock.validateStorageLayout(); - } - - function testConstantInflowNFTStorageLayout() public { - ConstantInflowNFTStorageLayoutMock constantInflowNFTBaseStorageLayoutMock = - new ConstantInflowNFTStorageLayoutMock(sf.host, sf.cfa, sf.gda, constantOutflowNFT); - constantInflowNFTBaseStorageLayoutMock.validateStorageLayout(); - } - - function testConstantOutflowNFTStorageLayout() public { - ConstantOutflowNFTStorageLayoutMock constantOutflowNFTBaseStorageLayoutMock = - new ConstantOutflowNFTStorageLayoutMock(sf.host, sf.cfa, sf.gda, constantInflowNFT); - constantOutflowNFTBaseStorageLayoutMock.validateStorageLayout(); - } - - /*////////////////////////////////////////////////////////////////////////// - Revert Tests - //////////////////////////////////////////////////////////////////////////*/ - function testRevertFlowNFTContractsCannotBeUpgradedByNonSuperTokenFactory(address notSuperTokenFactory) public { - vm.assume(notSuperTokenFactory != address(sf.superTokenFactory)); - ConstantOutflowNFT newOutflowLogic = new ConstantOutflowNFT(sf.host, sf.cfa, sf.gda, constantInflowNFT); - vm.expectRevert(IFlowNFTBase.CFA_NFT_ONLY_SUPER_TOKEN_FACTORY.selector); - vm.prank(notSuperTokenFactory); - constantOutflowNFT.updateCode(address(newOutflowLogic)); - - ConstantInflowNFT newInflowLogic = new ConstantInflowNFT(sf.host, sf.cfa, sf.gda, constantOutflowNFT); - vm.expectRevert(IFlowNFTBase.CFA_NFT_ONLY_SUPER_TOKEN_FACTORY.selector); - vm.prank(notSuperTokenFactory); - constantInflowNFT.updateCode(address(newInflowLogic)); - } - - /*////////////////////////////////////////////////////////////////////////// - Passing Tests - //////////////////////////////////////////////////////////////////////////*/ - function testFlowNFTContractsCanBeUpgradedBySuperTokenFactory() public { - ConstantOutflowNFT newOutflowLogic = new ConstantOutflowNFT(sf.host, sf.cfa, sf.gda, constantInflowNFT); - vm.prank(address(sf.superTokenFactory)); - constantOutflowNFT.updateCode(address(newOutflowLogic)); - - ConstantInflowNFT newInflowLogic = new ConstantInflowNFT(sf.host, sf.cfa, sf.gda, constantOutflowNFT); - vm.prank(address(sf.superTokenFactory)); - constantInflowNFT.updateCode(address(newInflowLogic)); - } -} diff --git a/packages/ethereum-contracts/test/foundry/superfluid/PoolNFTBase.t.sol b/packages/ethereum-contracts/test/foundry/superfluid/PoolNFTBase.t.sol index a54ed4c924..03fbf57e29 100644 --- a/packages/ethereum-contracts/test/foundry/superfluid/PoolNFTBase.t.sol +++ b/packages/ethereum-contracts/test/foundry/superfluid/PoolNFTBase.t.sol @@ -10,12 +10,9 @@ import { PoolMemberNFTStorageLayoutMock } from "./PoolNFTUpgradabilityMock.t.sol"; import { IPoolNFTBase, PoolNFTBase } from "../../../contracts/agreements/gdav1/PoolNFTBase.sol"; -import { ConstantOutflowNFT, IConstantOutflowNFT } from "../../../contracts/superfluid/ConstantOutflowNFT.sol"; -import { ConstantInflowNFT, IConstantInflowNFT } from "../../../contracts/superfluid/ConstantInflowNFT.sol"; import { TestToken } from "../../../contracts/utils/TestToken.sol"; import { PoolAdminNFT, IPoolAdminNFT } from "../../../contracts/agreements/gdav1/PoolAdminNFT.sol"; import { PoolMemberNFT, IPoolMemberNFT } from "../../../contracts/agreements/gdav1/PoolMemberNFT.sol"; -import { ConstantOutflowNFTMock, ConstantInflowNFTMock } from "./CFAv1NFTMock.t.sol"; import { PoolNFTBaseMock } from "./PoolNFTMock.t.sol"; import { ISuperfluidPool } from "../../../contracts/agreements/gdav1/SuperfluidPool.sol"; import { ERC721IntegrationTest } from "./ERC721.t.sol"; diff --git a/packages/ethereum-contracts/test/foundry/superfluid/SuperToken.t.sol b/packages/ethereum-contracts/test/foundry/superfluid/SuperToken.t.sol index 1c2f031429..02727ad7aa 100644 --- a/packages/ethereum-contracts/test/foundry/superfluid/SuperToken.t.sol +++ b/packages/ethereum-contracts/test/foundry/superfluid/SuperToken.t.sol @@ -4,9 +4,8 @@ pragma solidity ^0.8.23; import { Test } from "forge-std/Test.sol"; import { UUPSProxy } from "../../../contracts/upgradability/UUPSProxy.sol"; import { UUPSProxiable } from "../../../contracts/upgradability/UUPSProxiable.sol"; -import { IERC20, ISuperToken, SuperToken } from "../../../contracts/superfluid/SuperToken.sol"; -import { ConstantOutflowNFT, IConstantOutflowNFT } from "../../../contracts/superfluid/ConstantOutflowNFT.sol"; -import { ConstantInflowNFT, IConstantInflowNFT } from "../../../contracts/superfluid/ConstantInflowNFT.sol"; +import { IERC20, ISuperToken, SuperToken, IConstantOutflowNFT, IConstantInflowNFT } + from "../../../contracts/superfluid/SuperToken.sol"; import { PoolAdminNFT, IPoolAdminNFT } from "../../../contracts/agreements/gdav1/PoolAdminNFT.sol"; import { PoolMemberNFT, IPoolMemberNFT } from "../../../contracts/agreements/gdav1/PoolMemberNFT.sol"; import { FoundrySuperfluidTester } from "../FoundrySuperfluidTester.sol"; @@ -69,71 +68,6 @@ contract SuperTokenIntegrationTest is FoundrySuperfluidTester { ); } - function testRevertSuperTokenUpdateCodeWrongNFTProxies() public { - UUPSProxy cifProxy = new UUPSProxy(); - UUPSProxy cofProxy = new UUPSProxy(); - UUPSProxy paProxy = new UUPSProxy(); - UUPSProxy pmProxy = new UUPSProxy(); - - ConstantInflowNFT cifNFTLogic = - new ConstantInflowNFT(sf.host, sf.cfa, sf.gda, IConstantOutflowNFT(address(cofProxy))); - ConstantOutflowNFT cofNFTLogic = - new ConstantOutflowNFT(sf.host, sf.cfa, sf.gda, IConstantInflowNFT(address(cifProxy))); - PoolAdminNFT paNFTLogic = new PoolAdminNFT(sf.host, sf.gda); - PoolMemberNFT pmNFTLogic = new PoolMemberNFT(sf.host, sf.gda); - - cifNFTLogic.castrate(); - cofNFTLogic.castrate(); - paNFTLogic.castrate(); - pmNFTLogic.castrate(); - - cifProxy.initializeProxy(address(cifNFTLogic)); - cofProxy.initializeProxy(address(cofNFTLogic)); - paProxy.initializeProxy(address(paNFTLogic)); - pmProxy.initializeProxy(address(pmNFTLogic)); - - ConstantInflowNFT(address(cofProxy)).initialize("Constant Outflow NFT", "COF"); - ConstantOutflowNFT(address(cifProxy)).initialize("Constant Inflow NFT", "CIF"); - PoolAdminNFT(address(paProxy)).initialize("Pool Admin NFT", "PA"); - PoolMemberNFT(address(pmProxy)).initialize("Pool Member NFT", "PM"); - - // all nft proxies incorrect - SuperToken superTokenLogic = new SuperToken( - sf.host, - ConstantOutflowNFT(address(cofProxy)), - ConstantInflowNFT(address(cifProxy)), - PoolAdminNFT(address(paProxy)), - PoolMemberNFT(address(pmProxy)) - ); - vm.prank(address(sf.host)); - vm.expectRevert(ISuperToken.SUPER_TOKEN_NFT_PROXY_ADDRESS_CHANGED.selector); - UUPSProxiable(address(superToken)).updateCode(address(superTokenLogic)); - - // inflow nft proxy incorrect - superTokenLogic = new SuperToken( - sf.host, - superToken.CONSTANT_OUTFLOW_NFT(), - ConstantInflowNFT(address(cifProxy)), - superToken.POOL_ADMIN_NFT(), - superToken.POOL_MEMBER_NFT() - ); - vm.prank(address(sf.host)); - vm.expectRevert(ISuperToken.SUPER_TOKEN_NFT_PROXY_ADDRESS_CHANGED.selector); - UUPSProxiable(address(superToken)).updateCode(address(superTokenLogic)); - - // outflow nft proxy incorrect - superTokenLogic = new SuperToken( - sf.host, - ConstantOutflowNFT(address(cofProxy)), - superToken.CONSTANT_INFLOW_NFT(), - superToken.POOL_ADMIN_NFT(), - superToken.POOL_MEMBER_NFT() - ); - vm.prank(address(sf.host)); - vm.expectRevert(ISuperToken.SUPER_TOKEN_NFT_PROXY_ADDRESS_CHANGED.selector); - UUPSProxiable(address(superToken)).updateCode(address(superTokenLogic)); - } - function testInitializeSuperTokenWithAndWithoutAdmin(address _admin) public { (, ISuperToken localSuperToken) = sfDeployer.deployWrapperSuperToken("FTT", "FTT", 18, type(uint256).max, _admin); diff --git a/packages/ethereum-contracts/test/foundry/superfluid/SuperTokenFactory.t.sol b/packages/ethereum-contracts/test/foundry/superfluid/SuperTokenFactory.t.sol index e164348d98..068871c872 100644 --- a/packages/ethereum-contracts/test/foundry/superfluid/SuperTokenFactory.t.sol +++ b/packages/ethereum-contracts/test/foundry/superfluid/SuperTokenFactory.t.sol @@ -3,11 +3,9 @@ pragma solidity ^0.8.23; import { FoundrySuperfluidTester } from "../FoundrySuperfluidTester.sol"; import { SuperTokenFactory } from "../../../contracts/superfluid/SuperTokenFactory.sol"; -import { ConstantOutflowNFT, IConstantOutflowNFT } from "../../../contracts/superfluid/ConstantOutflowNFT.sol"; -import { ConstantInflowNFT, IConstantInflowNFT } from "../../../contracts/superfluid/ConstantInflowNFT.sol"; import { PoolAdminNFT, IPoolAdminNFT } from "../../../contracts/agreements/gdav1/PoolAdminNFT.sol"; import { PoolMemberNFT, IPoolMemberNFT } from "../../../contracts/agreements/gdav1/PoolMemberNFT.sol"; -import { ISuperToken, SuperToken } from "../../../contracts/superfluid/SuperToken.sol"; +import { ISuperToken, SuperToken, IConstantOutflowNFT, IConstantInflowNFT } from "../../../contracts/superfluid/SuperToken.sol"; import { UUPSProxiable } from "../../../contracts/upgradability/UUPSProxiable.sol"; contract SuperTokenFactoryTest is FoundrySuperfluidTester { @@ -20,32 +18,18 @@ contract SuperTokenFactoryTest is FoundrySuperfluidTester { function testUpdateCodeSetsNewContracts() public { SuperToken newSuperTokenLogic = new SuperToken( sf.host, - superToken.CONSTANT_OUTFLOW_NFT(), - superToken.CONSTANT_INFLOW_NFT(), + IConstantOutflowNFT(address(0)), + IConstantInflowNFT(address(0)), superToken.POOL_ADMIN_NFT(), superToken.POOL_MEMBER_NFT() ); - ConstantOutflowNFT newConstantOutflowNFTLogic = new ConstantOutflowNFT( - sf.host, sf.cfa, sf.gda, IConstantInflowNFT(address(superToken.CONSTANT_INFLOW_NFT())) - ); - ConstantInflowNFT newConstantInflowNFTLogic = new ConstantInflowNFT( - sf.host, sf.cfa, sf.gda, IConstantOutflowNFT(address(superToken.CONSTANT_OUTFLOW_NFT())) - ); PoolAdminNFT newPoolAdminNFTLogic = new PoolAdminNFT(sf.host, sf.gda); PoolMemberNFT newPoolMemberNFTLogic = new PoolMemberNFT(sf.host, sf.gda); - assertEq( - UUPSProxiable(address(superToken.CONSTANT_OUTFLOW_NFT())).getCodeAddress(), - address(sf.superTokenFactory.CONSTANT_OUTFLOW_NFT_LOGIC()) - ); - assertEq( - UUPSProxiable(address(superToken.CONSTANT_INFLOW_NFT())).getCodeAddress(), - address(sf.superTokenFactory.CONSTANT_INFLOW_NFT_LOGIC()) - ); SuperTokenFactory newSuperTokenFactoryLogic = new SuperTokenFactory( sf.host, newSuperTokenLogic, - newConstantOutflowNFTLogic, - newConstantInflowNFTLogic, + IConstantOutflowNFT(address(0)), + IConstantInflowNFT(address(0)), newPoolAdminNFTLogic, newPoolMemberNFTLogic ); @@ -56,11 +40,5 @@ contract SuperTokenFactoryTest is FoundrySuperfluidTester { } sf.superTokenFactory.updateCode(address(newSuperTokenFactoryLogic)); vm.stopPrank(); - - // We only assert this if the protocol is upgradable - if (!sf.host.NON_UPGRADABLE_DEPLOYMENT()) { - assertEq(address(newConstantOutflowNFTLogic), address(sf.superTokenFactory.CONSTANT_OUTFLOW_NFT_LOGIC())); - assertEq(address(newConstantInflowNFTLogic), address(sf.superTokenFactory.CONSTANT_INFLOW_NFT_LOGIC())); - } } } diff --git a/packages/hot-fuzz/hot-fuzz b/packages/hot-fuzz/hot-fuzz index 2aafee1a4d..587abe7dfa 100755 --- a/packages/hot-fuzz/hot-fuzz +++ b/packages/hot-fuzz/hot-fuzz @@ -43,7 +43,7 @@ cryticArgs: [ "--compile-force-framework=${CRYTIC_COMPILE_FRAMEWORK}", "--foundry-out-directory=${FOUNDRY_ROOT}/${FOUNDRY_OUT:-out}", # "--export-dir=${PROJECT_DIR}/crytic-export", TODO unfortunately this doesn't work - "--compile-libraries=(CFAv1ForwarderDeployerLibrary,0xf01),(GDAv1ForwarderDeployerLibrary,0xf02),(IDAv1ForwarderDeployerLibrary,0xf03),(ProxyDeployerLibrary,0xf04),(SlotsBitmapLibrary,0xf05),(SuperfluidCFAv1DeployerLibrary,0xf06),(SuperfluidFlowNFTLogicDeployerLibrary,0xf07),(SuperfluidGDAv1DeployerLibrary,0xf08),(SuperfluidGovDeployerLibrary,0xf09),(SuperfluidHostDeployerLibrary,0xf0a),(SuperfluidIDAv1DeployerLibrary,0xf0b),(SuperfluidPeripheryDeployerLibrary,0xf0c),(SuperfluidPoolDeployerLibrary,0xf0d),(SuperfluidPoolLogicDeployerLibrary,0xf0e),(SuperfluidPoolNFTLogicDeployerLibrary,0xf0f),(SuperTokenDeployerLibrary,0xf10),(SuperTokenFactoryDeployerLibrary,0xf11),(TokenDeployerLibrary,0xf12),(SuperfluidDMZForwarderDeployerLibrary,0xf13)" + "--compile-libraries=(CFAv1ForwarderDeployerLibrary,0xf01),(GDAv1ForwarderDeployerLibrary,0xf02),(IDAv1ForwarderDeployerLibrary,0xf03),(ProxyDeployerLibrary,0xf04),(SlotsBitmapLibrary,0xf05),(SuperfluidCFAv1DeployerLibrary,0xf06),(SuperfluidGDAv1DeployerLibrary,0xf08),(SuperfluidGovDeployerLibrary,0xf09),(SuperfluidHostDeployerLibrary,0xf0a),(SuperfluidIDAv1DeployerLibrary,0xf0b),(SuperfluidPeripheryDeployerLibrary,0xf0c),(SuperfluidPoolDeployerLibrary,0xf0d),(SuperfluidPoolLogicDeployerLibrary,0xf0e),(SuperfluidPoolNFTLogicDeployerLibrary,0xf0f),(SuperTokenDeployerLibrary,0xf10),(SuperTokenFactoryDeployerLibrary,0xf11),(TokenDeployerLibrary,0xf12),(SuperfluidDMZForwarderDeployerLibrary,0xf13)" ] deployContracts: [ ["0xf01", "CFAv1ForwarderDeployerLibrary"], @@ -52,7 +52,6 @@ deployContracts: [ ["0xf04", "ProxyDeployerLibrary"], ["0xf05", "SlotsBitmapLibrary"], ["0xf06", "SuperfluidCFAv1DeployerLibrary"], -["0xf07", "SuperfluidFlowNFTLogicDeployerLibrary"], ["0xf08", "SuperfluidGDAv1DeployerLibrary"], ["0xf09", "SuperfluidGovDeployerLibrary"], ["0xf0a", "SuperfluidHostDeployerLibrary"], diff --git a/packages/hot-fuzz/package.json b/packages/hot-fuzz/package.json index 98dcd72656..30237032c8 100644 --- a/packages/hot-fuzz/package.json +++ b/packages/hot-fuzz/package.json @@ -25,7 +25,7 @@ "@superfluid-finance/ethereum-contracts": "1.8.0" }, "devDependencies": { - "@superfluid-finance/ethereum-contracts": "^1.10.0" + "@superfluid-finance/ethereum-contracts": "^1.11.0" }, "license": "AGPL-3.0", "bugs": { diff --git a/packages/js-sdk/package.json b/packages/js-sdk/package.json index 1f665a8007..76003009a8 100644 --- a/packages/js-sdk/package.json +++ b/packages/js-sdk/package.json @@ -43,13 +43,13 @@ "cloc": "sh tasks/cloc.sh" }, "dependencies": { - "@superfluid-finance/metadata": "^1.3.1", + "@superfluid-finance/metadata": "^1.4.0", "@truffle/contract": "4.6.31", "auto-bind": "4.0.0", "node-fetch": "2.7.0" }, "devDependencies": { - "@superfluid-finance/ethereum-contracts": "^1.10.0", + "@superfluid-finance/ethereum-contracts": "^1.11.0", "chai-as-promised": "^7.1.1", "webpack": "^5.90.1", "webpack-bundle-analyzer": "^4.10.1", diff --git a/packages/metadata/CHANGELOG.md b/packages/metadata/CHANGELOG.md index 5082807fa4..60e1098462 100644 --- a/packages/metadata/CHANGELOG.md +++ b/packages/metadata/CHANGELOG.md @@ -3,6 +3,16 @@ All notable changes to the metadata will be documented in this file. This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + + +## [v1.4.0] +### Changed +- Removed FlowNFTs + +## [v1.3.0] +### Added +- VestingScheduler v2 + ## [v1.2.6] ### Changed - Added native token wrapper address for base-sepolia diff --git a/packages/metadata/main/networks/list.cjs b/packages/metadata/main/networks/list.cjs index 660750ca0b..1801ca457b 100644 --- a/packages/metadata/main/networks/list.cjs +++ b/packages/metadata/main/networks/list.cjs @@ -21,8 +21,6 @@ module.exports = "gdaV1": "0x51f571D934C59185f13d17301a36c07A2268B814", "gdaV1Forwarder": "0x6DA13Bde224A05a288748d857b9e7DDEffd1dE08", "superTokenFactory": "0x1C92042426B6bAAe497bEf461B6d8342D03aEc92", - "constantOutflowNFT": "0x49583f57EFeBe733EC872c5d5437116085a3eE3c", - "constantInflowNFT": "0x67d0Efab10b390206b356BA7FB453Ab56AAB7480", "superfluidLoader": "0x36446Ec9C7909608065dEB7f491701d815B880e5", "autowrap": { "manager": "0x30aE282CF477E2eF28B14d0125aCEAd57Fe1d7a1", @@ -68,8 +66,6 @@ module.exports = "gdaV1": "0x9823364056BcA85Dc3c4a3b96801314D082C8Eb9", "gdaV1Forwarder": "0x6DA13Bde224A05a288748d857b9e7DDEffd1dE08", "superTokenFactory": "0x254C2e152E8602839D288A7bccdf3d0974597193", - "constantOutflowNFT": "0xfBE332e001D6b54e1F4B63c2343B8E7746d99Ece", - "constantInflowNFT": "0xC95346B7394009ccEfaA62Eca28797804B2bCF1C", "superfluidLoader": "0x862F59081FC7907F940bE4227b9f485d700E6cdD", "existentialNFTCloneFactory": "0x0D1F0d4629B722b4dFabd195c14F12f2095418d9" }, @@ -106,8 +102,6 @@ module.exports = "gdaV1": "0xd453d38A001B47271488886532f1CCeAbf0c7eF3", "gdaV1Forwarder": "0x6DA13Bde224A05a288748d857b9e7DDEffd1dE08", "superTokenFactory": "0xfcF0489488397332579f35b0F711BE570Da0E8f5", - "constantOutflowNFT": "0xda6db863cb2EE39b196edB8159c38A1ed5c55344", - "constantInflowNFT": "0x87E00Dced5670e01BEe33a9a724B1dac790937eF", "flowScheduler": "0x73B1Ce21d03ad389C2A291B1d1dc4DAFE7B5Dc68", "vestingScheduler": "0x27444c0235a4D921F3106475faeba0B5e7ABDD7a", "vestingSchedulerV2": "0x3aa62b96f44D0f8892BeBBC819DE8e02E9DE69A8", @@ -161,8 +155,6 @@ module.exports = "idaV1": "0x296556422F44F19E5d216CBf98348A03BDc445E7", "gdaV1": "0x93fA9B627eE016990Fe5e654F923aaE8a480a75b", "gdaV1Forwarder": "0x6DA13Bde224A05a288748d857b9e7DDEffd1dE08", - "constantOutflowNFT": "0xEdB0A24DDb09cFeffF0C5348EB5d6D1C439d36bf", - "constantInflowNFT": "0x1DA4e4F848Cd4D0f528c2D0F19F41226BacB5489", "superfluidLoader": "0xe25603df330027d91A0BAcc3e80a7f9e84930FC6", "superTokenFactory": "0x87560833d59Be057aFc63cFFa3fc531589Ba428F" }, @@ -230,8 +222,6 @@ module.exports = "gdaV1": "0xd7992D358A20478c82dDEd98B3D8A9da46e99b82", "gdaV1Forwarder": "0x6DA13Bde224A05a288748d857b9e7DDEffd1dE08", "superTokenFactory": "0x23410e2659380784498509698ed70E414D384880", - "constantOutflowNFT": "0xfC00dEE8a980110c5608A823a5B3af3872635456", - "constantInflowNFT": "0x1497440B4E92DC4ca0F76223b28C20Cb9cB8a0f1", "superfluidLoader": "0xb688e4Da3100Bcec4b5B3140C8Fb482ad15D2013", "toga": "0xb7DE52F4281a7a276E18C40F94cd93159C4A2d22", "batchLiquidator": "0x27636F8E129cdd4ccA0F30E2b4C116DDaC773bE5", @@ -293,8 +283,6 @@ module.exports = "gdaV1": "0x961dd5A052741B49B6CBf6759591f9D8576fCFb0", "gdaV1Forwarder": "0x6DA13Bde224A05a288748d857b9e7DDEffd1dE08", "superTokenFactory": "0x2C90719f25B10Fc5646c82DA3240C76Fa5BcCF34", - "constantOutflowNFT": "0x554e2bbaCF43FD87417b7201A9F1649a3ED89d68", - "constantInflowNFT": "0x55909bB8cd8276887Aae35118d60b19755201c68", "superfluidLoader": "0x444A48dA32649Ed03eeC9B9cD416748262c320E6", "toga": "0x6AEAeE5Fd4D05A741723D752D30EE4D72690A8f7", "batchLiquidator": "0xA6Cdb472e7E22Bf30ae6fB752E4a13eBF3c12165", @@ -354,8 +342,6 @@ module.exports = "gdaV1": "0x68Ae17fa7a31b86F306c383277552fd4813b0d35", "gdaV1Forwarder": "0x6DA13Bde224A05a288748d857b9e7DDEffd1dE08", "superTokenFactory": "0x8276469A443D5C6B7146BED45e2abCaD3B6adad9", - "constantOutflowNFT": "0xFb2b126660BE2fdEBa254b1F6e4348644E8482e7", - "constantInflowNFT": "0x0C6D90a98426bfD572a5c5Be572a7f6Bd1C5ED76", "superfluidLoader": "0xe8B40071df98bBEe23833905AFcF7b28fC7Ca3cb", "toga": "0xA3c8502187fD7a7118eAD59dc811281448946C8f", "batchLiquidator": "0x36Df169DBf5CE3c6f58D46f0addeF58F01381232", @@ -416,8 +402,6 @@ module.exports = "gdaV1": "0x1e299701792a2aF01408B122419d65Fd2dF0Ba02", "gdaV1Forwarder": "0x6DA13Bde224A05a288748d857b9e7DDEffd1dE08", "superTokenFactory": "0x1C21Ead77fd45C84a4c916Db7A6635D0C6FF09D6", - "constantOutflowNFT": "0x051e766e2d8dc65ae2bFCF084A50AD0447634227", - "constantInflowNFT": "0x0043d7c85C8b96a49A72A92C0B48CdC4720437d7", "superfluidLoader": "0xe8B40071df98bBEe23833905AFcF7b28fC7Ca3cb", "toga": "0xFC63B7C762B10670Eda15cF3ca3970bCDB28C9eF", "batchLiquidator": "0x6C66e5c5D201A753ff497F2e9eC5D545631854d0", @@ -477,8 +461,6 @@ module.exports = "gdaV1": "0xA7b197cD5b0cEF6d62c4A0a851E3581f5E62e4D2", "gdaV1Forwarder": "0x6DA13Bde224A05a288748d857b9e7DDEffd1dE08", "superTokenFactory": "0x464AADdBB2B80f3Cb666522EB7381bE610F638b4", - "constantOutflowNFT": "0x4247bA6C3658Fa5C0F523BAcea8D0b97aF1a175e", - "constantInflowNFT": "0x82b9D8A91A5b333b5A6e78439551ea0E7da153E3", "superfluidLoader": "0x42B709822F18595443c308c1BE5E63CbFEf06481", "toga": "0x3D9A67D5ec1E72CEcA8157e028855056786b6159", "batchLiquidator": "0xdddaD64A9Fe7709A729C4a5428617e369278e0b6", @@ -538,8 +520,6 @@ module.exports = "gdaV1": "0x3bbFA4C406719424C7f66CD97A8Fe27Af383d3e2", "gdaV1Forwarder": "0x6DA13Bde224A05a288748d857b9e7DDEffd1dE08", "superTokenFactory": "0x8bde47397301F0Cd31b9000032fD517a39c946Eb", - "constantOutflowNFT": "0xcb05535bd212eCFC4B7b9db81d6C2C768b726776", - "constantInflowNFT": "0xbF7BCcE8D60A9C3F6bFaEc9346Aa85B9f781a4e9", "superfluidLoader": "0xF353978890204756fc5fa6dfbD16a91eac9E6f4d", "toga": "0xFCD84210f5d51Cd40a30443d44d6A5500d5D10dF", "batchLiquidator": "0x5487d078CA8933e83d91d5E7AFBe3A7bfC3412d6", @@ -655,8 +635,6 @@ module.exports = "gdaV1": "0x308b7405272d11494716e30C6E972DbF6fb89555", "gdaV1Forwarder": "0x6DA13Bde224A05a288748d857b9e7DDEffd1dE08", "superTokenFactory": "0x36be86dEe6BC726Ed0Cbd170ccD2F21760BC73D9", - "constantOutflowNFT": "0xbe49ac1EadAc65dccf204D4Df81d650B50122aB2", - "constantInflowNFT": "0x0FB7694c990CF19001127391Dbe53924dd7a61c7", "superfluidLoader": "0xF0d7d1D47109bA426B9D8A3Cde1941327af1eea3", "toga": "0x9bCa3a623e7b2e248510d88B2894F54898d88F91", "batchLiquidator": "0x21d4E9fbB9DB742E6ef4f29d189a7C18B0b59136", @@ -695,8 +673,6 @@ module.exports = "gdaV1": "0xfE6c87BE05feDB2059d2EC41bA0A09826C9FD7aa", "gdaV1Forwarder": "0x6DA13Bde224A05a288748d857b9e7DDEffd1dE08", "superTokenFactory": "0xe20B9a38E0c96F61d1bA6b42a61512D56Fea1Eb3", - "constantOutflowNFT": "0xD3C78bb5a16Ea4ab584844eeb8F90Ac710c16355", - "constantInflowNFT": "0x2d51962A9EE4D3C2819EF585eab7412c2a2C31Ac", "superfluidLoader": "0x9F9EEd9Bbc38E9e0514fD9dFcc0Bca9869A9c534", "toga": "0xA87F76e99f6C8Ff8996d14f550ceF47f193D9A09", "batchLiquidator": "0x889ebeCaD5F8C34Fd96023456d0fC5cE54eb74Cb", @@ -752,8 +728,6 @@ module.exports = "idaV1": "0x4112557F0F228A18654d3C39599421DE9F61144d", "gdaV1": "0x97a9f293d7eD13f3fbD499cE684Ed4F103295a28", "gdaV1Forwarder": "0x6DA13Bde224A05a288748d857b9e7DDEffd1dE08", - "constantOutflowNFT": "0x0de05fe0fF8F5eA9475CA8425e2D05Dd38ccED84", - "constantInflowNFT": "0x8c24Fc82c8fDd763F08E654212fc27e577EbD934", "superfluidLoader": "0x7613030429E95cDFC76FE70f9573037068B51815", "toga": "0x1bF9D75d50fD828a93f69ECB06f2B85767792CEB", "batchLiquidator": "0x3024A39099D4FAE7c9eA8329FAfe05576AEd2c00", @@ -789,8 +763,6 @@ module.exports = "idaV1": "0xb19CE3e7DA9FbAf9De2526BD662A82f26421A53E", "gdaV1": "0x210a01ad187003603B2287F78579ec103Eb70D9B", "gdaV1Forwarder": "0x6DA13Bde224A05a288748d857b9e7DDEffd1dE08", - "constantOutflowNFT": "0xFC29D2db9c952D8253d1291964100C838B236DbD", - "constantInflowNFT": "0xd97b1C090B3A3512E1776197A86fddf8a437D8D1", "superfluidLoader": "0x5fb676d66eAb8E0c22Ae24C5c10eD7E4A6397c1C", "toga": "0x38ed5512Ac11926bB697F4CF4eE0DD04358E2E7e", "batchLiquidator": "0x7BCE8e8401dc98E3Da26F1D701c3C2168b8e466c", diff --git a/packages/metadata/module/networks/list.d.ts b/packages/metadata/module/networks/list.d.ts index 89c1ab04ed..d3427c81e7 100644 --- a/packages/metadata/module/networks/list.d.ts +++ b/packages/metadata/module/networks/list.d.ts @@ -12,8 +12,6 @@ interface ContractAddresses { readonly gdaV1?: string; readonly gdaV1Forwarder?: string; readonly superTokenFactory: string; - readonly constantOutflowNFT?: string; - readonly constantInflowNFT?: string; readonly superfluidLoader: string; readonly toga?: string; readonly vestingScheduler?: string; diff --git a/packages/metadata/module/networks/list.js b/packages/metadata/module/networks/list.js index 203b64c1b6..2079f1be38 100644 --- a/packages/metadata/module/networks/list.js +++ b/packages/metadata/module/networks/list.js @@ -21,8 +21,6 @@ export default "gdaV1": "0x51f571D934C59185f13d17301a36c07A2268B814", "gdaV1Forwarder": "0x6DA13Bde224A05a288748d857b9e7DDEffd1dE08", "superTokenFactory": "0x1C92042426B6bAAe497bEf461B6d8342D03aEc92", - "constantOutflowNFT": "0x49583f57EFeBe733EC872c5d5437116085a3eE3c", - "constantInflowNFT": "0x67d0Efab10b390206b356BA7FB453Ab56AAB7480", "superfluidLoader": "0x36446Ec9C7909608065dEB7f491701d815B880e5", "autowrap": { "manager": "0x30aE282CF477E2eF28B14d0125aCEAd57Fe1d7a1", @@ -68,8 +66,6 @@ export default "gdaV1": "0x9823364056BcA85Dc3c4a3b96801314D082C8Eb9", "gdaV1Forwarder": "0x6DA13Bde224A05a288748d857b9e7DDEffd1dE08", "superTokenFactory": "0x254C2e152E8602839D288A7bccdf3d0974597193", - "constantOutflowNFT": "0xfBE332e001D6b54e1F4B63c2343B8E7746d99Ece", - "constantInflowNFT": "0xC95346B7394009ccEfaA62Eca28797804B2bCF1C", "superfluidLoader": "0x862F59081FC7907F940bE4227b9f485d700E6cdD", "existentialNFTCloneFactory": "0x0D1F0d4629B722b4dFabd195c14F12f2095418d9" }, @@ -106,8 +102,6 @@ export default "gdaV1": "0xd453d38A001B47271488886532f1CCeAbf0c7eF3", "gdaV1Forwarder": "0x6DA13Bde224A05a288748d857b9e7DDEffd1dE08", "superTokenFactory": "0xfcF0489488397332579f35b0F711BE570Da0E8f5", - "constantOutflowNFT": "0xda6db863cb2EE39b196edB8159c38A1ed5c55344", - "constantInflowNFT": "0x87E00Dced5670e01BEe33a9a724B1dac790937eF", "flowScheduler": "0x73B1Ce21d03ad389C2A291B1d1dc4DAFE7B5Dc68", "vestingScheduler": "0x27444c0235a4D921F3106475faeba0B5e7ABDD7a", "vestingSchedulerV2": "0x3aa62b96f44D0f8892BeBBC819DE8e02E9DE69A8", @@ -161,8 +155,6 @@ export default "idaV1": "0x296556422F44F19E5d216CBf98348A03BDc445E7", "gdaV1": "0x93fA9B627eE016990Fe5e654F923aaE8a480a75b", "gdaV1Forwarder": "0x6DA13Bde224A05a288748d857b9e7DDEffd1dE08", - "constantOutflowNFT": "0xEdB0A24DDb09cFeffF0C5348EB5d6D1C439d36bf", - "constantInflowNFT": "0x1DA4e4F848Cd4D0f528c2D0F19F41226BacB5489", "superfluidLoader": "0xe25603df330027d91A0BAcc3e80a7f9e84930FC6", "superTokenFactory": "0x87560833d59Be057aFc63cFFa3fc531589Ba428F" }, @@ -230,8 +222,6 @@ export default "gdaV1": "0xd7992D358A20478c82dDEd98B3D8A9da46e99b82", "gdaV1Forwarder": "0x6DA13Bde224A05a288748d857b9e7DDEffd1dE08", "superTokenFactory": "0x23410e2659380784498509698ed70E414D384880", - "constantOutflowNFT": "0xfC00dEE8a980110c5608A823a5B3af3872635456", - "constantInflowNFT": "0x1497440B4E92DC4ca0F76223b28C20Cb9cB8a0f1", "superfluidLoader": "0xb688e4Da3100Bcec4b5B3140C8Fb482ad15D2013", "toga": "0xb7DE52F4281a7a276E18C40F94cd93159C4A2d22", "batchLiquidator": "0x27636F8E129cdd4ccA0F30E2b4C116DDaC773bE5", @@ -293,8 +283,6 @@ export default "gdaV1": "0x961dd5A052741B49B6CBf6759591f9D8576fCFb0", "gdaV1Forwarder": "0x6DA13Bde224A05a288748d857b9e7DDEffd1dE08", "superTokenFactory": "0x2C90719f25B10Fc5646c82DA3240C76Fa5BcCF34", - "constantOutflowNFT": "0x554e2bbaCF43FD87417b7201A9F1649a3ED89d68", - "constantInflowNFT": "0x55909bB8cd8276887Aae35118d60b19755201c68", "superfluidLoader": "0x444A48dA32649Ed03eeC9B9cD416748262c320E6", "toga": "0x6AEAeE5Fd4D05A741723D752D30EE4D72690A8f7", "batchLiquidator": "0xA6Cdb472e7E22Bf30ae6fB752E4a13eBF3c12165", @@ -354,8 +342,6 @@ export default "gdaV1": "0x68Ae17fa7a31b86F306c383277552fd4813b0d35", "gdaV1Forwarder": "0x6DA13Bde224A05a288748d857b9e7DDEffd1dE08", "superTokenFactory": "0x8276469A443D5C6B7146BED45e2abCaD3B6adad9", - "constantOutflowNFT": "0xFb2b126660BE2fdEBa254b1F6e4348644E8482e7", - "constantInflowNFT": "0x0C6D90a98426bfD572a5c5Be572a7f6Bd1C5ED76", "superfluidLoader": "0xe8B40071df98bBEe23833905AFcF7b28fC7Ca3cb", "toga": "0xA3c8502187fD7a7118eAD59dc811281448946C8f", "batchLiquidator": "0x36Df169DBf5CE3c6f58D46f0addeF58F01381232", @@ -416,8 +402,6 @@ export default "gdaV1": "0x1e299701792a2aF01408B122419d65Fd2dF0Ba02", "gdaV1Forwarder": "0x6DA13Bde224A05a288748d857b9e7DDEffd1dE08", "superTokenFactory": "0x1C21Ead77fd45C84a4c916Db7A6635D0C6FF09D6", - "constantOutflowNFT": "0x051e766e2d8dc65ae2bFCF084A50AD0447634227", - "constantInflowNFT": "0x0043d7c85C8b96a49A72A92C0B48CdC4720437d7", "superfluidLoader": "0xe8B40071df98bBEe23833905AFcF7b28fC7Ca3cb", "toga": "0xFC63B7C762B10670Eda15cF3ca3970bCDB28C9eF", "batchLiquidator": "0x6C66e5c5D201A753ff497F2e9eC5D545631854d0", @@ -477,8 +461,6 @@ export default "gdaV1": "0xA7b197cD5b0cEF6d62c4A0a851E3581f5E62e4D2", "gdaV1Forwarder": "0x6DA13Bde224A05a288748d857b9e7DDEffd1dE08", "superTokenFactory": "0x464AADdBB2B80f3Cb666522EB7381bE610F638b4", - "constantOutflowNFT": "0x4247bA6C3658Fa5C0F523BAcea8D0b97aF1a175e", - "constantInflowNFT": "0x82b9D8A91A5b333b5A6e78439551ea0E7da153E3", "superfluidLoader": "0x42B709822F18595443c308c1BE5E63CbFEf06481", "toga": "0x3D9A67D5ec1E72CEcA8157e028855056786b6159", "batchLiquidator": "0xdddaD64A9Fe7709A729C4a5428617e369278e0b6", @@ -538,8 +520,6 @@ export default "gdaV1": "0x3bbFA4C406719424C7f66CD97A8Fe27Af383d3e2", "gdaV1Forwarder": "0x6DA13Bde224A05a288748d857b9e7DDEffd1dE08", "superTokenFactory": "0x8bde47397301F0Cd31b9000032fD517a39c946Eb", - "constantOutflowNFT": "0xcb05535bd212eCFC4B7b9db81d6C2C768b726776", - "constantInflowNFT": "0xbF7BCcE8D60A9C3F6bFaEc9346Aa85B9f781a4e9", "superfluidLoader": "0xF353978890204756fc5fa6dfbD16a91eac9E6f4d", "toga": "0xFCD84210f5d51Cd40a30443d44d6A5500d5D10dF", "batchLiquidator": "0x5487d078CA8933e83d91d5E7AFBe3A7bfC3412d6", @@ -655,8 +635,6 @@ export default "gdaV1": "0x308b7405272d11494716e30C6E972DbF6fb89555", "gdaV1Forwarder": "0x6DA13Bde224A05a288748d857b9e7DDEffd1dE08", "superTokenFactory": "0x36be86dEe6BC726Ed0Cbd170ccD2F21760BC73D9", - "constantOutflowNFT": "0xbe49ac1EadAc65dccf204D4Df81d650B50122aB2", - "constantInflowNFT": "0x0FB7694c990CF19001127391Dbe53924dd7a61c7", "superfluidLoader": "0xF0d7d1D47109bA426B9D8A3Cde1941327af1eea3", "toga": "0x9bCa3a623e7b2e248510d88B2894F54898d88F91", "batchLiquidator": "0x21d4E9fbB9DB742E6ef4f29d189a7C18B0b59136", @@ -695,8 +673,6 @@ export default "gdaV1": "0xfE6c87BE05feDB2059d2EC41bA0A09826C9FD7aa", "gdaV1Forwarder": "0x6DA13Bde224A05a288748d857b9e7DDEffd1dE08", "superTokenFactory": "0xe20B9a38E0c96F61d1bA6b42a61512D56Fea1Eb3", - "constantOutflowNFT": "0xD3C78bb5a16Ea4ab584844eeb8F90Ac710c16355", - "constantInflowNFT": "0x2d51962A9EE4D3C2819EF585eab7412c2a2C31Ac", "superfluidLoader": "0x9F9EEd9Bbc38E9e0514fD9dFcc0Bca9869A9c534", "toga": "0xA87F76e99f6C8Ff8996d14f550ceF47f193D9A09", "batchLiquidator": "0x889ebeCaD5F8C34Fd96023456d0fC5cE54eb74Cb", @@ -752,8 +728,6 @@ export default "idaV1": "0x4112557F0F228A18654d3C39599421DE9F61144d", "gdaV1": "0x97a9f293d7eD13f3fbD499cE684Ed4F103295a28", "gdaV1Forwarder": "0x6DA13Bde224A05a288748d857b9e7DDEffd1dE08", - "constantOutflowNFT": "0x0de05fe0fF8F5eA9475CA8425e2D05Dd38ccED84", - "constantInflowNFT": "0x8c24Fc82c8fDd763F08E654212fc27e577EbD934", "superfluidLoader": "0x7613030429E95cDFC76FE70f9573037068B51815", "toga": "0x1bF9D75d50fD828a93f69ECB06f2B85767792CEB", "batchLiquidator": "0x3024A39099D4FAE7c9eA8329FAfe05576AEd2c00", @@ -789,8 +763,6 @@ export default "idaV1": "0xb19CE3e7DA9FbAf9De2526BD662A82f26421A53E", "gdaV1": "0x210a01ad187003603B2287F78579ec103Eb70D9B", "gdaV1Forwarder": "0x6DA13Bde224A05a288748d857b9e7DDEffd1dE08", - "constantOutflowNFT": "0xFC29D2db9c952D8253d1291964100C838B236DbD", - "constantInflowNFT": "0xd97b1C090B3A3512E1776197A86fddf8a437D8D1", "superfluidLoader": "0x5fb676d66eAb8E0c22Ae24C5c10eD7E4A6397c1C", "toga": "0x38ed5512Ac11926bB697F4CF4eE0DD04358E2E7e", "batchLiquidator": "0x7BCE8e8401dc98E3Da26F1D701c3C2168b8e466c", diff --git a/packages/metadata/networks.json b/packages/metadata/networks.json index 4afe442ba2..a0df12d090 100644 --- a/packages/metadata/networks.json +++ b/packages/metadata/networks.json @@ -19,8 +19,6 @@ "gdaV1": "0x51f571D934C59185f13d17301a36c07A2268B814", "gdaV1Forwarder": "0x6DA13Bde224A05a288748d857b9e7DDEffd1dE08", "superTokenFactory": "0x1C92042426B6bAAe497bEf461B6d8342D03aEc92", - "constantOutflowNFT": "0x49583f57EFeBe733EC872c5d5437116085a3eE3c", - "constantInflowNFT": "0x67d0Efab10b390206b356BA7FB453Ab56AAB7480", "superfluidLoader": "0x36446Ec9C7909608065dEB7f491701d815B880e5", "autowrap": { "manager": "0x30aE282CF477E2eF28B14d0125aCEAd57Fe1d7a1", @@ -66,8 +64,6 @@ "gdaV1": "0x9823364056BcA85Dc3c4a3b96801314D082C8Eb9", "gdaV1Forwarder": "0x6DA13Bde224A05a288748d857b9e7DDEffd1dE08", "superTokenFactory": "0x254C2e152E8602839D288A7bccdf3d0974597193", - "constantOutflowNFT": "0xfBE332e001D6b54e1F4B63c2343B8E7746d99Ece", - "constantInflowNFT": "0xC95346B7394009ccEfaA62Eca28797804B2bCF1C", "superfluidLoader": "0x862F59081FC7907F940bE4227b9f485d700E6cdD", "existentialNFTCloneFactory": "0x0D1F0d4629B722b4dFabd195c14F12f2095418d9" }, @@ -104,8 +100,6 @@ "gdaV1": "0xd453d38A001B47271488886532f1CCeAbf0c7eF3", "gdaV1Forwarder": "0x6DA13Bde224A05a288748d857b9e7DDEffd1dE08", "superTokenFactory": "0xfcF0489488397332579f35b0F711BE570Da0E8f5", - "constantOutflowNFT": "0xda6db863cb2EE39b196edB8159c38A1ed5c55344", - "constantInflowNFT": "0x87E00Dced5670e01BEe33a9a724B1dac790937eF", "flowScheduler": "0x73B1Ce21d03ad389C2A291B1d1dc4DAFE7B5Dc68", "vestingScheduler": "0x27444c0235a4D921F3106475faeba0B5e7ABDD7a", "vestingSchedulerV2": "0x3aa62b96f44D0f8892BeBBC819DE8e02E9DE69A8", @@ -159,8 +153,6 @@ "idaV1": "0x296556422F44F19E5d216CBf98348A03BDc445E7", "gdaV1": "0x93fA9B627eE016990Fe5e654F923aaE8a480a75b", "gdaV1Forwarder": "0x6DA13Bde224A05a288748d857b9e7DDEffd1dE08", - "constantOutflowNFT": "0xEdB0A24DDb09cFeffF0C5348EB5d6D1C439d36bf", - "constantInflowNFT": "0x1DA4e4F848Cd4D0f528c2D0F19F41226BacB5489", "superfluidLoader": "0xe25603df330027d91A0BAcc3e80a7f9e84930FC6", "superTokenFactory": "0x87560833d59Be057aFc63cFFa3fc531589Ba428F" }, @@ -228,8 +220,6 @@ "gdaV1": "0xd7992D358A20478c82dDEd98B3D8A9da46e99b82", "gdaV1Forwarder": "0x6DA13Bde224A05a288748d857b9e7DDEffd1dE08", "superTokenFactory": "0x23410e2659380784498509698ed70E414D384880", - "constantOutflowNFT": "0xfC00dEE8a980110c5608A823a5B3af3872635456", - "constantInflowNFT": "0x1497440B4E92DC4ca0F76223b28C20Cb9cB8a0f1", "superfluidLoader": "0xb688e4Da3100Bcec4b5B3140C8Fb482ad15D2013", "toga": "0xb7DE52F4281a7a276E18C40F94cd93159C4A2d22", "batchLiquidator": "0x27636F8E129cdd4ccA0F30E2b4C116DDaC773bE5", @@ -291,8 +281,6 @@ "gdaV1": "0x961dd5A052741B49B6CBf6759591f9D8576fCFb0", "gdaV1Forwarder": "0x6DA13Bde224A05a288748d857b9e7DDEffd1dE08", "superTokenFactory": "0x2C90719f25B10Fc5646c82DA3240C76Fa5BcCF34", - "constantOutflowNFT": "0x554e2bbaCF43FD87417b7201A9F1649a3ED89d68", - "constantInflowNFT": "0x55909bB8cd8276887Aae35118d60b19755201c68", "superfluidLoader": "0x444A48dA32649Ed03eeC9B9cD416748262c320E6", "toga": "0x6AEAeE5Fd4D05A741723D752D30EE4D72690A8f7", "batchLiquidator": "0xA6Cdb472e7E22Bf30ae6fB752E4a13eBF3c12165", @@ -352,8 +340,6 @@ "gdaV1": "0x68Ae17fa7a31b86F306c383277552fd4813b0d35", "gdaV1Forwarder": "0x6DA13Bde224A05a288748d857b9e7DDEffd1dE08", "superTokenFactory": "0x8276469A443D5C6B7146BED45e2abCaD3B6adad9", - "constantOutflowNFT": "0xFb2b126660BE2fdEBa254b1F6e4348644E8482e7", - "constantInflowNFT": "0x0C6D90a98426bfD572a5c5Be572a7f6Bd1C5ED76", "superfluidLoader": "0xe8B40071df98bBEe23833905AFcF7b28fC7Ca3cb", "toga": "0xA3c8502187fD7a7118eAD59dc811281448946C8f", "batchLiquidator": "0x36Df169DBf5CE3c6f58D46f0addeF58F01381232", @@ -414,8 +400,6 @@ "gdaV1": "0x1e299701792a2aF01408B122419d65Fd2dF0Ba02", "gdaV1Forwarder": "0x6DA13Bde224A05a288748d857b9e7DDEffd1dE08", "superTokenFactory": "0x1C21Ead77fd45C84a4c916Db7A6635D0C6FF09D6", - "constantOutflowNFT": "0x051e766e2d8dc65ae2bFCF084A50AD0447634227", - "constantInflowNFT": "0x0043d7c85C8b96a49A72A92C0B48CdC4720437d7", "superfluidLoader": "0xe8B40071df98bBEe23833905AFcF7b28fC7Ca3cb", "toga": "0xFC63B7C762B10670Eda15cF3ca3970bCDB28C9eF", "batchLiquidator": "0x6C66e5c5D201A753ff497F2e9eC5D545631854d0", @@ -475,8 +459,6 @@ "gdaV1": "0xA7b197cD5b0cEF6d62c4A0a851E3581f5E62e4D2", "gdaV1Forwarder": "0x6DA13Bde224A05a288748d857b9e7DDEffd1dE08", "superTokenFactory": "0x464AADdBB2B80f3Cb666522EB7381bE610F638b4", - "constantOutflowNFT": "0x4247bA6C3658Fa5C0F523BAcea8D0b97aF1a175e", - "constantInflowNFT": "0x82b9D8A91A5b333b5A6e78439551ea0E7da153E3", "superfluidLoader": "0x42B709822F18595443c308c1BE5E63CbFEf06481", "toga": "0x3D9A67D5ec1E72CEcA8157e028855056786b6159", "batchLiquidator": "0xdddaD64A9Fe7709A729C4a5428617e369278e0b6", @@ -536,8 +518,6 @@ "gdaV1": "0x3bbFA4C406719424C7f66CD97A8Fe27Af383d3e2", "gdaV1Forwarder": "0x6DA13Bde224A05a288748d857b9e7DDEffd1dE08", "superTokenFactory": "0x8bde47397301F0Cd31b9000032fD517a39c946Eb", - "constantOutflowNFT": "0xcb05535bd212eCFC4B7b9db81d6C2C768b726776", - "constantInflowNFT": "0xbF7BCcE8D60A9C3F6bFaEc9346Aa85B9f781a4e9", "superfluidLoader": "0xF353978890204756fc5fa6dfbD16a91eac9E6f4d", "toga": "0xFCD84210f5d51Cd40a30443d44d6A5500d5D10dF", "batchLiquidator": "0x5487d078CA8933e83d91d5E7AFBe3A7bfC3412d6", @@ -653,8 +633,6 @@ "gdaV1": "0x308b7405272d11494716e30C6E972DbF6fb89555", "gdaV1Forwarder": "0x6DA13Bde224A05a288748d857b9e7DDEffd1dE08", "superTokenFactory": "0x36be86dEe6BC726Ed0Cbd170ccD2F21760BC73D9", - "constantOutflowNFT": "0xbe49ac1EadAc65dccf204D4Df81d650B50122aB2", - "constantInflowNFT": "0x0FB7694c990CF19001127391Dbe53924dd7a61c7", "superfluidLoader": "0xF0d7d1D47109bA426B9D8A3Cde1941327af1eea3", "toga": "0x9bCa3a623e7b2e248510d88B2894F54898d88F91", "batchLiquidator": "0x21d4E9fbB9DB742E6ef4f29d189a7C18B0b59136", @@ -693,8 +671,6 @@ "gdaV1": "0xfE6c87BE05feDB2059d2EC41bA0A09826C9FD7aa", "gdaV1Forwarder": "0x6DA13Bde224A05a288748d857b9e7DDEffd1dE08", "superTokenFactory": "0xe20B9a38E0c96F61d1bA6b42a61512D56Fea1Eb3", - "constantOutflowNFT": "0xD3C78bb5a16Ea4ab584844eeb8F90Ac710c16355", - "constantInflowNFT": "0x2d51962A9EE4D3C2819EF585eab7412c2a2C31Ac", "superfluidLoader": "0x9F9EEd9Bbc38E9e0514fD9dFcc0Bca9869A9c534", "toga": "0xA87F76e99f6C8Ff8996d14f550ceF47f193D9A09", "batchLiquidator": "0x889ebeCaD5F8C34Fd96023456d0fC5cE54eb74Cb", @@ -750,8 +726,6 @@ "idaV1": "0x4112557F0F228A18654d3C39599421DE9F61144d", "gdaV1": "0x97a9f293d7eD13f3fbD499cE684Ed4F103295a28", "gdaV1Forwarder": "0x6DA13Bde224A05a288748d857b9e7DDEffd1dE08", - "constantOutflowNFT": "0x0de05fe0fF8F5eA9475CA8425e2D05Dd38ccED84", - "constantInflowNFT": "0x8c24Fc82c8fDd763F08E654212fc27e577EbD934", "superfluidLoader": "0x7613030429E95cDFC76FE70f9573037068B51815", "toga": "0x1bF9D75d50fD828a93f69ECB06f2B85767792CEB", "batchLiquidator": "0x3024A39099D4FAE7c9eA8329FAfe05576AEd2c00", @@ -787,8 +761,6 @@ "idaV1": "0xb19CE3e7DA9FbAf9De2526BD662A82f26421A53E", "gdaV1": "0x210a01ad187003603B2287F78579ec103Eb70D9B", "gdaV1Forwarder": "0x6DA13Bde224A05a288748d857b9e7DDEffd1dE08", - "constantOutflowNFT": "0xFC29D2db9c952D8253d1291964100C838B236DbD", - "constantInflowNFT": "0xd97b1C090B3A3512E1776197A86fddf8a437D8D1", "superfluidLoader": "0x5fb676d66eAb8E0c22Ae24C5c10eD7E4A6397c1C", "toga": "0x38ed5512Ac11926bB697F4CF4eE0DD04358E2E7e", "batchLiquidator": "0x7BCE8e8401dc98E3Da26F1D701c3C2168b8e466c", diff --git a/packages/metadata/package.json b/packages/metadata/package.json index d3de958985..b48874142a 100644 --- a/packages/metadata/package.json +++ b/packages/metadata/package.json @@ -1,6 +1,6 @@ { "name": "@superfluid-finance/metadata", - "version": "1.3.1", + "version": "1.4.0", "description": "Superfluid Metadata", "main": "main/index.cjs", "module": "module/index.js", diff --git a/packages/sdk-core/CHANGELOG.md b/packages/sdk-core/CHANGELOG.md index ed3a55597f..256e301e42 100644 --- a/packages/sdk-core/CHANGELOG.md +++ b/packages/sdk-core/CHANGELOG.md @@ -10,6 +10,12 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm ### Changed ### Fixed +## [0.8.0] - 2024-08-01 + +### Breaking + +- Removed all FlowNFT related functionality, because deprecated from the protocol + ## [0.7.1] - 2024-06-19 ### Updated diff --git a/packages/sdk-core/package.json b/packages/sdk-core/package.json index 526ad6c16b..4b1724c92a 100644 --- a/packages/sdk-core/package.json +++ b/packages/sdk-core/package.json @@ -1,6 +1,6 @@ { "name": "@superfluid-finance/sdk-core", - "version": "0.7.1", + "version": "0.8.0", "description": "SDK Core for building with Superfluid Protocol", "homepage": "https://github.com/superfluid-finance/protocol-monorepo/tree/dev/packages/sdk-core#readme", "repository": { @@ -46,18 +46,19 @@ "generate": "run-s generate:*", "generate:ajv-validations": "ts-node scripts/ajv.ts", "generate:graphql-types": "graphql-codegen --config subgraph-codegen.yml", - "generate-graphql-schema": "yarn generate-graphql-schema:v1", - "generate-graphql-schema:local": "get-graphql-schema http://localhost:8000/subgraphs/name/superfluid-test > src/subgraph/schema.graphql", - "generate-graphql-schema:v1": "get-graphql-schema https://subgraph-endpoints.superfluid.dev/optimism-mainnet/protocol-v1 > src/subgraph/schema.graphql", - "generate-graphql-schema:dev": "get-graphql-schema https://subgraph-endpoints.superfluid.dev/optimism-sepolia/protocol-v1 > src/subgraph/schema.graphql", + "get-graphql-schema": "yarn get-graphql-schema:v1", + "get-graphql-schema:local": "get-graphql-schema http://localhost:8000/subgraphs/name/superfluid-test > src/subgraph/schema.graphql", + "get-graphql-schema:v1": "get-graphql-schema https://subgraph-endpoints.superfluid.dev/optimism-mainnet/protocol-v1 > src/subgraph/schema.graphql", + "get-graphql-schema:dev": "get-graphql-schema https://subgraph-endpoints.superfluid.dev/optimism-sepolia/protocol-v1 > src/subgraph/schema.graphql", + "get-graphql-schema:custom-url": "get-graphql-schema $1 > src/subgraph/schema.graphql", "cloc": "sh tasks/cloc.sh" }, "bugs": { "url": "https://github.com/superfluid-finance/protocol-monorepo/issues" }, "dependencies": { - "@superfluid-finance/ethereum-contracts": "^1.10.0", - "@superfluid-finance/metadata": "^1.3.1", + "@superfluid-finance/ethereum-contracts": "^1.11.0", + "@superfluid-finance/metadata": "^1.4.0", "browserify": "^17.0.0", "graphql-request": "^6.1.0", "lodash": "^4.17.21", diff --git a/packages/sdk-core/src/ConstantInflowNFT.ts b/packages/sdk-core/src/ConstantInflowNFT.ts deleted file mode 100644 index 85abb311d8..0000000000 --- a/packages/sdk-core/src/ConstantInflowNFT.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { ethers } from "ethers"; - -import FlowNFTBase from "./FlowNFTBase"; -import { - ConstantInflowNFT__factory, - IConstantInflowNFT, -} from "./typechain-types"; - -export default class ConstantInflowNFT extends FlowNFTBase { - override readonly contract: IConstantInflowNFT; - constructor(address: string) { - super(address); - this.contract = new ethers.Contract( - address, - ConstantInflowNFT__factory.abi - ) as IConstantInflowNFT; - } -} diff --git a/packages/sdk-core/src/ConstantOutflowNFT.ts b/packages/sdk-core/src/ConstantOutflowNFT.ts deleted file mode 100644 index e081da27df..0000000000 --- a/packages/sdk-core/src/ConstantOutflowNFT.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { ethers } from "ethers"; - -import FlowNFTBase from "./FlowNFTBase"; -import { - ConstantOutflowNFT__factory, - IConstantOutflowNFT, -} from "./typechain-types"; - -export default class ConstantOutflowNFT extends FlowNFTBase { - override readonly contract: IConstantOutflowNFT; - constructor(address: string) { - super(address); - this.contract = new ethers.Contract( - address, - ConstantOutflowNFT__factory.abi - ) as IConstantOutflowNFT; - } -} diff --git a/packages/sdk-core/src/ERC721Token.ts b/packages/sdk-core/src/ERC721Token.ts index f7feee9647..aafb6d5473 100644 --- a/packages/sdk-core/src/ERC721Token.ts +++ b/packages/sdk-core/src/ERC721Token.ts @@ -12,15 +12,10 @@ import { ERC721SetApprovalForAllParams, ERC721TokenURIParams, ERC721TransferFromParams, - NFTFlowData, ProviderOrSigner, } from "./interfaces"; -import { - IERC721Metadata, - IERC721Metadata__factory, - IFlowNFTBase, -} from "./typechain-types"; -import { getSanitizedTimestamp, normalizeAddress } from "./utils"; +import { IERC721Metadata, IERC721Metadata__factory } from "./typechain-types"; +import { normalizeAddress } from "./utils"; export default class ERC721MetadataToken { readonly address: string; @@ -292,19 +287,4 @@ export default class ERC721MetadataToken { ); return new Operation(txn, "UNSUPPORTED"); }; - - /** - * Sanitizes NFTFlowData, converting number to Date. - * @param params NFTFlowData - * @returns {NFTFlowData} sanitized NFTFlowData - */ - _sanitizeNFTFlowData = ( - params: IFlowNFTBase.FlowNFTDataStructOutput - ): NFTFlowData => { - return { - flowSender: params.flowSender, - flowStartDate: getSanitizedTimestamp(params.flowStartDate), - flowReceiver: params.flowReceiver, - }; - }; } diff --git a/packages/sdk-core/src/FlowNFTBase.ts b/packages/sdk-core/src/FlowNFTBase.ts deleted file mode 100644 index 9b95fd2872..0000000000 --- a/packages/sdk-core/src/FlowNFTBase.ts +++ /dev/null @@ -1,85 +0,0 @@ -import { ethers } from "ethers"; - -import ERC721MetadataToken from "./ERC721Token"; -import { SFError } from "./SFError"; -import { NFTFlowData } from "./interfaces"; -import { FlowNFTBase__factory, IFlowNFTBase } from "./typechain-types"; -import { normalizeAddress } from "./utils"; - -export default class FlowNFTBase extends ERC721MetadataToken { - override readonly contract: IFlowNFTBase; - constructor(address: string) { - super(address); - this.contract = new ethers.Contract( - address, - FlowNFTBase__factory.abi - ) as IFlowNFTBase; - } - - /** ### ConstantInflowNFT Contract Read Functions ### */ - - /** - * Returns the computed `tokenId` of a flow NFT given a sender and receiver. - * @param sender the flow sender - * @param receiver the flow receiver - * @returns - */ - getTokenId = async ({ - superToken, - sender, - receiver, - providerOrSigner, - }: { - superToken: string; - sender: string; - receiver: string; - providerOrSigner: ethers.providers.Provider | ethers.Signer; - }): Promise => { - const normalizedSuperToken = normalizeAddress(superToken); - const normalizedSender = normalizeAddress(sender); - const normalizedReceiver = normalizeAddress(receiver); - try { - const tokenId = await this.contract - - .connect(providerOrSigner) - .getTokenId( - normalizedSuperToken, - normalizedSender, - normalizedReceiver - ); - return tokenId.toString(); - } catch (err) { - throw new SFError({ - type: "NFT_READ", - message: "There was an error getting token id", - cause: err, - }); - } - }; - - /** - * Returns the NFT flow data of the NFT with `tokenId`. - * @param tokenId the token id - * @returns {NFTFlowData} the NFT flow data - */ - flowDataByTokenId = async ({ - tokenId, - providerOrSigner, - }: { - tokenId: string; - providerOrSigner: ethers.providers.Provider | ethers.Signer; - }): Promise => { - try { - const flowData = await this.contract - .connect(providerOrSigner) - .flowDataByTokenId(tokenId); - return this._sanitizeNFTFlowData(flowData); - } catch (err) { - throw new SFError({ - type: "NFT_READ", - message: "There was an error getting flow data by token id", - cause: err, - }); - } - }; -} diff --git a/packages/sdk-core/src/SuperToken.ts b/packages/sdk-core/src/SuperToken.ts index b44286b5d4..51c7965842 100644 --- a/packages/sdk-core/src/SuperToken.ts +++ b/packages/sdk-core/src/SuperToken.ts @@ -1,8 +1,6 @@ import { BytesLike, ethers, Overrides } from "ethers"; import ConstantFlowAgreementV1 from "./ConstantFlowAgreementV1"; -import ConstantInflowNFT from "./ConstantInflowNFT"; -import ConstantOutflowNFT from "./ConstantOutflowNFT"; import ERC20Token from "./ERC20Token"; import GeneralDistributionAgreementV1 from "./GeneralDistributionAgreementV1"; import Governance from "./Governance"; @@ -72,11 +70,6 @@ import { tryGet, } from "./utils"; -export interface NFTAddresses { - readonly constantInflowNFTProxy: string; - readonly constantOutflowNFTProxy: string; -} - export interface ITokenSettings { readonly address: string; readonly config: IConfig; @@ -105,10 +98,6 @@ export default abstract class SuperToken extends ERC20Token { readonly gdaV1: GeneralDistributionAgreementV1; readonly governance: Governance; readonly underlyingToken?: ERC20Token; - readonly constantOutflowNFTProxy?: ConstantOutflowNFT; - readonly constantInflowNFTProxy?: ConstantInflowNFT; - readonly constantOutflowNFTLogic?: string; - readonly constantInflowNFTLogic?: string; override readonly contract: ISuperToken; protected constructor(options: ITokenOptions, settings: ITokenSettings) { @@ -183,73 +172,21 @@ export default abstract class SuperToken extends ERC20Token { const nativeTokenSymbol = resolverData.nativeTokenSymbol || "ETH"; const nativeSuperTokenSymbol = nativeTokenSymbol + "x"; - // @note This is tech debt and should be reverted once GoodDollar upgrades their token contract - // @note We are using tryGet here just to handle GoodDollar not having - // CONSTANT_OUTFLOW_NFT in its SuperToken implementation. - let constantOutflowNFTProxy = await tryGet( - superToken.CONSTANT_OUTFLOW_NFT(), - ethers.constants.AddressZero - ); - let constantInflowNFTProxy = await tryGet( - superToken.CONSTANT_INFLOW_NFT(), - ethers.constants.AddressZero - ); - - // @note We only want to run this bit of code for GoodDollar SuperTokens - // (dev and mainnet) - const GOOD_DOLLAR_SYMBOL = "G$"; - if (tokenSymbol === GOOD_DOLLAR_SYMBOL) { - // @note we need to create a new interface for the old GoodDollar SuperToken - // which contains the functions for constantInflowNFT and constantOutflowNFT - const oldSuperTokenInterface = new ethers.utils.Interface([ - "function constantInflowNFT() view returns (address)", - "function constantOutflowNFT() view returns (address)", - ]); - const goodDollarSpecificToken = new ethers.Contract( - superToken.address, - oldSuperTokenInterface - ); - - // @note we attempt to get the constantInflowNFT and constantOutflowNFT - if (constantOutflowNFTProxy === ethers.constants.AddressZero) { - constantOutflowNFTProxy = await tryGet( - goodDollarSpecificToken.constantOutflowNFT(), - ethers.constants.AddressZero - ); - } - if (constantInflowNFTProxy === ethers.constants.AddressZero) { - constantInflowNFTProxy = await tryGet( - goodDollarSpecificToken.constantInflowNFT(), - ethers.constants.AddressZero - ); - } - } - - const nftAddresses: NFTAddresses = { - constantOutflowNFTProxy, - constantInflowNFTProxy, - }; - if (nativeSuperTokenSymbol === tokenSymbol) { return new NativeAssetSuperToken( options, settings, - nativeTokenSymbol, - nftAddresses + nativeTokenSymbol ); } if (underlyingTokenAddress !== ethers.constants.AddressZero) { - return new WrapperSuperToken( - options, - { - ...settings, - underlyingTokenAddress, - }, - nftAddresses - ); + return new WrapperSuperToken(options, { + ...settings, + underlyingTokenAddress, + }); } - return new PureSuperToken(options, settings, nftAddresses); + return new PureSuperToken(options, settings); } catch (err) { throw new SFError({ type: "SUPERTOKEN_INITIALIZATION", @@ -1042,22 +979,13 @@ export default abstract class SuperToken extends ERC20Token { */ export class WrapperSuperToken extends SuperToken { override readonly underlyingToken: ERC20Token; - override readonly constantOutflowNFTProxy: ConstantOutflowNFT; - override readonly constantInflowNFTProxy: ConstantInflowNFT; constructor( options: ITokenOptions, - settings: ITokenSettings & { underlyingTokenAddress: string }, - nftAddresses: NFTAddresses + settings: ITokenSettings & { underlyingTokenAddress: string } ) { super(options, settings); this.underlyingToken = new ERC20Token(settings.underlyingTokenAddress); - this.constantInflowNFTProxy = new ConstantInflowNFT( - nftAddresses.constantInflowNFTProxy - ); - this.constantOutflowNFTProxy = new ConstantOutflowNFT( - nftAddresses.constantOutflowNFTProxy - ); } /** ### WrapperSuperToken Contract Write Functions ### */ @@ -1159,21 +1087,8 @@ export class WrapperSuperToken extends SuperToken { * PureSuperToken doesn't have any underlying ERC20 token. */ export class PureSuperToken extends SuperToken { - override readonly constantOutflowNFTProxy: ConstantOutflowNFT; - override readonly constantInflowNFTProxy: ConstantInflowNFT; - - constructor( - options: ITokenOptions, - settings: ITokenSettings, - nftAddresses: NFTAddresses - ) { + constructor(options: ITokenOptions, settings: ITokenSettings) { super(options, settings); - this.constantInflowNFTProxy = new ConstantInflowNFT( - nftAddresses.constantInflowNFTProxy - ); - this.constantOutflowNFTProxy = new ConstantOutflowNFT( - nftAddresses.constantOutflowNFTProxy - ); } } @@ -1182,23 +1097,14 @@ export class PureSuperToken extends SuperToken { */ export class NativeAssetSuperToken extends SuperToken { readonly nativeTokenSymbol: string; - override readonly constantOutflowNFTProxy: ConstantOutflowNFT; - override readonly constantInflowNFTProxy: ConstantInflowNFT; constructor( options: ITokenOptions, settings: ITokenSettings, - nativeTokenSymbol: string, - nftAddresses: NFTAddresses + nativeTokenSymbol: string ) { super(options, settings); this.nativeTokenSymbol = nativeTokenSymbol; - this.constantInflowNFTProxy = new ConstantInflowNFT( - nftAddresses.constantInflowNFTProxy - ); - this.constantOutflowNFTProxy = new ConstantOutflowNFT( - nftAddresses.constantOutflowNFTProxy - ); } get nativeAssetContract() { diff --git a/packages/sdk-core/src/events.ts b/packages/sdk-core/src/events.ts index ad2cd8aa0d..03c9c8a07a 100644 --- a/packages/sdk-core/src/events.ts +++ b/packages/sdk-core/src/events.ts @@ -68,8 +68,6 @@ export type OtherEvents = | DistributionClaimedEvent | MemberUnitsUpdatedEvent | ApprovalEvent - | ApprovalForAllEvent - | MetadataUpdateEvent | UnknownEvent; export type AllEvents = AccountEvents | OtherEvents; @@ -183,7 +181,6 @@ export interface TransferEvent extends EventBase { to: string; value: string; token: string; - isNFTTransfer: boolean; } export interface AgreementClassRegisteredEvent extends EventBase { @@ -469,13 +466,6 @@ export interface MemberUnitsUpdatedEvent extends EventBase { } export interface ApprovalEvent extends EventBase { name: "ApprovalEvent"; - isNFTApproval: boolean; -} -export interface ApprovalForAllEvent extends EventBase { - name: "ApprovalForAllEvent"; -} -export interface MetadataUpdateEvent extends EventBase { - name: "MetadataUpdateEvent"; } export interface UnknownEvent extends EventBase { diff --git a/packages/sdk-core/src/mapGetAllEventsQueryEvents.ts b/packages/sdk-core/src/mapGetAllEventsQueryEvents.ts index 9d144e19af..dabd3f5969 100644 --- a/packages/sdk-core/src/mapGetAllEventsQueryEvents.ts +++ b/packages/sdk-core/src/mapGetAllEventsQueryEvents.ts @@ -598,7 +598,6 @@ export const mapGetAllEventsQueryEvents = ( to: x.to.id, token: x.token, value: x.value, - isNFTTransfer: x.isNFTTransfer, }); case "TrustedForwarderChangedEvent": return typeGuard({ @@ -761,29 +760,6 @@ export const mapGetAllEventsQueryEvents = ( order: Number(x.order), timestamp: Number(x.timestamp), logIndex: Number(x.logIndex), - isNFTApproval: x.isNFTApproval, - }); - case "ApprovalForAllEvent": - return typeGuard({ - name: "ApprovalForAllEvent", - id: x.id, - blockNumber: Number(x.blockNumber), - transactionHash: x.transactionHash, - gasPrice: x.gasPrice, - order: Number(x.order), - timestamp: Number(x.timestamp), - logIndex: Number(x.logIndex), - }); - case "MetadataUpdateEvent": - return typeGuard({ - name: "MetadataUpdateEvent", - id: x.id, - blockNumber: Number(x.blockNumber), - transactionHash: x.transactionHash, - gasPrice: x.gasPrice, - order: Number(x.order), - timestamp: Number(x.timestamp), - logIndex: Number(x.logIndex), }); default: // eslint-disable-next-line no-case-declarations diff --git a/packages/sdk-core/src/subgraph/events/events.graphql b/packages/sdk-core/src/subgraph/events/events.graphql index e72b88c012..b3e583d42e 100644 --- a/packages/sdk-core/src/subgraph/events/events.graphql +++ b/packages/sdk-core/src/subgraph/events/events.graphql @@ -1033,12 +1033,6 @@ query events( ... on ApprovalEvent { ...approvalEvent } - ... on ApprovalForAllEvent { - ...approvalForAllEvent - } - ... on MetadataUpdateEvent { - ...metadataUpdateEvent - } } } @@ -1207,7 +1201,6 @@ fragment transferEvent on TransferEvent { ...eventFields value token - isNFTTransfer to { id } @@ -1479,11 +1472,4 @@ fragment memberUnitsUpdatedEvent on MemberUnitsUpdatedEvent { } fragment approvalEvent on ApprovalEvent { ...eventFields - isNFTApproval -} -fragment approvalForAllEvent on ApprovalForAllEvent { - ...eventFields -} -fragment metadataUpdateEvent on MetadataUpdateEvent { - ...eventFields -} +} \ No newline at end of file diff --git a/packages/sdk-core/src/subgraph/queries/getAllEvents.graphql b/packages/sdk-core/src/subgraph/queries/getAllEvents.graphql index 3846b67f48..a4d132a140 100644 --- a/packages/sdk-core/src/subgraph/queries/getAllEvents.graphql +++ b/packages/sdk-core/src/subgraph/queries/getAllEvents.graphql @@ -162,7 +162,6 @@ query getAllEvents( from { id } - isNFTTransfer } ... on TokenUpgradedEvent { ...eventFields @@ -398,13 +397,6 @@ query getAllEvents( ...eventFields } ... on ApprovalEvent { - isNFTApproval - ...eventFields - } - ... on ApprovalForAllEvent { - ...eventFields - } - ... on MetadataUpdateEvent { ...eventFields } } diff --git a/packages/sdk-core/src/subgraph/schema.graphql b/packages/sdk-core/src/subgraph/schema.graphql index fb5e6f06c5..7781fd8a42 100644 --- a/packages/sdk-core/src/subgraph/schema.graphql +++ b/packages/sdk-core/src/subgraph/schema.graphql @@ -21,6 +21,9 @@ type _Block_ { """Integer representation of the timestamp stored in blocks for the chain""" timestamp: Int + + """The hash of the parent block""" + parentHash: Bytes } """The type for the top-level _meta field""" @@ -1605,6 +1608,11 @@ enum AccountTokenSnapshotLog_orderBy { accountTokenSnapshot__totalAmountTransferredUntilUpdatedAt } +enum Aggregation_interval { + hour + day +} + type AgreementClassRegisteredEvent implements Event { id: ID! transactionHash: Bytes! @@ -2629,7 +2637,7 @@ type ApprovalEvent implements Event { """ Contains the addresses that were impacted by this event: - addresses[0] = `isNFTApproval` ? `nft address` : `token` (superToken) + addresses[0] = `token` (superToken) addresses[1] = `owner` addresses[2] = `to` @@ -2640,37 +2648,23 @@ type ApprovalEvent implements Event { order: BigInt! """ - The address that will be granting allowance to transfer ERC20/NFT. + The address that will be granting allowance to transfer ERC20. """ owner: Account! """ - The address that will be granted allowance to transfer ERC20/NFT. + The address that will be granted allowance to transfer ERC20. """ to: Account! - """ - Indicates whether the event was emitted for the approval of an NFT. - - """ - isNFTApproval: Boolean! - """ If `amount` is non-zero, this event was emitted for the approval of an ERC20. Tne amount of ERC20 tokens that will be granted allowance to transfer. """ amount: BigInt! - - """ - If `tokenId` is non-zero, this event was emitted for the approval of an NFT. - The id of the NFT that will be granted allowance to transfer. - The id is: uint256(keccak256(abi.encode(block.chainid, superToken, sender, receiver))) - - """ - tokenId: BigInt! } input ApprovalEvent_filter { @@ -2808,10 +2802,6 @@ input ApprovalEvent_filter { to_not_ends_with: String to_not_ends_with_nocase: String to_: Account_filter - isNFTApproval: Boolean - isNFTApproval_not: Boolean - isNFTApproval_in: [Boolean!] - isNFTApproval_not_in: [Boolean!] amount: BigInt amount_not: BigInt amount_gt: BigInt @@ -2820,14 +2810,6 @@ input ApprovalEvent_filter { amount_lte: BigInt amount_in: [BigInt!] amount_not_in: [BigInt!] - tokenId: BigInt - tokenId_not: BigInt - tokenId_gt: BigInt - tokenId_lt: BigInt - tokenId_gte: BigInt - tokenId_lte: BigInt - tokenId_in: [BigInt!] - tokenId_not_in: [BigInt!] """Filter for the block changed event.""" _change_block: BlockChangedFilter @@ -2860,217 +2842,7 @@ enum ApprovalEvent_orderBy { to__updatedAtTimestamp to__updatedAtBlockNumber to__isSuperApp - isNFTApproval amount - tokenId -} - -type ApprovalForAllEvent implements Event { - id: ID! - transactionHash: Bytes! - gasPrice: BigInt! - gasUsed: BigInt! - timestamp: BigInt! - name: String! - - """ - Contains the addresses that were impacted by this event: - addresses[0] = NFT address - addresses[1] = `owner` - addresses[2] = `operator` - - """ - addresses: [Bytes!]! - blockNumber: BigInt! - logIndex: BigInt! - order: BigInt! - owner: Account! - - """ - The address that will be granted operator permissions for the all of the owner's tokens. - - """ - operator: Account! - - """ - Whether the operator is enabled or disabled for `owner`. - - """ - approved: Boolean! -} - -input ApprovalForAllEvent_filter { - id: ID - id_not: ID - id_gt: ID - id_lt: ID - id_gte: ID - id_lte: ID - id_in: [ID!] - id_not_in: [ID!] - transactionHash: Bytes - transactionHash_not: Bytes - transactionHash_gt: Bytes - transactionHash_lt: Bytes - transactionHash_gte: Bytes - transactionHash_lte: Bytes - transactionHash_in: [Bytes!] - transactionHash_not_in: [Bytes!] - transactionHash_contains: Bytes - transactionHash_not_contains: Bytes - gasPrice: BigInt - gasPrice_not: BigInt - gasPrice_gt: BigInt - gasPrice_lt: BigInt - gasPrice_gte: BigInt - gasPrice_lte: BigInt - gasPrice_in: [BigInt!] - gasPrice_not_in: [BigInt!] - gasUsed: BigInt - gasUsed_not: BigInt - gasUsed_gt: BigInt - gasUsed_lt: BigInt - gasUsed_gte: BigInt - gasUsed_lte: BigInt - gasUsed_in: [BigInt!] - gasUsed_not_in: [BigInt!] - timestamp: BigInt - timestamp_not: BigInt - timestamp_gt: BigInt - timestamp_lt: BigInt - timestamp_gte: BigInt - timestamp_lte: BigInt - timestamp_in: [BigInt!] - timestamp_not_in: [BigInt!] - name: String - name_not: String - name_gt: String - name_lt: String - name_gte: String - name_lte: String - name_in: [String!] - name_not_in: [String!] - name_contains: String - name_contains_nocase: String - name_not_contains: String - name_not_contains_nocase: String - name_starts_with: String - name_starts_with_nocase: String - name_not_starts_with: String - name_not_starts_with_nocase: String - name_ends_with: String - name_ends_with_nocase: String - name_not_ends_with: String - name_not_ends_with_nocase: String - addresses: [Bytes!] - addresses_not: [Bytes!] - addresses_contains: [Bytes!] - addresses_contains_nocase: [Bytes!] - addresses_not_contains: [Bytes!] - addresses_not_contains_nocase: [Bytes!] - blockNumber: BigInt - blockNumber_not: BigInt - blockNumber_gt: BigInt - blockNumber_lt: BigInt - blockNumber_gte: BigInt - blockNumber_lte: BigInt - blockNumber_in: [BigInt!] - blockNumber_not_in: [BigInt!] - logIndex: BigInt - logIndex_not: BigInt - logIndex_gt: BigInt - logIndex_lt: BigInt - logIndex_gte: BigInt - logIndex_lte: BigInt - logIndex_in: [BigInt!] - logIndex_not_in: [BigInt!] - order: BigInt - order_not: BigInt - order_gt: BigInt - order_lt: BigInt - order_gte: BigInt - order_lte: BigInt - order_in: [BigInt!] - order_not_in: [BigInt!] - owner: String - owner_not: String - owner_gt: String - owner_lt: String - owner_gte: String - owner_lte: String - owner_in: [String!] - owner_not_in: [String!] - owner_contains: String - owner_contains_nocase: String - owner_not_contains: String - owner_not_contains_nocase: String - owner_starts_with: String - owner_starts_with_nocase: String - owner_not_starts_with: String - owner_not_starts_with_nocase: String - owner_ends_with: String - owner_ends_with_nocase: String - owner_not_ends_with: String - owner_not_ends_with_nocase: String - owner_: Account_filter - operator: String - operator_not: String - operator_gt: String - operator_lt: String - operator_gte: String - operator_lte: String - operator_in: [String!] - operator_not_in: [String!] - operator_contains: String - operator_contains_nocase: String - operator_not_contains: String - operator_not_contains_nocase: String - operator_starts_with: String - operator_starts_with_nocase: String - operator_not_starts_with: String - operator_not_starts_with_nocase: String - operator_ends_with: String - operator_ends_with_nocase: String - operator_not_ends_with: String - operator_not_ends_with_nocase: String - operator_: Account_filter - approved: Boolean - approved_not: Boolean - approved_in: [Boolean!] - approved_not_in: [Boolean!] - - """Filter for the block changed event.""" - _change_block: BlockChangedFilter - and: [ApprovalForAllEvent_filter] - or: [ApprovalForAllEvent_filter] -} - -enum ApprovalForAllEvent_orderBy { - id - transactionHash - gasPrice - gasUsed - timestamp - name - addresses - blockNumber - logIndex - order - owner - owner__id - owner__createdAtTimestamp - owner__createdAtBlockNumber - owner__updatedAtTimestamp - owner__updatedAtBlockNumber - owner__isSuperApp - operator - operator__id - operator__createdAtTimestamp - operator__createdAtBlockNumber - operator__updatedAtTimestamp - operator__updatedAtBlockNumber - operator__isSuperApp - approved } scalar BigDecimal @@ -8865,153 +8637,6 @@ enum MemberUnitsUpdatedEvent_orderBy { poolMember__syncedPerUnitFlowRate } -type MetadataUpdateEvent implements Event { - id: ID! - transactionHash: Bytes! - gasPrice: BigInt! - gasUsed: BigInt! - timestamp: BigInt! - name: String! - - """ - Empty addresses array. - - """ - addresses: [Bytes!]! - blockNumber: BigInt! - logIndex: BigInt! - order: BigInt! - - """ - The id of the NFT that will be granted allowance to transfer. - The id is: uint256(keccak256(abi.encode(block.chainid, superToken, sender, receiver))) - - """ - tokenId: BigInt! -} - -input MetadataUpdateEvent_filter { - id: ID - id_not: ID - id_gt: ID - id_lt: ID - id_gte: ID - id_lte: ID - id_in: [ID!] - id_not_in: [ID!] - transactionHash: Bytes - transactionHash_not: Bytes - transactionHash_gt: Bytes - transactionHash_lt: Bytes - transactionHash_gte: Bytes - transactionHash_lte: Bytes - transactionHash_in: [Bytes!] - transactionHash_not_in: [Bytes!] - transactionHash_contains: Bytes - transactionHash_not_contains: Bytes - gasPrice: BigInt - gasPrice_not: BigInt - gasPrice_gt: BigInt - gasPrice_lt: BigInt - gasPrice_gte: BigInt - gasPrice_lte: BigInt - gasPrice_in: [BigInt!] - gasPrice_not_in: [BigInt!] - gasUsed: BigInt - gasUsed_not: BigInt - gasUsed_gt: BigInt - gasUsed_lt: BigInt - gasUsed_gte: BigInt - gasUsed_lte: BigInt - gasUsed_in: [BigInt!] - gasUsed_not_in: [BigInt!] - timestamp: BigInt - timestamp_not: BigInt - timestamp_gt: BigInt - timestamp_lt: BigInt - timestamp_gte: BigInt - timestamp_lte: BigInt - timestamp_in: [BigInt!] - timestamp_not_in: [BigInt!] - name: String - name_not: String - name_gt: String - name_lt: String - name_gte: String - name_lte: String - name_in: [String!] - name_not_in: [String!] - name_contains: String - name_contains_nocase: String - name_not_contains: String - name_not_contains_nocase: String - name_starts_with: String - name_starts_with_nocase: String - name_not_starts_with: String - name_not_starts_with_nocase: String - name_ends_with: String - name_ends_with_nocase: String - name_not_ends_with: String - name_not_ends_with_nocase: String - addresses: [Bytes!] - addresses_not: [Bytes!] - addresses_contains: [Bytes!] - addresses_contains_nocase: [Bytes!] - addresses_not_contains: [Bytes!] - addresses_not_contains_nocase: [Bytes!] - blockNumber: BigInt - blockNumber_not: BigInt - blockNumber_gt: BigInt - blockNumber_lt: BigInt - blockNumber_gte: BigInt - blockNumber_lte: BigInt - blockNumber_in: [BigInt!] - blockNumber_not_in: [BigInt!] - logIndex: BigInt - logIndex_not: BigInt - logIndex_gt: BigInt - logIndex_lt: BigInt - logIndex_gte: BigInt - logIndex_lte: BigInt - logIndex_in: [BigInt!] - logIndex_not_in: [BigInt!] - order: BigInt - order_not: BigInt - order_gt: BigInt - order_lt: BigInt - order_gte: BigInt - order_lte: BigInt - order_in: [BigInt!] - order_not_in: [BigInt!] - tokenId: BigInt - tokenId_not: BigInt - tokenId_gt: BigInt - tokenId_lt: BigInt - tokenId_gte: BigInt - tokenId_lte: BigInt - tokenId_in: [BigInt!] - tokenId_not_in: [BigInt!] - - """Filter for the block changed event.""" - _change_block: BlockChangedFilter - and: [MetadataUpdateEvent_filter] - or: [MetadataUpdateEvent_filter] -} - -enum MetadataUpdateEvent_orderBy { - id - transactionHash - gasPrice - gasUsed - timestamp - name - addresses - blockNumber - logIndex - order - tokenId -} - type MintedEvent implements Event { id: ID! transactionHash: Bytes! @@ -12625,86 +12250,6 @@ type Query { """ subgraphError: _SubgraphErrorPolicy_! = deny ): [ApprovalEvent!]! - approvalForAllEvent( - id: ID! - - """ - The block at which the query should be executed. Can either be a `{ hash: - Bytes }` value containing a block hash, a `{ number: Int }` containing the - block number, or a `{ number_gte: Int }` containing the minimum block - number. In the case of `number_gte`, the query will be executed on the - latest block only if the subgraph has progressed to or past the minimum - block number. Defaults to the latest block when omitted. - """ - block: Block_height - - """ - Set to `allow` to receive data even if the subgraph has skipped over errors while syncing. - """ - subgraphError: _SubgraphErrorPolicy_! = deny - ): ApprovalForAllEvent - approvalForAllEvents( - skip: Int = 0 - first: Int = 100 - orderBy: ApprovalForAllEvent_orderBy - orderDirection: OrderDirection - where: ApprovalForAllEvent_filter - - """ - The block at which the query should be executed. Can either be a `{ hash: - Bytes }` value containing a block hash, a `{ number: Int }` containing the - block number, or a `{ number_gte: Int }` containing the minimum block - number. In the case of `number_gte`, the query will be executed on the - latest block only if the subgraph has progressed to or past the minimum - block number. Defaults to the latest block when omitted. - """ - block: Block_height - - """ - Set to `allow` to receive data even if the subgraph has skipped over errors while syncing. - """ - subgraphError: _SubgraphErrorPolicy_! = deny - ): [ApprovalForAllEvent!]! - metadataUpdateEvent( - id: ID! - - """ - The block at which the query should be executed. Can either be a `{ hash: - Bytes }` value containing a block hash, a `{ number: Int }` containing the - block number, or a `{ number_gte: Int }` containing the minimum block - number. In the case of `number_gte`, the query will be executed on the - latest block only if the subgraph has progressed to or past the minimum - block number. Defaults to the latest block when omitted. - """ - block: Block_height - - """ - Set to `allow` to receive data even if the subgraph has skipped over errors while syncing. - """ - subgraphError: _SubgraphErrorPolicy_! = deny - ): MetadataUpdateEvent - metadataUpdateEvents( - skip: Int = 0 - first: Int = 100 - orderBy: MetadataUpdateEvent_orderBy - orderDirection: OrderDirection - where: MetadataUpdateEvent_filter - - """ - The block at which the query should be executed. Can either be a `{ hash: - Bytes }` value containing a block hash, a `{ number: Int }` containing the - block number, or a `{ number_gte: Int }` containing the minimum block - number. In the case of `number_gte`, the query will be executed on the - latest block only if the subgraph has progressed to or past the minimum - block number. Defaults to the latest block when omitted. - """ - block: Block_height - - """ - Set to `allow` to receive data even if the subgraph has skipped over errors while syncing. - """ - subgraphError: _SubgraphErrorPolicy_! = deny - ): [MetadataUpdateEvent!]! customSuperTokenCreatedEvent( id: ID! @@ -17478,86 +17023,6 @@ type Subscription { """ subgraphError: _SubgraphErrorPolicy_! = deny ): [ApprovalEvent!]! - approvalForAllEvent( - id: ID! - - """ - The block at which the query should be executed. Can either be a `{ hash: - Bytes }` value containing a block hash, a `{ number: Int }` containing the - block number, or a `{ number_gte: Int }` containing the minimum block - number. In the case of `number_gte`, the query will be executed on the - latest block only if the subgraph has progressed to or past the minimum - block number. Defaults to the latest block when omitted. - """ - block: Block_height - - """ - Set to `allow` to receive data even if the subgraph has skipped over errors while syncing. - """ - subgraphError: _SubgraphErrorPolicy_! = deny - ): ApprovalForAllEvent - approvalForAllEvents( - skip: Int = 0 - first: Int = 100 - orderBy: ApprovalForAllEvent_orderBy - orderDirection: OrderDirection - where: ApprovalForAllEvent_filter - - """ - The block at which the query should be executed. Can either be a `{ hash: - Bytes }` value containing a block hash, a `{ number: Int }` containing the - block number, or a `{ number_gte: Int }` containing the minimum block - number. In the case of `number_gte`, the query will be executed on the - latest block only if the subgraph has progressed to or past the minimum - block number. Defaults to the latest block when omitted. - """ - block: Block_height - - """ - Set to `allow` to receive data even if the subgraph has skipped over errors while syncing. - """ - subgraphError: _SubgraphErrorPolicy_! = deny - ): [ApprovalForAllEvent!]! - metadataUpdateEvent( - id: ID! - - """ - The block at which the query should be executed. Can either be a `{ hash: - Bytes }` value containing a block hash, a `{ number: Int }` containing the - block number, or a `{ number_gte: Int }` containing the minimum block - number. In the case of `number_gte`, the query will be executed on the - latest block only if the subgraph has progressed to or past the minimum - block number. Defaults to the latest block when omitted. - """ - block: Block_height - - """ - Set to `allow` to receive data even if the subgraph has skipped over errors while syncing. - """ - subgraphError: _SubgraphErrorPolicy_! = deny - ): MetadataUpdateEvent - metadataUpdateEvents( - skip: Int = 0 - first: Int = 100 - orderBy: MetadataUpdateEvent_orderBy - orderDirection: OrderDirection - where: MetadataUpdateEvent_filter - - """ - The block at which the query should be executed. Can either be a `{ hash: - Bytes }` value containing a block hash, a `{ number: Int }` containing the - block number, or a `{ number_gte: Int }` containing the minimum block - number. In the case of `number_gte`, the query will be executed on the - latest block only if the subgraph has progressed to or past the minimum - block number. Defaults to the latest block when omitted. - """ - block: Block_height - - """ - Set to `allow` to receive data even if the subgraph has skipped over errors while syncing. - """ - subgraphError: _SubgraphErrorPolicy_! = deny - ): [MetadataUpdateEvent!]! customSuperTokenCreatedEvent( id: ID! @@ -20321,6 +19786,12 @@ enum SuperTokenMinimumDepositChangedEvent_orderBy { minimumDeposit } +""" +A string representation of microseconds UNIX timestamp (16 digits) + +""" +scalar Timestamp + """ Token: A higher order entity created for super tokens (and underlying tokens) that are "valid" (tokens that have Superfluid's host contract address set as the host). @@ -22204,7 +21675,7 @@ type TransferEvent implements Event { """ Contains the addresses that were impacted by this event: - addresses[0] = `token` (superToken if `isNFTTransfer` is false, otherwise the ConstantOutflowNFT or ConstantInflowNFT) + addresses[0] = `token` addresses[1] = `from` addresses[2] = `to` @@ -22215,18 +21686,7 @@ type TransferEvent implements Event { order: BigInt! from: Account! to: Account! - isNFTTransfer: Boolean! - - """ - If `isNFTTransfer` is true, value is the `tokenId` of the NFT transferred. - - """ value: BigInt! - - """ - If `isNFTTransfer` is true, value is the NFT address, else it is the SuperToken address. - - """ token: Bytes! } @@ -22365,10 +21825,6 @@ input TransferEvent_filter { to_not_ends_with: String to_not_ends_with_nocase: String to_: Account_filter - isNFTTransfer: Boolean - isNFTTransfer_not: Boolean - isNFTTransfer_in: [Boolean!] - isNFTTransfer_not_in: [Boolean!] value: BigInt value_not: BigInt value_gt: BigInt @@ -22419,7 +21875,6 @@ enum TransferEvent_orderBy { to__updatedAtTimestamp to__updatedAtBlockNumber to__isSuperApp - isNFTTransfer value token } diff --git a/packages/sdk-core/test/1.4_supertoken_nft.test.ts b/packages/sdk-core/test/1.4_supertoken_nft.test.ts deleted file mode 100644 index 8ff3085f3a..0000000000 --- a/packages/sdk-core/test/1.4_supertoken_nft.test.ts +++ /dev/null @@ -1,348 +0,0 @@ -import { expect } from "chai"; - -import { makeSuite, TestEnvironment } from "./TestEnvironment"; -import { getPerSecondFlowRateByMonth } from "../src"; - -const createFlow = async (testEnv: TestEnvironment) => { - const flowRate = getPerSecondFlowRateByMonth("1000"); - await testEnv.wrapperSuperToken - .createFlow({ - sender: testEnv.alice.address, - receiver: testEnv.bob.address, - flowRate, - }) - .exec(testEnv.alice); - - return await testEnv.wrapperSuperToken.constantOutflowNFTProxy.getTokenId({ - superToken: testEnv.wrapperSuperToken.address, - sender: testEnv.alice.address, - receiver: testEnv.bob.address, - providerOrSigner: testEnv.alice, - }); -}; - -makeSuite("SuperToken-NFT Tests", (testEnv: TestEnvironment) => { - describe("Revert cases", () => { - it("Should revert when trying to transferFrom", async () => { - const tokenId = await createFlow(testEnv); - - await expect( - testEnv.wrapperSuperToken.constantOutflowNFTProxy - .transferFrom({ - from: testEnv.alice.address, - to: testEnv.bob.address, - tokenId, - }) - .exec(testEnv.alice) - ).to.be.revertedWithCustomError( - testEnv.wrapperSuperToken.constantOutflowNFTProxy.contract, - "CFA_NFT_TRANSFER_IS_NOT_ALLOWED" - ); - }); - - it("Should revert when trying to safeTransferFrom", async () => { - const tokenId = await createFlow(testEnv); - - await expect( - testEnv.wrapperSuperToken.constantOutflowNFTProxy - .safeTransferFrom({ - from: testEnv.alice.address, - to: testEnv.bob.address, - tokenId, - }) - .exec(testEnv.alice) - ).to.be.revertedWithCustomError( - testEnv.wrapperSuperToken.constantOutflowNFTProxy.contract, - "CFA_NFT_TRANSFER_IS_NOT_ALLOWED" - ); - }); - - it("Should revert when trying to safeTransferFromWithData", async () => { - const tokenId = await createFlow(testEnv); - - await expect( - testEnv.wrapperSuperToken.constantOutflowNFTProxy - .safeTransferFromWithData({ - from: testEnv.alice.address, - to: testEnv.bob.address, - tokenId, - data: "0x", - }) - .exec(testEnv.alice) - ).to.be.revertedWithCustomError( - testEnv.wrapperSuperToken.constantOutflowNFTProxy.contract, - "CFA_NFT_TRANSFER_IS_NOT_ALLOWED" - ); - }); - - it("Should revert if ownerOf token does not exist", async () => { - try { - await testEnv.wrapperSuperToken.constantOutflowNFTProxy.ownerOf( - { - tokenId: "69", - providerOrSigner: testEnv.alice, - } - ); - } catch (err: any) { - expect(err.message).to.contain("CFA_NFT_INVALID_TOKEN_ID"); - } - }); - - it("Should revert if approve to owner", async () => { - const tokenId = await createFlow(testEnv); - - await expect( - testEnv.wrapperSuperToken.constantOutflowNFTProxy - .approve({ - approved: testEnv.alice.address, - tokenId, - }) - .exec(testEnv.alice) - ).to.be.revertedWithCustomError( - testEnv.wrapperSuperToken.constantOutflowNFTProxy.contract, - "CFA_NFT_APPROVE_TO_CURRENT_OWNER" - ); - }); - - it("Should revert if approve on behalf of someone else", async () => { - const tokenId = await createFlow(testEnv); - - await expect( - testEnv.wrapperSuperToken.constantOutflowNFTProxy - .approve({ - approved: testEnv.bob.address, - tokenId, - }) - .exec(testEnv.bob) - ).to.be.revertedWithCustomError( - testEnv.wrapperSuperToken.constantOutflowNFTProxy.contract, - "CFA_NFT_APPROVE_CALLER_NOT_OWNER_OR_APPROVED_FOR_ALL" - ); - }); - - it("Should catch error in balanceOf", async () => { - try { - await testEnv.wrapperSuperToken.constantOutflowNFTProxy.balanceOf( - { - owner: "0x", - providerOrSigner: testEnv.alice, - } - ); - } catch (err: any) { - expect(err.message).to.contain( - "There was an error getting balanceOf" - ); - } - }); - - it("Should catch error in getApproved", async () => { - try { - await testEnv.wrapperSuperToken.constantOutflowNFTProxy.getApproved( - { - tokenId: "0x", - providerOrSigner: testEnv.alice, - } - ); - } catch (err: any) { - expect(err.message).to.contain( - "There was an error getting getApproved" - ); - } - }); - - it("Should catch error in isApprovedForAll", async () => { - try { - await testEnv.wrapperSuperToken.constantOutflowNFTProxy.isApprovedForAll( - { - owner: "0x", - operator: "0x", - providerOrSigner: testEnv.alice, - } - ); - } catch (err: any) { - expect(err.message).to.contain( - "There was an error getting isApprovedForAll" - ); - } - }); - - it("Should catch error in name", async () => { - try { - await testEnv.wrapperSuperToken.constantOutflowNFTProxy.name({ - providerOrSigner: testEnv.alice, - }); - } catch (err: any) { - expect(err.message).to.contain( - "There was an error getting name" - ); - } - }); - - it("Should catch error in symbol", async () => { - try { - await testEnv.wrapperSuperToken.constantOutflowNFTProxy.symbol({ - providerOrSigner: testEnv.alice, - }); - } catch (err: any) { - expect(err.message).to.contain( - "There was an error getting symbol" - ); - } - }); - - it("Should catch error in tokenURI", async () => { - try { - await testEnv.wrapperSuperToken.constantOutflowNFTProxy.tokenURI( - { - tokenId: "0x", - providerOrSigner: testEnv.alice, - } - ); - } catch (err: any) { - expect(err.message).to.contain( - "There was an error getting tokenURI" - ); - } - }); - - it("Should catch error in getTokenId", async () => { - try { - await testEnv.wrapperSuperToken.constantOutflowNFTProxy.getTokenId( - { - superToken: testEnv.wrapperSuperToken.address, - sender: testEnv.alice.address, - receiver: testEnv.bob.address, - providerOrSigner: "testEnv.alice" as any, - } - ); - } catch (err: any) { - expect(err.message).to.contain( - "There was an error getting token id" - ); - } - }); - - it("Should catch error in flowDataByTokenId", async () => { - try { - await testEnv.wrapperSuperToken.constantOutflowNFTProxy.flowDataByTokenId( - { - tokenId: "0x", - providerOrSigner: testEnv.alice, - } - ); - } catch (err: any) { - expect(err.message).to.contain( - "There was an error getting flow data by token id" - ); - } - }); - }); - - describe("Happy Path Tests", () => { - it("Should be able to get flowDataByTokenId", async () => { - const tokenId = await createFlow(testEnv); - - const flowData = - await testEnv.wrapperSuperToken.constantOutflowNFTProxy.flowDataByTokenId( - { - tokenId, - providerOrSigner: testEnv.alice, - } - ); - expect(flowData.flowSender).to.equal(testEnv.alice.address); - expect(flowData.flowReceiver).to.equal(testEnv.bob.address); - }); - - it("Should be able to approve", async () => { - const tokenId = await createFlow(testEnv); - - await testEnv.wrapperSuperToken.constantOutflowNFTProxy - .approve({ - approved: testEnv.bob.address, - tokenId, - }) - .exec(testEnv.alice); - - const approved = - await testEnv.wrapperSuperToken.constantOutflowNFTProxy.getApproved( - { - tokenId, - providerOrSigner: testEnv.alice, - } - ); - expect(approved).to.equal(testEnv.bob.address); - }); - - it("Should be able to setApprovalForAll", async () => { - await testEnv.wrapperSuperToken.constantOutflowNFTProxy - .setApprovalForAll({ - operator: testEnv.bob.address, - approved: true, - }) - .exec(testEnv.alice); - - const approved = - await testEnv.wrapperSuperToken.constantOutflowNFTProxy.isApprovedForAll( - { - owner: testEnv.alice.address, - operator: testEnv.bob.address, - providerOrSigner: testEnv.alice, - } - ); - expect(approved).to.equal(true); - }); - - it("Should be able to get ownerOf", async () => { - const tokenId = await createFlow(testEnv); - - const owner = - await testEnv.wrapperSuperToken.constantOutflowNFTProxy.ownerOf( - { - tokenId, - providerOrSigner: testEnv.alice, - } - ); - expect(owner).to.equal(testEnv.alice.address); - }); - - it("Should be able to get balanceOf (always returns 1)", async () => { - const balance = - await testEnv.wrapperSuperToken.constantOutflowNFTProxy.balanceOf( - { - owner: testEnv.alice.address, - providerOrSigner: testEnv.alice, - } - ); - expect(balance.toString()).to.equal("1"); - }); - - it("Should be able to get name", async () => { - const name = - await testEnv.wrapperSuperToken.constantOutflowNFTProxy.name({ - providerOrSigner: testEnv.alice, - }); - expect(name).to.equal("Constant Outflow NFT"); - }); - - it("Should be able to get tokenURI", async () => { - const tokenId = await createFlow(testEnv); - - const tokenURI = - await testEnv.wrapperSuperToken.constantOutflowNFTProxy.tokenURI( - { - tokenId, - providerOrSigner: testEnv.alice, - } - ); - expect(tokenURI).to.not.be.empty; - }); - - it("Should be able to get symbol", async () => { - const symbol = - await testEnv.wrapperSuperToken.constantOutflowNFTProxy.symbol({ - providerOrSigner: testEnv.alice, - }); - expect(symbol.toString()).to.equal("COF"); - }); - }); -}); diff --git a/packages/sdk-redux/CHANGELOG.md b/packages/sdk-redux/CHANGELOG.md index cb3e71513f..b35a69bd06 100644 --- a/packages/sdk-redux/CHANGELOG.md +++ b/packages/sdk-redux/CHANGELOG.md @@ -7,6 +7,12 @@ All notable changes to the SDK-redux will be documented in this file. ### Changed ### Fixed +## [0.6.1] - 2024-08-01 + +### Changed + +- sdk-core dependency update + ## [0.6.0] - 2023-05-01 ### Changed diff --git a/packages/sdk-redux/package.json b/packages/sdk-redux/package.json index 2430bca178..f196714c45 100644 --- a/packages/sdk-redux/package.json +++ b/packages/sdk-redux/package.json @@ -1,6 +1,6 @@ { "name": "@superfluid-finance/sdk-redux", - "version": "0.6.0", + "version": "0.6.1", "description": "SDK Redux for streamlined front-end application development with Superfluid Protocol", "homepage": "https://docs.superfluid.finance/", "repository": { @@ -52,7 +52,7 @@ }, "peerDependencies": { "@reduxjs/toolkit": "^1.7.0 || ^1.8.0 || ^1.9.0", - "@superfluid-finance/sdk-core": "^0.7.0" + "@superfluid-finance/sdk-core": ">0.7.0" }, "files": [ "dist/main", diff --git a/packages/subgraph/CHANGELOG.md b/packages/subgraph/CHANGELOG.md index b9d7348e2e..dfaa232bb8 100644 --- a/packages/subgraph/CHANGELOG.md +++ b/packages/subgraph/CHANGELOG.md @@ -6,6 +6,12 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm ## [Unreleased] +## [2.1.0] + +## Breaking + +- Removed FlowNFT related entities and attributes + ## [2.0.0] ### Changed diff --git a/packages/subgraph/README.md b/packages/subgraph/README.md index fe052bbcae..3c560b8b13 100644 --- a/packages/subgraph/README.md +++ b/packages/subgraph/README.md @@ -38,7 +38,7 @@ If you get stuck, see The Graph [docs](https://thegraph.com/docs/quick-start#loc First install these dependencies: - [docker](https://docs.docker.com/install/) -- [docker-compose](https://docs.docker.com/compose/install/) +- [docker compose](https://docs.docker.com/compose/install/) Now install the necessary node packages with the following commands: @@ -56,7 +56,7 @@ npx hardhat node --hostname 0.0.0.0 ### Setting up a local Subgraph node instance -Run `docker-compose up` in `packages/subgraph`. There is a `docker-compose.yml` file which sets up a local graph node container. +Run `docker compose up` in `packages/subgraph`. There is a `docker-compose.yml` file which sets up a local graph node container. You should see logs start coming in on the same terminal window once everything is set up: diff --git a/packages/subgraph/config/mock.json b/packages/subgraph/config/mock.json index 0a91e0f421..0fa37532d9 100644 --- a/packages/subgraph/config/mock.json +++ b/packages/subgraph/config/mock.json @@ -7,7 +7,5 @@ "gdaAddress": "0x0000000000000000000000000000000000000000", "superTokenFactoryAddress": "0x0000000000000000000000000000000000000000", "resolverV1Address": "0x0000000000000000000000000000000000000000", - "nativeAssetSuperTokenAddress": "0x0000000000000000000000000000000000000000", - "constantOutflowNFTAddress": "0x0000000000000000000000000000000000000000", - "constantInflowNFTAddress": "0x0000000000000000000000000000000000000000" + "nativeAssetSuperTokenAddress": "0x0000000000000000000000000000000000000000" } diff --git a/packages/subgraph/package.json b/packages/subgraph/package.json index 3b6554cbfe..201715ce97 100644 --- a/packages/subgraph/package.json +++ b/packages/subgraph/package.json @@ -1,6 +1,6 @@ { "name": "@superfluid-finance/subgraph", - "version": "2.0.0", + "version": "2.1.0", "description": "Subgraph for the Superfluid Ethereum contracts.", "homepage": "https://github.com/superfluid-finance/protocol-monorepo/tree/dev/packages/subgraph", "repository": { @@ -52,11 +52,11 @@ "dependencies": { "@graphprotocol/graph-cli": "0.73.0", "@graphprotocol/graph-ts": "0.35.1", - "@superfluid-finance/sdk-core": "^0.7.1", + "@superfluid-finance/sdk-core": "^0.8.0", "mustache": "^4.2.0" }, "devDependencies": { - "@superfluid-finance/metadata": "^1.3.1", + "@superfluid-finance/metadata": "^1.4.0", "coingecko-api": "^1.0.10", "graphql": "^16.8.1", "graphql-request": "^6.1.0", diff --git a/packages/subgraph/schema.graphql b/packages/subgraph/schema.graphql index d66a1060da..6e81290bf0 100644 --- a/packages/subgraph/schema.graphql +++ b/packages/subgraph/schema.graphql @@ -1423,7 +1423,7 @@ type TransferEvent implements Event @entity(immutable: true) { """ Contains the addresses that were impacted by this event: - addresses[0] = `token` (superToken if `isNFTTransfer` is false, otherwise the ConstantOutflowNFT or ConstantInflowNFT) + addresses[0] = `token` addresses[1] = `from` addresses[2] = `to` """ @@ -1434,15 +1434,8 @@ type TransferEvent implements Event @entity(immutable: true) { from: Account! to: Account! - isNFTTransfer: Boolean! - """ - If `isNFTTransfer` is true, value is the `tokenId` of the NFT transferred. - """ value: BigInt! - """ - If `isNFTTransfer` is true, value is the NFT address, else it is the SuperToken address. - """ token: Bytes! } @@ -1492,8 +1485,6 @@ type TokenUpgradedEvent implements Event @entity(immutable: true) { amount: BigInt! } - -# NFTs # type ApprovalEvent implements Event @entity(immutable: true) { id: ID! transactionHash: Bytes! @@ -1504,7 +1495,7 @@ type ApprovalEvent implements Event @entity(immutable: true) { """ Contains the addresses that were impacted by this event: - addresses[0] = `isNFTApproval` ? `nft address` : `token` (superToken) + addresses[0] = `token` (superToken) addresses[1] = `owner` addresses[2] = `to` """ @@ -1514,86 +1505,20 @@ type ApprovalEvent implements Event @entity(immutable: true) { order: BigInt! """ - The address that will be granting allowance to transfer ERC20/NFT. + The address that will be granting allowance to transfer ERC20. """ owner: Account! """ - The address that will be granted allowance to transfer ERC20/NFT. + The address that will be granted allowance to transfer ERC20. """ to: Account! - """ - Indicates whether the event was emitted for the approval of an NFT. - """ - isNFTApproval: Boolean! - """ If `amount` is non-zero, this event was emitted for the approval of an ERC20. Tne amount of ERC20 tokens that will be granted allowance to transfer. """ amount: BigInt! - - """ - If `tokenId` is non-zero, this event was emitted for the approval of an NFT. - The id of the NFT that will be granted allowance to transfer. - The id is: uint256(keccak256(abi.encode(block.chainid, superToken, sender, receiver))) - """ - tokenId: BigInt! -} - -type ApprovalForAllEvent implements Event @entity(immutable: true) { - id: ID! - transactionHash: Bytes! - gasPrice: BigInt! - gasUsed: BigInt! - timestamp: BigInt! - name: String! - - """ - Contains the addresses that were impacted by this event: - addresses[0] = NFT address - addresses[1] = `owner` - addresses[2] = `operator` - """ - addresses: [Bytes!]! - blockNumber: BigInt! - logIndex: BigInt! - order: BigInt! - - owner: Account! - - """ - The address that will be granted operator permissions for the all of the owner's tokens. - """ - operator: Account! - """ - Whether the operator is enabled or disabled for `owner`. - """ - approved: Boolean! -} - -type MetadataUpdateEvent implements Event @entity(immutable: true) { - id: ID! - transactionHash: Bytes! - gasPrice: BigInt! - gasUsed: BigInt! - timestamp: BigInt! - name: String! - - """ - Empty addresses array. - """ - addresses: [Bytes!]! - blockNumber: BigInt! - logIndex: BigInt! - order: BigInt! - - """ - The id of the NFT that will be granted allowance to transfer. - The id is: uint256(keccak256(abi.encode(block.chainid, superToken, sender, receiver))) - """ - tokenId: BigInt! } # SuperTokenFactory # diff --git a/packages/subgraph/scripts/buildNetworkConfig.ts b/packages/subgraph/scripts/buildNetworkConfig.ts index b73edf3c99..d89d5f56f7 100644 --- a/packages/subgraph/scripts/buildNetworkConfig.ts +++ b/packages/subgraph/scripts/buildNetworkConfig.ts @@ -12,8 +12,6 @@ interface SubgraphConfig { readonly superTokenFactoryAddress: string; readonly resolverV1Address: string; readonly nativeAssetSuperTokenAddress: string; - readonly constantOutflowNFTAddress: string; - readonly constantInflowNFTAddress: string; readonly indexerHints_prune: string; } @@ -35,7 +33,7 @@ function main() { const networkName = process.argv[2]; const vendorName = process.argv[3]; - const networkMetadata = metadata.getNetworkByName(networkName); + const networkMetadata = metadata.getNetworkByName(networkName); if (!networkMetadata) { throw new Error("No metadata found"); @@ -51,8 +49,6 @@ function main() { superTokenFactoryAddress: networkMetadata.contractsV1.superTokenFactory, resolverV1Address: networkMetadata.contractsV1.resolver, nativeAssetSuperTokenAddress: networkMetadata.nativeTokenWrapper, - constantOutflowNFTAddress: networkMetadata.contractsV1.constantOutflowNFT || ADDRESS_ZERO, - constantInflowNFTAddress: networkMetadata.contractsV1.constantInflowNFT || ADDRESS_ZERO, indexerHints_prune: vendorHistoryPruning[vendorName] || "never", }; diff --git a/packages/subgraph/scripts/getAbi.js b/packages/subgraph/scripts/getAbi.js index b3502b1385..924c0cdfe9 100755 --- a/packages/subgraph/scripts/getAbi.js +++ b/packages/subgraph/scripts/getAbi.js @@ -4,7 +4,6 @@ const path = require("path"); const contracts = [ "ERC20", "IConstantFlowAgreementV1", - "IFlowNFTBase", "ISuperTokenFactory", "ISuperToken", "ISuperfluid", diff --git a/packages/subgraph/src/mappings/flowNFT.ts b/packages/subgraph/src/mappings/flowNFT.ts deleted file mode 100644 index af232c8485..0000000000 --- a/packages/subgraph/src/mappings/flowNFT.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { - Approval, - ApprovalForAll, - Transfer, - MetadataUpdate, -} from "../../generated/ConstantInflowNFT/IFlowNFTBase"; -import { - ApprovalEvent, - ApprovalForAllEvent, - MetadataUpdateEvent, - TransferEvent, -} from "../../generated/schema"; -import { getOrInitAccount } from "../mappingHelpers"; -import { BIG_INT_ONE, createEventID, initializeEventEntity } from "../utils"; - -export function handleApproval(event: Approval): void { - const eventId = createEventID("Approval", event); - const ev = new ApprovalEvent(eventId); - initializeEventEntity(ev, event, [event.address, event.params.owner, event.params.approved]); - ev.owner = event.params.owner.toHex(); - ev.to = event.params.approved.toHex(); - ev.tokenId = event.params.tokenId; - ev.amount = BIG_INT_ONE.neg(); - ev.isNFTApproval = true; - - ev.save(); -} - -export function handleApprovalForAll(event: ApprovalForAll): void { - const eventId = createEventID("ApprovalForAll", event); - const ev = new ApprovalForAllEvent(eventId); - initializeEventEntity(ev, event, [event.address, event.params.owner, event.params.operator]); - ev.owner = event.params.owner.toHex(); - ev.operator = event.params.operator.toHex(); - ev.approved = event.params.approved; - - ev.save(); -} - -export function handleTransfer(event: Transfer): void { - const eventId = createEventID("Transfer", event); - const ev = new TransferEvent(eventId); - initializeEventEntity(ev, event, [ - event.address, - event.params.from, - event.params.to, - ]); - ev.isNFTTransfer = true; - ev.from = event.params.from.toHex(); - ev.to = event.params.to.toHex(); - ev.value = event.params.tokenId; - ev.token = event.address; - - ev.save(); - - getOrInitAccount(event.params.to, event.block); - getOrInitAccount(event.params.from, event.block); -} - -export function handleMetadataUpdate(event: MetadataUpdate): void { - const eventId = createEventID("MetadataUpdate", event); - const ev = new MetadataUpdateEvent(eventId); - initializeEventEntity(ev, event, []); - ev.tokenId = event.params.tokenId; - - ev.save(); -} \ No newline at end of file diff --git a/packages/subgraph/src/mappings/superToken.ts b/packages/subgraph/src/mappings/superToken.ts index 18be4b2050..164a2c8abf 100644 --- a/packages/subgraph/src/mappings/superToken.ts +++ b/packages/subgraph/src/mappings/superToken.ts @@ -444,7 +444,6 @@ function _createTransferEventEntity(event: Transfer): void { event.params.from, event.params.to, ]); - ev.isNFTTransfer = false; ev.from = event.params.from.toHex(); ev.to = event.params.to.toHex(); ev.value = event.params.value; @@ -458,9 +457,7 @@ export function handleApproval(event: Approval): void { initializeEventEntity(ev, event, [event.address, event.params.owner, event.params.spender]); ev.owner = event.params.owner.toHex(); ev.to = event.params.spender.toHex(); - ev.tokenId = BIG_INT_ZERO; ev.amount = event.params.value; - ev.isNFTApproval = false; ev.save(); diff --git a/packages/subgraph/subgraph.template.yaml b/packages/subgraph/subgraph.template.yaml index 5c0226f970..498fa057d3 100644 --- a/packages/subgraph/subgraph.template.yaml +++ b/packages/subgraph/subgraph.template.yaml @@ -291,76 +291,6 @@ dataSources: - event: Set(indexed string,address) handler: handleSet receipt: true - - kind: ethereum/contract - name: ConstantOutflowNFT - network: {{ network }} - source: - address: "{{ constantOutflowNFTAddress }}" - abi: IFlowNFTBase - startBlock: {{ hostStartBlock }} - mapping: - kind: ethereum/events - apiVersion: 0.0.8 - language: wasm/assemblyscript - file: ./src/mappings/flowNFT.ts - entities: - - ApprovalEvent - - ApprovalForAllEvent - - MetadataUpdateEvent - - TransferEvent - abis: - - name: IFlowNFTBase - file: ./abis/IFlowNFTBase.json - - name: ISuperfluid - file: ./abis/ISuperfluid.json - eventHandlers: - - event: Transfer(indexed address,indexed address,indexed uint256) - handler: handleTransfer - receipt: true - - event: Approval(indexed address,indexed address,indexed uint256) - handler: handleApproval - receipt: true - - event: ApprovalForAll(indexed address,indexed address,bool) - handler: handleApprovalForAll - receipt: true - - event: MetadataUpdate(uint256) - handler: handleMetadataUpdate - receipt: true - - kind: ethereum/contract - name: ConstantInflowNFT - network: {{ network }} - source: - address: "{{ constantInflowNFTAddress }}" - abi: IFlowNFTBase - startBlock: {{ hostStartBlock }} - mapping: - kind: ethereum/events - apiVersion: 0.0.8 - language: wasm/assemblyscript - file: ./src/mappings/flowNFT.ts - entities: - - ApprovalEvent - - ApprovalForAllEvent - - MetadataUpdateEvent - - TransferEvent - abis: - - name: IFlowNFTBase - file: ./abis/IFlowNFTBase.json - - name: ISuperfluid - file: ./abis/ISuperfluid.json - eventHandlers: - - event: Transfer(indexed address,indexed address,indexed uint256) - handler: handleTransfer - receipt: true - - event: Approval(indexed address,indexed address,indexed uint256) - handler: handleApproval - receipt: true - - event: ApprovalForAll(indexed address,indexed address,bool) - handler: handleApprovalForAll - receipt: true - - event: MetadataUpdate(uint256) - handler: handleMetadataUpdate - receipt: true templates: - name: SuperToken kind: ethereum/contract diff --git a/packages/subgraph/tasks/setup-graph-node.sh b/packages/subgraph/tasks/setup-graph-node.sh index f5050dae5d..f7758a3d98 100644 --- a/packages/subgraph/tasks/setup-graph-node.sh +++ b/packages/subgraph/tasks/setup-graph-node.sh @@ -7,8 +7,8 @@ if ! which docker >/dev/null 2>&1 ; then exit 1 fi -if ! which docker-compose >/dev/null 2>&1; then - echo "Please install 'docker-compose' first" +if ! docker compose --help >/dev/null 2>&1; then + echo "Please install 'docker compose' first" exit 1 fi @@ -18,10 +18,10 @@ if ! which jq >/dev/null 2>&1; then fi # Create the graph-node container -docker-compose up --no-start graph-node +docker compose up --no-start graph-node # Start graph-node so we can inspect it -docker-compose start graph-node +docker compose start graph-node # Identify the container ID CONTAINER_ID=$(docker container ls | grep graph-node | cut -d' ' -f1) @@ -36,7 +36,7 @@ sed -i -e "s/host.docker.internal/$HOST_IP/g" docker-compose.yml function stop_graph_node { # Ensure graph-node is stopped - docker-compose stop graph-node + docker compose stop graph-node } trap stop_graph_node EXIT diff --git a/packages/subgraph/tests/superToken/event/superToken.event.test.ts b/packages/subgraph/tests/superToken/event/superToken.event.test.ts index b04f280ba2..f2ae06e9af 100644 --- a/packages/subgraph/tests/superToken/event/superToken.event.test.ts +++ b/packages/subgraph/tests/superToken/event/superToken.event.test.ts @@ -359,8 +359,6 @@ describe("SuperToken Mapper Unit Tests", () => { assert.fieldEquals("ApprovalEvent", id, "owner", owner); assert.fieldEquals("ApprovalEvent", id, "to", spender); assert.fieldEquals("ApprovalEvent", id, "amount", value.toString()); - assert.fieldEquals("ApprovalEvent", id, "isNFTApproval", FALSE); - assert.fieldEquals("ApprovalEvent", id, "tokenId", "0"); }); test("handleTransfer() - Should create a new TransferEvent entity", () => { @@ -506,21 +504,21 @@ describe("SuperToken Mapper Unit Tests", () => { "operatorData", operatorData.toHexString() ); - }); + }); test("TokenStatistic::totalNumberOfHolders should decrease its count when a user transfers tokens and the balance reaches 0.", () => { const from = alice; const to = bob; const value = BigInt.fromI32(100); - + const transferEvent = createTransferEvent( from, to, value ); - + handleTransfer(transferEvent); - + const id = assertEventBaseProperties( transferEvent, "Transfer" @@ -528,7 +526,7 @@ describe("SuperToken Mapper Unit Tests", () => { assert.fieldEquals("TransferEvent", id, "from", from); assert.fieldEquals("TransferEvent", id, "to", to); assert.fieldEquals("TransferEvent", id, "value", value.toString()); - + assertTokenStatisticProperties( null, null, @@ -558,7 +556,7 @@ describe("SuperToken Mapper Unit Tests", () => { BIG_INT_ZERO, // totalSupply = 0 2, // totalNumberOfAccounts, 2 // totalNumberOfHolders - ); + ); const secondTransferEvent = createTransferEvent(