Last active
May 10, 2021 17:21
-
-
Save pi0neerpat/4669f393d5b9cc199c88ab6e9c68686f to your computer and use it in GitHub Desktop.
Created using remix-ide: Realtime Ethereum Contract Compiler and Runtime. Load this file by pasting this gists URL or ID at https://remix.ethereum.org/#version=soljson-v0.7.6+commit.7338295f.js&optimize=false&runs=200&gist=
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Instructions: https://docs.superfluid.finance/superfluid/resources/examples/soda-machine |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| pragma solidity ^0.7.0; | |
| import { | |
| ISuperfluid, | |
| ISuperToken, | |
| ISuperApp, | |
| ISuperAgreement, | |
| SuperAppDefinitions | |
| } from "https://github.com/superfluid-finance/protocol-monorepo/blob/remix-support-soda-machine/packages/ethereum-contracts/contracts/interfaces/superfluid/ISuperfluid.sol"; | |
| import { | |
| ISuperTokenFactory | |
| } | |
| from "https://github.com/superfluid-finance/protocol-monorepo/blob/remix-support-soda-machine/packages/ethereum-contracts/contracts/interfaces/superfluid/ISuperTokenFactory.sol"; | |
| import { | |
| IConstantFlowAgreementV1 | |
| } from "https://github.com/superfluid-finance/protocol-monorepo/blob/remix-support-soda-machine/packages/ethereum-contracts/contracts/interfaces/agreements/IConstantFlowAgreementV1.sol"; | |
| import { INativeSuperToken, NativeSuperTokenProxy } from "./NativeSuperToken.sol"; | |
| import { SodaMachine } from "./SodaMachine.sol"; | |
| contract Example { | |
| event NewContract(address _contract); | |
| ISuperfluid private _host; // host | |
| IConstantFlowAgreementV1 private _cfa; // the stored constant flow agreement class address | |
| ISuperToken private _acceptedToken; // accepted token | |
| INativeSuperToken public _sodaToken; | |
| ISuperTokenFactory private _superTokenFactory; | |
| address public _sodaMachine; | |
| uint256 constant TOTAL_SUPPLY = 1000000000000000000000000; // 1 M tokens | |
| constructor( | |
| ISuperfluid host, | |
| IConstantFlowAgreementV1 cfa, | |
| ISuperToken acceptedToken, | |
| ISuperTokenFactory superTokenFactory | |
| ) { | |
| _host = host; | |
| _cfa = cfa; | |
| _acceptedToken= acceptedToken; | |
| _superTokenFactory = superTokenFactory; | |
| step1_deploy(); | |
| step2_initProxy(); | |
| step3_initToken(); | |
| } | |
| function step1_deploy() internal { | |
| // Deploy the Custom Super Token proxy | |
| _sodaToken = INativeSuperToken(address(new NativeSuperTokenProxy())); | |
| emit NewContract(address(_sodaToken)); | |
| // Deploy the machine using the new SODA token address | |
| _sodaMachine = address(new SodaMachine(_host, _cfa, _acceptedToken, ISuperToken(address(_sodaToken)))); | |
| emit NewContract(_sodaMachine); | |
| } | |
| function step2_initProxy() internal { | |
| // Set the proxy to use the Super Token logic managed by Superfluid Protocol Governance | |
| _superTokenFactory.initializeCustomSuperToken(address(_sodaToken)); | |
| } | |
| function step3_initToken() internal { | |
| // Set up the token and mint 1M tokens to the machine | |
| _sodaToken.initialize( | |
| "Soda", | |
| "SODA", | |
| TOTAL_SUPPLY, | |
| address(_sodaMachine) | |
| ); | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // SPDX-License-Identifier: AGPLv3 | |
| pragma solidity ^0.7.0; | |
| import { | |
| ISuperToken, | |
| CustomSuperTokenProxyBase | |
| } | |
| from "https://github.com/superfluid-finance/protocol-monorepo/blob/remix-support-soda-machine/packages/ethereum-contracts/contracts/interfaces/superfluid/CustomSuperTokenProxyBase.sol"; | |
| import { IERC20 } from "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v3.2.0-solc-0.7/contracts/token/ERC20/IERC20.sol"; | |
| /** | |
| * @dev Native SuperToken custom token functions | |
| * | |
| * @author Superfluid | |
| */ | |
| interface INativeSuperTokenCustom { | |
| function initialize(string calldata name, string calldata symbol, uint256 initialSupply, address recipient) external; | |
| } | |
| /** | |
| * @dev Native SuperToken full interface | |
| * | |
| * @author Superfluid | |
| */ | |
| interface INativeSuperToken is INativeSuperTokenCustom, ISuperToken { | |
| function initialize(string calldata name, string calldata symbol, uint256 initialSupply, address recipient) external override; | |
| } | |
| /** | |
| * @dev Native SuperToken custom super token implementation | |
| * | |
| * NOTE: | |
| * - This is a simple implementation where the supply is pre-minted. | |
| * | |
| * @author Superfluid | |
| */ | |
| contract NativeSuperTokenProxy is INativeSuperTokenCustom, CustomSuperTokenProxyBase { | |
| function initialize(string calldata name, string calldata symbol, uint256 totalSupply, address recipient) | |
| external override | |
| { | |
| ISuperToken(address(this)).initialize( | |
| IERC20(0x0), // no underlying/wrapped token | |
| 18, // shouldn't matter if there's no wrapped token | |
| name, | |
| symbol | |
| ); | |
| ISuperToken(address(this)).selfMint(recipient, totalSupply, new bytes(0)); | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| pragma solidity ^0.7.0; | |
| import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v3.2.0-solc-0.7/contracts/token/ERC777/IERC777.sol"; | |
| import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v3.2.0-solc-0.7/contracts/introspection/IERC1820Registry.sol"; | |
| import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v3.2.0-solc-0.7/contracts/token/ERC777/IERC777Recipient.sol"; | |
| /** | |
| * @title Simple777Recipient | |
| * @dev Very simple ERC777 Recipient | |
| * see https://forum.openzeppelin.com/t/simple-erc777-token-example/746 | |
| */ | |
| contract Simple777Recipient is IERC777Recipient { | |
| IERC1820Registry private _erc1820 = IERC1820Registry(0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24); | |
| bytes32 constant private TOKENS_RECIPIENT_INTERFACE_HASH = keccak256("ERC777TokensRecipient"); | |
| IERC777 private _token; | |
| // event DoneStuff(address operator, address from, address to, uint256 amount, bytes userData, bytes operatorData); | |
| constructor (address token) { | |
| _token = IERC777(token); | |
| _erc1820.setInterfaceImplementer(address(this), TOKENS_RECIPIENT_INTERFACE_HASH, address(this)); | |
| } | |
| function tokensReceived( | |
| address, | |
| address, | |
| address, | |
| uint256, | |
| bytes calldata, | |
| bytes calldata | |
| ) external override { | |
| require(msg.sender == address(_token), "Simple777Recipient: Invalid token"); | |
| // do nothing | |
| // emit DoneStuff(operator, from, to, amount, userData, operatorData); | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // SPDX-License-Identifier: MIT | |
| pragma solidity ^0.7.0; | |
| pragma experimental ABIEncoderV2; | |
| import { | |
| ISuperfluid, | |
| ISuperToken, | |
| ISuperApp, | |
| ISuperAgreement, | |
| SuperAppDefinitions | |
| } from "https://github.com/superfluid-finance/protocol-monorepo/blob/remix-support-soda-machine/packages/ethereum-contracts/contracts/interfaces/superfluid/ISuperfluid.sol"; | |
| // When you're ready to leave Remix, change imports to follow this pattern: | |
| // "@superfluid-finance/ethereum-contracts/contracts/interfaces/superfluid/ISuperfluid.sol"; | |
| import { | |
| IConstantFlowAgreementV1 | |
| } from "https://github.com/superfluid-finance/protocol-monorepo/blob/remix-support-soda-machine/packages/ethereum-contracts/contracts/interfaces/agreements/IConstantFlowAgreementV1.sol"; | |
| import { | |
| SuperAppBase | |
| } from "https://github.com/superfluid-finance/protocol-monorepo/blob/remix-support-soda-machine/packages/ethereum-contracts/contracts/apps/SuperAppBase.sol"; | |
| import { Simple777Recipient } from "./Simple777Recipient.sol"; | |
| contract SodaMachine is Simple777Recipient, SuperAppBase { | |
| ISuperfluid private _host; // host | |
| IConstantFlowAgreementV1 private _cfa; // the stored constant flow agreement class address | |
| ISuperToken private _acceptedToken; // accepted token | |
| address private _receiver; | |
| ISuperToken private _sodaToken; | |
| constructor( | |
| ISuperfluid host, | |
| IConstantFlowAgreementV1 cfa, | |
| ISuperToken acceptedToken, | |
| ISuperToken sodaToken | |
| ) | |
| Simple777Recipient(address(sodaToken)) | |
| { | |
| assert(address(host) != address(0)); | |
| assert(address(cfa) != address(0)); | |
| assert(address(acceptedToken) != address(0)); | |
| assert(address(sodaToken) != address(0)); | |
| _host = host; | |
| _cfa = cfa; | |
| _acceptedToken = acceptedToken; | |
| _sodaToken = sodaToken; | |
| uint256 configWord = | |
| SuperAppDefinitions.APP_LEVEL_FINAL | | |
| SuperAppDefinitions.BEFORE_AGREEMENT_CREATED_NOOP | | |
| SuperAppDefinitions.BEFORE_AGREEMENT_UPDATED_NOOP | | |
| SuperAppDefinitions.BEFORE_AGREEMENT_TERMINATED_NOOP; | |
| _host.registerApp(configWord); | |
| } | |
| /************************************************************************** | |
| * SatisfyFlows Logic | |
| *************************************************************************/ | |
| /// @dev If a new stream is opened, or an existing one is opened | |
| function _updateOutflow(bytes calldata ctx, address customer, bytes32 agreementId) | |
| private | |
| returns (bytes memory newCtx) | |
| { | |
| newCtx = ctx; | |
| (,int96 inFlowRate,,) = _cfa.getFlowByID(_acceptedToken, agreementId); | |
| (,int96 outFlowRate,,) = _cfa.getFlow(_sodaToken, address(this), customer); | |
| if (inFlowRate < 0 ) inFlowRate = -inFlowRate; // Fixes issue when inFlowRate is negative | |
| if (outFlowRate != int96(0)){ | |
| // @dev if there already exists an outflow, then update it. | |
| (newCtx, ) = _host.callAgreementWithContext( | |
| _cfa, | |
| abi.encodeWithSelector( | |
| _cfa.updateFlow.selector, | |
| _sodaToken, | |
| customer, | |
| inFlowRate, | |
| new bytes(0) // placeholder | |
| ), | |
| "0x", | |
| newCtx | |
| ); | |
| } else if (inFlowRate == int96(0)) { | |
| // @dev if inFlowRate is zero, delete outflow. | |
| (newCtx, ) = _host.callAgreementWithContext( | |
| _cfa, | |
| abi.encodeWithSelector( | |
| _cfa.deleteFlow.selector, | |
| _sodaToken, | |
| address(this), | |
| customer, | |
| new bytes(0) // placeholder | |
| ), | |
| "0x", | |
| newCtx | |
| ); | |
| } else { | |
| // @dev If there is no existing outflow, then create new flow to equal inflow | |
| (newCtx, ) = _host.callAgreementWithContext( | |
| _cfa, | |
| abi.encodeWithSelector( | |
| _cfa.createFlow.selector, | |
| _sodaToken, | |
| customer, | |
| inFlowRate, | |
| new bytes(0) // placeholder | |
| ), | |
| "0x", | |
| newCtx | |
| ); | |
| } | |
| } | |
| /************************************************************************** | |
| * SuperApp callbacks | |
| *************************************************************************/ | |
| function afterAgreementCreated( | |
| ISuperToken _superToken, | |
| address _agreementClass, | |
| bytes32 _agreementId, | |
| bytes calldata /*_agreementData*/, | |
| bytes calldata ,// _cbdata, | |
| bytes calldata _ctx | |
| ) | |
| external override | |
| onlyExpected(_superToken, _agreementClass) | |
| onlyHost | |
| returns (bytes memory newCtx) | |
| { | |
| address customer = _host.decodeCtx(_ctx).msgSender; | |
| return _updateOutflow(_ctx, customer, _agreementId); | |
| } | |
| function afterAgreementUpdated( | |
| ISuperToken _superToken, | |
| address _agreementClass, | |
| bytes32 _agreementId, | |
| bytes calldata /*_agreementData*/, | |
| bytes calldata ,//_cbdata, | |
| bytes calldata _ctx | |
| ) | |
| external override | |
| onlyExpected(_superToken, _agreementClass) | |
| onlyHost | |
| returns (bytes memory newCtx) | |
| { | |
| address customer = _host.decodeCtx(_ctx).msgSender; | |
| return _updateOutflow(_ctx, customer, _agreementId); | |
| } | |
| function afterAgreementTerminated( | |
| ISuperToken _superToken, | |
| address _agreementClass, | |
| bytes32 _agreementId, | |
| bytes calldata _agreementData, | |
| bytes calldata ,//_cbdata, | |
| bytes calldata _ctx | |
| ) | |
| external override | |
| onlyHost | |
| returns (bytes memory newCtx) | |
| { | |
| // According to the app basic law, we should never revert in a termination callback | |
| if (!_isSameToken(_superToken) || !_isCFAv1(_agreementClass)) return _ctx; | |
| (address customer,) = abi.decode(_agreementData, (address, address)); | |
| return _updateOutflow(_ctx, customer, _agreementId); | |
| } | |
| function getNetFlow() public view returns (int96) { | |
| return _cfa.getNetFlow(_acceptedToken, address(this)); | |
| } | |
| function _isSameToken(ISuperToken superToken) private view returns (bool) { | |
| return address(superToken) == address(_acceptedToken); | |
| } | |
| function _isCFAv1(address agreementClass) private view returns (bool) { | |
| return ISuperAgreement(agreementClass).agreementType() | |
| == keccak256("org.superfluid-finance.agreements.ConstantFlowAgreement.v1"); | |
| } | |
| modifier onlyHost() { | |
| require(msg.sender == address(_host), "SatisfyFlows: support only one host"); | |
| _; | |
| } | |
| modifier onlyExpected(ISuperToken superToken, address agreementClass) { | |
| require(_isSameToken(superToken), "SatisfyFlows: not accepted token"); | |
| require(_isCFAv1(agreementClass), "SatisfyFlows: only CFAv1 supported"); | |
| _; | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment