├── 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 | 41 | 42 | 43 | {items} 44 |
{"Address"}{"FlowRate"}{"Won so far"}
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 | 77 | 78 | 79 | 80 | {items} 81 |
{"Address"}{"Winning for"}{"FlowRate"}{"Total Won"}
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 | --------------------------------------------------------------------------------