├── ethereum-contracts
├── .npmrc
├── .eslintignore
├── .gitattributes
├── .solhintignore
├── .solcover.js
├── js-sdk
│ ├── index.js
│ ├── getConfig.js
│ └── Framework.js
├── migrations
│ ├── .eslintrc.js
│ └── 2_erc1820
├── test
│ ├── contracts.test.js
│ ├── superfluid
│ │ └── SuperTokenStorage.test.js
│ ├── .eslintrc.js
│ ├── sdk.test.js
│ └── deployment.test.js
├── .gitignore
├── scripts
│ ├── .eslintrc.js
│ ├── build-abi-js.sh
│ ├── deploy-test-environment.js
│ ├── reset-deployment.js
│ ├── utils.js
│ ├── deploy-test-token.js
│ ├── deploy-super-token.js
│ ├── deploy-erc1820.js
│ └── inspect-account.js
├── contracts
│ ├── interfaces
│ │ ├── misc
│ │ │ └── IResolver.sol
│ │ ├── tokens
│ │ │ ├── ERC20WithTokenInfo.sol
│ │ │ └── TokenInfo.sol
│ │ ├── superfluid
│ │ │ ├── SuperAppDefinitions.sol
│ │ │ ├── ISuperAgreement.sol
│ │ │ ├── ISuperfluidGovernance.sol
│ │ │ └── ISuperApp.sol
│ │ └── agreements
│ │ │ └── IConstantFlowAgreementV1.sol
│ ├── test
│ │ ├── TestToken.sol
│ │ ├── TestResolver.sol
│ │ └── TestGovernance.sol
│ ├── upgradability
│ │ ├── Proxiable.sol
│ │ ├── ProxyUtils.sol
│ │ └── Proxy.sol
│ ├── mocks
│ │ ├── SuperTokenStorageTester.sol
│ │ └── ERC777SenderRecipientMock.sol
│ ├── access
│ │ └── Ownable.sol
│ └── apps
│ │ └── SuperAppBase.sol
├── .eslintrc.js
├── .solhint.json
├── .editorconfig
├── build
│ └── contracts
│ │ ├── Context.json
│ │ ├── Math.json
│ │ ├── Address.json
│ │ ├── SignedSafeMath.json
│ │ ├── Create2.json
│ │ ├── IResolver.json
│ │ ├── ProxyUtils.json
│ │ ├── SafeMath.json
│ │ ├── EnumerableSet.json
│ │ ├── IERC1820Implementer.json
│ │ ├── Proxiable.json
│ │ ├── IERC777Recipient.json
│ │ ├── ERC1820Implementer.json
│ │ ├── IERC777Sender.json
│ │ ├── TokenInfo.json
│ │ ├── AgreementLibrary.json
│ │ └── Proxy.json
├── package.json
└── README.md
├── .gitignore
├── sample-integrations
├── flowlottery
│ ├── ui
│ │ ├── public
│ │ │ ├── robots.txt
│ │ │ ├── favicon.ico
│ │ │ ├── logo192.png
│ │ │ ├── logo512.png
│ │ │ ├── neutral.gif
│ │ │ ├── winning.gif
│ │ │ ├── waterfall.gif
│ │ │ ├── manifest.json
│ │ │ └── index.html
│ │ ├── src
│ │ │ ├── logo.jpeg
│ │ │ ├── ethereumLogo.png
│ │ │ ├── utils
│ │ │ │ ├── utils.js
│ │ │ │ └── web3Modal.js
│ │ │ ├── setupTests.js
│ │ │ ├── App.test.js
│ │ │ ├── graphql
│ │ │ │ └── subgraph.js
│ │ │ ├── index.css
│ │ │ ├── index.js
│ │ │ └── components
│ │ │ │ ├── BottomTables.js
│ │ │ │ └── index.js
│ │ ├── .gitignore
│ │ ├── .editorconfig
│ │ ├── package.json
│ │ ├── scripts
│ │ │ └── ipfs.js
│ │ └── README.md
│ ├── migrations
│ │ ├── .eslintrc.js
│ │ └── 2_erc1820.js
│ ├── .gitignore
│ ├── package.json
│ ├── README.md
│ ├── scripts
│ │ └── deploy.js
│ └── truffle-config.js
├── dividends-rights-token-demo
│ ├── migrations
│ │ ├── .eslintrc.js
│ │ └── 2_erc1820.js
│ ├── .gitignore
│ ├── README.md
│ ├── package.json
│ ├── scripts
│ │ └── deploy.js
│ ├── ui
│ │ └── index.html
│ └── truffle-config.js
├── superfluid-console-demo
│ ├── .gitignore
│ ├── README.md
│ ├── package.json
│ └── index.js
└── superfluid-AfterEffect
│ ├── contracts
│ ├── Wallet.sol
│ ├── interfaces
│ │ ├── IERC165.sol
│ │ └── IERC173.sol
│ └── Ownable.sol
│ ├── scripts
│ └── deploy.js
│ ├── package.json
│ ├── truffle-config.js
│ └── test
│ └── DmsApp.test.js
├── Changelog
├── sync-ethereum-contracts.sh
├── README.md
└── test-scripts
├── console-quick-start.js
└── cfa-test.js
/ethereum-contracts/.npmrc:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/ethereum-contracts/.eslintignore:
--------------------------------------------------------------------------------
1 | coverage
2 | coverage.json
3 | build
4 |
--------------------------------------------------------------------------------
/ethereum-contracts/.gitattributes:
--------------------------------------------------------------------------------
1 | *.sol linguist-language=Solidity
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /ethereum-contracts-v0.1
2 |
3 | sample-integrations/.DS_Store
4 |
--------------------------------------------------------------------------------
/ethereum-contracts/.solhintignore:
--------------------------------------------------------------------------------
1 | contracts/test/SuperTokenStorageTester.sol
2 |
--------------------------------------------------------------------------------
/sample-integrations/flowlottery/ui/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 |
--------------------------------------------------------------------------------
/ethereum-contracts/.solcover.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | skipFiles: ["test/", "SuperAgreementBase.sol", "ERC20Base.sol"]
3 | };
4 |
--------------------------------------------------------------------------------
/ethereum-contracts/js-sdk/index.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | getConfig: require("./getConfig"),
3 | Framework: require("./Framework"),
4 | };
5 |
--------------------------------------------------------------------------------
/ethereum-contracts/migrations/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | "globals": {
3 | },
4 | "rules": {
5 | "no-console": "off"
6 | }
7 | };
8 |
--------------------------------------------------------------------------------
/sample-integrations/flowlottery/migrations/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | "globals": {
3 | },
4 | "rules": {
5 | "no-console": "off"
6 | }
7 | };
8 |
--------------------------------------------------------------------------------
/sample-integrations/flowlottery/ui/src/logo.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/superfluid-finance/superfluid-protocol-preview/HEAD/sample-integrations/flowlottery/ui/src/logo.jpeg
--------------------------------------------------------------------------------
/sample-integrations/flowlottery/ui/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/superfluid-finance/superfluid-protocol-preview/HEAD/sample-integrations/flowlottery/ui/public/favicon.ico
--------------------------------------------------------------------------------
/sample-integrations/flowlottery/ui/public/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/superfluid-finance/superfluid-protocol-preview/HEAD/sample-integrations/flowlottery/ui/public/logo192.png
--------------------------------------------------------------------------------
/sample-integrations/flowlottery/ui/public/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/superfluid-finance/superfluid-protocol-preview/HEAD/sample-integrations/flowlottery/ui/public/logo512.png
--------------------------------------------------------------------------------
/sample-integrations/flowlottery/ui/public/neutral.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/superfluid-finance/superfluid-protocol-preview/HEAD/sample-integrations/flowlottery/ui/public/neutral.gif
--------------------------------------------------------------------------------
/sample-integrations/flowlottery/ui/public/winning.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/superfluid-finance/superfluid-protocol-preview/HEAD/sample-integrations/flowlottery/ui/public/winning.gif
--------------------------------------------------------------------------------
/sample-integrations/flowlottery/ui/public/waterfall.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/superfluid-finance/superfluid-protocol-preview/HEAD/sample-integrations/flowlottery/ui/public/waterfall.gif
--------------------------------------------------------------------------------
/sample-integrations/flowlottery/ui/src/ethereumLogo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/superfluid-finance/superfluid-protocol-preview/HEAD/sample-integrations/flowlottery/ui/src/ethereumLogo.png
--------------------------------------------------------------------------------
/sample-integrations/dividends-rights-token-demo/migrations/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | "globals": {
3 | },
4 | "rules": {
5 | "no-console": "off"
6 | }
7 | };
8 |
--------------------------------------------------------------------------------
/sample-integrations/flowlottery/.gitignore:
--------------------------------------------------------------------------------
1 | /data
2 | /node_modules
3 | /build
4 | /coverage.json
5 | /coverage
6 | /.env
7 | /data
8 | *.ignore.*
9 | yarn.lock
10 | .DS_Store
11 |
12 | *.env
13 |
14 | .vscode/
15 |
--------------------------------------------------------------------------------
/sample-integrations/flowlottery/ui/.gitignore:
--------------------------------------------------------------------------------
1 | /data
2 | /node_modules
3 | /build
4 | /coverage.json
5 | /coverage
6 | /.env
7 | /data
8 | *.ignore.*
9 | yarn.lock
10 | .DS_Store
11 |
12 | *.env
13 |
14 | .vscode/
15 |
--------------------------------------------------------------------------------
/sample-integrations/dividends-rights-token-demo/.gitignore:
--------------------------------------------------------------------------------
1 | /data
2 | /node_modules
3 | /build
4 | /coverage.json
5 | /coverage
6 | /.env
7 | /data
8 | *.ignore.*
9 | yarn.lock
10 | .DS_Store
11 |
12 | *.env
13 |
14 | .vscode/
15 |
--------------------------------------------------------------------------------
/sample-integrations/superfluid-console-demo/.gitignore:
--------------------------------------------------------------------------------
1 | /data
2 | /node_modules
3 | /build
4 | /coverage.json
5 | /coverage
6 | /.env
7 | /data
8 | *.ignore.*
9 | yarn.lock
10 | .DS_Store
11 |
12 | *.env
13 |
14 | .vscode/
15 |
16 |
--------------------------------------------------------------------------------
/ethereum-contracts/test/contracts.test.js:
--------------------------------------------------------------------------------
1 | require("./superfluid/Superfluid.test.js");
2 | require("./superfluid/SuperToken.test.js");
3 | require("./agreements/ConstantFlowAgreementV1.test.js");
4 | require("./agreements/InstantDistributionAgreementV1.test.js");
5 | require("./apps/MultiFlowsApp.test.js");
6 |
--------------------------------------------------------------------------------
/ethereum-contracts/.gitignore:
--------------------------------------------------------------------------------
1 | /data
2 | /node_modules
3 | /coverage.json
4 | /coverage
5 | /.env
6 | /data
7 | *.ignore.*
8 | yarn.lock
9 | .DS_Store
10 |
11 | *.env
12 |
13 | .vscode/
14 |
15 |
16 | # NOT PUBLIC YET
17 | /.github
18 | /maths
19 | /contracts/superfluid
20 | /contracts/agreements
21 |
--------------------------------------------------------------------------------
/sample-integrations/flowlottery/ui/src/utils/utils.js:
--------------------------------------------------------------------------------
1 | export function flowForHumans(flow, cadence = " /month") {
2 | return (flow * ((3600 * 24 * 30) / 1e18)).toFixed(2) + cadence;
3 | }
4 |
5 | export function showTick(bool) {
6 | if (typeof bool === "undefined") return "";
7 | if (bool) return "✔️";
8 | }
9 |
--------------------------------------------------------------------------------
/sample-integrations/flowlottery/ui/src/setupTests.js:
--------------------------------------------------------------------------------
1 | // jest-dom adds custom jest matchers for asserting on DOM nodes.
2 | // allows you to do things like:
3 | // expect(element).toHaveTextContent(/react/i)
4 | // learn more: https://github.com/testing-library/jest-dom
5 | import "@testing-library/jest-dom/extend-expect";
6 |
--------------------------------------------------------------------------------
/ethereum-contracts/migrations/2_erc1820:
--------------------------------------------------------------------------------
1 | const Web3 = require("web3");
2 | const deploy = require("../scripts/deploy-erc1820");
3 |
4 | module.exports = async function(deployer) {
5 | const errorHandler = err => { if (err) throw err; };
6 | global.web3 = new Web3(deployer.provider);
7 | await deploy(errorHandler);
8 | };
9 |
--------------------------------------------------------------------------------
/sample-integrations/flowlottery/ui/src/App.test.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { render } from "@testing-library/react";
3 | import App from "./App";
4 |
5 | test("renders learn react link", () => {
6 | const { getByText } = render();
7 | const linkElement = getByText(/learn react/i);
8 | expect(linkElement).toBeInTheDocument();
9 | });
10 |
--------------------------------------------------------------------------------
/ethereum-contracts/test/superfluid/SuperTokenStorage.test.js:
--------------------------------------------------------------------------------
1 | const SuperTokenStorageTester = artifacts.require("SuperTokenStorageTester");
2 |
3 | contract("SuperTokenStorage", () => {
4 | it("#0 validate immutable storage layout", async () => {
5 | const tester = await SuperTokenStorageTester.new();
6 | await tester.validate.call();
7 | });
8 | });
9 |
--------------------------------------------------------------------------------
/sample-integrations/flowlottery/migrations/2_erc1820.js:
--------------------------------------------------------------------------------
1 | const Web3 = require("web3");
2 | const deploy = require("@superfluid-finance/ethereum-contracts/scripts/deploy-erc1820");
3 |
4 | module.exports = async function(deployer) {
5 | const errorHandler = err => { if (err) throw err; };
6 | global.web3 = new Web3(deployer.provider);
7 | await deploy(errorHandler);
8 | };
9 |
--------------------------------------------------------------------------------
/ethereum-contracts/scripts/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | "globals": {
3 | "web3": true,
4 | "artifacts": true,
5 | "describe": true,
6 | "contract": true,
7 | "before": true,
8 | "beforeEach": true,
9 | "it": true,
10 | "assert": true,
11 | },
12 | "rules": {
13 | "no-console": "off"
14 | }
15 | };
16 |
--------------------------------------------------------------------------------
/sample-integrations/dividends-rights-token-demo/migrations/2_erc1820.js:
--------------------------------------------------------------------------------
1 | const Web3 = require("web3");
2 | const deploy = require("@superfluid-finance/ethereum-contracts/scripts/deploy-erc1820");
3 |
4 | module.exports = async function(deployer) {
5 | const errorHandler = err => { if (err) throw err; };
6 | global.web3 = new Web3(deployer.provider);
7 | await deploy(errorHandler);
8 | };
9 |
--------------------------------------------------------------------------------
/sample-integrations/flowlottery/ui/src/graphql/subgraph.js:
--------------------------------------------------------------------------------
1 | import { gql } from "apollo-boost";
2 |
3 | // See more example queries on https://thegraph.com/explorer/subgraph/paulrberg/create-eth-app
4 | const GET_TRANSFERS = gql`
5 | {
6 | transfers(first: 10) {
7 | id
8 | from
9 | to
10 | value
11 | }
12 | }
13 | `;
14 |
15 | export default GET_TRANSFERS;
16 |
--------------------------------------------------------------------------------
/sample-integrations/superfluid-AfterEffect/contracts/Wallet.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity ^0.7.4;
3 |
4 | import "./interfaces/IERC165.sol";
5 | import "./Ownable.sol";
6 |
7 | contract Wallet is IERC165, Ownable {
8 |
9 | function supportsInterface(bytes4 interfaceID) external view override returns (bool) {
10 | return interfaceID == 0x7f5828d0;
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/sample-integrations/superfluid-console-demo/README.md:
--------------------------------------------------------------------------------
1 | # Superfluid Console Demo
2 |
3 | ## Step 1: Create .env
4 | ```
5 | GOERLI_MNEMONIC="your mnemonic where accounts have goerli eth"
6 | GOERLI_PROVIDER_URL="https://goerli.infura.io/v3/your_api_key"
7 |
8 | ## Step 2: Install dependencies
9 |
10 | ```
11 | $ npm ci
12 | ```
13 |
14 | ## Step 3: Execute
15 |
16 | ```
17 | $ node index.js
18 | ```
19 |
--------------------------------------------------------------------------------
/ethereum-contracts/contracts/interfaces/misc/IResolver.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity >= 0.5.0;
3 |
4 | /**
5 | * @dev Abstraction for a address resolver contract
6 | *
7 | * @author Superfluid
8 | */
9 | interface IResolver {
10 |
11 | /**
12 | * @dev Get address by name.
13 | */
14 | function get(string calldata name) external view returns (address);
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/ethereum-contracts/test/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | "globals": {
3 | "web3": true,
4 | "artifacts": true,
5 | "describe": true,
6 | "contract": true,
7 | "before": true,
8 | "beforeEach": true,
9 | "afterEach": true,
10 | "it": true,
11 | "assert": true,
12 | },
13 | "rules": {
14 | "no-console": "off"
15 | }
16 | };
17 |
--------------------------------------------------------------------------------
/ethereum-contracts/js-sdk/getConfig.js:
--------------------------------------------------------------------------------
1 | const DEFAULT_CONFIG = {
2 | 5: {
3 | resolverAddress: "0x3710AB3fDE2B61736B8BB0CE845D6c61F667a78E"
4 | }
5 | };
6 |
7 | /// @dev Get the network configuration
8 | module.exports = function getConfig(chainId) {
9 | const defaultConfig = DEFAULT_CONFIG[chainId] || {};
10 | return {
11 | resolverAddress: process.env.TEST_RESOLVER_ADDRESS || defaultConfig.resolverAddress
12 | };
13 | };
14 |
--------------------------------------------------------------------------------
/ethereum-contracts/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | extends: "eslint:recommended",
4 | env: {
5 | node: true,
6 | es2017: true
7 | },
8 | rules: {
9 | "max-len": ["error", 120, { code: 80, ignoreUrls: true }],
10 | "indent": ["error", 4],
11 | "linebreak-style": ["error", "unix"],
12 | "quotes": ["error", "double"],
13 | "semi": ["error", "always" ],
14 | }
15 | };
16 |
--------------------------------------------------------------------------------
/Changelog:
--------------------------------------------------------------------------------
1 | 0.1.2-preview-20201014-fix5
2 |
3 | * Breaking change: using new resolver address for goerli
4 |
5 | 0.1.2-preview-20201014-fix3
6 |
7 | * This change is backward incompatible. New deployment is available at
8 | version `0.1.2-preview-20201014`.
9 | * Fixed a bug in the updateFlow callback.
10 | * SuperToken is now ERC-777, in order to test locally it is recommended to
11 | add `scripts/deploy-erc1820` usage to your migrations. See projects in
12 | sample-integrations.
13 |
--------------------------------------------------------------------------------
/sample-integrations/flowlottery/ui/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
4 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
5 | sans-serif;
6 | -webkit-font-smoothing: antialiased;
7 | -moz-osx-font-smoothing: grayscale;
8 | }
9 |
10 | code {
11 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
12 | monospace;
13 | }
14 |
15 | h1,
16 | h2,
17 | h3,
18 | h4,
19 | h5 {
20 | font-family: "Rock Salt", cursive;
21 | }
22 |
--------------------------------------------------------------------------------
/sample-integrations/superfluid-console-demo/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "superfluid-console-demo",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "dependencies": {
7 | "@superfluid-finance/ethereum-contracts": "latest",
8 | "@truffle/contract": "^4.2.23",
9 | "@truffle/hdwallet-provider": "^1.1.0",
10 | "dotenv": "^8.2.0"
11 | },
12 | "devDependencies": {},
13 | "scripts": {
14 | "test": "echo \"Error: no test specified\" && exit 1"
15 | },
16 | "author": "Superfluid",
17 | "license": "MIT"
18 | }
19 |
--------------------------------------------------------------------------------
/ethereum-contracts/.solhint.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": ["solhint:recommended"],
3 | "rules": {
4 | "max-states-count": "off",
5 | "no-inline-assembly": "off",
6 | "mark-callable-contracts": "off",
7 | "max-line-length": ["error", 120],
8 | "func-param-name-mixedcase": "error",
9 | "modifier-name-mixedcase": "error",
10 | "private-vars-leading-underscore": ["error", { "strict": true }],
11 | "reason-string": ["error", { "maxLength": 64 } ],
12 | "compiler-version": ["error", ">=0.5.0"],
13 | "func-visibility" : ["error", { "ignoreConstructors": true }]
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/sample-integrations/flowlottery/ui/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "Eth App",
3 | "name": "Create Eth App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "logo192.png",
12 | "type": "image/png",
13 | "sizes": "192x192"
14 | },
15 | {
16 | "src": "logo512.png",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
--------------------------------------------------------------------------------
/sample-integrations/superfluid-AfterEffect/contracts/interfaces/IERC165.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity 0.7.4;
3 |
4 | interface IERC165 {
5 | /// @notice Query if a contract implements an interface
6 | /// @param interfaceID The interface identifier, as specified in ERC-165
7 | /// @dev Interface identification is specified in ERC-165. This function
8 | /// uses less than 30,000 gas.
9 | /// @return `true` if the contract implements `interfaceID` and
10 | /// `interfaceID` is not 0xffffffff, `false` otherwise
11 | function supportsInterface(bytes4 interfaceID) external view returns (bool);
12 | }
13 |
--------------------------------------------------------------------------------
/sample-integrations/dividends-rights-token-demo/README.md:
--------------------------------------------------------------------------------
1 | Dividend Rights Token
2 | =====================
3 |
4 | A ERC20 token that tokenizes units in the [Instant Distribution Agreements](https://docs.superfluid.finance/tutorials/instant-distribution/).
5 |
6 | All holders of the rights tokens can receive cash token rewards in one distribution transaction in two ways:
7 |
8 | - If the subscription to the token is approved by its holder, then the distribution is available the moment distribution is done,
9 | - if not, then the pending distribution could be claimed by its holder any time in a separated transaction.
10 |
11 | **NB! STILL WORK IN PROGRESS**
12 |
--------------------------------------------------------------------------------
/ethereum-contracts/contracts/interfaces/tokens/ERC20WithTokenInfo.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity >= 0.5.0;
3 |
4 | import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
5 | import { TokenInfo } from "./TokenInfo.sol";
6 |
7 |
8 | /**
9 | *
10 | * @dev Interface for ERC20 token with token info
11 | *
12 | * NOTE: Using abstract contract instead of interfaces because old solidity
13 | * does not support interface inheriting other interfaces
14 | * solhint-disable-next-line no-empty-blocks
15 | *
16 | */
17 | // solhint-disable-next-line no-empty-blocks
18 | abstract contract ERC20WithTokenInfo is IERC20, TokenInfo {}
19 |
--------------------------------------------------------------------------------
/sample-integrations/flowlottery/ui/src/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom";
3 | import ApolloClient from "apollo-boost";
4 | import { ApolloProvider } from "@apollo/react-hooks";
5 | import "./index.css";
6 | import App from "./App";
7 |
8 | // You should replace this url with your own and put it into a .env file
9 | // See all subgraphs: https://thegraph.com/explorer/
10 | const client = new ApolloClient({
11 | uri: "https://api.thegraph.com/subgraphs/name/paulrberg/create-eth-app",
12 | });
13 |
14 | ReactDOM.render(
15 |
16 |
17 | ,
18 | document.getElementById("root"),
19 | );
20 |
--------------------------------------------------------------------------------
/ethereum-contracts/scripts/build-abi-js.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | cd "$(dirname "$0")/.."
4 |
5 | which jq &>/dev/null || { echo "Install jq utility!" && exit 1; }
6 |
7 | CONTRACTS=(
8 | IERC20
9 | TokenInfo
10 | ERC20WithTokenInfo
11 | TestToken
12 | IResolver
13 | ISuperfluid
14 | ISuperToken
15 | IConstantFlowAgreementV1
16 | IInstantDistributionAgreementV1
17 | )
18 |
19 | {
20 | echo "if (typeof module === \"undefined\") module = {};"
21 | echo "Superfluid_ABI = module.exports = {"
22 | for i in "${CONTRACTS[@]}";do
23 | echo " $i: $(jq -c '.abi' build/contracts/$i.json),"
24 | done
25 | echo "};"
26 | } > build/abi.js
27 |
--------------------------------------------------------------------------------
/ethereum-contracts/contracts/test/TestToken.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity 0.7.1;
3 |
4 | import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
5 |
6 | /**
7 | * @dev Test ERC20 token that allows any one mint new tokens.
8 | */
9 | contract TestToken is ERC20 {
10 |
11 | constructor(string memory name, string memory symbol)
12 | /* solhint-disable-next-line no-empty-blocks */ // BUG from solhint?
13 | ERC20(symbol, name) {
14 | }
15 |
16 | /**
17 | * @dev See {ERC20-_mint}.
18 | */
19 | function mint(address account, uint256 amount) public returns (bool) {
20 | ERC20._mint(account, amount);
21 | return true;
22 | }
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/sample-integrations/superfluid-AfterEffect/contracts/interfaces/IERC173.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity 0.7.4;
3 | /// @title ERC-173 Contract Ownership Standard
4 | /// Note: the ERC-165 identifier for this interface is 0x7f5828d0
5 | interface IERC173 /* is ERC165 */ {
6 | /// @dev This emits when ownership of a contract changes.
7 | event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
8 |
9 | /// @notice Get the address of the owner
10 | /// @return The address of the owner.
11 | function owner() view external returns(address);
12 |
13 | /// @notice Set the address of the new owner of the contract
14 | /// @dev Set _newOwner to address(0) to renounce any ownership.
15 | /// @param _newOwner The address of the new owner of the contract
16 | function transferOwnership(address _newOwner) external;
17 | }
18 |
--------------------------------------------------------------------------------
/sample-integrations/flowlottery/ui/src/utils/web3Modal.js:
--------------------------------------------------------------------------------
1 | import Web3Modal from "web3modal"; //import WalletConnectProvider from "@walletconnect/web3-provider";
2 |
3 | // Enter a valid infura key here to avoid being rate limited
4 | // You can get a key for free at https://infura.io/register
5 | const INFURA_ID = "90db0e566ddf4de7b05ed1e57306bbe4";
6 |
7 | // Web3Modal also supports many other wallets.
8 | // You can see other options at https://github.com/Web3Modal/web3modal
9 | export const web3Modal = new Web3Modal({
10 | network: "goerli",
11 | cacheProvider: true
12 | // providerOptions: {
13 | // walletconnect: {
14 | // package: WalletConnectProvider,
15 | // options: {
16 | // infuraId: INFURA_ID
17 | // }
18 | // }
19 | // }
20 | });
21 |
22 | export const logoutOfWeb3Modal = async function() {
23 | await web3Modal.clearCachedProvider();
24 | window.location.reload();
25 | };
26 |
--------------------------------------------------------------------------------
/ethereum-contracts/contracts/interfaces/superfluid/SuperAppDefinitions.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity >= 0.7.0;
3 |
4 | /**
5 | * @dev Super app definitions library
6 | */
7 | library SuperAppDefinitions {
8 |
9 | //
10 | // App manifest config word
11 | //
12 | uint constant public TYPE_APP_FINAL = 1 << 0;
13 | uint constant public TYPE_APP_SECOND = 1 << 1;
14 | uint constant public JAIL = 1 << 15;
15 |
16 | //
17 | // Callback implementation bit masks
18 | //
19 | uint constant public BEFORE_AGREEMENT_CREATED_NOOP = 1 << (32 + 0);
20 | uint constant public AFTER_AGREEMENT_CREATED_NOOP = 1 << (32 + 1);
21 | uint constant public BEFORE_AGREEMENT_UPDATED_NOOP = 1 << (32 + 2);
22 | uint constant public AFTER_AGREEMENT_UPDATED_NOOP = 1 << (32 + 3);
23 | uint constant public BEFORE_AGREEMENT_TERMINATED_NOOP = 1 << (32 + 4);
24 | uint constant public AFTER_AGREEMENT_TERMINATED_NOOP = 1 << (32 + 5);
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/sample-integrations/flowlottery/ui/.editorconfig:
--------------------------------------------------------------------------------
1 | ################################################
2 | # ╔═╗╔╦╗╦╔╦╗╔═╗╦═╗┌─┐┌─┐┌┐┌┌─┐┬┌─┐
3 | # ║╣ ║║║ ║ ║ ║╠╦╝│ │ ││││├┤ ││ ┬
4 | # o╚═╝═╩╝╩ ╩ ╚═╝╩╚═└─┘└─┘┘└┘└ ┴└─┘
5 | #
6 | # > Formatting conventions for your Sails app.
7 | #
8 | # This file (`.editorconfig`) exists to help
9 | # maintain consistent formatting throughout the
10 | # files in your Sails app.
11 | #
12 | # For the sake of convention, the Sails team's
13 | # preferred settings are included here out of the
14 | # box. You can also change this file to fit your
15 | # team's preferences (for example, if all of the
16 | # developers on your team have a strong preference
17 | # for tabs over spaces),
18 | #
19 | # To review what each of these options mean, see:
20 | # http://editorconfig.org/
21 | #
22 | ################################################
23 | root = true
24 |
25 | [*]
26 | indent_style = space
27 | indent_size = 2
28 | end_of_line = lf
29 | charset = utf-8
30 | trim_trailing_whitespace = true
31 | insert_final_newline = true
32 |
--------------------------------------------------------------------------------
/sample-integrations/flowlottery/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "flowlottery-superapp",
3 | "version": "1.0.0",
4 | "description": "Flow lottery - a superfluid SuperApp demo",
5 | "main": "scripts/demo.js",
6 | "scripts": {
7 | "build": "truffle compile --all",
8 | "pretest": "rm -rf build;mkdir -p build/contracts;cp node_modules/@superfluid-finance/ethereum-contracts/build/contracts/* build/contracts/",
9 | "test": "truffle test",
10 | "deploy": "npm run build && RELEASE_VERSION=0.1.2-preview-20201014 npx truffle --network goerli exec scripts/deploy.js"
11 | },
12 | "author": "Superfluid",
13 | "license": "MIT",
14 | "devDependencies": {
15 | "@decentral.ee/web3-helpers": "^0.3.2",
16 | "@openzeppelin/contracts": "^3.2.1-solc-0.7",
17 | "@openzeppelin/test-helpers": "^0.5.7",
18 | "@superfluid-finance/ethereum-contracts": "0.1.2-preview-20201014-fix5",
19 | "@truffle/contract": "^4.2.25",
20 | "@truffle/hdwallet-provider": "^1.1.0",
21 | "dotenv": "^8.2.0",
22 | "truffle": "^5.1.48"
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/sample-integrations/superfluid-AfterEffect/scripts/deploy.js:
--------------------------------------------------------------------------------
1 | const {
2 | web3tx
3 | } = require("@decentral.ee/web3-helpers");
4 | const SuperfluidSDK = require("@superfluid-finance/ethereum-contracts");
5 | const Dms = artifacts.require("DmsApp");
6 |
7 | module.exports = async function (callback, argv) {
8 | const errorHandler = err => { if (err) throw err; };
9 |
10 | try {
11 | global.web3 = web3;
12 |
13 | const version = process.env.RELEASE_VERSION || "test";
14 | console.log("release version:", version);
15 |
16 | const sf = new SuperfluidSDK.Framework({
17 | chainId: 5,
18 | version: version,
19 | web3Provider: web3.currentProvider
20 | });
21 | await sf.initialize();
22 |
23 | const app = await web3tx(Dms.new, "Deploy DmsApp")(
24 | sf.host.address,
25 | sf.agreements.cfa.address
26 | );
27 | console.log("App deployed at", app.address);
28 | callback();
29 | } catch (err) {
30 | callback(err);
31 | }
32 | }
33 |
34 |
--------------------------------------------------------------------------------
/ethereum-contracts/.editorconfig:
--------------------------------------------------------------------------------
1 | ################################################
2 | # ╔═╗╔╦╗╦╔╦╗╔═╗╦═╗┌─┐┌─┐┌┐┌┌─┐┬┌─┐
3 | # ║╣ ║║║ ║ ║ ║╠╦╝│ │ ││││├┤ ││ ┬
4 | # o╚═╝═╩╝╩ ╩ ╚═╝╩╚═└─┘└─┘┘└┘└ ┴└─┘
5 | #
6 | # > Formatting conventions for your Sails app.
7 | #
8 | # This file (`.editorconfig`) exists to help
9 | # maintain consistent formatting throughout the
10 | # files in your Sails app.
11 | #
12 | # For the sake of convention, the Sails team's
13 | # preferred settings are included here out of the
14 | # box. You can also change this file to fit your
15 | # team's preferences (for example, if all of the
16 | # developers on your team have a strong preference
17 | # for tabs over spaces),
18 | #
19 | # To review what each of these options mean, see:
20 | # http://editorconfig.org/
21 | #
22 | ################################################
23 | root = true
24 |
25 | [*]
26 | indent_style = space
27 | indent_size = 4
28 | end_of_line = lf
29 | charset = utf-8
30 | trim_trailing_whitespace = true
31 | insert_final_newline = true
32 |
33 | [.github/workflows/*.yaml]
34 | indent_size = 2
35 |
--------------------------------------------------------------------------------
/sample-integrations/flowlottery/README.md:
--------------------------------------------------------------------------------
1 | Flow Lottery Game
2 | =================
3 |
4 | A game of chance built on Superfluid. Users join the game by sending a stream to our contract.
5 | All incoming streams are summed and the resulting reward stream is sent to the winner, until a new one is chosen!
6 |
7 | Read more about how to build this game from [this medium article](https://medium.com/superfluid-blog/hacking-on-superfluid-bbb9ade94f98).
8 |
9 | A version works for the goerli testnet is also deployed to [https://flowlottery.eth.link/](https://flowlottery.eth.link/).
10 |
11 | Development
12 | ===========
13 |
14 | ## Build contracts
15 |
16 | ```
17 | $ npm ci
18 | $ npm run test
19 | $ npm run build
20 | ```
21 |
22 | ## Deploy the SuperApp
23 |
24 | ```
25 | $ npm run deploy
26 | ```
27 |
28 | ## Test the UI
29 |
30 | To use the already deployed the SuperApp:
31 |
32 | ```
33 | $ cd ui
34 | $ npm ci
35 | $ npm start
36 | ```
37 |
38 | ## Hack It
39 |
40 | - `contracts/LotterySuperApp.sol`: The flow lottery SuperApp.
41 | - `test/LotterySuperApp.test.js`: The test cases.
42 | - `ui`: The flow lottery dapp UI.
43 |
--------------------------------------------------------------------------------
/sample-integrations/superfluid-AfterEffect/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "afterfact",
3 | "version": "1.0.0",
4 | "main": "truffle-config.js",
5 | "directories": {
6 | "test": "test"
7 | },
8 | "scripts": {
9 | "build": "truffle compile --all",
10 | "pretest": "rm -rf build;mkdir -p build/contracts;cp node_modules/@superfluid-finance/ethereum-contracts/build/contracts/* build/contracts/",
11 | "test": "truffle test",
12 | "deploy": "npm run build && RELEASE_VERSION=0.1.2-preview-20201014 npx truffle --network goerli exec scripts/deploy.js"
13 | },
14 | "author": "",
15 | "license": "MIT",
16 | "description": "",
17 | "devDependencies": {
18 | "@decentral.ee/web3-helpers": "^0.3.4",
19 | "@openzeppelin/contracts": "^3.2.1-solc-0.7",
20 | "@openzeppelin/test-helpers": "^0.5.9",
21 | "@truffle/contract": "^4.2.30",
22 | "@truffle/hdwallet-provider": "^1.2.0",
23 | "dotenv": "^8.2.0",
24 | "truffle": "^5.1.53"
25 | },
26 | "dependencies": {
27 | "@superfluid-finance/ethereum-contracts": "^0.1.2-preview-20201014-fix5",
28 | "ganache-time-traveler": "^1.0.15"
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/sample-integrations/dividends-rights-token-demo/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "dividend-rights-token",
3 | "version": "1.0.0",
4 | "description": "Dividend Rights Token - a superfluid superapp demo",
5 | "main": "scripts/demo.js",
6 | "scripts": {
7 | "build": "truffle compile --all",
8 | "--pretest.local": "rm -rf build;mkdir -p build/contracts;cp ../../ethereum-contracts/build/contracts/* build/contracts/",
9 | "pretest": "rm -rf build;mkdir -p build/contracts;cp node_modules/@superfluid-finance/ethereum-contracts/build/contracts/* build/contracts/",
10 | "test": "truffle test",
11 | "deploy": "npm run build && RELEASE_VERSION=0.1.2-preview-20201014 npx truffle --network goerli exec scripts/deploy.js"
12 | },
13 | "author": "Superfluid",
14 | "license": "MIT",
15 | "devDependencies": {
16 | "@decentral.ee/web3-helpers": "^0.3.2",
17 | "@openzeppelin/contracts": "^3.2.1-solc-0.7",
18 | "@openzeppelin/test-helpers": "^0.5.7",
19 | "@superfluid-finance/ethereum-contracts": "0.1.2-preview-20201014-fix5",
20 | "@truffle/contract": "^4.2.25",
21 | "@truffle/hdwallet-provider": "^1.1.0",
22 | "dotenv": "^8.2.0",
23 | "truffle": "^5.1.48"
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/sample-integrations/superfluid-AfterEffect/contracts/Ownable.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity 0.7.4;
3 |
4 | /*
5 | https://github.com/FriendlyUser/solidity-smart-contracts//blob/v0.2.0/contracts/other/CredVert/Ownable.sol
6 | */
7 |
8 | contract Ownable {
9 |
10 | address public owner;
11 |
12 | event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
13 |
14 | /**
15 | * @dev The Ownable constructor sets the original `owner` of the contract to the sender
16 | * account.
17 | */
18 | constructor () public {
19 | owner = msg.sender;
20 | }
21 |
22 |
23 | /**
24 | * @dev Throws if called by any account other than the owner.
25 | */
26 | modifier onlyOwner() {
27 | require(msg.sender == owner);
28 | _;
29 | }
30 |
31 |
32 | /**
33 | * @dev Allows the current owner to transfer control of the contract to a newOwner.
34 | * @param newOwner The address to transfer ownership to.
35 | */
36 | function transferOwnership(address newOwner) public onlyOwner {
37 | require(newOwner != address(0));
38 | emit OwnershipTransferred(owner, newOwner);
39 | owner = newOwner;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/ethereum-contracts/contracts/upgradability/Proxiable.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity 0.7.1;
3 |
4 | import "./ProxyUtils.sol";
5 | import "./Proxy.sol";
6 |
7 | /**
8 | * @dev Proxiable contract.
9 | * Inspired by https://eips.ethereum.org/EIPS/eip-1822
10 | */
11 | abstract contract Proxiable {
12 |
13 | /**
14 | * @dev Get current implementation code address.
15 | */
16 | function getCodeAddress() external view returns (address codeAddress){
17 | return ProxyUtils.implementation();
18 | }
19 |
20 | /**
21 | * @dev Proxiable UUID marker function.
22 | * This would help to avoid wrong logic contract to be used for upgrading.
23 | */
24 | function proxiableUUID() public pure virtual returns (bytes32);
25 |
26 | /**
27 | * @dev Update code address function.
28 | * It is internal, so the derived contract could setup its own permission logic.
29 | */
30 | function _updateCodeAddress(address newAddress) internal {
31 | require(
32 | proxiableUUID() == Proxiable(newAddress).proxiableUUID(),
33 | "Proxiable: NOT_COMPATIBLE"
34 | );
35 | ProxyUtils.setImplementation(newAddress);
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/ethereum-contracts/contracts/interfaces/superfluid/ISuperAgreement.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity >= 0.7.0;
3 |
4 | import { ISuperToken } from "./ISuperToken.sol";
5 |
6 | /**
7 | * @title Superfluid's agreement interface.
8 | *
9 | * @author Superfluid
10 | */
11 | interface ISuperAgreement {
12 |
13 | /**
14 | * @dev Get the type of the agreement class.
15 | */
16 | function agreementType() external pure returns (bytes32);
17 |
18 | /**
19 | * @dev Calculate the real-time balance for the account of this agreement class.
20 | * @param account Account the state belongs to
21 | * @param time Future time used for the calculation.
22 | * @return dynamicBalance Dynamic balance portion of real-time balance of this agreement.
23 | * @return deposit Account deposit amount of this agreement.
24 | * @return owedDeposit Account owed deposit amount of this agreement.
25 | */
26 | function realtimeBalanceOf(
27 | ISuperToken token,
28 | address account,
29 | uint256 time
30 | )
31 | external
32 | view
33 | returns (
34 | int256 dynamicBalance,
35 | uint256 deposit,
36 | uint256 owedDeposit
37 | );
38 | }
39 |
--------------------------------------------------------------------------------
/ethereum-contracts/build/contracts/Context.json:
--------------------------------------------------------------------------------
1 | {
2 | "contractName": "Context",
3 | "abi": [],
4 | "metadata": "{\"compiler\":{\"version\":\"0.7.1+commit.f4a555be\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"@openzeppelin/contracts/GSN/Context.sol\":\"Context\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/GSN/Context.sol\":{\"keccak256\":\"0x910a2e625b71168563edf9eeef55a50d6d699acfe27ceba3921f291829a8f938\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://248246ac66e6479dce1ad7d4945ec5540c98ceb09881e93c93f7c48d5772925c\",\"dweb:/ipfs/QmXr8tmUiZgEYid6ixeeBRmTdUnASWjKzhP3KRxMPy8fRt\"]}},\"version\":1}",
5 | "bytecode": "0x",
6 | "deployedBytecode": "0x",
7 | "immutableReferences": {},
8 | "compiler": {
9 | "name": "solc",
10 | "version": "0.7.1+commit.f4a555be.Emscripten.clang"
11 | },
12 | "networks": {},
13 | "schemaVersion": "3.2.5",
14 | "devdoc": {
15 | "kind": "dev",
16 | "methods": {},
17 | "version": 1
18 | },
19 | "userdoc": {
20 | "kind": "user",
21 | "methods": {},
22 | "version": 1
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/ethereum-contracts/contracts/test/TestResolver.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | /* solhint-disable not-rely-on-time */
3 | pragma solidity 0.7.1;
4 |
5 | import { AccessControl } from "@openzeppelin/contracts/access/AccessControl.sol";
6 | import { IResolver } from "../interfaces/misc/IResolver.sol";
7 |
8 |
9 | contract TestResolver is IResolver, AccessControl {
10 |
11 | bytes32 public constant RESOLVER_ADMIN_ROLE = keccak256("RESOLVER_ADMIN_ROLE");
12 |
13 | mapping(string => address) private _registry;
14 |
15 | constructor() {
16 | _setupRole(RESOLVER_ADMIN_ROLE, msg.sender);
17 | }
18 |
19 | function isAdmin(address account) external view returns (bool) {
20 | return hasRole(RESOLVER_ADMIN_ROLE, account);
21 | }
22 |
23 | function grantAdmin(address account) external {
24 | require(hasRole(RESOLVER_ADMIN_ROLE, _msgSender()), "AccessControl: sender must be an admin to grant");
25 |
26 | _setupRole(RESOLVER_ADMIN_ROLE, account);
27 | }
28 |
29 | function set(string calldata name, address target) external {
30 | require(hasRole(RESOLVER_ADMIN_ROLE, _msgSender()), "Caller is not an admin");
31 | _registry[name] = target;
32 | }
33 |
34 | function get(string calldata name) external view override returns (address) {
35 | return _registry[name];
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/ethereum-contracts/contracts/upgradability/ProxyUtils.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity 0.7.1;
3 |
4 | /**
5 | * @title Proxy Shared Library
6 | */
7 | library ProxyUtils {
8 | /**
9 | * @dev Implementation slot constant.
10 | * Using https://eips.ethereum.org/EIPS/eip-1967 standard
11 | * Storage slot 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc
12 | * (obtained as bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)).
13 | */
14 | bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
15 |
16 | /// @dev Get implementation slot value.
17 | function implementationSlot() internal pure returns (bytes32 slot) {
18 | return _IMPLEMENTATION_SLOT;
19 | }
20 |
21 | /// @dev Get implementation address.
22 | function implementation() internal view returns (address impl) {
23 | assembly { // solium-disable-line
24 | impl := sload(_IMPLEMENTATION_SLOT)
25 | }
26 | }
27 |
28 | /// @dev Set new implementation address.
29 | function setImplementation(address codeAddress) internal {
30 | assembly {
31 | // solium-disable-line
32 | sstore(
33 | _IMPLEMENTATION_SLOT,
34 | codeAddress
35 | )
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/ethereum-contracts/contracts/interfaces/tokens/TokenInfo.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity >= 0.5.0;
3 |
4 | /**
5 | * @dev ERC20 token info interface
6 | *
7 | * NOTE: ERC20 standard interface does not specify these functions, but
8 | * often the token implementations have them.
9 | *
10 | */
11 | interface TokenInfo {
12 | /**
13 | * @dev Returns the name of the token.
14 | */
15 | function name() external view returns (string memory);
16 |
17 | /**
18 | * @dev Returns the symbol of the token, usually a shorter version of the
19 | * name.
20 | */
21 | function symbol() external view returns (string memory);
22 |
23 | /**
24 | * @dev Returns the number of decimals used to get its user representation.
25 | * For example, if `decimals` equals `2`, a balance of `505` tokens should
26 | * be displayed to a user as `5,05` (`505 / 10 ** 2`).
27 | *
28 | * Tokens usually opt for a value of 18, imitating the relationship between
29 | * Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is
30 | * called.
31 | *
32 | * NOTE: This information is only used for _display_ purposes: it in
33 | * no way affects any of the arithmetic of the contract, including
34 | * {IERC20-balanceOf} and {IERC20-transfer}.
35 | */
36 | function decimals() external view returns (uint8);
37 | }
38 |
--------------------------------------------------------------------------------
/sample-integrations/flowlottery/scripts/deploy.js:
--------------------------------------------------------------------------------
1 | const {
2 | web3tx
3 | } = require("@decentral.ee/web3-helpers");
4 | const SuperfluidSDK = require("@superfluid-finance/ethereum-contracts");
5 | const LotterySuperApp = artifacts.require("LotterySuperApp");
6 |
7 | module.exports = async function (callback, argv) {
8 | const errorHandler = err => { if (err) throw err; };
9 |
10 | try {
11 | global.web3 = web3;
12 |
13 | const version = process.env.RELEASE_VERSION || "test";
14 | console.log("release version:", version);
15 |
16 | const sf = new SuperfluidSDK.Framework({
17 | chainId: 5,
18 | version: version,
19 | web3Provider: web3.currentProvider
20 | });
21 | await sf.initialize();
22 |
23 | const daiAddress = await sf.resolver.get("tokens.fDAI");
24 | const dai = await sf.contracts.TestToken.at(daiAddress);
25 | const daixWrapper = await sf.getERC20Wrapper(dai);
26 | const daix = await sf.contracts.ISuperToken.at(daixWrapper.wrapperAddress);
27 |
28 | const app = await web3tx(LotterySuperApp.new, "Deploy LotterySuperApp")(
29 | sf.host.address,
30 | sf.agreements.cfa.address,
31 | daix.address
32 | );
33 | console.log("App deployed at", app.address);
34 | callback();
35 | } catch (err) {
36 | callback(err);
37 | }
38 | }
39 |
40 |
--------------------------------------------------------------------------------
/sample-integrations/dividends-rights-token-demo/scripts/deploy.js:
--------------------------------------------------------------------------------
1 | const {
2 | web3tx
3 | } = require("@decentral.ee/web3-helpers");
4 | const SuperfluidSDK = require("@superfluid-finance/ethereum-contracts");
5 | const DividendRightsToken = artifacts.require("DividendRightsToken");
6 |
7 | module.exports = async function (callback, argv) {
8 | const errorHandler = err => { if (err) throw err; };
9 |
10 | try {
11 | global.web3 = web3;
12 |
13 | const version = process.env.RELEASE_VERSION || "test";
14 | console.log("release version:", version);
15 |
16 | const sf = new SuperfluidSDK.Framework({
17 | chainId: 5,
18 | version: version,
19 | web3Provider: web3.currentProvider
20 | });
21 | await sf.initialize();
22 |
23 | const daiAddress = await sf.resolver.get("tokens.fDAI");
24 | const dai = await sf.contracts.TestToken.at(daiAddress);
25 | const daixWrapper = await sf.getERC20Wrapper(dai);
26 | const daix = await sf.contracts.ISuperToken.at(daixWrapper.wrapperAddress);
27 |
28 | const app = await web3tx(DividendRightsToken.new, "Deploy DividendRightsToken")(
29 | "Dividend Rights Token", "DRT",
30 | daix.address,
31 | sf.host.address, sf.agreements.ida.address,
32 | );
33 | console.log("App deployed at", app.address);
34 | callback();
35 | } catch (err) {
36 | callback(err);
37 | }
38 | }
39 |
40 |
--------------------------------------------------------------------------------
/sample-integrations/superfluid-AfterEffect/truffle-config.js:
--------------------------------------------------------------------------------
1 | const HDWalletProvider = require("@truffle/hdwallet-provider");
2 | require("dotenv").config();
3 | const GAS_LIMIT = 8e6;
4 |
5 |
6 | module.exports = {
7 |
8 | networks: {
9 |
10 | ganache: {
11 | host: "127.0.0.1",
12 | network_id: "*",
13 | port: 8545
14 | },
15 |
16 | goerli: {
17 | provider: () => new HDWalletProvider(
18 | process.env.GOERLI_MNEMONIC,
19 | process.env.GOERLI_PROVIDER_URL,
20 | ),
21 | network_id: 5, // Goerli's id
22 | gas: GAS_LIMIT,
23 | gasPrice: 10e9, // 10 GWEI
24 | //confirmations: 6, // # of confs to wait between deployments. (default: 0)
25 | timeoutBlocks: 50, // # of blocks before a deployment times out (minimum/default: 50)
26 | skipDryRun: false // Skip dry run before migrations? (default: false for public nets )
27 | },
28 | },
29 |
30 | // Set default mocha options here, use special reporters etc.
31 | mocha: {
32 | // timeout: 100000
33 | },
34 |
35 | // Configure your compilers
36 | compilers: {
37 | solc: {
38 | version: "0.7.4", // Fetch exact version from solc-bin (default: truffle's version)
39 | // docker: true, // Use "0.5.1" you've installed locally with docker (default: false)
40 | // settings: { // See the solidity docs for advice about optimization and evmVersion
41 | // optimizer: {
42 | // enabled: false,
43 | // runs: 200
44 | // },
45 | // evmVersion: "byzantium"
46 | // }
47 | },
48 | },
49 | };
50 |
--------------------------------------------------------------------------------
/sync-ethereum-contracts.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash -xe
2 |
3 | PACKAGE_VERSION=0.1.2-preview-20201014-fix5
4 |
5 | cd "$(dirname "$0")"
6 |
7 | if [ ! -d ethereum-contracts-v0.1 ];then
8 | git clone \
9 | --branch v0.1 --single-branch \
10 | https://github.com/superfluid-finance/ethereum-contracts.git \
11 | ethereum-contracts-v0.1
12 | else (
13 | cd ethereum-contracts-v0.1
14 | git pull
15 | ) fi
16 |
17 | (
18 | cd ethereum-contracts-v0.1
19 | if [ -z "$NO_REBUILD" ];then
20 | npm ci
21 | npm run build
22 | fi
23 | )
24 |
25 | rm -rf ethereum-contracts/{build,contracts,js-sdk,test,scripts}
26 | cp -R \
27 | ./ethereum-contracts-v0.1/{README.md,package.json,package-lock.json,truffle-config.js} \
28 | ./ethereum-contracts-v0.1/{build,contracts,js-sdk,test,scripts} \
29 | ethereum-contracts/
30 |
31 | # sanitizing
32 | (
33 | cd ethereum-contracts
34 | rm -f contracts/{superfluid,agreements}/*
35 | for i in build/contracts/*.json;do
36 | cp $i $i.bak
37 | jq 'del(.source,.sourcePath,.sourceMap,.deployedSourceMap,.ast,.legacyAST,.updatedAt)' $i.bak > $i
38 | rm -f $i.bak
39 | done
40 | jq ".version=\"${PACKAGE_VERSION}\"|del(.publishConfig)" package.json > package.json.new
41 | mv package.json.new package.json
42 | jq ".version=\"${PACKAGE_VERSION}\"" package-lock.json > package-lock.json.new
43 | mv package-lock.json.new package-lock.json
44 | )
45 |
46 |
47 | # to depoy
48 | # GOERLI_GAS_PRICE=100e9 RELEASE_VERSION=0.1.2-preview-20201014 npx truffle exec --network goerli scripts/deploy-test-environment.js
49 |
50 |
--------------------------------------------------------------------------------
/ethereum-contracts/scripts/deploy-test-environment.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @dev Deploy the superfluid framework and test tokens for local testing
3 | *
4 | * Usage: npx truffle exec scripts/deploy-all.js
5 | */
6 |
7 |
8 | module.exports = async function (callback) {
9 | // otherwise other scripts do not see the artifacts exported from the truffle framework
10 | global.artifacts = artifacts;
11 | const deployFramework = require("./deploy-framework");
12 | const deployTestToken = require("./deploy-test-token");
13 | const deploySuperToken = require("./deploy-super-token");
14 |
15 | const errorHandler = err => { if (err) throw err; };
16 |
17 | try {
18 | global.web3 = web3;
19 |
20 | console.log("==== Deploying superfluid framework...");
21 | await deployFramework(errorHandler);
22 | console.log("==== Superfluid framework deployed.");
23 |
24 | const tokens = ["fDAI", "fUSDC", "fTUSD"];
25 | for (let i = 0; i < tokens.length; ++i) {
26 | console.log(`==== Deploying test token ${tokens[i]}...`);
27 | await deployTestToken(errorHandler, [":", tokens[i]]);
28 | console.log(`==== Test token ${tokens[i]} deployed.`);
29 |
30 | console.log(`==== Creating super token ${tokens[i]}...`);
31 | await deploySuperToken(errorHandler, [":", tokens[i]]);
32 | console.log(`==== Super token ${tokens[i]} deployed.`);
33 | }
34 |
35 | if (process.env.TEST_RESOLVER_ADDRESS) {
36 | console.log("=============== TEST ENVIRONMENT RESOLVER ======================");
37 | console.log(`export TEST_RESOLVER_ADDRESS=${process.env.TEST_RESOLVER_ADDRESS}`);
38 | }
39 |
40 | callback();
41 | } catch (err) {
42 | callback(err);
43 | }
44 | };
45 |
--------------------------------------------------------------------------------
/sample-integrations/flowlottery/ui/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "superapp-demo-ui",
3 | "version": "1.0.0",
4 | "homepage": "./",
5 | "browserslist": {
6 | "production": [
7 | ">0.2%",
8 | "not dead",
9 | "not op_mini all"
10 | ],
11 | "development": [
12 | "last 1 chrome version",
13 | "last 1 firefox version",
14 | "last 1 safari version"
15 | ]
16 | },
17 | "dependencies": {
18 | "@apollo/react-hooks": "^3.1.5",
19 | "@decentral.ee/web3-helpers": "^0.3.2",
20 | "@ethersproject/contracts": "^5.0.1",
21 | "@ethersproject/providers": "^5.0.4",
22 | "@openzeppelin/test-helpers": "^0.5.6",
23 | "@superfluid-finance/ethereum-contracts": "0.1.2-preview-20201014-fix5",
24 | "@testing-library/dom": "^6.12.2",
25 | "@testing-library/jest-dom": "^4.2.4",
26 | "@testing-library/react": "^9.5.0",
27 | "@testing-library/user-event": "^7.2.1",
28 | "@types/react": "^16.9.19",
29 | "@walletconnect/web3-provider": "^1.2.2",
30 | "animated-number-react": "^0.1.1",
31 | "apollo-boost": "^0.4.7",
32 | "apollo-client": "^2.6.8",
33 | "apollo-utilities": "^1.3.3",
34 | "chalk": "^4.1.0",
35 | "eslint": "^6.8.0",
36 | "eslint-plugin-flowtype": "^4.6.0",
37 | "graphql": "^14.6.0",
38 | "ipfs-http-client": "^45.0.0",
39 | "react": "16.12.0",
40 | "react-dom": "16.12.0",
41 | "react-scripts": "3.4.1",
42 | "styled-components": "^5.1.1",
43 | "web3modal": "^1.9.0"
44 | },
45 | "eslintConfig": {
46 | "extends": "react-app"
47 | },
48 | "scripts": {
49 | "build": "react-scripts build",
50 | "eject": "react-scripts eject",
51 | "ipfs": "yarn build && node scripts/ipfs.js",
52 | "start": "react-scripts start",
53 | "test": "react-scripts test"
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/ethereum-contracts/build/contracts/Math.json:
--------------------------------------------------------------------------------
1 | {
2 | "contractName": "Math",
3 | "abi": [],
4 | "metadata": "{\"compiler\":{\"version\":\"0.7.1+commit.f4a555be\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"details\":\"Standard math utilities missing in the Solidity language.\",\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"@openzeppelin/contracts/math/Math.sol\":\"Math\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/math/Math.sol\":{\"keccak256\":\"0xa4fdec0ea7d943692cac780111ff2ff9d89848cad0494a59cfaed63a705054b4\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://33ce43e57ca89276dc54f022f92ebf1b57bb50c8a5ec18415ce3ae3513f8bbf1\",\"dweb:/ipfs/QmcMEoXaS9dCa9EYN4y4zvq75Pmehy7DA6Q4VLiPaPCc9e\"]}},\"version\":1}",
5 | "bytecode": "0x60566023600b82828239805160001a607314601657fe5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212204d1f6f6e63f640fe4c6173bca05cbf3ca34f7161ef3951a1ffbc6d89da3e490364736f6c63430007010033",
6 | "deployedBytecode": "0x73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212204d1f6f6e63f640fe4c6173bca05cbf3ca34f7161ef3951a1ffbc6d89da3e490364736f6c63430007010033",
7 | "immutableReferences": {},
8 | "compiler": {
9 | "name": "solc",
10 | "version": "0.7.1+commit.f4a555be.Emscripten.clang"
11 | },
12 | "networks": {},
13 | "schemaVersion": "3.2.5",
14 | "devdoc": {
15 | "details": "Standard math utilities missing in the Solidity language.",
16 | "kind": "dev",
17 | "methods": {},
18 | "version": 1
19 | },
20 | "userdoc": {
21 | "kind": "user",
22 | "methods": {},
23 | "version": 1
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/ethereum-contracts/build/contracts/Address.json:
--------------------------------------------------------------------------------
1 | {
2 | "contractName": "Address",
3 | "abi": [],
4 | "metadata": "{\"compiler\":{\"version\":\"0.7.1+commit.f4a555be\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"details\":\"Collection of functions related to the address type\",\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"@openzeppelin/contracts/utils/Address.sol\":\"Address\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/utils/Address.sol\":{\"keccak256\":\"0x698f929f1097637d051976b322a2d532c27df022b09010e8d091e2888a5ebdf8\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://4bd4c9419d1182612ef415c60a83a9039b227fccb799937963448114c0473b58\",\"dweb:/ipfs/Qmat1U571v55F5JDDHHX7igGcmLF8Ehk9CzsWpjbdx3RTH\"]}},\"version\":1}",
5 | "bytecode": "0x60566023600b82828239805160001a607314601657fe5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212205a0f40a0c32363f624c6086af5461f6ccc93691d01aeebd39c59f5e9e74ff0e564736f6c63430007010033",
6 | "deployedBytecode": "0x73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212205a0f40a0c32363f624c6086af5461f6ccc93691d01aeebd39c59f5e9e74ff0e564736f6c63430007010033",
7 | "immutableReferences": {},
8 | "compiler": {
9 | "name": "solc",
10 | "version": "0.7.1+commit.f4a555be.Emscripten.clang"
11 | },
12 | "networks": {},
13 | "schemaVersion": "3.2.5",
14 | "devdoc": {
15 | "details": "Collection of functions related to the address type",
16 | "kind": "dev",
17 | "methods": {},
18 | "version": 1
19 | },
20 | "userdoc": {
21 | "kind": "user",
22 | "methods": {},
23 | "version": 1
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/ethereum-contracts/scripts/reset-deployment.js:
--------------------------------------------------------------------------------
1 | const { web3tx } = require("@decentral.ee/web3-helpers");
2 | const TestResolver = artifacts.require("TestResolver");
3 | const SuperfluidSDK = require("..");
4 |
5 | const {
6 | parseColonArgs,
7 | rl
8 | } = require("./utils");
9 |
10 | /**
11 | * @dev Reset the superfluid framework deployment.
12 | *
13 | * Usage: npx truffle exec scripts/reset-deployment.js : {VERSION}
14 | */
15 | module.exports = async function (callback, argv) {
16 | try {
17 | global.web3 = web3;
18 |
19 | const args = parseColonArgs(argv || process.argv);
20 | if (args.length !== 1) {
21 | throw new Error("Not enough arguments");
22 | }
23 | const version = args.pop();
24 |
25 | if (version != await rl("Please confirm the version: ")) {
26 | console.error("Mismatched versions");
27 | callback();
28 | }
29 |
30 | const chainId = await web3.eth.net.getId(); // FIXME use eth.getChainId;
31 |
32 | const config = SuperfluidSDK.getConfig(chainId);
33 |
34 | let testResolver;
35 | if (config.resolverAddress) {
36 | testResolver = await TestResolver.at(config.resolverAddress);
37 | } else {
38 | testResolver = await web3tx(TestResolver.new, "TestResolver.new")();
39 | // make it available for the sdk for testing purpose
40 | process.env.TEST_RESOLVER_ADDRESS = testResolver.address;
41 | }
42 | console.log("Resolver address", testResolver.address);
43 |
44 | await web3tx(testResolver.set, "Clear Superfluid deployment")(
45 | `Superfluid.${version}`, "0x" + "0".repeat(40)
46 | );
47 | await web3tx(testResolver.set, "Clear TestGovernance deployment")(
48 | `TestGovernance.${version}`, "0x" + "0".repeat(40)
49 | );
50 |
51 | callback();
52 | } catch (err) {
53 | callback(err);
54 | }
55 | };
56 |
57 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Superfluid Protocol (Preview)
2 | =============================
3 |
4 | Welcome to the preview version of the Superfluid protocol.
5 |
6 | Ethereum Contracts
7 | ==================
8 |
9 | The ethereum contracts is published under the `ethereum-contracts` folder.
10 |
11 | Currently the core logics are not yet published publicly, but they will be coming very soon!
12 |
13 | How to Integrate
14 | ----------------
15 |
16 | Install the SDK and its peer dependency:
17 |
18 | ```
19 | $ npm install --save @superfluid-finance/ethereum-contracts
20 | $ npm install --save @truffle/contract
21 | ```
22 |
23 | To start with the SDK (with Goerli testnet):
24 |
25 | ```
26 | const SuperfluidSDK = require("@superfluid-finance/ethereum-contracts");
27 | const sf = new SuperfluidSDK.Framework({
28 | version: "0.1.2-preview-20201014", // This is for using different protocol release
29 | web3Provider: web3.currentProvider // your web3 provider
30 | });
31 | ```
32 |
33 | For more information about the SDK, read [SDK Integration](ethereum-contracts/README.md#integration).
34 |
35 | For more information about the protocol, please visit [docs](https://docs.superfluid.finance/).
36 |
37 | Example Integrations
38 | --------------------
39 |
40 | ## Superfluid Console Demo
41 |
42 | [This demo](sample-integrations/superfluid-console-demo) show cases how to write a console only app using
43 | the superfluid SDK.
44 |
45 | ## Flow Lottery - A Super App Demo
46 |
47 | [Flow lottery](sample-integrations/flowlottery) is a super app which showcases how to write a SuperApp
48 | that composes agreements into a fun money game.
49 |
50 | ## Dividend Rights Token
51 |
52 | [A ERC20 token](sample-integrations/dividends-rights-token-demo) that tokenizes units in the [Instant Distribution Agreements](https://docs.superfluid.finance/tutorials/instant-distribution/).
53 |
54 | Further Readings
55 | ================
56 |
57 | To read more about Superfluid Finance and our vision, please visit [our website](https://www.superfluid.finance/).
58 |
--------------------------------------------------------------------------------
/ethereum-contracts/build/contracts/SignedSafeMath.json:
--------------------------------------------------------------------------------
1 | {
2 | "contractName": "SignedSafeMath",
3 | "abi": [],
4 | "metadata": "{\"compiler\":{\"version\":\"0.7.1+commit.f4a555be\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"details\":\"Signed math operations with safety checks that revert on error.\",\"kind\":\"dev\",\"methods\":{},\"title\":\"SignedSafeMath\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"@openzeppelin/contracts/math/SignedSafeMath.sol\":\"SignedSafeMath\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/math/SignedSafeMath.sol\":{\"keccak256\":\"0xba085261d44cf28d2583f7c8cdb2f0a6a495ff1a640f86d995ea9d36b42b0046\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://03481543f67d854c94f73b006609ccd0e11a2461837296bf9d27b14b4bde7de6\",\"dweb:/ipfs/QmVt8ZoWv6jPdtoo5zikqrj7ijDvKoQ4BWYiufctStkXd3\"]}},\"version\":1}",
5 | "bytecode": "0x60566023600b82828239805160001a607314601657fe5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220d039790f89268bbd945287559cc0ac6a9350a4cfb827f91e9bc24eedde4b999664736f6c63430007010033",
6 | "deployedBytecode": "0x73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220d039790f89268bbd945287559cc0ac6a9350a4cfb827f91e9bc24eedde4b999664736f6c63430007010033",
7 | "immutableReferences": {},
8 | "compiler": {
9 | "name": "solc",
10 | "version": "0.7.1+commit.f4a555be.Emscripten.clang"
11 | },
12 | "networks": {},
13 | "schemaVersion": "3.2.5",
14 | "devdoc": {
15 | "details": "Signed math operations with safety checks that revert on error.",
16 | "kind": "dev",
17 | "methods": {},
18 | "title": "SignedSafeMath",
19 | "version": 1
20 | },
21 | "userdoc": {
22 | "kind": "user",
23 | "methods": {},
24 | "version": 1
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/ethereum-contracts/contracts/interfaces/superfluid/ISuperfluidGovernance.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity >= 0.7.0;
3 |
4 |
5 | /**
6 | * @dev Superfluid's Governance interface
7 | *
8 | * @author Superfluid
9 | */
10 | interface ISuperfluidGovernance {
11 |
12 | /**
13 | * @dev Get the Reward address that receives the liquidation fees.
14 | * @param superToken Super token address.
15 | */
16 | function getRewardAddress(
17 | address superToken
18 | )
19 | external
20 | view
21 | returns(address rewardAddress);
22 |
23 | /**
24 | * @dev Get the Period that is allowed to perform a liquidation
25 | * @param superToken Super token address.
26 | */
27 | function getLiquidationPeriod(
28 | address superToken
29 | )
30 | external
31 | view
32 | returns(uint256 period);
33 |
34 | /**
35 | * @dev Add an agreement to the whitelist
36 | */
37 | function addAgreement(address agreementClass) external;
38 |
39 | /**
40 | * @dev Check if the agreement is whitelisted
41 | */
42 | function isAgreementListed(address agreementClass)
43 | external view
44 | returns(bool yes);
45 |
46 | /**
47 | * @dev Map list of the agreements using a bitmap
48 | * @param bitmap Agreement class ID based bitmap
49 | */
50 | function mapAgreements(uint256 bitmap)
51 | external view
52 | returns (address[] memory agreementClasses);
53 |
54 | /**
55 | * @dev Create a new bitmask by adding agreement class to it.
56 | */
57 | function maskAgreementBit(uint256 bitmap, address agreementClass)
58 | external view
59 | returns (uint256 newBitmap);
60 |
61 | /**
62 | * @dev Create a new bitmask by removing agreement class from it.
63 | */
64 | function unmaskAgreementBit(uint256 bitmap, address agreementClass)
65 | external view
66 | returns (uint256 newBitmap);
67 |
68 | }
69 |
--------------------------------------------------------------------------------
/ethereum-contracts/scripts/utils.js:
--------------------------------------------------------------------------------
1 | const { promisify } = require("util");
2 | const readline = require("readline");
3 |
4 | // promisify the readline
5 | const rl = readline.createInterface({
6 | input: process.stdin,
7 | output: process.stdout
8 | });
9 | // Prepare readline.question for promisification
10 | rl.question[promisify.custom] = (question) => {
11 | return new Promise((resolve) => {
12 | rl.question(question, resolve);
13 | });
14 | };
15 |
16 | // Provide arguments to the script through ":" separator
17 | function parseColonArgs(argv) {
18 | const argIndex = argv.indexOf(":");
19 | if (argIndex < 0) {
20 | throw new Error("No colon arguments provided");
21 | }
22 | const args = argv.slice(argIndex + 1);
23 | console.log("Colon arguments", args);
24 | return args;
25 | }
26 |
27 | const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
28 |
29 | async function hasCode(address) {
30 | const code = await web3.eth.getCode(address);
31 | return code.length > 3;
32 | }
33 |
34 | async function codeChanged(contract, address) {
35 | const code = await web3.eth.getCode(address);
36 | // no code
37 | if (code.length <= 3) return true;
38 | // SEE: https://github.com/ConsenSys/bytecode-verifier/blob/master/src/verifier.js
39 | // find the second occurance of the init code
40 | const bytecodeFromCompiler = contract.bytecode;
41 | // console.log(code);
42 | // console.log(bytecodeFromCompiler);
43 | // console.log(bytecodeFromCompiler.indexOf(code.slice(2)));
44 | return bytecodeFromCompiler.indexOf(code.slice(2)) === -1;
45 | }
46 |
47 | async function proxiableCodeChanged(Proxiable, contract, address) {
48 | const p = await Proxiable.at(address);
49 | return await codeChanged(contract, await p.getCodeAddress());
50 | }
51 |
52 | module.exports = {
53 | parseColonArgs,
54 | ZERO_ADDRESS,
55 | hasCode,
56 | codeChanged,
57 | proxiableCodeChanged,
58 | rl: promisify(rl.question),
59 | };
60 |
--------------------------------------------------------------------------------
/sample-integrations/flowlottery/ui/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
14 |
15 |
24 | Flow Lottery SuperApp
25 |
29 |
30 |
31 |
32 |
33 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/ethereum-contracts/scripts/deploy-test-token.js:
--------------------------------------------------------------------------------
1 | const { web3tx } = require("@decentral.ee/web3-helpers");
2 | const Superfluid = require("..");
3 | const { parseColonArgs } = require("./utils");
4 |
5 | const TestResolver = artifacts.require("TestResolver");
6 | const TestToken = artifacts.require("TestToken");
7 |
8 |
9 | /**
10 | * @dev Deploy test token (Mintable ERC20) to the network.
11 | *
12 | * Usage: npx truffle exec scripts/deploy-test-token.js : {TOKEN_NAME}
13 | */
14 | module.exports = async function (callback, argv) {
15 |
16 | try {
17 | global.web3 = web3;
18 |
19 | const reset = !!process.env.RESET_TOKEN;
20 | const chainId = await web3.eth.net.getId(); // TODO use eth.getChainId;
21 | const config = Superfluid.getConfig(chainId);
22 | console.log("reset: ", reset);
23 | console.log("chain ID: ", chainId);
24 |
25 | const args = parseColonArgs(argv || process.argv);
26 | if (args.length !== 1) {
27 | throw new Error("Not enough arguments");
28 | }
29 | const tokenName = args.pop();
30 | console.log("Token name", tokenName);
31 |
32 | const testResolver = await TestResolver.at(config.resolverAddress);
33 | console.log("Resolver address", testResolver.address);
34 |
35 | // deploy test token and its super token
36 | const name = `tokens.${tokenName}`;
37 | let testTokenAddress = await testResolver.get(name);
38 | if (reset || testTokenAddress === "0x0000000000000000000000000000000000000000") {
39 | const testToken = await web3tx(TestToken.new, "TestToken.new")(
40 | tokenName,
41 | tokenName + " Fake Token"
42 | );
43 | testTokenAddress = testToken.address;
44 | await web3tx(testResolver.set, `TestResolver set ${name}`)(
45 | name,
46 | testTokenAddress
47 | );
48 | } else {
49 | console.log("Token already deployed");
50 | }
51 | console.log(`Token ${tokenName} address`, testTokenAddress);
52 |
53 | callback();
54 | } catch (err) {
55 | callback(err);
56 | }
57 | };
58 |
--------------------------------------------------------------------------------
/test-scripts/console-quick-start.js:
--------------------------------------------------------------------------------
1 | const SuperfluidSDK = require("../ethereum-contracts");
2 | const { wad4human } = require("@decentral.ee/web3-helpers");
3 |
4 | // To run the script"
5 | // - go to ethereum-contracts directory
6 | // - setup your env file with these variables:
7 | // - `GOERLI_MNEMONIC` - your mnemonic
8 | // - `GOERLI_PROVIDER_URL` - your goerli web3 provider url
9 | // - and run: `npx truffle --network goerli`
10 | // - then in the console: `exec ../test-scripts/console-quick-start.js`
11 |
12 | module.exports = async function (callback) {
13 | global.web3 = web3;
14 |
15 | try {
16 | const accounts = await web3.eth.getAccounts();
17 | const bob = accounts[0];
18 | const alice = accounts[1];
19 | const dan = accounts[2];
20 | const minAmount = web3.utils.toWei("100", "ether");
21 |
22 | const sf = new SuperfluidSDK.Framework({
23 | chainId: 5,
24 | version: "preview-20200928",
25 | web3Provider: web3.currentProvider,
26 | });
27 | await sf.initialize();
28 | const daiAddress = await sf.resolver.get("tokens.fDAI");
29 | const dai = await sf.contracts.TestToken.at(daiAddress);
30 | const daixWrapper = await sf.getERC20Wrapper(dai);
31 | const daix = await sf.contracts.ISuperToken.at(daixWrapper.wrapperAddress);
32 | console.log("daix address", daix.address);
33 |
34 | // minting
35 | if (
36 | web3.utils.toBN(await daix.balanceOf(bob)).lt(web3.utils.toBN(minAmount))
37 | ) {
38 | console.log("Minting and upgrading...");
39 | await dai.mint(bob, minAmount, { from: bob });
40 | await dai.approve(daix.address, minAmount, { from: bob });
41 | await daix.upgrade(minAmount, { from: bob });
42 | console.log("Done minting and upgrading.");
43 | }
44 | console.log("bob balance ", wad4human(await daix.balanceOf(bob)));
45 | console.log("alice balance ", wad4human(await daix.balanceOf(alice)));
46 | console.log("dan balance ", wad4human(await daix.balanceOf(dan)));
47 | console.log(
48 | "bob net flow",
49 | (await sf.agreements.cfa.getNetFlow(daix.address, bob)).toString()
50 | );
51 | console.log("Ready to interact with Superfluid!");
52 | callback();
53 | } catch (err) {
54 | callback(err);
55 | }
56 | };
57 |
--------------------------------------------------------------------------------
/ethereum-contracts/scripts/deploy-super-token.js:
--------------------------------------------------------------------------------
1 | const SuperfluidSDK = require("..");
2 | const { parseColonArgs } = require("./utils");
3 |
4 |
5 | /**
6 | * @dev Deploy test token (Mintable ERC20) to the network.
7 | *
8 | * Usage: npx truffle exec scripts/deploy-super-token.js : {TOKEN_NAME}
9 | */
10 | module.exports = async function (callback, argv) {
11 | try {
12 | global.web3 = web3;
13 |
14 | const chainId = await web3.eth.net.getId(); // TODO use eth.getChainId;
15 | const version = process.env.RELEASE_VERSION || "test";
16 | console.log("network ID: ", chainId);
17 | console.log("release version:", version);
18 |
19 | const args = parseColonArgs(argv || process.argv);
20 | if (args.length !== 1) {
21 | throw new Error("Not enough arguments");
22 | }
23 | const tokenName = args.pop();
24 |
25 | global.artifacts = artifacts;
26 | const sf = new SuperfluidSDK.Framework({
27 | isTruffle: true,
28 | version
29 | });
30 | await sf.initialize();
31 |
32 | const tokenAddress = await sf.resolver.get(`tokens.${tokenName}`);
33 | const tokenInfo = await sf.contracts.TokenInfo.at(tokenAddress);
34 | const tokenInfoName = await tokenInfo.name.call();
35 | const tokenInfoSymbol = await tokenInfo.symbol.call();
36 | const tokenInfoDecimals = await tokenInfo.decimals.call();
37 | console.log("Token address", tokenAddress);
38 | console.log("Token name", tokenName);
39 | console.log("Token info name()", tokenInfoName);
40 | console.log("Token info symbol()", tokenInfoSymbol);
41 | console.log("Token info decimals()", tokenInfoDecimals.toString());
42 |
43 | const superTokenWrapper = await sf.getERC20Wrapper(tokenInfo);
44 | console.log("SuperToken wrapper address: ", superTokenWrapper.wrapperAddress);
45 | if (!superTokenWrapper.created) {
46 | console.log("Creating the wrapper...");
47 | await sf.createERC20Wrapper(tokenInfo);
48 | console.log("Wrapper created.");
49 | } else {
50 | console.log("SuperToken wrapper already created.");
51 | }
52 |
53 | callback();
54 | } catch (err) {
55 | callback(err);
56 | }
57 | };
58 |
--------------------------------------------------------------------------------
/ethereum-contracts/build/contracts/Create2.json:
--------------------------------------------------------------------------------
1 | {
2 | "contractName": "Create2",
3 | "abi": [],
4 | "metadata": "{\"compiler\":{\"version\":\"0.7.1+commit.f4a555be\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"details\":\"Helper to make usage of the `CREATE2` EVM opcode easier and safer. `CREATE2` can be used to compute in advance the address where a smart contract will be deployed, which allows for interesting new mechanisms known as 'counterfactual interactions'. See the https://eips.ethereum.org/EIPS/eip-1014#motivation[EIP] for more information.\",\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"@openzeppelin/contracts/utils/Create2.sol\":\"Create2\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/utils/Create2.sol\":{\"keccak256\":\"0x539295edd21ad514c0b1a0d1c89ada0831942f379ea83b6eb85769211fc7937e\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://f5103ed47a4ed483216a8ff32c933ae8e09f43c5de8e4c212b2c166445ea2282\",\"dweb:/ipfs/QmebXzutVHoJDC3wyostmiUjk4MPZ54ak1pzvvmJGCLoXr\"]}},\"version\":1}",
5 | "bytecode": "0x60566023600b82828239805160001a607314601657fe5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212209d563d08ff3185f01fdeb7ff1da9c60d4bb235dd39978688eae7de832ee3d12b64736f6c63430007010033",
6 | "deployedBytecode": "0x73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212209d563d08ff3185f01fdeb7ff1da9c60d4bb235dd39978688eae7de832ee3d12b64736f6c63430007010033",
7 | "immutableReferences": {},
8 | "compiler": {
9 | "name": "solc",
10 | "version": "0.7.1+commit.f4a555be.Emscripten.clang"
11 | },
12 | "networks": {},
13 | "schemaVersion": "3.2.5",
14 | "devdoc": {
15 | "details": "Helper to make usage of the `CREATE2` EVM opcode easier and safer. `CREATE2` can be used to compute in advance the address where a smart contract will be deployed, which allows for interesting new mechanisms known as 'counterfactual interactions'. See the https://eips.ethereum.org/EIPS/eip-1014#motivation[EIP] for more information.",
16 | "kind": "dev",
17 | "methods": {},
18 | "version": 1
19 | },
20 | "userdoc": {
21 | "kind": "user",
22 | "methods": {},
23 | "version": 1
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/ethereum-contracts/build/contracts/IResolver.json:
--------------------------------------------------------------------------------
1 | {
2 | "contractName": "IResolver",
3 | "abi": [
4 | {
5 | "inputs": [
6 | {
7 | "internalType": "string",
8 | "name": "name",
9 | "type": "string"
10 | }
11 | ],
12 | "name": "get",
13 | "outputs": [
14 | {
15 | "internalType": "address",
16 | "name": "",
17 | "type": "address"
18 | }
19 | ],
20 | "stateMutability": "view",
21 | "type": "function"
22 | }
23 | ],
24 | "metadata": "{\"compiler\":{\"version\":\"0.7.1+commit.f4a555be\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"}],\"name\":\"get\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"author\":\"Superfluid\",\"details\":\"Abstraction for a address resolver contract\",\"kind\":\"dev\",\"methods\":{\"get(string)\":{\"details\":\"Get address by name.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"/home/hellwolf/Projects/superfluid/superfluid-protocol-preview/ethereum-contracts-v0.1/contracts/interfaces/misc/IResolver.sol\":\"IResolver\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"/home/hellwolf/Projects/superfluid/superfluid-protocol-preview/ethereum-contracts-v0.1/contracts/interfaces/misc/IResolver.sol\":{\"keccak256\":\"0x364e3361b7845259ca156a92a65c2eddfccdbb37ddf056f52fed8ae05e7a7202\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://e9b95aeca9a96ad76c445337a9a443cffc24adec157f5bf9c313f6aeee90ae45\",\"dweb:/ipfs/QmRHgWeuyvTxChaXeFbbuFH1bwQcoMgV7Cn2BEDLNXKiay\"]}},\"version\":1}",
25 | "bytecode": "0x",
26 | "deployedBytecode": "0x",
27 | "immutableReferences": {},
28 | "compiler": {
29 | "name": "solc",
30 | "version": "0.7.1+commit.f4a555be.Emscripten.clang"
31 | },
32 | "networks": {},
33 | "schemaVersion": "3.2.5",
34 | "devdoc": {
35 | "author": "Superfluid",
36 | "details": "Abstraction for a address resolver contract",
37 | "kind": "dev",
38 | "methods": {
39 | "get(string)": {
40 | "details": "Get address by name."
41 | }
42 | },
43 | "version": 1
44 | },
45 | "userdoc": {
46 | "kind": "user",
47 | "methods": {},
48 | "version": 1
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/ethereum-contracts/scripts/deploy-erc1820.js:
--------------------------------------------------------------------------------
1 | // Adapted from https://github.com/0xjac/ERC1820/blob/master/js/deployment.js
2 |
3 | const assert = require("assert").strict;
4 |
5 | const Transaction = require("ethereumjs-tx").Transaction;
6 | const ethUtils = require("ethereumjs-util");
7 |
8 | const {
9 | hasCode
10 | } = require("./utils");
11 |
12 |
13 | /**
14 | * @dev Deploy ERC1820 to the network.
15 | *
16 | * Usage: npx truffle exec scripts/deploy-erc1820.js
17 | */
18 | module.exports = async function (callback) {
19 | global.web3 = web3;
20 |
21 | try {
22 | const rawTransaction = {
23 | nonce: 0,
24 | gasPrice: 100000000000,
25 | value: 0,
26 | data: "0x" + require("../contracts/introspection/ERC1820Registry.json").bin,
27 | gasLimit: 800000,
28 | v: 27,
29 | r: "0x1820182018201820182018201820182018201820182018201820182018201820",
30 | s: "0x1820182018201820182018201820182018201820182018201820182018201820"
31 | };
32 | const tx = new Transaction(rawTransaction);
33 | const res = {
34 | sender: ethUtils.toChecksumAddress(
35 | "0x" + tx.getSenderAddress().toString("hex")
36 | ),
37 | rawTx: "0x" + tx.serialize().toString("hex"),
38 | contractAddr: ethUtils.toChecksumAddress(
39 | "0x" + ethUtils.generateAddress(tx.getSenderAddress(), ethUtils.toBuffer(0)).toString("hex")
40 | ),
41 | };
42 | assert.equal("0xa990077c3205cbDf861e17Fa532eeB069cE9fF96", res.sender);
43 | assert.equal("0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24", res.contractAddr);
44 |
45 | console.log("Checking ERC1820 deployment at", res.contractAddr);
46 | if (!(await hasCode(res.contractAddr))) {
47 | console.log("Deploying...");
48 | const account = (await web3.eth.getAccounts())[0];
49 | console.log("Step 1: send ETH");
50 | await web3.eth.sendTransaction({
51 | from: account,
52 | to: res.sender,
53 | value: "100000000000000000" //web3.utils.toWei(0.1)
54 | });
55 | console.log("Step 2: send signed transaction");
56 | await web3.eth.sendSignedTransaction(res.rawTx);
57 | console.log("Deployment done.");
58 | } else {
59 | console.log("Code is already deployoed.");
60 | }
61 | } catch (err) {
62 | callback(err);
63 | }
64 | };
65 |
--------------------------------------------------------------------------------
/sample-integrations/flowlottery/ui/src/components/BottomTables.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Span, BottomTable, XL } from "./";
3 | import { flowForHumans } from "../utils/utils.js";
4 |
5 | const { wad4human } = require("@decentral.ee/web3-helpers");
6 | export function TableOfPlayers({ playerList, winner }) {
7 | var items = [];
8 | //console.log("this is playerList");
9 | //console.log(playerList);
10 | if (playerList.length > 0) {
11 | //console.log("playerList definitely >0");
12 | var i = 0;
13 | for (const value of playerList) {
14 | const { address, flowRate, total } = value;
15 | //console.log("address: ", address, " netFlow: ", flowRate);
16 | var item = (
17 |
18 | | {address} |
19 |
20 | {address === winner ? (
21 | +{flowForHumans(flowRate)}
22 | ) : (
23 | -{flowForHumans(flowRate)}
24 | )}
25 | |
26 |
27 | {"Won so far: " + wad4human(total)}
28 | {address === winner && 👑}
29 | |
30 |
31 | );
32 | if (address === winner) items.unshift(item);
33 | else items.push(item);
34 | }
35 | }
36 | return (
37 |
38 | Active Players
39 |
40 | | {"Address"} |
41 | {"FlowRate"} |
42 | {"Won so far"} |
43 | {items}
44 |
45 |
46 | );
47 | }
48 |
49 | export function TableOfWinners({ winnerList }) {
50 | var items = [];
51 | console.log(winnerList);
52 | if (winnerList.length > 0) {
53 | var i = 0;
54 | for (const value of winnerList) {
55 | const { address, duration, total, flowRate } = value;
56 | var item = (
57 |
58 | | {address} |
59 |
60 | {Math.round(duration / 60)}
61 | {" minutes"}
62 | |
63 | {flowForHumans(flowRate)} |
64 |
65 | {wad4human(total)} {" won"}
66 | |
67 |
68 | );
69 | items.unshift(item);
70 | }
71 | }
72 | return (
73 |
74 | Winners
75 |
76 | | {"Address"} |
77 | {"Winning for"} |
78 | {"FlowRate"} |
79 | {"Total Won"} |
80 | {items}
81 |
82 |
83 | );
84 | }
85 |
--------------------------------------------------------------------------------
/ethereum-contracts/build/contracts/ProxyUtils.json:
--------------------------------------------------------------------------------
1 | {
2 | "contractName": "ProxyUtils",
3 | "abi": [],
4 | "metadata": "{\"compiler\":{\"version\":\"0.7.1+commit.f4a555be\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"stateVariables\":{\"_IMPLEMENTATION_SLOT\":{\"details\":\"Implementation slot constant. Using https://eips.ethereum.org/EIPS/eip-1967 standard Storage slot 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc (obtained as bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)).\"}},\"title\":\"Proxy Shared Library\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"/home/hellwolf/Projects/superfluid/superfluid-protocol-preview/ethereum-contracts-v0.1/contracts/upgradability/ProxyUtils.sol\":\"ProxyUtils\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"/home/hellwolf/Projects/superfluid/superfluid-protocol-preview/ethereum-contracts-v0.1/contracts/upgradability/ProxyUtils.sol\":{\"keccak256\":\"0x34c692cb060d21fe40af5d6c6ddb2b4b9e52ffb6e44340195c7b91cbf664feca\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://6e2df14a12f9d4dfb780f75942e5ee5aa727e08b0f32f2950eb8816868f0c915\",\"dweb:/ipfs/QmdWakruAjcgqMkQBrJF9EffMnjaByCfygtDRrs3XnzSfA\"]}},\"version\":1}",
5 | "bytecode": "0x60566023600b82828239805160001a607314601657fe5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220cf295613af2f7f46a4d0f9404f81ba8be092e41b465a8b118890615943ef3b8d64736f6c63430007010033",
6 | "deployedBytecode": "0x73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220cf295613af2f7f46a4d0f9404f81ba8be092e41b465a8b118890615943ef3b8d64736f6c63430007010033",
7 | "immutableReferences": {},
8 | "compiler": {
9 | "name": "solc",
10 | "version": "0.7.1+commit.f4a555be.Emscripten.clang"
11 | },
12 | "networks": {},
13 | "schemaVersion": "3.2.5",
14 | "devdoc": {
15 | "kind": "dev",
16 | "methods": {},
17 | "stateVariables": {
18 | "_IMPLEMENTATION_SLOT": {
19 | "details": "Implementation slot constant. Using https://eips.ethereum.org/EIPS/eip-1967 standard Storage slot 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc (obtained as bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1))."
20 | }
21 | },
22 | "title": "Proxy Shared Library",
23 | "version": 1
24 | },
25 | "userdoc": {
26 | "kind": "user",
27 | "methods": {},
28 | "version": 1
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/ethereum-contracts/contracts/upgradability/Proxy.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity 0.7.1;
3 |
4 | import "./ProxyUtils.sol";
5 |
6 | /**
7 | * @title Proxy
8 | * @dev Implements delegation of calls to other contracts, with proper
9 | * forwarding of return values and bubbling of failures.
10 | * It defines a fallback function that delegates all calls to the implementation.
11 | */
12 | contract Proxy {
13 |
14 | // Empty constructor is more friendlier to CREATE2, otherwise parameters will be part of the
15 | // address computation. Use initalizeProxy for initializing the logic contract address.
16 |
17 | /**
18 | * @dev Proxy initialization function.
19 | * This should only be called once and it is permission-less.
20 | * @param initialAddress Initial logic contract code address to be used.
21 | */
22 | function initializeProxy(address initialAddress) external {
23 | require(initialAddress != address(0), "Proxy: INITIALIZED_WITH_ZERO_ADDRESS");
24 | require(ProxyUtils.implementation() == address(0), "Proxy: ALREADY_INITIALIZED");
25 | ProxyUtils.setImplementation(initialAddress);
26 | }
27 |
28 | /**
29 | * @dev Fallback function.
30 | * Implemented entirely in `_delegate`.
31 | */
32 | fallback () external payable {
33 | _delegate(ProxyUtils.implementation());
34 | }
35 |
36 | /**
37 | * @dev Receive function.
38 | * It should be forbidden.
39 | */
40 | receive () external payable {
41 | require(false, "Proxy: RECEIVE_FORBIDDEN");
42 | }
43 |
44 | /**
45 | * @dev Delegates execution to an implementation contract.
46 | *
47 | * Original implementation:
48 | * https://github.com/OpenZeppelin/openzeppelin-sdk/blob/master/packages/lib/contracts/upgradeability/Proxy.sol
49 | */
50 | function _delegate(address implementation) internal {
51 | assembly { // solium-disable-line
52 | // Copy msg.data. We take full control of memory in this inline assembly
53 | // block because it will not return to Solidity code. We overwrite the
54 | // Solidity scratch pad at memory position 0.
55 | calldatacopy(0, 0, calldatasize())
56 |
57 | // Call the implementation.
58 | // out and outsize are 0 because we don't know the size yet.
59 | let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
60 |
61 | // Copy the returned data.
62 | returndatacopy(0, 0, returndatasize())
63 |
64 | switch result
65 | // delegatecall returns 0 on error.
66 | case 0 { revert(0, returndatasize()) }
67 | default { return(0, returndatasize()) }
68 | }
69 | }
70 |
71 | }
72 |
--------------------------------------------------------------------------------
/ethereum-contracts/build/contracts/SafeMath.json:
--------------------------------------------------------------------------------
1 | {
2 | "contractName": "SafeMath",
3 | "abi": [],
4 | "metadata": "{\"compiler\":{\"version\":\"0.7.1+commit.f4a555be\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"details\":\"Wrappers over Solidity's arithmetic operations with added overflow checks. Arithmetic operations in Solidity wrap on overflow. This can easily result in bugs, because programmers usually assume that an overflow raises an error, which is the standard behavior in high level programming languages. `SafeMath` restores this intuition by reverting the transaction when an operation overflows. Using this library instead of the unchecked operations eliminates an entire class of bugs, so it's recommended to use it always.\",\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"@openzeppelin/contracts/math/SafeMath.sol\":\"SafeMath\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/math/SafeMath.sol\":{\"keccak256\":\"0xba96bc371ba999f452985a98717cca1e4c4abb598dc038a9a9c3db08129b1ba4\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://26e50e3f7b6482fb6f598f2e006994a74aa492687daa4b3eee7fd4fb5398ce7f\",\"dweb:/ipfs/QmZudqoPSkA4USLMFsBBmt19dDPZFS8aaAmL5R7pECXu6t\"]}},\"version\":1}",
5 | "bytecode": "0x60566023600b82828239805160001a607314601657fe5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea264697066735822122076309099b40aceed5a6198a3242300cd8dba34d4048b7f4f45776f81d1cb471264736f6c63430007010033",
6 | "deployedBytecode": "0x73000000000000000000000000000000000000000030146080604052600080fdfea264697066735822122076309099b40aceed5a6198a3242300cd8dba34d4048b7f4f45776f81d1cb471264736f6c63430007010033",
7 | "immutableReferences": {},
8 | "compiler": {
9 | "name": "solc",
10 | "version": "0.7.1+commit.f4a555be.Emscripten.clang"
11 | },
12 | "networks": {},
13 | "schemaVersion": "3.2.5",
14 | "devdoc": {
15 | "details": "Wrappers over Solidity's arithmetic operations with added overflow checks. Arithmetic operations in Solidity wrap on overflow. This can easily result in bugs, because programmers usually assume that an overflow raises an error, which is the standard behavior in high level programming languages. `SafeMath` restores this intuition by reverting the transaction when an operation overflows. Using this library instead of the unchecked operations eliminates an entire class of bugs, so it's recommended to use it always.",
16 | "kind": "dev",
17 | "methods": {},
18 | "version": 1
19 | },
20 | "userdoc": {
21 | "kind": "user",
22 | "methods": {},
23 | "version": 1
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/ethereum-contracts/contracts/mocks/SuperTokenStorageTester.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | /* solhint-disable */
3 | pragma solidity 0.7.1;
4 |
5 | import {SuperToken} from "../superfluid/SuperToken.sol";
6 |
7 | /**
8 | * @dev Test SuperTokenStorag Layout changes
9 | */
10 | contract SuperTokenStorageTester is SuperToken {
11 | function validate() public pure {
12 | uint256 slot;
13 | uint256 offset;
14 |
15 | // address public _owner;
16 | assembly { slot:= _owner.slot offset := _owner.offset }
17 | require (slot == 0 && offset == 0, "_owner changed location");
18 |
19 | // bool public initialized;
20 | assembly { slot:= _initialized.slot offset := _initialized.offset }
21 | require (slot == 0 && offset == 20, "initialized changed location");
22 |
23 | // IERC20 internal _token;
24 | assembly { slot:= _underlyingToken.slot offset := _underlyingToken.offset }
25 | require (slot == 1 && offset == 0, "_underlyingToken changed location");
26 |
27 | // uint8 internal _decimals;
28 | assembly { slot:= _underlyingDecimals.slot offset := _underlyingDecimals.offset }
29 | require (slot == 1 && offset == 20, "_underlyingDecimals changed location");
30 |
31 | // string internal _name;
32 | assembly { slot:= _name.slot offset := _name.offset }
33 | require (slot == 2 && offset == 0, "_name changed location");
34 |
35 | // string internal _symbol;
36 | assembly { slot:= _symbol.slot offset := _symbol.offset }
37 | require (slot == 3 && offset == 0, "_symbol changed location");
38 |
39 | // ISuperfluid internal _host
40 | assembly { slot:= _host.slot offset := _host.offset }
41 | require (slot == 4 && offset == 0, "_host changed location");
42 |
43 | // mapping(address => int256) internal _balances;
44 | assembly { slot:= _balances.slot offset := _balances.offset }
45 | require (slot == 5 && offset == 0, "_balances changed location");
46 |
47 | // mapping (address => mapping (address => uint256)) internal _allowances;
48 | assembly { slot:= _allowances.slot offset := _allowances.offset }
49 | require (slot == 6 && offset == 0, "_allowances changed location");
50 |
51 | // mapping(address => address[]) internal _inactiveAgreementBitmap;
52 | assembly { slot:= _inactiveAgreementBitmap.slot offset := _inactiveAgreementBitmap.offset }
53 | require (slot == 7 && offset == 0, "_inactiveAgreementBitmap changed location");
54 |
55 | // mapping(address => mapping(address => bool)) internal _operators;
56 | assembly { slot:= _operators.slot offset := _operators.offset }
57 | require (slot == 8 && offset == 0, "_operators changed location");
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/ethereum-contracts/contracts/access/Ownable.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity 0.7.1;
3 |
4 |
5 | /**
6 | * @dev Contract module which provides a basic access control mechanism, where
7 | * there is an account (an owner) that can be granted exclusive access to
8 | * specific functions.
9 | *
10 | * This module is used through inheritance. It will make available the modifier
11 | * `onlyOwner`, which can be applied to your functions to restrict their use to
12 | * the owner.
13 | *
14 | * It is a fork from openzeppelin Ownable, making it Proxiable contract friendly
15 | * by having `_owner` variable internal. It also removes the usage of GSN Context,
16 | * as in superfluid we use a different mechanism for providing transaction Context.
17 | *
18 | * @author Superfluid
19 | */
20 | contract Ownable {
21 | /// @dev For ownable contract
22 | address internal _owner;
23 |
24 | event OwnershipTransferred(
25 | address indexed previousOwner,
26 | address indexed newOwner
27 | );
28 |
29 | /**
30 | * @dev Returns the address of the current owner.
31 | */
32 | function owner() public view returns (address) {
33 | return _owner;
34 | }
35 |
36 | /**
37 | * @dev Returns true if the caller is the current owner.
38 | */
39 | function isOwner() public view returns (bool) {
40 | return msg.sender == _owner;
41 | }
42 |
43 | /**
44 | * @dev Leaves the contract without owner. It will not be possible to call
45 | * `onlyOwner` functions anymore. Can only be called by the current owner.
46 | *
47 | * > Note: Renouncing ownership will leave the contract without an owner,
48 | * thereby removing any functionality that is only available to the owner.
49 | */
50 | function renounceOwnership() public onlyOwner {
51 | emit OwnershipTransferred(_owner, address(0));
52 | _owner = address(0);
53 | }
54 |
55 | /**
56 | * @dev Transfers ownership of the contract to a new account (`newOwner`).
57 | * Can only be called by the current owner.
58 | */
59 | function transferOwnership(address newOwner) public onlyOwner {
60 | _transferOwnership(newOwner);
61 | }
62 |
63 | /**
64 | * @dev Transfers ownership of the contract to a new account (`newOwner`).
65 | */
66 | function _transferOwnership(address newOwner) internal {
67 | require(
68 | newOwner != address(0),
69 | "Ownable: new owner is the zero address"
70 | );
71 | emit OwnershipTransferred(_owner, newOwner);
72 | _owner = newOwner;
73 | }
74 |
75 | /**
76 | * @dev Throws if called by any account other than the owner.
77 | */
78 | modifier onlyOwner() {
79 | require(isOwner(), "Ownable: caller is not the owner");
80 | _;
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/ethereum-contracts/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@superfluid-finance/ethereum-contracts",
3 | "version": "0.1.2-preview-20201014-fix5",
4 | "description": " Ethereum contracts implementation for the Superfluid Protocol",
5 | "repository": "github:superfluid-finance/ethereum-contracts",
6 | "license": "MIT",
7 | "main": "js-sdk/index.js",
8 | "files": [
9 | "/contracts/**/*.sol",
10 | "/contracts/**/*.json",
11 | "!/contracts/mocks/*",
12 | "/build/abi.js",
13 | "/build/contracts/*.json",
14 | "!/build/contracts/*Tester.json",
15 | "!/build/contracts/*Mock.json",
16 | "scripts/**/*.js",
17 | "js-sdk/**/*.js"
18 | ],
19 | "dependencies": {
20 | "@openzeppelin/contracts": "3.2.1-solc-0.7",
21 | "ethereumjs-tx": "2.1.2",
22 | "ethereumjs-util": "7.0.6"
23 | },
24 | "peerDependencies": {
25 | "@truffle/contract": "^4.2.23"
26 | },
27 | "devDependencies": {
28 | "@decentral.ee/web3-helpers": "0.3.2",
29 | "@openzeppelin/test-helpers": "0.5.6",
30 | "@truffle/hdwallet-provider": "1.1.0",
31 | "dotenv": "8.2.0",
32 | "eslint": "7.10.0",
33 | "eth-gas-reporter": "0.2.17",
34 | "ganache-time-traveler": "1.0.15",
35 | "husky": "4.3.0",
36 | "npm-run-all": "4.1.5",
37 | "readline": "1.3.0",
38 | "solhint": "3.2.1",
39 | "solidity-coverage": "0.7.10",
40 | "truffle": "5.1.46",
41 | "truffle-flattener": "1.5.0",
42 | "truffle-plugin-verify": "0.4.0"
43 | },
44 | "scripts": {
45 | "build": "run-s build:*",
46 | "build:contracts": "rm -f build/contracts/*;truffle compile",
47 | "build:abi": "scripts/build-abi-js.sh",
48 | "test": "run-s lint:js lint:sol build:* test:*",
49 | "test:contracts": "truffle test test/contracts.test.js && cat build/eth-gas-report.txt | tee build/contracts-eth-gas-report.txt",
50 | "test:sdk": "truffle test test/sdk.test.js",
51 | "test:deployment": "truffle test test/deployment.test.js",
52 | "test-coverage": "truffle run coverage --file test/contracts.test.js",
53 | "dev": "nodemon -e sol,js -i build -x 'npm run test 2>&1'",
54 | "proxify": "truffle-flattener contracts/RToken.sol > flat.ignore.sol && sol-proxy create flat.ignore.sol",
55 | "lint": "run-s lint:*",
56 | "lint:js": "eslint . --max-warnings=0 --report-unused-disable-directives && echo '✔ Your .js files look good.'",
57 | "lint:sol": "solhint -w 0 contracts/*.sol contracts/*/*.sol && echo '✔ Your .sol files look good.'",
58 | "lint:tests": "grep -FR .only test || { echo '✔ No test is focused.';exit 0; } && { echo '✘ You have focused tests.'; exit 1; }"
59 | },
60 | "husky": {
61 | "hooks": {
62 | "pre-commit": "npm run lint"
63 | }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/ethereum-contracts/build/contracts/EnumerableSet.json:
--------------------------------------------------------------------------------
1 | {
2 | "contractName": "EnumerableSet",
3 | "abi": [],
4 | "metadata": "{\"compiler\":{\"version\":\"0.7.1+commit.f4a555be\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"details\":\"Library for managing https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive types. Sets have the following properties: - Elements are added, removed, and checked for existence in constant time (O(1)). - Elements are enumerated in O(n). No guarantees are made on the ordering. ``` contract Example { // Add the library methods using EnumerableSet for EnumerableSet.AddressSet; // Declare a set state variable EnumerableSet.AddressSet private mySet; } ``` As of v3.0.0, only sets of type `address` (`AddressSet`) and `uint256` (`UintSet`) are supported.\",\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"@openzeppelin/contracts/utils/EnumerableSet.sol\":\"EnumerableSet\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/utils/EnumerableSet.sol\":{\"keccak256\":\"0x5420cb92cf72960b0be9dacec46b15a5558f89688d846cc6e53ec1c2d807f673\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://f6dd826d43bc5d033e6197236f8b55e56dfdda6d1a364f5ddfa79c134a664875\",\"dweb:/ipfs/Qmcztt4dk38dzvUtDQoJrnWNvafotNRttyah1zRVmsNyB6\"]}},\"version\":1}",
5 | "bytecode": "0x60566023600b82828239805160001a607314601657fe5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212202b274918fad4788323bd761d54c5b2d4381873ad93e523c7e02f63ac063c6f2564736f6c63430007010033",
6 | "deployedBytecode": "0x73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212202b274918fad4788323bd761d54c5b2d4381873ad93e523c7e02f63ac063c6f2564736f6c63430007010033",
7 | "immutableReferences": {},
8 | "compiler": {
9 | "name": "solc",
10 | "version": "0.7.1+commit.f4a555be.Emscripten.clang"
11 | },
12 | "networks": {},
13 | "schemaVersion": "3.2.5",
14 | "devdoc": {
15 | "details": "Library for managing https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive types. Sets have the following properties: - Elements are added, removed, and checked for existence in constant time (O(1)). - Elements are enumerated in O(n). No guarantees are made on the ordering. ``` contract Example { // Add the library methods using EnumerableSet for EnumerableSet.AddressSet; // Declare a set state variable EnumerableSet.AddressSet private mySet; } ``` As of v3.0.0, only sets of type `address` (`AddressSet`) and `uint256` (`UintSet`) are supported.",
16 | "kind": "dev",
17 | "methods": {},
18 | "version": 1
19 | },
20 | "userdoc": {
21 | "kind": "user",
22 | "methods": {},
23 | "version": 1
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/ethereum-contracts/contracts/apps/SuperAppBase.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity >= 0.7.0;
3 |
4 | import {
5 | ISuperfluid,
6 | ISuperToken,
7 | ISuperApp,
8 | SuperAppDefinitions
9 | } from "../interfaces/superfluid/ISuperfluid.sol";
10 |
11 | abstract contract SuperAppBase is ISuperApp {
12 |
13 | function beforeAgreementCreated(
14 | ISuperToken /*superToken*/,
15 | bytes calldata /*ctx*/,
16 | address /*agreementClass*/,
17 | bytes32 /*agreementId*/
18 | )
19 | external
20 | view
21 | virtual
22 | override
23 | returns (bytes memory /*cbdata*/)
24 | {
25 | revert("Unsupported callback - Before Agreement Created");
26 | }
27 |
28 | function afterAgreementCreated(
29 | ISuperToken /*superToken*/,
30 | bytes calldata /*ctx*/,
31 | address /*agreementClass*/,
32 | bytes32 /*agreementId*/,
33 | bytes calldata /*cbdata*/
34 | )
35 | external
36 | virtual
37 | override
38 | returns (bytes memory /*newCtx*/)
39 | {
40 | revert("Unsupported callback - After Agreement Created");
41 | }
42 |
43 | function beforeAgreementUpdated(
44 | ISuperToken /*superToken*/,
45 | bytes calldata /*ctx*/,
46 | address /*agreementClass*/,
47 | bytes32 /*agreementId*/
48 | )
49 | external
50 | view
51 | virtual
52 | override
53 | returns (bytes memory /*cbdata*/)
54 | {
55 | revert("Unsupported callback - Before Agreement updated");
56 | }
57 |
58 | function afterAgreementUpdated(
59 | ISuperToken /*superToken*/,
60 | bytes calldata /*ctx*/,
61 | address /*agreementClass*/,
62 | bytes32 /*agreementId*/,
63 | bytes calldata /*cbdata*/
64 | )
65 | external
66 | virtual
67 | override
68 | returns (bytes memory /*newCtx*/)
69 | {
70 | revert("Unsupported callback - After Agreement Updated");
71 | }
72 |
73 | function beforeAgreementTerminated(
74 | ISuperToken /*superToken*/,
75 | bytes calldata /*ctx*/,
76 | address /*agreementClass*/,
77 | bytes32 /*agreementId*/
78 | )
79 | external
80 | view
81 | virtual
82 | override
83 | returns (bytes memory /*cbdata*/)
84 | {
85 | revert("Unsupported callback - Before Agreement Terminated");
86 | }
87 |
88 | function afterAgreementTerminated(
89 | ISuperToken /*superToken*/,
90 | bytes calldata /*ctx*/,
91 | address /*agreementClass*/,
92 | bytes32 /*agreementId*/,
93 | bytes memory /*cbdata*/
94 | )
95 | external
96 | virtual
97 | override
98 | returns (bytes memory /*newCtx*/)
99 | {
100 | revert("Unsupported callback - After Agreement Terminated");
101 | }
102 |
103 | }
104 |
--------------------------------------------------------------------------------
/sample-integrations/flowlottery/ui/src/components/index.js:
--------------------------------------------------------------------------------
1 | import styled from "styled-components";
2 |
3 | export const Header = styled.header`
4 | background-color: #000;
5 | min-height: 70px;
6 | display: flex;
7 | flex-direction: row;
8 | align-items: center;
9 | justify-content: flex-end;
10 | color: white;
11 | padding-left: 18px;
12 | `;
13 |
14 | export const Body = styled.body`
15 | align-items: center;
16 | color: white;
17 | font-size: 20px;
18 | justify-content: center;
19 | background-color: #000;
20 | padding-bottom: 18px;
21 | `;
22 |
23 | export const BoxContainer = styled.div`
24 | min-height: 60vh;
25 | background-size: 70vh; /* You must set a specified height */
26 | background-position-x: center; /* Center the image */
27 | background-repeat: no-repeat; /* Do not repeat the image */
28 | ${({ winner }) => {
29 | switch (winner) {
30 | case "winner":
31 | return `background-image: url("./winning.gif");`;
32 | case "loser":
33 | return `background-image: url("./waterfall.gif");`;
34 | default:
35 | return `background-image: url("./neutral.gif");`;
36 | }
37 | }}
38 | display: flex;
39 | width: 100%;
40 | flex-direction: row;
41 | `;
42 |
43 | export const Image = styled.img`
44 | height: 10vmin;
45 | margin-bottom: 16px;
46 | pointer-events: none;
47 | `;
48 |
49 | export const Link = styled.a.attrs({
50 | target: "_blank",
51 | rel: "noopener noreferrer"
52 | })`
53 | color: #61dafb;
54 | margin-top: 10px;
55 | `;
56 |
57 | export const Div100 = styled.div`
58 | width: 100%;
59 | `;
60 | export const Button = styled.button`
61 | background-color: #cd4337;
62 | border: none;
63 | border-radius: 8px;
64 | color: #fff;
65 | box-shadow: 0px 0px 10px 6px rgba(200, 200, 255, 0.75);
66 | cursor: pointer;
67 | font-size: 22px;
68 | text-align: center;
69 | text-decoration: none;
70 | margin: 10px 20px;
71 | padding: 12px 24px;
72 | white-space: nowrap;
73 | :disabled {
74 | background: #444;
75 | }
76 |
77 | ${props => props.hidden && "hidden"} :focus {
78 | border: none;
79 | outline: none;
80 | }
81 | `;
82 |
83 | export const Center = styled.div`
84 | text-align: center;
85 | `;
86 | export const Right = styled.div`
87 | text-align: right;
88 | `;
89 |
90 | export const Box = styled.div`
91 | font-size: 1em;
92 | max-width: 50%;
93 | padding: 14px;
94 | flex-grow: 1;
95 | `;
96 | export const ShrinkBox = styled.div`
97 | flex-grow: 0;
98 | display: flex;
99 | flex-direction: column;
100 | `;
101 |
102 | export const Span = styled.span`
103 | ${({ color }) => `color: ${color}`}
104 | `;
105 |
106 | export const BottomTable = styled.div`
107 | min-height: 40vh;
108 | background: #000;
109 | padding: 14px;
110 | h3 {
111 | padding-left: 42px;
112 | }
113 | td {
114 | padding: 2px 5px;
115 | }
116 | `;
117 |
118 | export const Left = styled.span`
119 | text-align: left !important;
120 | `;
121 |
122 | export const XL = styled.span`
123 | font-size: 2em;
124 | `;
125 |
--------------------------------------------------------------------------------
/test-scripts/cfa-test.js:
--------------------------------------------------------------------------------
1 | const SuperfluidSDK = require("../ethereum-contracts")
2 |
3 | // To run the script"
4 | // - go to ethereum-contracts directory
5 | // - setup your env file with these variables:
6 | // - `GOERLI_MNEMONIC` - your mnemonic
7 | // - `GOERLI_PROVIDER_URL` - your goerli web3 provider url
8 | // - and run: `npx truffle --network goerli exec ../test-scripts/test.js`
9 | module.exports = async function (callback) {
10 | global.web3 = web3;
11 |
12 | try {
13 | const accounts = await web3.eth.getAccounts();
14 | const admin = accounts[0];
15 | const bob = accounts[1];
16 | const minAmount = web3.utils.toWei("100", "ether");
17 |
18 | const sf = new SuperfluidSDK.Framework({
19 | chainId: 5,
20 | version: "preview-20200928",
21 | web3Provider: web3.currentProvider
22 | });
23 | await sf.initialize();
24 | const daiAddress = await sf.resolver.get("tokens.fDAI");
25 | const dai = await sf.contracts.TestToken.at(daiAddress);
26 | const daixWrapper = await sf.getERC20Wrapper(dai);
27 | const daix = await sf.contracts.ISuperToken.at(daixWrapper.wrapperAddress);
28 | console.log("daix address", daix.address);
29 |
30 | // minting
31 | if (web3.utils.toBN(await daix.balanceOf(admin)).lt(web3.utils.toBN(minAmount))) {
32 | console.log("Minting and upgrading...");
33 | await dai.mint(admin, minAmount, { from: admin });
34 | await dai.approve(daix.address, minAmount, { from: admin });
35 | await daix.upgrade(minAmount, { from: admin });
36 | console.log("Done minting and upgrading.");
37 | }
38 | console.log("admin balance", (await daix.balanceOf(admin)).toString());
39 | console.log("bob balance", (await daix.balanceOf(bob)).toString());
40 |
41 | if ((await sf.agreements.cfa.getFlow(daix.address, admin, bob)).timestamp.toString() != "0") {
42 | console.log("Deleting the existing flow...");
43 | await sf.host.callAgreement(
44 | sf.agreements.cfa.address,
45 | sf.agreements.cfa.contract.methods.deleteFlow(
46 | daix.address, admin, bob, "0x"
47 | ).encodeABI(), {
48 | from: admin
49 | }
50 | );
51 | console.log("Flow deleted.");
52 | }
53 |
54 | console.log("Creating a new flow...");
55 | await sf.host.callAgreement(
56 | sf.agreements.cfa.address,
57 | sf.agreements.cfa.contract.methods.createFlow(
58 | daix.address, bob, "385802469135802", "0x"
59 | ).encodeABI(), {
60 | from: admin
61 | }
62 | );
63 | console.log("Flow created.")
64 |
65 | console.log("Admin net flow", (await sf.agreements.cfa.getNetFlow(daix.address, admin)).toString());
66 | console.log("Bob net flow", (await sf.agreements.cfa.getNetFlow(daix.address, bob)).toString());
67 | callback();
68 | } catch (err) {
69 | callback(err);
70 | }
71 | }
72 |
73 |
--------------------------------------------------------------------------------
/sample-integrations/flowlottery/ui/scripts/ipfs.js:
--------------------------------------------------------------------------------
1 | const chalk = require("chalk");
2 | const ipfsApi = require("ipfs-http-client");
3 | const { clearLine } = require("readline");
4 |
5 | const { globSource } = ipfsApi;
6 |
7 | const infura = { host: "ipfs.infura.io", port: "5001", protocol: "https" };
8 | // Run your own ipfs daemon: https://docs.ipfs.io/how-to/command-line-quick-start/#install-ipfs
9 | // const localhost = { host: "localhost", port: "5001", protocol: "http" };
10 |
11 | const ipfs = ipfsApi(infura);
12 | const ipfsGateway = "https://ipfs.io/ipfs/";
13 |
14 | const addOptions = {
15 | pin: true,
16 | };
17 |
18 | async function pushDirectoryToIpfs(path) {
19 | try {
20 | const response = await ipfs.add(globSource(path, { recursive: true }), addOptions);
21 | return response;
22 | } catch (e) {
23 | return {};
24 | }
25 | }
26 |
27 | async function publishHashToIpns(ipfsHash) {
28 | try {
29 | const response = await ipfs.name.publish(`/ipfs/${ipfsHash}`);
30 | return response;
31 | } catch (e) {
32 | return {};
33 | }
34 | }
35 |
36 | function nodeMayAllowPublish(ipfsClient) {
37 | // You must have your own IPFS node in order to publish an IPNS name
38 | // This contains a blacklist of known nodes which do not allow users to publish IPNS names.
39 | const nonPublishingNodes = ["ipfs.infura.io"];
40 | const { host } = ipfsClient.getEndpointConfig();
41 |
42 | return !nonPublishingNodes.some(nodeUrl => {
43 | return host.includes(nodeUrl);
44 | });
45 | }
46 |
47 | (async function() {
48 | console.log("🛰 Sending to IPFS...");
49 | console.log();
50 |
51 | const { cid } = await pushDirectoryToIpfs("./build");
52 | if (!cid) {
53 | console.log(`📡 App deployment failed`);
54 | return false;
55 | }
56 |
57 | console.log(`📡 App deployed to IPFS with hash: ${chalk.cyan(cid.toString())}`);
58 | console.log();
59 |
60 | let ipnsName = "";
61 | if (nodeMayAllowPublish(ipfs)) {
62 | console.log(`✍️ Publishing /ipfs/${cid.toString()} to IPNS...`);
63 | process.stdout.write(" Publishing to IPNS can take up to roughly two minutes.\r");
64 | ipnsName = (await publishHashToIpns(cid.toString())).name;
65 | clearLine(process.stdout, 0);
66 |
67 | if (!ipnsName) {
68 | console.log(" Publishing IPNS name on node failed.");
69 | }
70 |
71 | console.log(`🔖 App published to IPNS with name: ${chalk.cyan(ipnsName)}`);
72 | console.log();
73 | }
74 |
75 | console.log("🚀 Deployment to IPFS complete!");
76 | console.log();
77 |
78 | console.log(`🌐 Use the link${ipnsName ? "s" : ""} below to access your app:`);
79 | const link = ipfsGateway + cid.toString();
80 | console.log(` IPFS: ${chalk.cyan(link)}`);
81 |
82 | if (ipnsName) {
83 | const ipnsUrl = `${ipfsGateway}${ipnsName}`;
84 | console.log(` IPNS: ${chalk.cyan(ipnsUrl)}`);
85 | console.log();
86 | console.log(
87 | "Each new deployment will have a unique IPFS hash while the IPNS name will always point at the most recent deployment.",
88 | );
89 | console.log(
90 | "It is recommended that you share the IPNS link so that people always see the newest version of your app.",
91 | );
92 | }
93 | console.log();
94 | return true;
95 | })();
96 |
--------------------------------------------------------------------------------
/ethereum-contracts/js-sdk/Framework.js:
--------------------------------------------------------------------------------
1 | const Web3 = require("web3");
2 | const TruffleContract = require("@truffle/contract");
3 | const SuperfluidABI = require("../build/abi");
4 | const getConfig = require("./getConfig");
5 |
6 | function Framework({
7 | web3Provider,
8 | isTruffle,
9 | version,
10 | chainId
11 | }) {
12 | const contractNames = Object.keys(SuperfluidABI);
13 |
14 | this.chainId = chainId;
15 | this.version = version || "test";
16 |
17 | // load contracts
18 | this.contracts = {};
19 | if (!isTruffle) {
20 | if (!web3Provider) throw new Error("web3Provider is required");
21 | // load contracts from ABI
22 | contractNames.forEach(i => {
23 | const c = this.contracts[i] = TruffleContract({
24 | contractName: i,
25 | abi: SuperfluidABI[i]
26 | });
27 | c.setProvider(web3Provider);
28 | });
29 | this.web3 = new Web3(web3Provider);
30 | } else {
31 | // load contracts from truffle artifacts
32 | contractNames.forEach(i => {
33 | this.contracts[i] = global.artifacts.require(i);
34 | });
35 | // assuming web3 is available when truffle artifacts available
36 | this.web3 = global.web3;
37 | }
38 | }
39 |
40 | Framework.prototype.initialize = async function () {
41 | const chainId = this.chainId || await this.web3.eth.net.getId(); // TODO use eth.getChainId;
42 | console.log("chainId", chainId);
43 |
44 | const config = getConfig(chainId);
45 |
46 | console.debug("Resolver at", config.resolverAddress);
47 | this.resolver = await this.contracts.IResolver.at(config.resolverAddress);
48 |
49 | console.debug("Resolving contracts with version", this.version);
50 | const superfluidAddress = await this.resolver.get.call(`Superfluid.${this.version}`);
51 | const cfaAddress = await this.resolver.get.call(`ConstantFlowAgreementV1.${this.version}`);
52 | const idaAddress = await this.resolver.get.call(`InstantDistributionAgreementV1.${this.version}`);
53 | console.debug("Superfluid", superfluidAddress);
54 | console.debug("ConstantFlowAgreementV1", cfaAddress);
55 | console.debug("InstantDistributionAgreementV1", idaAddress);
56 |
57 | this.host = await this.contracts.ISuperfluid.at(superfluidAddress);
58 | this.agreements = {
59 | cfa : await this.contracts.IConstantFlowAgreementV1.at(cfaAddress),
60 | ida : await this.contracts.IInstantDistributionAgreementV1.at(idaAddress),
61 | };
62 | };
63 |
64 | Framework.prototype.getERC20Wrapper = async function(tokenInfo) {
65 | const tokenInfoSymbol = await tokenInfo.symbol.call();
66 | return await this.host.getERC20Wrapper.call(
67 | tokenInfo.address,
68 | `${tokenInfoSymbol}x`,
69 | );
70 | };
71 |
72 | Framework.prototype.createERC20Wrapper = async function(tokenInfo) {
73 | const tokenInfoName = await tokenInfo.name.call();
74 | const tokenInfoSymbol = await tokenInfo.symbol.call();
75 | const tokenInfoDecimals = await tokenInfo.decimals.call();
76 | await this.host.createERC20Wrapper(
77 | tokenInfo.address,
78 | tokenInfoDecimals,
79 | `Super ${tokenInfoName}`,
80 | `${tokenInfoSymbol}x`,
81 | );
82 | };
83 |
84 | module.exports = Framework;
85 |
--------------------------------------------------------------------------------
/sample-integrations/flowlottery/ui/README.md:
--------------------------------------------------------------------------------
1 | # @project/react-app
2 |
3 | This package is a fork of the default template provided by [Create React App](https://github.com/facebook/create-react-app).
4 |
5 | ## Available Scripts
6 |
7 | In the project directory, you can run:
8 |
9 | ### `yarn start`
10 |
11 | Runs the app in development mode.
12 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
13 |
14 | The page will automatically reload if you make changes to the code.
15 | You will see the build errors and lint warnings in the console.
16 |
17 | ### `yarn test`
18 |
19 | Runs the test watcher in an interactive mode.
20 | By default, runs tests related to files changed since the last commit.
21 |
22 | [Read more about testing.](https://facebook.github.io/create-react-app/docs/running-tests)
23 |
24 | ### `yarn build`
25 |
26 | Builds the app for production to the `build` folder.
27 | It correctly bundles React in production mode and optimizes the build for the best performance.
28 |
29 | The build is minified and the filenames include the hashes.
30 | Your app is ready to be deployed!
31 |
32 | See the React documentation on [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
33 |
34 | ### `yarn react-app:eject`
35 |
36 | **Note: this is a one-way operation. Once you `eject`, you can’t go back!**
37 |
38 | If you aren’t satisfied with the build tool and configuration choices, you can `eject` the React app at any time. This command will
39 | remove the single build dependency from your React package.
40 |
41 | Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right
42 | into your project so you have full control over them. All of the commands except `eject` will still work, but
43 | they will point to the copied scripts so you can tweak them. At this point you’re on your own.
44 |
45 | You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it.
46 |
47 | ## Learn More
48 |
49 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
50 |
51 | To learn React, check out the [React documentation](https://reactjs.org/).
52 |
53 | ### Code Splitting
54 |
55 | This section has moved here: https://facebook.github.io/create-react-app/docs/code-splitting
56 |
57 | ### Analyzing the Bundle Size
58 |
59 | This section has moved here: https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size
60 |
61 | ### Making a Progressive Web App
62 |
63 | This section has moved here: https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app
64 |
65 | ### Advanced Configuration
66 |
67 | This section has moved here: https://facebook.github.io/create-react-app/docs/advanced-configuration
68 |
69 | ### Deployment
70 |
71 | This section has moved here: https://facebook.github.io/create-react-app/docs/deployment
72 |
73 | ### `yarn build` fails to minify
74 |
75 | This section has moved here: https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify
76 |
--------------------------------------------------------------------------------
/ethereum-contracts/build/contracts/IERC1820Implementer.json:
--------------------------------------------------------------------------------
1 | {
2 | "contractName": "IERC1820Implementer",
3 | "abi": [
4 | {
5 | "inputs": [
6 | {
7 | "internalType": "bytes32",
8 | "name": "interfaceHash",
9 | "type": "bytes32"
10 | },
11 | {
12 | "internalType": "address",
13 | "name": "account",
14 | "type": "address"
15 | }
16 | ],
17 | "name": "canImplementInterfaceForAddress",
18 | "outputs": [
19 | {
20 | "internalType": "bytes32",
21 | "name": "",
22 | "type": "bytes32"
23 | }
24 | ],
25 | "stateMutability": "view",
26 | "type": "function"
27 | }
28 | ],
29 | "metadata": "{\"compiler\":{\"version\":\"0.7.1+commit.f4a555be\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"interfaceHash\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"canImplementInterfaceForAddress\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Interface for an ERC1820 implementer, as defined in the https://eips.ethereum.org/EIPS/eip-1820#interface-implementation-erc1820implementerinterface[EIP]. Used by contracts that will be registered as implementers in the {IERC1820Registry}.\",\"kind\":\"dev\",\"methods\":{\"canImplementInterfaceForAddress(bytes32,address)\":{\"details\":\"Returns a special value (`ERC1820_ACCEPT_MAGIC`) if this contract implements `interfaceHash` for `account`. See {IERC1820Registry-setInterfaceImplementer}.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"@openzeppelin/contracts/introspection/IERC1820Implementer.sol\":\"IERC1820Implementer\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/introspection/IERC1820Implementer.sol\":{\"keccak256\":\"0x1b3a9cb2088366ff1df7bf5743d3d22ae2821df4db4202da506a878c732b27a1\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://ae71f314bd6c2e4fa351f299be07017d9c629a46b9c7b32efd9e86e93f6cc03d\",\"dweb:/ipfs/QmPFPoanRcy38bw83rY2KdQRtvMWgkj9ascPLZgLVzQsM7\"]}},\"version\":1}",
30 | "bytecode": "0x",
31 | "deployedBytecode": "0x",
32 | "immutableReferences": {},
33 | "compiler": {
34 | "name": "solc",
35 | "version": "0.7.1+commit.f4a555be.Emscripten.clang"
36 | },
37 | "networks": {},
38 | "schemaVersion": "3.2.5",
39 | "devdoc": {
40 | "details": "Interface for an ERC1820 implementer, as defined in the https://eips.ethereum.org/EIPS/eip-1820#interface-implementation-erc1820implementerinterface[EIP]. Used by contracts that will be registered as implementers in the {IERC1820Registry}.",
41 | "kind": "dev",
42 | "methods": {
43 | "canImplementInterfaceForAddress(bytes32,address)": {
44 | "details": "Returns a special value (`ERC1820_ACCEPT_MAGIC`) if this contract implements `interfaceHash` for `account`. See {IERC1820Registry-setInterfaceImplementer}."
45 | }
46 | },
47 | "version": 1
48 | },
49 | "userdoc": {
50 | "kind": "user",
51 | "methods": {},
52 | "version": 1
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/ethereum-contracts/contracts/test/TestGovernance.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity 0.7.1;
3 |
4 | import { Ownable } from "../access/Ownable.sol";
5 | import {
6 | ISuperfluid,
7 | ISuperfluidGovernance
8 | } from "../interfaces/superfluid/ISuperfluid.sol";
9 |
10 | contract TestGovernance is
11 | Ownable,
12 | ISuperfluidGovernance
13 | {
14 | address private _rewardAddress;
15 | uint256 private _liquidationPeriod;
16 | address[] private _agreementList;
17 | mapping (address => uint) private _agreementMap;
18 |
19 | constructor(
20 | address rewardAddress,
21 | uint256 liquidationPeriod
22 | )
23 | {
24 | _owner = msg.sender;
25 | _rewardAddress = rewardAddress;
26 | _liquidationPeriod = liquidationPeriod;
27 | }
28 |
29 | function getRewardAddress(
30 | address /* superToken */
31 | )
32 | external
33 | view
34 | override
35 | returns(address rewardAddress)
36 | {
37 | return _rewardAddress;
38 | }
39 |
40 | function setRewardAddress(
41 | address rewardAddress
42 | )
43 | external
44 | onlyOwner
45 | {
46 | _rewardAddress = rewardAddress;
47 | }
48 |
49 | function getLiquidationPeriod(
50 | address /* superToken */
51 | )
52 | external
53 | view
54 | override
55 | returns(uint256 period)
56 | {
57 | return _liquidationPeriod;
58 | }
59 |
60 | function addAgreement(address agreementClass) external onlyOwner override {
61 | require(agreementClass != address(0), "TestGovernance: 0x address detected");
62 | _agreementList.push(agreementClass);
63 | _agreementMap[agreementClass] = _agreementList.length;
64 | }
65 |
66 | function isAgreementListed(address agreementClass) external override view returns(bool yes) {
67 | return _agreementMap[agreementClass] > 0;
68 | }
69 |
70 | function mapAgreements(uint256 bitmap)
71 | external view override
72 | returns (address[] memory agreementClasses) {
73 | uint i;
74 | uint n;
75 | // create memory output using the counted size
76 | agreementClasses = new address[](_agreementList.length);
77 | // add to the output
78 | n = 0;
79 | for (i = 0; i < _agreementList.length; ++i) {
80 | if ((bitmap & (1 << i)) > 0) {
81 | agreementClasses[n++] = _agreementList[i];
82 | }
83 | }
84 | // resize memory arrays
85 | assembly {
86 | mstore(agreementClasses, n)
87 | }
88 | }
89 |
90 | function maskAgreementBit(uint256 bitmap, address agreementClass)
91 | external view override
92 | returns (uint256 newBitmap)
93 | {
94 | require(_agreementMap[agreementClass] > 0, "TestGovernance: Agreement not listed");
95 | return bitmap | (1 << (_agreementMap[agreementClass] - 1));
96 | }
97 |
98 | function unmaskAgreementBit(uint256 bitmap, address agreementClass)
99 | external view override
100 | returns (uint256 newBitmap)
101 | {
102 | require(_agreementMap[agreementClass] > 0, "TestGovernance: Agreement not listed");
103 | return bitmap & ~(1 << (_agreementMap[agreementClass] - 1));
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/ethereum-contracts/scripts/inspect-account.js:
--------------------------------------------------------------------------------
1 | const SuperfluidSDK = require("..");
2 | const { parseColonArgs } = require("./utils");
3 |
4 | function normalizeFlowRate(fr) {
5 | return (fr.toString() / 1e18 * 3600 * 24 * 30).toFixed(4) + " / mo";
6 | }
7 |
8 | function getLatestFlows(flows) {
9 | return Object.values(flows.reduce((acc, i) => {
10 | acc[i.args.sender + ":" + i.args.receiver] = i;
11 | return acc;
12 | }, {})).filter(i => i.args.flowRate.toString() != "0");
13 | }
14 |
15 | /**
16 | * @dev Inspect accounts and their agreements
17 | *
18 | * Usage: npx truffle exec scripts/inspect-account.js : 0xACC1 0xACC2 ...
19 | */
20 | module.exports = async function (callback, argv) {
21 | global.web3 = web3;
22 |
23 | try {
24 |
25 | const args = parseColonArgs(argv || process.argv);
26 | if (args.length < 1) {
27 | throw new Error("Not enough arguments");
28 | }
29 | const sf = new SuperfluidSDK.Framework({
30 | chainId: 5,
31 | version: process.env.RELEASE_VERSION || "test",
32 | web3Provider: web3.currentProvider
33 | });
34 | await sf.initialize();
35 |
36 | const tokens = ["fDAI"];
37 | while (args.length) {
38 | const account = args.shift();
39 | console.log("=".repeat(80));
40 | console.log("account", account);
41 | for (let i = 0; i < tokens.length; ++i) {
42 | const tokenName = tokens[i];
43 | const tokenAddress = await sf.resolver.get(`tokens.${tokenName}`);
44 | const token = await sf.contracts.ERC20WithTokenInfo.at(tokenAddress);
45 | const tokenWrapper = await sf.getERC20Wrapper(token);
46 | const superToken = await sf.contracts.ISuperToken.at(tokenWrapper.wrapperAddress);
47 | console.log(`${tokenName} balance`, (await token.balanceOf.call(account)).toString() / 1e18);
48 | const realtimeBalance = await superToken.realtimeBalanceOf.call(account, parseInt(Date.now() / 1000));
49 | console.log(`${tokenName}x balance`,
50 | realtimeBalance.availableBalance.toString() / 1e18,
51 | realtimeBalance.deposit.toString() / 1e18,
52 | realtimeBalance.owedDeposit.toString() / 1e18,
53 | );
54 | const netFlowRate = await sf.agreements.cfa.getNetFlow.call(superToken.address, account);
55 | console.log(`Net flowrate ${normalizeFlowRate(netFlowRate)}`);
56 | console.log("In Flows:");
57 | console.log(getLatestFlows(await sf.agreements.cfa.getPastEvents("FlowUpdated", {
58 | fromBlock: 0,
59 | filter: {
60 | receiver: account
61 | }
62 | })).map(f => `${f.args.sender} -> ${normalizeFlowRate(f.args.flowRate)}`));
63 | console.log("Out Flows:");
64 | console.log(getLatestFlows(await sf.agreements.cfa.getPastEvents("FlowUpdated", {
65 | fromBlock: 0,
66 | filter: {
67 | sender: account
68 | }
69 | })).map(f => `${f.args.sender} -> ${normalizeFlowRate(f.args.flowRate)}`));
70 | }
71 | console.log("=".repeat(80));
72 | }
73 |
74 | callback();
75 |
76 | } catch (err) {
77 | callback(err);
78 | }
79 | };
80 |
81 |
--------------------------------------------------------------------------------
/ethereum-contracts/test/sdk.test.js:
--------------------------------------------------------------------------------
1 | const deployFramework = require("../scripts/deploy-framework");
2 | const { web3tx } = require("@decentral.ee/web3-helpers");
3 | const { assert } = require("chai");
4 |
5 |
6 | contract("sdk test", () => {
7 |
8 | const errorHandler = err => { if (err) throw err; };
9 |
10 | const Superfluid = require("..");
11 |
12 | function testLoadedContracts(sf) {
13 | const {
14 | IERC20,
15 | IResolver,
16 | TokenInfo,
17 | ISuperfluid,
18 | ISuperToken,
19 | IConstantFlowAgreementV1,
20 | IInstantDistributionAgreementV1,
21 | } = sf.contracts;
22 |
23 | assert.isDefined(IERC20.abi);
24 | assert.equal(IERC20.contractName, "IERC20");
25 | assert.isTrue(IERC20.abi.filter(i => i.name === "Transfer").length > 0);
26 |
27 | assert.isDefined(IResolver.abi);
28 | assert.equal(IResolver.contractName, "IResolver");
29 | assert.isTrue(IResolver.abi.filter(i => i.name === "get").length > 0);
30 |
31 | assert.isDefined(TokenInfo.abi);
32 | assert.equal(TokenInfo.contractName, "TokenInfo");
33 | assert.isTrue(TokenInfo.abi.filter(i => i.name === "symbol").length > 0);
34 |
35 | assert.isDefined(ISuperfluid.abi);
36 | assert.equal(ISuperfluid.contractName, "ISuperfluid");
37 | assert.isTrue(ISuperfluid.abi.filter(i => i.name === "getERC20Wrapper").length > 0);
38 |
39 | assert.isDefined(ISuperToken.abi);
40 | assert.equal(ISuperToken.contractName, "ISuperToken");
41 | assert.isTrue(ISuperToken.abi.filter(i => i.name === "upgrade").length > 0);
42 |
43 | assert.isDefined(IConstantFlowAgreementV1.abi);
44 | assert.equal(IConstantFlowAgreementV1.contractName, "IConstantFlowAgreementV1");
45 | assert.isTrue(IConstantFlowAgreementV1.abi.filter(i => i.name === "updateFlow").length > 0);
46 |
47 | assert.isDefined(IInstantDistributionAgreementV1.abi);
48 | assert.equal(IInstantDistributionAgreementV1.contractName, "IInstantDistributionAgreementV1");
49 | assert.isTrue(IInstantDistributionAgreementV1.abi.filter(i => i.name === "createIndex").length > 0);
50 | }
51 |
52 | it("get config", async () => {
53 | // goerli
54 | const goerliConfig = Superfluid.getConfig(5);
55 | assert.isNotEmpty(goerliConfig.resolverAddress);
56 | /*
57 | // test environment
58 | let testConfig = Superfluid.getConfig(5555);
59 | assert.isUndefined(testConfig.resolverAddress);
60 | process.env.TEST_RESOLVER_ADDRESS="0x42";
61 | testConfig = Superfluid.getConfig(5555);
62 | assert.equal(testConfig.resolverAddress, "0x42");
63 | */
64 | });
65 |
66 | it("load framework without truffle framework", async () => {
67 | const TestResolver = artifacts.require("TestResolver");
68 | const testResolver = await web3tx(TestResolver.new, "TestResolver.new")();
69 | process.env.TEST_RESOLVER_ADDRESS = testResolver.address;
70 | process.env.RESET = 1;
71 | await deployFramework(errorHandler);
72 |
73 | const sf = new Superfluid.Framework({ web3Provider: web3.currentProvider });
74 | testLoadedContracts(sf);
75 |
76 | await sf.initialize();
77 | });
78 |
79 | it("load framework with truffle framework", async () => {
80 | const TestResolver = artifacts.require("TestResolver");
81 | const testResolver = await web3tx(TestResolver.new, "TestResolver.new")();
82 | process.env.TEST_RESOLVER_ADDRESS = testResolver.address;
83 | process.env.RESET = 1;
84 | await deployFramework(errorHandler);
85 |
86 | const sf = new Superfluid.Framework({ isTruffle: true });
87 | testLoadedContracts(sf);
88 |
89 | await sf.initialize();
90 | });
91 |
92 | });
93 |
--------------------------------------------------------------------------------
/ethereum-contracts/build/contracts/Proxiable.json:
--------------------------------------------------------------------------------
1 | {
2 | "contractName": "Proxiable",
3 | "abi": [
4 | {
5 | "inputs": [],
6 | "name": "getCodeAddress",
7 | "outputs": [
8 | {
9 | "internalType": "address",
10 | "name": "codeAddress",
11 | "type": "address"
12 | }
13 | ],
14 | "stateMutability": "view",
15 | "type": "function"
16 | },
17 | {
18 | "inputs": [],
19 | "name": "proxiableUUID",
20 | "outputs": [
21 | {
22 | "internalType": "bytes32",
23 | "name": "",
24 | "type": "bytes32"
25 | }
26 | ],
27 | "stateMutability": "pure",
28 | "type": "function"
29 | }
30 | ],
31 | "metadata": "{\"compiler\":{\"version\":\"0.7.1+commit.f4a555be\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"getCodeAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"codeAddress\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"proxiableUUID\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"pure\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Proxiable contract. Inspired by https://eips.ethereum.org/EIPS/eip-1822\",\"kind\":\"dev\",\"methods\":{\"getCodeAddress()\":{\"details\":\"Get current implementation code address.\"},\"proxiableUUID()\":{\"details\":\"Proxiable UUID marker function. This would help to avoid wrong logic contract to be used for upgrading.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"/home/hellwolf/Projects/superfluid/superfluid-protocol-preview/ethereum-contracts-v0.1/contracts/upgradability/Proxiable.sol\":\"Proxiable\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"/home/hellwolf/Projects/superfluid/superfluid-protocol-preview/ethereum-contracts-v0.1/contracts/upgradability/Proxiable.sol\":{\"keccak256\":\"0x51d2c00317c8c6fb90b2dcf9578da8f2df14a857c26d8ab0060b5b6d95a14162\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7cf5d604a863d497dcfc3e780f4b863fffb113b306a60e672362b13df443453e\",\"dweb:/ipfs/QmYtr3foitBcyc9LsbhxMMK2uJGXxAdnmYKw4oUAaUcnMT\"]},\"/home/hellwolf/Projects/superfluid/superfluid-protocol-preview/ethereum-contracts-v0.1/contracts/upgradability/Proxy.sol\":{\"keccak256\":\"0xf9dbe1f9395d4346826ac3eb5e8fe19839de7056b27ae642521856b8225a7b7e\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://98afb08f2457daaed853ee5ddead49690f1d74a748065476f075526dac345141\",\"dweb:/ipfs/QmevKozaDcvtsDqhq7qFrtN2wkhWnQLuvdxMHTFENdGrHR\"]},\"/home/hellwolf/Projects/superfluid/superfluid-protocol-preview/ethereum-contracts-v0.1/contracts/upgradability/ProxyUtils.sol\":{\"keccak256\":\"0x34c692cb060d21fe40af5d6c6ddb2b4b9e52ffb6e44340195c7b91cbf664feca\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://6e2df14a12f9d4dfb780f75942e5ee5aa727e08b0f32f2950eb8816868f0c915\",\"dweb:/ipfs/QmdWakruAjcgqMkQBrJF9EffMnjaByCfygtDRrs3XnzSfA\"]}},\"version\":1}",
32 | "bytecode": "0x",
33 | "deployedBytecode": "0x",
34 | "immutableReferences": {},
35 | "compiler": {
36 | "name": "solc",
37 | "version": "0.7.1+commit.f4a555be.Emscripten.clang"
38 | },
39 | "networks": {},
40 | "schemaVersion": "3.2.5",
41 | "devdoc": {
42 | "details": "Proxiable contract. Inspired by https://eips.ethereum.org/EIPS/eip-1822",
43 | "kind": "dev",
44 | "methods": {
45 | "getCodeAddress()": {
46 | "details": "Get current implementation code address."
47 | },
48 | "proxiableUUID()": {
49 | "details": "Proxiable UUID marker function. This would help to avoid wrong logic contract to be used for upgrading."
50 | }
51 | },
52 | "version": 1
53 | },
54 | "userdoc": {
55 | "kind": "user",
56 | "methods": {},
57 | "version": 1
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/ethereum-contracts/build/contracts/IERC777Recipient.json:
--------------------------------------------------------------------------------
1 | {
2 | "contractName": "IERC777Recipient",
3 | "abi": [
4 | {
5 | "inputs": [
6 | {
7 | "internalType": "address",
8 | "name": "operator",
9 | "type": "address"
10 | },
11 | {
12 | "internalType": "address",
13 | "name": "from",
14 | "type": "address"
15 | },
16 | {
17 | "internalType": "address",
18 | "name": "to",
19 | "type": "address"
20 | },
21 | {
22 | "internalType": "uint256",
23 | "name": "amount",
24 | "type": "uint256"
25 | },
26 | {
27 | "internalType": "bytes",
28 | "name": "userData",
29 | "type": "bytes"
30 | },
31 | {
32 | "internalType": "bytes",
33 | "name": "operatorData",
34 | "type": "bytes"
35 | }
36 | ],
37 | "name": "tokensReceived",
38 | "outputs": [],
39 | "stateMutability": "nonpayable",
40 | "type": "function"
41 | }
42 | ],
43 | "metadata": "{\"compiler\":{\"version\":\"0.7.1+commit.f4a555be\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"userData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"operatorData\",\"type\":\"bytes\"}],\"name\":\"tokensReceived\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Interface of the ERC777TokensRecipient standard as defined in the EIP. Accounts can be notified of {IERC777} tokens being sent to them by having a contract implement this interface (contract holders can be their own implementer) and registering it on the https://eips.ethereum.org/EIPS/eip-1820[ERC1820 global registry]. See {IERC1820Registry} and {ERC1820Implementer}.\",\"kind\":\"dev\",\"methods\":{\"tokensReceived(address,address,address,uint256,bytes,bytes)\":{\"details\":\"Called by an {IERC777} token contract whenever tokens are being moved or created into a registered account (`to`). The type of operation is conveyed by `from` being the zero address or not. This call occurs _after_ the token contract's state is updated, so {IERC777-balanceOf}, etc., can be used to query the post-operation state. This function may revert to prevent the operation from being executed.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"@openzeppelin/contracts/token/ERC777/IERC777Recipient.sol\":\"IERC777Recipient\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC777/IERC777Recipient.sol\":{\"keccak256\":\"0x753e499703a17a6fff894ca3da861a5956afd81535c4d423540d9ad173e39d83\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://22908861346d81768add259a8fe11ca07c9af9d175ae23fd9981e6b961a3a55e\",\"dweb:/ipfs/QmXZ7nvBYxCoTd3mvonyyXRA2Zd6p686MMDiwREEJEn614\"]}},\"version\":1}",
44 | "bytecode": "0x",
45 | "deployedBytecode": "0x",
46 | "immutableReferences": {},
47 | "compiler": {
48 | "name": "solc",
49 | "version": "0.7.1+commit.f4a555be.Emscripten.clang"
50 | },
51 | "networks": {},
52 | "schemaVersion": "3.2.5",
53 | "devdoc": {
54 | "details": "Interface of the ERC777TokensRecipient standard as defined in the EIP. Accounts can be notified of {IERC777} tokens being sent to them by having a contract implement this interface (contract holders can be their own implementer) and registering it on the https://eips.ethereum.org/EIPS/eip-1820[ERC1820 global registry]. See {IERC1820Registry} and {ERC1820Implementer}.",
55 | "kind": "dev",
56 | "methods": {
57 | "tokensReceived(address,address,address,uint256,bytes,bytes)": {
58 | "details": "Called by an {IERC777} token contract whenever tokens are being moved or created into a registered account (`to`). The type of operation is conveyed by `from` being the zero address or not. This call occurs _after_ the token contract's state is updated, so {IERC777-balanceOf}, etc., can be used to query the post-operation state. This function may revert to prevent the operation from being executed."
59 | }
60 | },
61 | "version": 1
62 | },
63 | "userdoc": {
64 | "kind": "user",
65 | "methods": {},
66 | "version": 1
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/ethereum-contracts/build/contracts/ERC1820Implementer.json:
--------------------------------------------------------------------------------
1 | {
2 | "contractName": "ERC1820Implementer",
3 | "abi": [
4 | {
5 | "inputs": [
6 | {
7 | "internalType": "bytes32",
8 | "name": "interfaceHash",
9 | "type": "bytes32"
10 | },
11 | {
12 | "internalType": "address",
13 | "name": "account",
14 | "type": "address"
15 | }
16 | ],
17 | "name": "canImplementInterfaceForAddress",
18 | "outputs": [
19 | {
20 | "internalType": "bytes32",
21 | "name": "",
22 | "type": "bytes32"
23 | }
24 | ],
25 | "stateMutability": "view",
26 | "type": "function"
27 | }
28 | ],
29 | "metadata": "{\"compiler\":{\"version\":\"0.7.1+commit.f4a555be\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"interfaceHash\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"canImplementInterfaceForAddress\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Implementation of the {IERC1820Implementer} interface. Contracts may inherit from this and call {_registerInterfaceForAddress} to declare their willingness to be implementers. {IERC1820Registry-setInterfaceImplementer} should then be called for the registration to be complete.\",\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"canImplementInterfaceForAddress(bytes32,address)\":{\"notice\":\"See {IERC1820Implementer-canImplementInterfaceForAddress}.\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"@openzeppelin/contracts/introspection/ERC1820Implementer.sol\":\"ERC1820Implementer\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/introspection/ERC1820Implementer.sol\":{\"keccak256\":\"0x1f3f9f5e05738c4da5730ddd8463eb5918267b3efb541d858290ab40f81703cb\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://e6ecf76a60b289baeb83c8d058219b78f92768cdbee4509aef742442698fae62\",\"dweb:/ipfs/QmTf4wLKdwAq2TsaL1i7tFqrhkKpHYhxAwqB5qfRVWc8bt\"]},\"@openzeppelin/contracts/introspection/IERC1820Implementer.sol\":{\"keccak256\":\"0x1b3a9cb2088366ff1df7bf5743d3d22ae2821df4db4202da506a878c732b27a1\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://ae71f314bd6c2e4fa351f299be07017d9c629a46b9c7b32efd9e86e93f6cc03d\",\"dweb:/ipfs/QmPFPoanRcy38bw83rY2KdQRtvMWgkj9ascPLZgLVzQsM7\"]}},\"version\":1}",
30 | "bytecode": "0x608060405234801561001057600080fd5b50610111806100206000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063249cb3fa14602d575b600080fd5b605660048036036040811015604157600080fd5b50803590602001356001600160a01b03166068565b60408051918252519081900360200190f35b6000828152602081815260408083206001600160a01b038516845290915281205460ff16609557600060d4565b604051602001808073455243313832305f4143434550545f4d4147494360601b8152506014019050604051602081830303815290604052805190602001205b939250505056fea2646970667358221220a65812b30689858ea5b100486dae5206c1c3733e45b6746108bfc8700c9938fc64736f6c63430007010033",
31 | "deployedBytecode": "0x6080604052348015600f57600080fd5b506004361060285760003560e01c8063249cb3fa14602d575b600080fd5b605660048036036040811015604157600080fd5b50803590602001356001600160a01b03166068565b60408051918252519081900360200190f35b6000828152602081815260408083206001600160a01b038516845290915281205460ff16609557600060d4565b604051602001808073455243313832305f4143434550545f4d4147494360601b8152506014019050604051602081830303815290604052805190602001205b939250505056fea2646970667358221220a65812b30689858ea5b100486dae5206c1c3733e45b6746108bfc8700c9938fc64736f6c63430007010033",
32 | "immutableReferences": {},
33 | "compiler": {
34 | "name": "solc",
35 | "version": "0.7.1+commit.f4a555be.Emscripten.clang"
36 | },
37 | "networks": {},
38 | "schemaVersion": "3.2.5",
39 | "devdoc": {
40 | "details": "Implementation of the {IERC1820Implementer} interface. Contracts may inherit from this and call {_registerInterfaceForAddress} to declare their willingness to be implementers. {IERC1820Registry-setInterfaceImplementer} should then be called for the registration to be complete.",
41 | "kind": "dev",
42 | "methods": {},
43 | "version": 1
44 | },
45 | "userdoc": {
46 | "kind": "user",
47 | "methods": {
48 | "canImplementInterfaceForAddress(bytes32,address)": {
49 | "notice": "See {IERC1820Implementer-canImplementInterfaceForAddress}."
50 | }
51 | },
52 | "version": 1
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/ethereum-contracts/build/contracts/IERC777Sender.json:
--------------------------------------------------------------------------------
1 | {
2 | "contractName": "IERC777Sender",
3 | "abi": [
4 | {
5 | "inputs": [
6 | {
7 | "internalType": "address",
8 | "name": "operator",
9 | "type": "address"
10 | },
11 | {
12 | "internalType": "address",
13 | "name": "from",
14 | "type": "address"
15 | },
16 | {
17 | "internalType": "address",
18 | "name": "to",
19 | "type": "address"
20 | },
21 | {
22 | "internalType": "uint256",
23 | "name": "amount",
24 | "type": "uint256"
25 | },
26 | {
27 | "internalType": "bytes",
28 | "name": "userData",
29 | "type": "bytes"
30 | },
31 | {
32 | "internalType": "bytes",
33 | "name": "operatorData",
34 | "type": "bytes"
35 | }
36 | ],
37 | "name": "tokensToSend",
38 | "outputs": [],
39 | "stateMutability": "nonpayable",
40 | "type": "function"
41 | }
42 | ],
43 | "metadata": "{\"compiler\":{\"version\":\"0.7.1+commit.f4a555be\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"userData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"operatorData\",\"type\":\"bytes\"}],\"name\":\"tokensToSend\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Interface of the ERC777TokensSender standard as defined in the EIP. {IERC777} Token holders can be notified of operations performed on their tokens by having a contract implement this interface (contract holders can be their own implementer) and registering it on the https://eips.ethereum.org/EIPS/eip-1820[ERC1820 global registry]. See {IERC1820Registry} and {ERC1820Implementer}.\",\"kind\":\"dev\",\"methods\":{\"tokensToSend(address,address,address,uint256,bytes,bytes)\":{\"details\":\"Called by an {IERC777} token contract whenever a registered holder's (`from`) tokens are about to be moved or destroyed. The type of operation is conveyed by `to` being the zero address or not. This call occurs _before_ the token contract's state is updated, so {IERC777-balanceOf}, etc., can be used to query the pre-operation state. This function may revert to prevent the operation from being executed.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"@openzeppelin/contracts/token/ERC777/IERC777Sender.sol\":\"IERC777Sender\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC777/IERC777Sender.sol\":{\"keccak256\":\"0xe6bb9808d669f35a2a4033d91be51af56d80e630b0ab2450794fbf65c838be53\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://a398a80ebff5151f3c0c8e99eef56a80fa0fb0c3039d9bec2bf1361ba493ef08\",\"dweb:/ipfs/QmX9BqE9UeYwv75ZwapDTQyhXw4wwtehcYXEWryrtmpma8\"]}},\"version\":1}",
44 | "bytecode": "0x",
45 | "deployedBytecode": "0x",
46 | "immutableReferences": {},
47 | "compiler": {
48 | "name": "solc",
49 | "version": "0.7.1+commit.f4a555be.Emscripten.clang"
50 | },
51 | "networks": {},
52 | "schemaVersion": "3.2.5",
53 | "devdoc": {
54 | "details": "Interface of the ERC777TokensSender standard as defined in the EIP. {IERC777} Token holders can be notified of operations performed on their tokens by having a contract implement this interface (contract holders can be their own implementer) and registering it on the https://eips.ethereum.org/EIPS/eip-1820[ERC1820 global registry]. See {IERC1820Registry} and {ERC1820Implementer}.",
55 | "kind": "dev",
56 | "methods": {
57 | "tokensToSend(address,address,address,uint256,bytes,bytes)": {
58 | "details": "Called by an {IERC777} token contract whenever a registered holder's (`from`) tokens are about to be moved or destroyed. The type of operation is conveyed by `to` being the zero address or not. This call occurs _before_ the token contract's state is updated, so {IERC777-balanceOf}, etc., can be used to query the pre-operation state. This function may revert to prevent the operation from being executed."
59 | }
60 | },
61 | "version": 1
62 | },
63 | "userdoc": {
64 | "kind": "user",
65 | "methods": {},
66 | "version": 1
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/ethereum-contracts/build/contracts/TokenInfo.json:
--------------------------------------------------------------------------------
1 | {
2 | "contractName": "TokenInfo",
3 | "abi": [
4 | {
5 | "inputs": [],
6 | "name": "name",
7 | "outputs": [
8 | {
9 | "internalType": "string",
10 | "name": "",
11 | "type": "string"
12 | }
13 | ],
14 | "stateMutability": "view",
15 | "type": "function"
16 | },
17 | {
18 | "inputs": [],
19 | "name": "symbol",
20 | "outputs": [
21 | {
22 | "internalType": "string",
23 | "name": "",
24 | "type": "string"
25 | }
26 | ],
27 | "stateMutability": "view",
28 | "type": "function"
29 | },
30 | {
31 | "inputs": [],
32 | "name": "decimals",
33 | "outputs": [
34 | {
35 | "internalType": "uint8",
36 | "name": "",
37 | "type": "uint8"
38 | }
39 | ],
40 | "stateMutability": "view",
41 | "type": "function"
42 | }
43 | ],
44 | "metadata": "{\"compiler\":{\"version\":\"0.7.1+commit.f4a555be\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"ERC20 token info interface NOTE: ERC20 standard interface does not specify these functions, but often the token implementations have them.\",\"kind\":\"dev\",\"methods\":{\"decimals()\":{\"details\":\"Returns the number of decimals used to get its user representation. For example, if `decimals` equals `2`, a balance of `505` tokens should be displayed to a user as `5,05` (`505 / 10 ** 2`). Tokens usually opt for a value of 18, imitating the relationship between Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is called. NOTE: This information is only used for _display_ purposes: it in no way affects any of the arithmetic of the contract, including {IERC20-balanceOf} and {IERC20-transfer}.\"},\"name()\":{\"details\":\"Returns the name of the token.\"},\"symbol()\":{\"details\":\"Returns the symbol of the token, usually a shorter version of the name.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"/home/hellwolf/Projects/superfluid/superfluid-protocol-preview/ethereum-contracts-v0.1/contracts/interfaces/tokens/TokenInfo.sol\":\"TokenInfo\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"/home/hellwolf/Projects/superfluid/superfluid-protocol-preview/ethereum-contracts-v0.1/contracts/interfaces/tokens/TokenInfo.sol\":{\"keccak256\":\"0xa60ff361f5c525b21081288ebee8ed4d68f8b5b8e86d8138198d046141fba35c\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7e3239450da65109f576d28fc11cb0df7ce7aa8a41566a5f0ef97a7c8a1f3a55\",\"dweb:/ipfs/QmQcjb6dNQELxPWq12x21Cd18TbYszPNxFMXxYpXGC1Wi8\"]}},\"version\":1}",
45 | "bytecode": "0x",
46 | "deployedBytecode": "0x",
47 | "immutableReferences": {},
48 | "compiler": {
49 | "name": "solc",
50 | "version": "0.7.1+commit.f4a555be.Emscripten.clang"
51 | },
52 | "networks": {},
53 | "schemaVersion": "3.2.5",
54 | "devdoc": {
55 | "details": "ERC20 token info interface NOTE: ERC20 standard interface does not specify these functions, but often the token implementations have them.",
56 | "kind": "dev",
57 | "methods": {
58 | "decimals()": {
59 | "details": "Returns the number of decimals used to get its user representation. For example, if `decimals` equals `2`, a balance of `505` tokens should be displayed to a user as `5,05` (`505 / 10 ** 2`). Tokens usually opt for a value of 18, imitating the relationship between Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is called. NOTE: This information is only used for _display_ purposes: it in no way affects any of the arithmetic of the contract, including {IERC20-balanceOf} and {IERC20-transfer}."
60 | },
61 | "name()": {
62 | "details": "Returns the name of the token."
63 | },
64 | "symbol()": {
65 | "details": "Returns the symbol of the token, usually a shorter version of the name."
66 | }
67 | },
68 | "version": 1
69 | },
70 | "userdoc": {
71 | "kind": "user",
72 | "methods": {},
73 | "version": 1
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/ethereum-contracts/test/deployment.test.js:
--------------------------------------------------------------------------------
1 | //const { assert } = require("chai");
2 | const { web3tx } = require("@decentral.ee/web3-helpers");
3 | const deployFramework = require("../scripts/deploy-framework");
4 | const deployTestToken = require("../scripts/deploy-test-token");
5 | const deploySuperToken = require("../scripts/deploy-super-token");
6 | const TestResolver = artifacts.require("TestResolver");
7 | const ISuperfluidGovernance = artifacts.require("ISuperfluidGovernance");
8 | const Superfluid = artifacts.require("Superfluid");
9 |
10 | contract("deployment test", () => {
11 |
12 | const errorHandler = err => { if (err) throw err; };
13 |
14 | it("codeChanged function", async () => {
15 | const ConstantFlowAgreementV1 = artifacts.require("ConstantFlowAgreementV1");
16 | const {
17 | codeChanged
18 | } = require("../scripts/utils");
19 | const a1 = await web3tx(ConstantFlowAgreementV1.new, "ConstantFlowAgreementV1.new 1")();
20 | assert.isFalse(await codeChanged(ConstantFlowAgreementV1, a1.address));
21 | });
22 |
23 | it("Deploy/upgrade/reset Superfluid Framework", async () => {
24 | const version = process.env.RELEASE_VERSION || "test";
25 |
26 | const superfluidName = `Superfluid.${version}`;
27 | const cfaName = `ConstantFlowAgreementV1.${version}`;
28 | const idaName = `InstantDistributionAgreementV1.${version}`;
29 | const govName = `TestGovernance.${version}`;
30 |
31 | const testResolver = await web3tx(TestResolver.new, "TestResolver.new")();
32 | delete process.env.RESET;
33 | process.env.TEST_RESOLVER_ADDRESS = testResolver.address;
34 | console.log("First deployment");
35 | await deployFramework(errorHandler);
36 | const superfluid1 = await testResolver.get(superfluidName);
37 | const gov1 = await testResolver.get(govName);
38 | const cfa1 = await testResolver.get(cfaName);
39 | const ida1 = await testResolver.get(idaName);
40 | assert.notEqual(superfluid1, "0x0000000000000000000000000000000000000000");
41 | assert.notEqual(gov1, "0x0000000000000000000000000000000000000000");
42 | assert.notEqual(cfa1, "0x0000000000000000000000000000000000000000");
43 | assert.notEqual(ida1, "0x0000000000000000000000000000000000000000");
44 | const gov1Contract = await ISuperfluidGovernance.at(gov1);
45 | assert.isTrue(await gov1Contract.isAgreementListed.call(cfa1));
46 | assert.isTrue(await gov1Contract.isAgreementListed.call(ida1));
47 |
48 | console.log("Upgrade logic contract");
49 | await deployFramework(errorHandler);
50 | const superfluid2 = await testResolver.get(superfluidName);
51 | const gov2 = await testResolver.get(govName);
52 | const cfa2 = await testResolver.get(cfaName);
53 | const ida2 = await testResolver.get(idaName);
54 | assert.equal(superfluid1, superfluid2);
55 | assert.equal(
56 | await (await Superfluid.at(superfluid1)).getCodeAddress(),
57 | await (await Superfluid.at(superfluid2)).getCodeAddress());
58 | assert.equal(gov1, gov2, "Governance deployment not required");
59 | assert.equal(cfa1, cfa2, "cfa deployment not required");
60 | assert.equal(ida1, ida2, "cfa deployment not required");
61 |
62 | console.log("Reset all");
63 | process.env.RESET = 1;
64 | await deployFramework(errorHandler);
65 | const superfluid3 = await testResolver.get(superfluidName);
66 | const gov3 = await testResolver.get(govName);
67 | const cfa3 = await testResolver.get(cfaName);
68 | const ida3 = await testResolver.get(idaName);
69 | assert.notEqual(superfluid3, "0x0000000000000000000000000000000000000000");
70 | assert.notEqual(gov3, "0x0000000000000000000000000000000000000000");
71 | assert.notEqual(cfa3, "0x0000000000000000000000000000000000000000");
72 | assert.notEqual(ida3, "0x0000000000000000000000000000000000000000");
73 | assert.notEqual(superfluid1, superfluid3);
74 | assert.notEqual(gov1, gov3);
75 | assert.notEqual(cfa1, cfa3);
76 | assert.notEqual(ida1, ida3);
77 | });
78 |
79 | it("Deployment without resolver", async () => {
80 | await deployFramework(errorHandler);
81 | });
82 |
83 | it("Deploy/upgrade/reset Super Token", async () => {
84 | const testResolver = await web3tx(TestResolver.new, "TestResolver.new")();
85 | delete process.env.RESET;
86 | process.env.TEST_RESOLVER_ADDRESS = testResolver.address;
87 | await deployFramework(errorHandler);
88 | await deployTestToken(errorHandler, [":", "TEST"]);
89 | await deploySuperToken(errorHandler, [":", "TEST"]);
90 | });
91 | });
92 |
--------------------------------------------------------------------------------
/sample-integrations/superfluid-AfterEffect/test/DmsApp.test.js:
--------------------------------------------------------------------------------
1 | const {
2 | web3tx,
3 | toWad,
4 | toBN,
5 | } = require("@decentral.ee/web3-helpers");
6 |
7 | const { expectRevert } = require("@openzeppelin/test-helpers");
8 | const deployFramework = require("@superfluid-finance/ethereum-contracts/scripts/deploy-framework");
9 | const deployTestToken = require("@superfluid-finance/ethereum-contracts/scripts/deploy-test-token");
10 | const deploySuperToken = require("@superfluid-finance/ethereum-contracts/scripts/deploy-super-token");
11 | const deployERC1820 = require("@superfluid-finance/ethereum-contracts/scripts/deploy-erc1820");
12 | const SuperfluidSDK = require("@superfluid-finance/ethereum-contracts");
13 | const DmsApp = artifacts.require("DmsApp");
14 | const Wallet = artifacts.require("Wallet");
15 |
16 | const traveler = require("ganache-time-traveler");
17 | const TEST_TRAVEL_TIME = 3600 * 2; // 1 hours
18 |
19 | contract("DmsApp", accounts => {
20 |
21 | const errorHandler = err => { if (err) throw err; };
22 |
23 | const ZERO_ADDRESS = "0x"+"0".repeat(40);
24 | const FEE = toWad(1).div(toBN(3600*24*30));
25 | accounts = accounts.slice(0, 3);
26 | const [admin, alice, bob] = accounts;
27 |
28 | let sf;
29 | let dai;
30 | let daix;
31 | let app;
32 | let wallet;
33 | beforeEach(async function () {
34 |
35 | await deployFramework(errorHandler);
36 | sf = new SuperfluidSDK.Framework({ web3Provider: web3.currentProvider });
37 | await sf.initialize();
38 |
39 | await deployTestToken(errorHandler, [":", "fDAI"]);
40 | const daiAddress = await sf.resolver.get("tokens.fDAI");
41 | dai = await sf.contracts.TestToken.at(daiAddress);
42 | for (let i = 0; i < accounts.length; ++i) {
43 | await web3tx(dai.mint, `Account ${i} mints many dai`)(
44 | accounts[i],
45 | toWad(10000000),
46 | { from: accounts[i] }
47 | );
48 | }
49 |
50 | console.log(sf.host.address);
51 |
52 | await deployERC1820(errorHandler);
53 | await deploySuperToken(errorHandler, [":", "fDAI"]);
54 |
55 | const daixWrapper = await sf.getERC20Wrapper(dai);
56 | daix = await sf.contracts.ISuperToken.at(daixWrapper.wrapperAddress);
57 |
58 | const testUnderlaying = await daix.getUnderlayingToken();
59 | console.log("Under: ", testUnderlaying, " DAI: ", dai.address);
60 |
61 | app = await web3tx(DmsApp.new, "Deploy DmsApp")(
62 | sf.host.address,
63 | sf.agreements.cfa.address
64 | );
65 |
66 | wallet = await web3tx(Wallet.new, "Deploy Wallet")(
67 | { from: alice }
68 | )
69 |
70 | await web3tx(wallet.transferOwnership, "Wallet: Transfer Ownership to App")(
71 | app.address, {
72 | from: alice
73 | }
74 | )
75 |
76 | for (let i = 0; i < accounts.length; ++i) {
77 | await web3tx(dai.approve, `Account ${i} approves daix`)(daix.address, toWad(100), { from: accounts[i] });
78 | }
79 |
80 | });
81 |
82 | it("Case #1 - Basic Use", async() => {
83 |
84 | await web3tx(daix.upgrade, `Alice upgrade daix`)(toWad(1), { from: alice });
85 | const isApp = await sf.host.isApp(app.address);
86 | console.log("Is app: ", isApp);
87 | const isJailed = await sf.host.isAppJailed(app.address);
88 | console.log("Jail: ", isJailed);
89 | const ownerWallet = await wallet.owner();
90 | console.log("Owner of Wallet ", ownerWallet);
91 | //Create a configuration
92 | await web3tx(app.config, "Dms.config")(
93 | wallet.address,
94 | bob, {
95 | from: alice
96 | }
97 | );
98 |
99 | await sf.host.callAgreement(
100 | sf.agreements.cfa.address,
101 | sf.agreements.cfa.contract.methods.createFlow(daix.address, app.address, FEE.toString(), "0x").encodeABI(),
102 | {
103 | from: alice
104 | }
105 | );
106 | await daix.transferAll(bob, {from: alice });
107 | await traveler.advanceTimeAndBlock(TEST_TRAVEL_TIME);
108 | await sf.host.callAgreement(
109 | sf.agreements.cfa.address,
110 | sf.agreements.cfa.contract.methods.deleteFlow(daix.address,alice,app.address,"0x").encodeABI(), {
111 | from: admin
112 | }
113 | );
114 |
115 | const newOwnerWallet = await wallet.owner();
116 | console.log("New owner of Wallet ", newOwnerWallet);
117 | assert.notEqual(ownerWallet, newOwnerWallet, "Didn't change owner");
118 | });
119 | });
120 |
--------------------------------------------------------------------------------
/sample-integrations/dividends-rights-token-demo/ui/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Dividend Rights Token - A Superfluid Demo
8 |
9 |
10 |
11 |
12 |
13 |
14 | DAIx
15 | DRT
16 | Subscriber
17 | 0
18 | 0
19 | no
20 | 0
21 |
22 |
23 |
24 | Issuer
25 |
26 |
27 |
28 |
29 |
30 |
31 |
118 |
119 |
120 |
--------------------------------------------------------------------------------
/ethereum-contracts/README.md:
--------------------------------------------------------------------------------
1 | Superfluid Protocol
2 | ===================
3 |
4 | The Superfluid Protocol is a framework that realizes the real-time finance vision
5 | where user accounts are connected together, and transactions can happen between
6 | user accounts instantaneously as a result.
7 |
8 | This repository implements the superfluid protocol as Ethereum contracts. It also
9 | contains a Javascript SDK for developing Web3 applications using the superfluid
10 | protocol.
11 |
12 | For technical document, references and tutorials, etc, please refer to the
13 | [docs site](http://docs.superfluid.finance/).
14 |
15 | Installation
16 | ============
17 |
18 | To install, using its npm package is recommended.
19 |
20 | ```
21 | $ npm install @superfluid-finance/ethereum-contracts
22 | ```
23 |
24 | Development
25 | ===========
26 |
27 | To develop the project, pull the repository from GitHub and install its
28 | dependencies. You will need npm installed.
29 |
30 | ```
31 | $ git clone https://github.com/superfluid-finance/ethereum-contracts
32 | $ cd ethereum-contracts
33 | $ npm ci
34 | ```
35 |
36 | Linting
37 | -------
38 |
39 | Javascripts are linted using [eslint](https://eslint.org/).
40 |
41 | Solidity are linted using [solhint](https://protofire.github.io/solhint/)
42 |
43 | Testing
44 | -------
45 |
46 | For any feature development, test driven development is recommended:
47 |
48 | ```
49 | $ npm run dev
50 | ```
51 |
52 | This will detect any code changes then run lint, build and test suite.
53 |
54 | **NB!**: Since these tests take long time to execute, it is quite possible
55 | that you want to use the [execlusive tests](https://mochajs.org/#exclusive-tests)
56 | feature from MochaJS to speed up isolated feature development.
57 |
58 | There are three major test suite:
59 |
60 | - Contracts (test/contracts.test.js)
61 | - Deployment (test/deployment.test.js)
62 | - SDK (test/sdk.test.js)
63 |
64 | Each contracts test suite is named as `test/{Type}/{ContractName}.test.js`.
65 |
66 | Deployment test is for testing the deployment script.
67 |
68 | SDK test is to test the JS SDK.
69 |
70 | Code Coverage
71 | --------------
72 |
73 | To run the coverage tests please use:
74 |
75 | ```
76 | $ truffle run test-coverage
77 | ```
78 |
79 | This step is not integraded with the unit test because of the time it consumes to execute.
80 |
81 | Integration
82 | ===========
83 |
84 | It is recommended that you use our JS SDK to interact with the protocol.
85 |
86 | **NB!** The SDK is still under development, its API and interfaces can change.
87 |
88 | Initialize the SDK
89 | ------------------
90 |
91 |
92 | ```
93 | const SuperfluidSDK = require("@superfluid-finance/ethereum-contracts");
94 | const sf = new SuperfluidSDK.Framework({
95 | version: "0.1.2-preview-20201014", // This is for using different protocol release
96 | web3Provider: web3.currentProvider // your web3 provider
97 | });
98 |
99 | await sf.initialize();
100 |
101 | const daiAddress = await sf.resolver.get("tokens.fDAI");
102 | const dai = await sf.contracts.TestToken.at(daiAddress);
103 | const daixWrapper = await sf.getERC20Wrapper(dai);
104 | // assert(daixWrapper.created);
105 | const daix = await sf.contracts.ISuperToken.at(daixWrapper.wrapperAddress);
106 | ```
107 |
108 | What's In the Bag
109 | --------------------
110 |
111 | * `sf.host` : The [truffle contract instance](https://www.trufflesuite.com/docs/truffle/getting-started/interacting-with-your-contracts)
112 | to interact with the host contract (Superfluid.sol).
113 | * `sf.contracts` : The [truffle contract](https://www.trufflesuite.com/docs/truffle/reference/contract-abstractions) objects loaded by the SDK:
114 | - `IERC20` : The ERC20 Interface.
115 | - `TokenInfo` : A customary ERC20 token info interface (name/symbol/decimals).
116 | - `ERC20WithTokenInfo` : A combination of IERC20 and TokenInfo.
117 | - `TestToken` : A ERC20 Test token.
118 | - `IResolver` : A simple resolver interface to locate different versions of the contracts.
119 | - `ISuperfluid` : The Superfluid host contract interface.
120 | - `ISuperToken` : The Super token contract interface.
121 | - `IConstantFlowAgreementV1` : The constant flow agreement (v1) contract interface.
122 | - `IInstantDistributionAgreementV1` : The instant distribution agreement (v1) contract interface.
123 | * Token wrapper convenient functions:
124 | - `sf.getERC20Wrapper`
125 | - `sf.createERC20Wrapper`
126 | * `sf.resolver`: The resolver used by the SDK.
127 | - In test nets, there are some test tokens can be located with the resolver:
128 | - `fDAI` : The fake DAI. `sf.resolver.get("tokens.fDAI")`.
129 | - `fUSDC` : The fake USDC. `sf.resolver.get("tokens.fUSDC")`.
130 | * `sf.agreements` :
131 | - `sf.agreements.cfa` : Constant flow agreement truffle contract instance.
132 | - `sf.agreements.ida` : Instant distribution agreement truffle contract instance.
133 |
--------------------------------------------------------------------------------
/ethereum-contracts/contracts/mocks/ERC777SenderRecipientMock.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity 0.7.1;
3 |
4 | import "@openzeppelin/contracts/GSN/Context.sol";
5 | import "@openzeppelin/contracts/token/ERC777/IERC777.sol";
6 | import "@openzeppelin/contracts/token/ERC777/IERC777Sender.sol";
7 | import "@openzeppelin/contracts/token/ERC777/IERC777Recipient.sol";
8 | import "@openzeppelin/contracts/introspection/IERC1820Registry.sol";
9 | import "@openzeppelin/contracts/introspection/ERC1820Implementer.sol";
10 |
11 | contract ERC777SenderRecipientMock is Context, IERC777Sender, IERC777Recipient, ERC1820Implementer {
12 | event TokensToSendCalled(
13 | address operator,
14 | address from,
15 | address to,
16 | uint256 amount,
17 | bytes data,
18 | bytes operatorData,
19 | address token,
20 | uint256 fromBalance,
21 | uint256 toBalance
22 | );
23 |
24 | event TokensReceivedCalled(
25 | address operator,
26 | address from,
27 | address to,
28 | uint256 amount,
29 | bytes data,
30 | bytes operatorData,
31 | address token,
32 | uint256 fromBalance,
33 | uint256 toBalance
34 | );
35 |
36 | bool private _shouldRevertSend;
37 | bool private _shouldRevertReceive;
38 |
39 | IERC1820Registry private _erc1820 = IERC1820Registry(0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24);
40 |
41 | bytes32 constant private _TOKENS_SENDER_INTERFACE_HASH = keccak256("ERC777TokensSender");
42 | bytes32 constant private _TOKENS_RECIPIENT_INTERFACE_HASH = keccak256("ERC777TokensRecipient");
43 |
44 | function tokensToSend(
45 | address operator,
46 | address from,
47 | address to,
48 | uint256 amount,
49 | bytes calldata userData,
50 | bytes calldata operatorData
51 | ) external override {
52 | if (_shouldRevertSend) {
53 | revert("_shouldRevertSend");
54 | }
55 |
56 | IERC777 token = IERC777(_msgSender());
57 |
58 | uint256 fromBalance = token.balanceOf(from);
59 | // when called due to burn, to will be the zero address, which will have a balance of 0
60 | uint256 toBalance = token.balanceOf(to);
61 |
62 | emit TokensToSendCalled(
63 | operator,
64 | from,
65 | to,
66 | amount,
67 | userData,
68 | operatorData,
69 | address(token),
70 | fromBalance,
71 | toBalance
72 | );
73 | }
74 |
75 | function tokensReceived(
76 | address operator,
77 | address from,
78 | address to,
79 | uint256 amount,
80 | bytes calldata userData,
81 | bytes calldata operatorData
82 | ) external override {
83 | if (_shouldRevertReceive) {
84 | revert("_shouldRevertReceive");
85 | }
86 |
87 | IERC777 token = IERC777(_msgSender());
88 |
89 | uint256 fromBalance = token.balanceOf(from);
90 | // when called due to burn, to will be the zero address, which will have a balance of 0
91 | uint256 toBalance = token.balanceOf(to);
92 |
93 | emit TokensReceivedCalled(
94 | operator,
95 | from,
96 | to,
97 | amount,
98 | userData,
99 | operatorData,
100 | address(token),
101 | fromBalance,
102 | toBalance
103 | );
104 | }
105 |
106 | function senderFor(address account) public {
107 | _registerInterfaceForAddress(_TOKENS_SENDER_INTERFACE_HASH, account);
108 |
109 | address self = address(this);
110 | if (account == self) {
111 | registerSender(self);
112 | }
113 | }
114 |
115 | function registerSender(address sender) public {
116 | _erc1820.setInterfaceImplementer(address(this), _TOKENS_SENDER_INTERFACE_HASH, sender);
117 | }
118 |
119 | function recipientFor(address account) public {
120 | _registerInterfaceForAddress(_TOKENS_RECIPIENT_INTERFACE_HASH, account);
121 |
122 | address self = address(this);
123 | if (account == self) {
124 | registerRecipient(self);
125 | }
126 | }
127 |
128 | function registerRecipient(address recipient) public {
129 | _erc1820.setInterfaceImplementer(address(this), _TOKENS_RECIPIENT_INTERFACE_HASH, recipient);
130 | }
131 |
132 | function setShouldRevertSend(bool shouldRevert) public {
133 | _shouldRevertSend = shouldRevert;
134 | }
135 |
136 | function setShouldRevertReceive(bool shouldRevert) public {
137 | _shouldRevertReceive = shouldRevert;
138 | }
139 |
140 | function send(IERC777 token, address to, uint256 amount, bytes memory data) public {
141 | // This is 777's send function, not the Solidity send function
142 | token.send(to, amount, data); // solhint-disable-line check-send-result
143 | }
144 |
145 | function burn(IERC777 token, uint256 amount, bytes memory data) public {
146 | token.burn(amount, data);
147 | }
148 | }
149 |
--------------------------------------------------------------------------------
/ethereum-contracts/build/contracts/AgreementLibrary.json:
--------------------------------------------------------------------------------
1 | {
2 | "contractName": "AgreementLibrary",
3 | "abi": [],
4 | "metadata": "{\"compiler\":{\"version\":\"0.7.1+commit.f4a555be\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"/home/hellwolf/Projects/superfluid/superfluid-protocol-preview/ethereum-contracts-v0.1/contracts/agreements/AgreementLibrary.sol\":\"AgreementLibrary\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"/home/hellwolf/Projects/superfluid/superfluid-protocol-preview/ethereum-contracts-v0.1/contracts/agreements/AgreementLibrary.sol\":{\"keccak256\":\"0x91fdf1bf9015a0ddc914fda2cf77513de5efe492b7fd975ab5460c36c5a20477\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://d76e42c5254d21ca1336688b7d4dc34e2517e06e343dda18e2555d34288a5c5e\",\"dweb:/ipfs/QmPub4oZaEjXNC6fowSR8HLjbsgE2L3oXXGi9YFYk6Xa9b\"]},\"/home/hellwolf/Projects/superfluid/superfluid-protocol-preview/ethereum-contracts-v0.1/contracts/interfaces/superfluid/ISuperAgreement.sol\":{\"keccak256\":\"0x1515ee00700f5ae5cece8dda6d62e0c12056176dc2c41933487ba11b8aaa743b\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://f0840cdf8e3c6545b76b60c205c03abc011b8ede8256c5d5a65476de4584a5f5\",\"dweb:/ipfs/Qmf6JcWedy2BxmzN5xFJ86SwfxGEX81Ac3Rza8NdqWj19H\"]},\"/home/hellwolf/Projects/superfluid/superfluid-protocol-preview/ethereum-contracts-v0.1/contracts/interfaces/superfluid/ISuperApp.sol\":{\"keccak256\":\"0x8a71d633e698727749295ee6abaf6c37fa42f1b77b2d222d1a4eaffa208c8c49\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://47a2af58bed4fbffc85650b99d913105ca8988962ace76153dedd00d4bc3ca8a\",\"dweb:/ipfs/QmPZ5vHgUaUADJFVN6LnFzQgh28UzK1Lt7F6cFDTcWBE8W\"]},\"/home/hellwolf/Projects/superfluid/superfluid-protocol-preview/ethereum-contracts-v0.1/contracts/interfaces/superfluid/ISuperToken.sol\":{\"keccak256\":\"0xd30f1588320e14a4834520749d9a625f3593aadddd0d1724ab6365915003ccf3\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://92077b3a9d6ab82c64f672bb33b95a92e699069f4b1955fb0fab6104364789a5\",\"dweb:/ipfs/QmZ49sPQpxn9LKj3i2w8VEcc1oBfUUu656QuB1SY6mo5NF\"]},\"/home/hellwolf/Projects/superfluid/superfluid-protocol-preview/ethereum-contracts-v0.1/contracts/interfaces/superfluid/ISuperfluid.sol\":{\"keccak256\":\"0xf42f2e194f917c020c2e4d099bae76697957cd7f68e27afd1dcde0c87c0bf6d2\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://c0f785af02fb3950ae45171dd3eb729c0674f6bb451696e0786b481da5b844e2\",\"dweb:/ipfs/QmR9EgrVS9VZhB67zfpub8CMxbYQvhn7JTnjRYWEciMKPe\"]},\"/home/hellwolf/Projects/superfluid/superfluid-protocol-preview/ethereum-contracts-v0.1/contracts/interfaces/superfluid/ISuperfluidGovernance.sol\":{\"keccak256\":\"0xf1fc334274dc956d0508ab5d3037979de789e9e858ecc346b87cdec472d7261b\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://950a5fd2942ee58611ea24bbe23d0e6cbb83f6e5c32384134c85f179c373dbb1\",\"dweb:/ipfs/QmdcZkqVuxTu5C5NhpbSXYunUDkZbcs8NMxBW1EYtThAtY\"]},\"/home/hellwolf/Projects/superfluid/superfluid-protocol-preview/ethereum-contracts-v0.1/contracts/interfaces/superfluid/SuperAppDefinitions.sol\":{\"keccak256\":\"0x1a5356278b5f0f2100e7d3db525a9c20d303cc0de571e53123cb7fd9485e9bfb\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://4bee42a2ce61d07d84b18c36e1683d1f0a713883caa41698282aa3d64a876ae2\",\"dweb:/ipfs/QmXmnuEpXunMGYBZhraHa2bLit4dNqhnhfD6cQ1w6zucmB\"]},\"/home/hellwolf/Projects/superfluid/superfluid-protocol-preview/ethereum-contracts-v0.1/contracts/interfaces/tokens/TokenInfo.sol\":{\"keccak256\":\"0xa60ff361f5c525b21081288ebee8ed4d68f8b5b8e86d8138198d046141fba35c\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7e3239450da65109f576d28fc11cb0df7ce7aa8a41566a5f0ef97a7c8a1f3a55\",\"dweb:/ipfs/QmQcjb6dNQELxPWq12x21Cd18TbYszPNxFMXxYpXGC1Wi8\"]},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"keccak256\":\"0xbd74f587ab9b9711801baf667db1426e4a03fd2d7f15af33e0e0d0394e7cef76\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://2d0913dfbfce90d170df0d496ad7596c0778518e5fa7aba6c32562522546f66b\",\"dweb:/ipfs/QmR6B8nLj2PJf5e1JWD9Nk7ErkAwkqUwadCnvE82FJr1RU\"]},\"@openzeppelin/contracts/token/ERC777/IERC777.sol\":{\"keccak256\":\"0x66622d89fb8f57aa1c09f69b1088d242aa92ceba96462854396ddb724e71849f\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://abb0340421d8a39de72aa4679351f2eba6eee62f4ccfaa649852431f5d361165\",\"dweb:/ipfs/QmULDf3ot52Qd1s5LDjD11bGFCM8f212KTmazvvaT64Uk4\"]}},\"version\":1}",
5 | "bytecode": "0x60566023600b82828239805160001a607314601657fe5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220854fe0f3fbce382ff6caacec18ed03e39c4c1f640aada6a6384b4ceec80d64ea64736f6c63430007010033",
6 | "deployedBytecode": "0x73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220854fe0f3fbce382ff6caacec18ed03e39c4c1f640aada6a6384b4ceec80d64ea64736f6c63430007010033",
7 | "immutableReferences": {},
8 | "compiler": {
9 | "name": "solc",
10 | "version": "0.7.1+commit.f4a555be.Emscripten.clang"
11 | },
12 | "networks": {},
13 | "schemaVersion": "3.2.5",
14 | "devdoc": {
15 | "kind": "dev",
16 | "methods": {},
17 | "version": 1
18 | },
19 | "userdoc": {
20 | "kind": "user",
21 | "methods": {},
22 | "version": 1
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/sample-integrations/flowlottery/truffle-config.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Use this file to configure your truffle project. It's seeded with some
3 | * common settings for different networks and features like migrations,
4 | * compilation and testing. Uncomment the ones you need or modify
5 | * them to suit your project as necessary.
6 | *
7 | * More information about configuration can be found at:
8 | *
9 | * trufflesuite.com/docs/advanced/configuration
10 | *
11 | * To deploy via Infura you'll need a wallet provider (like @truffle/hdwallet-provider)
12 | * to sign your transactions before they're sent to a remote public node. Infura accounts
13 | * are available for free at: infura.io/register.
14 | *
15 | * You'll also need a mnemonic - the twelve word phrase the wallet uses to generate
16 | * public/private key pairs. If you're publishing your code to GitHub make sure you load this
17 | * phrase from a file you've .gitignored so it doesn't accidentally become public.
18 | *
19 | */
20 |
21 | // const HDWalletProvider = require('@truffle/hdwallet-provider');
22 | // const infuraKey = "fj4jll3k.....";
23 | //
24 | // const fs = require('fs');
25 | // const mnemonic = fs.readFileSync(".secret").toString().trim();
26 |
27 | const HDWalletProvider = require("@truffle/hdwallet-provider");
28 | require("dotenv").config();
29 | const GAS_LIMIT = 8e6;
30 |
31 |
32 | module.exports = {
33 | /**
34 | * Networks define how you connect to your ethereum client and let you set the
35 | * defaults web3 uses to send transactions. If you don't specify one truffle
36 | * will spin up a development blockchain for you on port 9545 when you
37 | * run `develop` or `test`. You can ask a truffle command to use a specific
38 | * network from the command line, e.g
39 | *
40 | * $ truffle test --network
41 | */
42 |
43 | networks: {
44 | // Useful for testing. The `development` name is special - truffle uses it by default
45 | // if it's defined here and no other network is specified at the command line.
46 | // You should run a client (like ganache-cli, geth or parity) in a separate terminal
47 | // tab if you use this network and you must also set the `host`, `port` and `network_id`
48 | // options below to some value.
49 | //
50 | // development: {
51 | // host: "127.0.0.1", // Localhost (default: none)
52 | // port: 8545, // Standard Ethereum port (default: none)
53 | // network_id: "*", // Any network (default: none)
54 | // },
55 | // Another network with more advanced options...
56 | // advanced: {
57 | // port: 8777, // Custom port
58 | // network_id: 1342, // Custom network
59 | // gas: 8500000, // Gas sent with each transaction (default: ~6700000)
60 | // gasPrice: 20000000000, // 20 gwei (in wei) (default: 100 gwei)
61 | // from: , // Account to send txs from (default: accounts[0])
62 | // websockets: true // Enable EventEmitter interface for web3 (default: false)
63 | // },
64 | // Useful for deploying to a public network.
65 | // NB: It's important to wrap the provider as a function.
66 | // ropsten: {
67 | // provider: () => new HDWalletProvider(mnemonic, `https://ropsten.infura.io/v3/YOUR-PROJECT-ID`),
68 | // network_id: 3, // Ropsten's id
69 | // gas: 5500000, // Ropsten has a lower block limit than mainnet
70 | // confirmations: 2, // # of confs to wait between deployments. (default: 0)
71 | // timeoutBlocks: 200, // # of blocks before a deployment times out (minimum/default: 50)
72 | // skipDryRun: true // Skip dry run before migrations? (default: false for public nets )
73 | // },
74 | // Useful for private networks
75 | // private: {
76 | // provider: () => new HDWalletProvider(mnemonic, `https://network.io`),
77 | // network_id: 2111, // This network is yours, in the cloud.
78 | // production: true // Treats this network as if it was a public net. (default: false)
79 | // }
80 |
81 | goerli: {
82 | provider: () => new HDWalletProvider(
83 | process.env.GOERLI_MNEMONIC,
84 | process.env.GOERLI_PROVIDER_URL,
85 | ),
86 | network_id: 5, // Goerli's id
87 | gas: GAS_LIMIT,
88 | gasPrice: 10e9, // 10 GWEI
89 | //confirmations: 6, // # of confs to wait between deployments. (default: 0)
90 | timeoutBlocks: 50, // # of blocks before a deployment times out (minimum/default: 50)
91 | skipDryRun: false // Skip dry run before migrations? (default: false for public nets )
92 | },
93 |
94 | },
95 |
96 | // Set default mocha options here, use special reporters etc.
97 | mocha: {
98 | // timeout: 100000
99 | },
100 |
101 | // Configure your compilers
102 | compilers: {
103 | solc: {
104 | version: "0.7.1", // Fetch exact version from solc-bin (default: truffle's version)
105 | // docker: true, // Use "0.5.1" you've installed locally with docker (default: false)
106 | // settings: { // See the solidity docs for advice about optimization and evmVersion
107 | // optimizer: {
108 | // enabled: false,
109 | // runs: 200
110 | // },
111 | // evmVersion: "byzantium"
112 | // }
113 | },
114 | },
115 | };
116 |
--------------------------------------------------------------------------------
/sample-integrations/dividends-rights-token-demo/truffle-config.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Use this file to configure your truffle project. It's seeded with some
3 | * common settings for different networks and features like migrations,
4 | * compilation and testing. Uncomment the ones you need or modify
5 | * them to suit your project as necessary.
6 | *
7 | * More information about configuration can be found at:
8 | *
9 | * trufflesuite.com/docs/advanced/configuration
10 | *
11 | * To deploy via Infura you'll need a wallet provider (like @truffle/hdwallet-provider)
12 | * to sign your transactions before they're sent to a remote public node. Infura accounts
13 | * are available for free at: infura.io/register.
14 | *
15 | * You'll also need a mnemonic - the twelve word phrase the wallet uses to generate
16 | * public/private key pairs. If you're publishing your code to GitHub make sure you load this
17 | * phrase from a file you've .gitignored so it doesn't accidentally become public.
18 | *
19 | */
20 |
21 | // const HDWalletProvider = require('@truffle/hdwallet-provider');
22 | // const infuraKey = "fj4jll3k.....";
23 | //
24 | // const fs = require('fs');
25 | // const mnemonic = fs.readFileSync(".secret").toString().trim();
26 |
27 | const HDWalletProvider = require("@truffle/hdwallet-provider");
28 | require("dotenv").config();
29 | const GAS_LIMIT = 8e6;
30 |
31 |
32 | module.exports = {
33 | /**
34 | * Networks define how you connect to your ethereum client and let you set the
35 | * defaults web3 uses to send transactions. If you don't specify one truffle
36 | * will spin up a development blockchain for you on port 9545 when you
37 | * run `develop` or `test`. You can ask a truffle command to use a specific
38 | * network from the command line, e.g
39 | *
40 | * $ truffle test --network
41 | */
42 |
43 | networks: {
44 | // Useful for testing. The `development` name is special - truffle uses it by default
45 | // if it's defined here and no other network is specified at the command line.
46 | // You should run a client (like ganache-cli, geth or parity) in a separate terminal
47 | // tab if you use this network and you must also set the `host`, `port` and `network_id`
48 | // options below to some value.
49 | //
50 | // development: {
51 | // host: "127.0.0.1", // Localhost (default: none)
52 | // port: 8545, // Standard Ethereum port (default: none)
53 | // network_id: "*", // Any network (default: none)
54 | // },
55 | // Another network with more advanced options...
56 | // advanced: {
57 | // port: 8777, // Custom port
58 | // network_id: 1342, // Custom network
59 | // gas: 8500000, // Gas sent with each transaction (default: ~6700000)
60 | // gasPrice: 20000000000, // 20 gwei (in wei) (default: 100 gwei)
61 | // from: , // Account to send txs from (default: accounts[0])
62 | // websockets: true // Enable EventEmitter interface for web3 (default: false)
63 | // },
64 | // Useful for deploying to a public network.
65 | // NB: It's important to wrap the provider as a function.
66 | // ropsten: {
67 | // provider: () => new HDWalletProvider(mnemonic, `https://ropsten.infura.io/v3/YOUR-PROJECT-ID`),
68 | // network_id: 3, // Ropsten's id
69 | // gas: 5500000, // Ropsten has a lower block limit than mainnet
70 | // confirmations: 2, // # of confs to wait between deployments. (default: 0)
71 | // timeoutBlocks: 200, // # of blocks before a deployment times out (minimum/default: 50)
72 | // skipDryRun: true // Skip dry run before migrations? (default: false for public nets )
73 | // },
74 | // Useful for private networks
75 | // private: {
76 | // provider: () => new HDWalletProvider(mnemonic, `https://network.io`),
77 | // network_id: 2111, // This network is yours, in the cloud.
78 | // production: true // Treats this network as if it was a public net. (default: false)
79 | // }
80 |
81 | goerli: {
82 | provider: () => new HDWalletProvider(
83 | process.env.GOERLI_MNEMONIC,
84 | process.env.GOERLI_PROVIDER_URL,
85 | ),
86 | network_id: 5, // Goerli's id
87 | gas: GAS_LIMIT,
88 | gasPrice: 10e9, // 10 GWEI
89 | //confirmations: 6, // # of confs to wait between deployments. (default: 0)
90 | timeoutBlocks: 50, // # of blocks before a deployment times out (minimum/default: 50)
91 | skipDryRun: false // Skip dry run before migrations? (default: false for public nets )
92 | },
93 |
94 | },
95 |
96 | // Set default mocha options here, use special reporters etc.
97 | mocha: {
98 | // timeout: 100000
99 | },
100 |
101 | // Configure your compilers
102 | compilers: {
103 | solc: {
104 | version: "0.7.1", // Fetch exact version from solc-bin (default: truffle's version)
105 | // docker: true, // Use "0.5.1" you've installed locally with docker (default: false)
106 | // settings: { // See the solidity docs for advice about optimization and evmVersion
107 | // optimizer: {
108 | // enabled: false,
109 | // runs: 200
110 | // },
111 | // evmVersion: "byzantium"
112 | // }
113 | },
114 | },
115 | };
116 |
--------------------------------------------------------------------------------
/ethereum-contracts/contracts/interfaces/agreements/IConstantFlowAgreementV1.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity >= 0.7.0;
3 |
4 | import "../superfluid/ISuperToken.sol";
5 | import "../superfluid/ISuperAgreement.sol";
6 |
7 |
8 | /**
9 | * @dev Superfluid's constant flow agreement interface
10 | *
11 | * @author Superfluid
12 | */
13 | abstract contract IConstantFlowAgreementV1 is ISuperAgreement {
14 |
15 | /// @dev ISuperAgreement.agreementType implementation
16 | function agreementType() external override pure returns (bytes32) {
17 | return keccak256("org.superfluid-finance.agreements.ConstantFlowAgreement.v1");
18 | }
19 |
20 | /**
21 | * @dev Create a flow betwen sender and receiver.
22 | * @param token Super token address.
23 | * @param receiver Flow receiver address.
24 | * @param flowRate New flow rate in amount per second.
25 | *
26 | * NOTE:
27 | * - A deposit is taken as safety margin for the solvency agents.
28 | * - A extra gas fee may be taken to pay for solvency agent liquidations.
29 | */
30 | function createFlow(
31 | ISuperToken token,
32 | address receiver,
33 | int96 flowRate,
34 | bytes calldata ctx
35 | )
36 | external
37 | virtual
38 | returns(bytes memory newCtx);
39 |
40 | /**
41 | * @dev Update the flow rate between sender and receiver.
42 | * @param token Super token address.
43 | * @param receiver Flow receiver address.
44 | * @param flowRate New flow rate in amount per second.
45 | *
46 | * NOTE:
47 | * - Only the flow sender may update the flow rate.
48 | * - Even if the flow rate is zero, the flow is not deleted
49 | * from the system.
50 | * - Deposit amount will be adjusted accordingly.
51 | * - No new gas fee is charged.
52 | */
53 | function updateFlow(
54 | ISuperToken token,
55 | address receiver,
56 | int96 flowRate,
57 | bytes calldata ctx
58 | )
59 | external
60 | virtual
61 | returns(bytes memory newCtx);
62 |
63 |
64 | /**
65 | * @dev Get the flow data between `sender` and `receiver`.
66 | * @param token Super token address.
67 | * @param sender Flow receiver.
68 | * @param receiver Flow sender.
69 | * @return timestamp Timestamp of when the flow is updated.
70 | * @return flowRate The flow rate.
71 | * @return deposit The amount of deposit the flow.
72 | * @return owedDeposit The amount of owed deposit of the flow.
73 | */
74 | function getFlow(
75 | ISuperToken token,
76 | address sender,
77 | address receiver
78 | )
79 | external
80 | view
81 | virtual
82 | returns (
83 | uint256 timestamp,
84 | int96 flowRate,
85 | uint256 deposit,
86 | uint256 owedDeposit
87 | );
88 |
89 | /**
90 | * @dev Get flow data using agreement ID
91 | * @param token Super token address.
92 | * @param agreementId The agreement ID.
93 | * @return timestamp Timestamp of when the flow is updated.
94 | * @return flowRate The flow rate.
95 | * @return deposit The amount of deposit the flow.
96 | * @return owedDeposit The amount of owed deposit of the flow.
97 | */
98 | function getFlowByID(
99 | ISuperToken token,
100 | bytes32 agreementId
101 | )
102 | external
103 | view
104 | virtual
105 | returns (
106 | uint256 timestamp,
107 | int96 flowRate,
108 | uint256 deposit,
109 | uint256 owedDeposit
110 | );
111 |
112 | /**
113 | * @dev Get the net flow rate of the account
114 | * @param token Super token address.
115 | * @param account Account for the query.
116 | * @return flowRate Flow rate.
117 | */
118 | function getNetFlow(
119 | ISuperToken token,
120 | address account)
121 | external
122 | view
123 | virtual
124 | returns (int96 flowRate);
125 |
126 | /**
127 | * @dev Delete the flow between sender and receiver
128 | * @param token Super token address.
129 | * @param ctx Context bytes.
130 | * @param receiver Flow receiver address.
131 | *
132 | * NOTE:
133 | * - Both flow sender and receiver may delete the flow.
134 | * - If Sender account is insolvent or in critical state, a solvency agent may
135 | * also terminate the agreement.
136 | * - Gas fee may be returned to the sender.
137 | */
138 | function deleteFlow(
139 | ISuperToken token,
140 | address sender,
141 | address receiver,
142 | bytes calldata ctx
143 | )
144 | external
145 | virtual
146 | returns(bytes memory newCtx);
147 |
148 | /**
149 | * @dev Flow updated event.
150 | * @param token Super token address.
151 | * @param sender Flow sender address.
152 | * @param receiver Flow recipient address.
153 | * @param flowRate Flow rate in amount per second for this flow.
154 | * @param flowRate Total flow rate in amount per second for the sender.
155 | * @param flowRate Total flow rate in amount per second for the receiver.
156 | */
157 | event FlowUpdated(
158 | ISuperToken indexed token,
159 | address indexed sender,
160 | address indexed receiver,
161 | int96 flowRate,
162 | int256 totalSenderFlowRate,
163 | int256 totalReceiverFlowRate
164 | );
165 |
166 | }
167 |
--------------------------------------------------------------------------------
/ethereum-contracts/contracts/interfaces/superfluid/ISuperApp.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity >= 0.7.0;
3 |
4 | import { ISuperToken } from "./ISuperToken.sol";
5 |
6 |
7 | /**
8 | * @title Superfluid's app interface.
9 | *
10 | * NOTE:
11 | * - Be fearful of the app jail, when the word permitted is used.
12 | *
13 | * @author Superfluid
14 | */
15 | interface ISuperApp {
16 |
17 | /**
18 | * @dev Callback before a new agreement is created.
19 | * @param superToken The super token used for the agreement.
20 | * @param ctx The context data.
21 | * @param agreementClass The agreement class address.
22 | * @param agreementId The agreementId
23 | * @return cbdata A free format in memory data the app can use to pass
24 | * arbitary information to the after-hook callback.
25 | *
26 | * NOTE:
27 | * - It will be invoked with `staticcall`, no state changes are permitted.
28 | * - Only revert with a "reason" is permitted.
29 | */
30 | function beforeAgreementCreated(
31 | ISuperToken superToken,
32 | bytes calldata ctx,
33 | address agreementClass,
34 | bytes32 agreementId
35 | )
36 | external
37 | view
38 | returns (bytes memory cbdata);
39 |
40 | /**
41 | * @dev Callback after a new agreement is created.
42 | * @param superToken The super token used for the agreement.
43 | * @param ctx The context data.
44 | * @param agreementClass The agreement class address.
45 | * @param agreementId The agreementId
46 | * @param cbdata The data returned from the before-hook callback.
47 | * @return newCtx The current context of the transaction.
48 | *
49 | * NOTE:
50 | * - State changes is permitted.
51 | * - Only revert with a "reason" is permitted.
52 | */
53 | function afterAgreementCreated(
54 | ISuperToken superToken,
55 | bytes calldata ctx,
56 | address agreementClass,
57 | bytes32 agreementId,
58 | bytes calldata cbdata
59 | )
60 | external
61 | returns (bytes memory newCtx);
62 |
63 | /**
64 | * @dev Callback before a new agreement is updated.
65 | * @param superToken The super token used for the agreement.
66 | * @param ctx The context data.
67 | * @param agreementClass The agreement class address.
68 | * @param agreementId The agreementId
69 | * @return cbdata A free format in memory data the app can use to pass
70 | * arbitary information to the after-hook callback.
71 | *
72 | * NOTE:
73 | * - It will be invoked with `staticcall`, no state changes are permitted.
74 | * - Only revert with a "reason" is permitted.
75 | */
76 | function beforeAgreementUpdated(
77 | ISuperToken superToken,
78 | bytes calldata ctx,
79 | address agreementClass,
80 | bytes32 agreementId
81 | )
82 | external
83 | view
84 | returns (bytes memory cbdata);
85 |
86 |
87 | /**
88 | * @dev Callback after a new agreement is updated.
89 | * @param superToken The super token used for the agreement.
90 | * @param ctx The context data.
91 | * @param agreementClass The agreement class address.
92 | * @param agreementId The agreementId
93 | * @param cbdata The data returned from the before-hook callback.
94 | * @return newCtx The current context of the transaction.
95 | *
96 | * NOTE:
97 | * - State changes is permitted.
98 | * - Only revert with a "reason" is permitted.
99 | */
100 | function afterAgreementUpdated(
101 | ISuperToken superToken,
102 | bytes calldata ctx,
103 | address agreementClass,
104 | bytes32 agreementId,
105 | bytes calldata cbdata
106 | )
107 | external
108 | returns (bytes memory newCtx);
109 |
110 | /**
111 | * @dev Callback before a new agreement is terminated.
112 | * @param superToken The super token used for the agreement.
113 | * @param ctx The context data.
114 | * @param agreementClass The agreement class address.
115 | * @param agreementId The agreementId
116 | * @return cbdata A free format in memory data the app can use to pass
117 | * arbitary information to the after-hook callback.
118 | *
119 | * NOTE:
120 | * - It will be invoked with `staticcall`, no state changes are permitted.
121 | * - Revert is not permitted.
122 | */
123 | function beforeAgreementTerminated(
124 | ISuperToken superToken,
125 | bytes calldata ctx,
126 | address agreementClass,
127 | bytes32 agreementId
128 | )
129 | external
130 | view
131 | returns (bytes memory cbdata);
132 |
133 | /**
134 | * @dev Callback after a new agreement is terminated.
135 | * @param superToken The super token used for the agreement.
136 | * @param ctx The context data.
137 | * @param agreementClass The agreement class address.
138 | * @param agreementId The agreementId
139 | * @param cbdata The data returned from the before-hook callback.
140 | * @return newCtx The current context of the transaction.
141 | *
142 | * NOTE:
143 | * - State changes is permitted.
144 | * - Revert is not permitted.
145 | */
146 | function afterAgreementTerminated(
147 | ISuperToken superToken,
148 | bytes calldata ctx,
149 | address agreementClass,
150 | bytes32 agreementId,
151 | bytes calldata cbdata
152 | )
153 | external
154 | returns (bytes memory newCtx);
155 | }
156 |
--------------------------------------------------------------------------------
/sample-integrations/superfluid-console-demo/index.js:
--------------------------------------------------------------------------------
1 | require("dotenv").config();
2 | const Web3 = require("web3");
3 | const SuperfluidSDK = require("@superfluid-finance/ethereum-contracts");
4 | const HDWalletProvider = require("@truffle/hdwallet-provider");
5 |
6 | if (!process.env.GOERLI_MNEMONIC ||
7 | !process.env.GOERLI_PROVIDER_URL) {
8 | console.error("add GOERLI_MNEMONIC and GOERLI_PROVIDER_URL to your .env file");
9 | process.exit(1);
10 | }
11 |
12 | async function main() {
13 | const web3Provider = new HDWalletProvider(
14 | process.env.GOERLI_MNEMONIC,
15 | process.env.GOERLI_PROVIDER_URL
16 | );
17 | const web3 = new Web3(web3Provider);
18 | const accounts = web3Provider.addresses;
19 | const minAmount = web3.utils.toBN(web3.utils.toWei("100", "ether"));
20 | const sf = new SuperfluidSDK.Framework({
21 | chainId: 5,
22 | version: process.env.RELEASE_VERSION || "preview-20200928", // This is for using different protocol release
23 | web3Provider: web3Provider // your web3 provider
24 | });
25 | await sf.initialize();
26 |
27 | const daiAddress = await sf.resolver.get("tokens.fDAI");
28 | const dai = await sf.contracts.TestToken.at(daiAddress);
29 | const daixWrapper = await sf.getERC20Wrapper(dai);
30 | const daix = await sf.contracts.ISuperToken.at(daixWrapper.wrapperAddress);
31 | console.log("daix address", daix.address);
32 |
33 | const admin = accounts[0];
34 | const bob = accounts[1];
35 | const adminBalance = web3.utils.toBN(await daix.balanceOf(admin));
36 | console.log("admin", admin, adminBalance.toString());
37 | console.log("bob", bob);
38 |
39 | // minting
40 | if (adminBalance.lt(minAmount.div(web3.utils.toBN(2)))) {
41 | console.log("Minting and upgrading...");
42 | await dai.mint(admin, minAmount, { from: admin });
43 | await dai.approve(daix.address, minAmount, { from: admin });
44 | await daix.upgrade(minAmount, { from: admin });
45 | console.log("Done minting and upgrading.");
46 | }
47 | //console.log("admin balance", (await daix.balanceOf(admin)).toString());
48 | //console.log("bob balance", (await daix.balanceOf(bob)).toString());
49 |
50 | console.log(
51 | "Admin net flow",
52 | (await sf.agreements.cfa.getNetFlow(daix.address, admin)).toString()
53 | );
54 | console.log(
55 | "Bob net flow",
56 | (await sf.agreements.cfa.getNetFlow(daix.address, bob)).toString()
57 | );
58 |
59 | // create flow
60 | const currentFlowData = await sf.agreements.cfa.getFlow(
61 | daix.address,
62 | admin,
63 | bob
64 | );
65 | const hasExistingFlow = currentFlowData.timestamp.toString() != "0";
66 | if (hasExistingFlow && process.env.RESET_FLOW) {
67 | console.log("Deleting the existing flow...");
68 | await sf.host.callAgreement(
69 | sf.agreements.cfa.address,
70 | sf.agreements.cfa.contract.methods
71 | .deleteFlow(daix.address, admin, bob, "0x")
72 | .encodeABI(),
73 | {
74 | from: admin
75 | }
76 | );
77 | console.log("Flow deleted.");
78 | console.log(
79 | "Admin net flow: ",
80 | (await sf.agreements.cfa.getNetFlow(daix.address, admin)).toString()
81 | );
82 | console.log(
83 | "Bob net flow: ",
84 | (await sf.agreements.cfa.getNetFlow(daix.address, bob)).toString()
85 | );
86 | hasExistingFlow = false;
87 | }
88 |
89 | if (!hasExistingFlow) {
90 | console.log("Creating a new flow...");
91 | await sf.host.callAgreement(
92 | sf.agreements.cfa.address,
93 | sf.agreements.cfa.contract.methods
94 | .createFlow(daix.address, bob, "385802469135802", "0x")
95 | .encodeABI(),
96 | {
97 | from: admin
98 | }
99 | );
100 | console.log("Flow created.");
101 | console.log("Admin net flow: ",
102 | (await sf.agreements.cfa.getNetFlow(daix.address, admin)).toString()
103 | );
104 | console.log("Bob net flow: ",
105 | (await sf.agreements.cfa.getNetFlow(daix.address, bob)).toString()
106 | );
107 | }
108 |
109 | // check net flow rates
110 | process.stdout.write("\nlive updating balance:\n");
111 | process.stdout.write("\nAdmin netFlow: ");
112 | process.stdout.write(
113 | (await sf.agreements.cfa.getNetFlow(daix.address, admin)).toString()
114 | );
115 | process.stdout.write(" - Bob netFlow: ");
116 | process.stdout.write(
117 | (await sf.agreements.cfa.getNetFlow(daix.address, bob)).toString()
118 | );
119 | process.stdout.write("\n");
120 | var adminB, bobB, oldAdminB, oldBobB;
121 | var p = 0;
122 | process.stdout.setEncoding("utf8");
123 | var spinner = ". ";
124 | while (p < 1000) {
125 | oldAdminB = adminB;
126 | oldBobB = bobB;
127 | adminB = (await daix.balanceOf(admin)).toString();
128 | bobB = (await daix.balanceOf(bob)).toString();
129 | (async () => {
130 | return new Promise(resolve => {
131 | setTimeout(resolve => {
132 | process.stdout.write("\r\x1b[K");
133 | process.stdout.write("Admin balance: ");
134 | process.stdout.write(adminB);
135 | process.stdout.write(" - Bob balance: ");
136 | process.stdout.write(bobB);
137 | process.stdout.write(" ");
138 | process.stdout.write(spinner);
139 | if (oldAdminB !== adminB || oldBobB !== bobB)
140 | process.stdout.write(" -- New Block!");
141 | return resolve;
142 | }, 1000);
143 | });
144 | })();
145 | switch (spinner) {
146 | case ". ":
147 | spinner = ".. ";
148 | break;
149 | case ".. ":
150 | spinner = "...";
151 | break;
152 | case "...":
153 | spinner = ". ";
154 | break;
155 | }
156 | p++;
157 | }
158 | }
159 |
160 | main();
161 |
--------------------------------------------------------------------------------
/ethereum-contracts/build/contracts/Proxy.json:
--------------------------------------------------------------------------------
1 | {
2 | "contractName": "Proxy",
3 | "abi": [
4 | {
5 | "stateMutability": "payable",
6 | "type": "fallback"
7 | },
8 | {
9 | "stateMutability": "payable",
10 | "type": "receive"
11 | },
12 | {
13 | "inputs": [
14 | {
15 | "internalType": "address",
16 | "name": "initialAddress",
17 | "type": "address"
18 | }
19 | ],
20 | "name": "initializeProxy",
21 | "outputs": [],
22 | "stateMutability": "nonpayable",
23 | "type": "function"
24 | }
25 | ],
26 | "metadata": "{\"compiler\":{\"version\":\"0.7.1+commit.f4a555be\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"initialAddress\",\"type\":\"address\"}],\"name\":\"initializeProxy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"details\":\"Implements delegation of calls to other contracts, with proper forwarding of return values and bubbling of failures. It defines a fallback function that delegates all calls to the implementation.\",\"kind\":\"dev\",\"methods\":{\"initializeProxy(address)\":{\"details\":\"Proxy initialization function. This should only be called once and it is permission-less.\",\"params\":{\"initialAddress\":\"Initial logic contract code address to be used.\"}}},\"title\":\"Proxy\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"/home/hellwolf/Projects/superfluid/superfluid-protocol-preview/ethereum-contracts-v0.1/contracts/upgradability/Proxy.sol\":\"Proxy\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"/home/hellwolf/Projects/superfluid/superfluid-protocol-preview/ethereum-contracts-v0.1/contracts/upgradability/Proxy.sol\":{\"keccak256\":\"0xf9dbe1f9395d4346826ac3eb5e8fe19839de7056b27ae642521856b8225a7b7e\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://98afb08f2457daaed853ee5ddead49690f1d74a748065476f075526dac345141\",\"dweb:/ipfs/QmevKozaDcvtsDqhq7qFrtN2wkhWnQLuvdxMHTFENdGrHR\"]},\"/home/hellwolf/Projects/superfluid/superfluid-protocol-preview/ethereum-contracts-v0.1/contracts/upgradability/ProxyUtils.sol\":{\"keccak256\":\"0x34c692cb060d21fe40af5d6c6ddb2b4b9e52ffb6e44340195c7b91cbf664feca\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://6e2df14a12f9d4dfb780f75942e5ee5aa727e08b0f32f2950eb8816868f0c915\",\"dweb:/ipfs/QmdWakruAjcgqMkQBrJF9EffMnjaByCfygtDRrs3XnzSfA\"]}},\"version\":1}",
27 | "bytecode": "0x608060405234801561001057600080fd5b50610236806100206000396000f3fe6080604052600436106100225760003560e01c80634a0687ef1461008657610076565b36610076576040805162461bcd60e51b815260206004820152601860248201527f50726f78793a20524543454956455f464f5242494444454e0000000000000000604482015290519081900360640190fd5b005b6100746100816100b9565b6100de565b34801561009257600080fd5b50610074600480360360208110156100a957600080fd5b50356001600160a01b0316610102565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b3660008037600080366000845af43d6000803e8080156100fd573d6000f35b3d6000fd5b6001600160a01b0381166101475760405162461bcd60e51b81526004018080602001828103825260248152602001806101dd6024913960400191505060405180910390fd5b60006101516100b9565b6001600160a01b0316146101ac576040805162461bcd60e51b815260206004820152601a60248201527f50726f78793a20414c52454144595f494e495449414c495a4544000000000000604482015290519081900360640190fd5b6101b5816101b8565b50565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5556fe50726f78793a20494e495449414c495a45445f574954485f5a45524f5f41444452455353a26469706673582212202e6d810b41384f7a7e8d90556356920fc289d3180a840445d85ebb4bec39b84864736f6c63430007010033",
28 | "deployedBytecode": "0x6080604052600436106100225760003560e01c80634a0687ef1461008657610076565b36610076576040805162461bcd60e51b815260206004820152601860248201527f50726f78793a20524543454956455f464f5242494444454e0000000000000000604482015290519081900360640190fd5b005b6100746100816100b9565b6100de565b34801561009257600080fd5b50610074600480360360208110156100a957600080fd5b50356001600160a01b0316610102565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b3660008037600080366000845af43d6000803e8080156100fd573d6000f35b3d6000fd5b6001600160a01b0381166101475760405162461bcd60e51b81526004018080602001828103825260248152602001806101dd6024913960400191505060405180910390fd5b60006101516100b9565b6001600160a01b0316146101ac576040805162461bcd60e51b815260206004820152601a60248201527f50726f78793a20414c52454144595f494e495449414c495a4544000000000000604482015290519081900360640190fd5b6101b5816101b8565b50565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5556fe50726f78793a20494e495449414c495a45445f574954485f5a45524f5f41444452455353a26469706673582212202e6d810b41384f7a7e8d90556356920fc289d3180a840445d85ebb4bec39b84864736f6c63430007010033",
29 | "immutableReferences": {},
30 | "compiler": {
31 | "name": "solc",
32 | "version": "0.7.1+commit.f4a555be.Emscripten.clang"
33 | },
34 | "networks": {},
35 | "schemaVersion": "3.2.5",
36 | "devdoc": {
37 | "details": "Implements delegation of calls to other contracts, with proper forwarding of return values and bubbling of failures. It defines a fallback function that delegates all calls to the implementation.",
38 | "kind": "dev",
39 | "methods": {
40 | "initializeProxy(address)": {
41 | "details": "Proxy initialization function. This should only be called once and it is permission-less.",
42 | "params": {
43 | "initialAddress": "Initial logic contract code address to be used."
44 | }
45 | }
46 | },
47 | "title": "Proxy",
48 | "version": 1
49 | },
50 | "userdoc": {
51 | "kind": "user",
52 | "methods": {},
53 | "version": 1
54 | }
55 | }
56 |
--------------------------------------------------------------------------------