Skip to content
This repository has been archived by the owner on Aug 30, 2024. It is now read-only.

Commit

Permalink
update to XdexStream
Browse files Browse the repository at this point in the history
jingleizhang committed Jan 31, 2021
1 parent 9d871c1 commit 1ca90e7
Showing 6 changed files with 1,466 additions and 228 deletions.
931 changes: 931 additions & 0 deletions abi/FarmMaster.json

Large diffs are not rendered by default.

387 changes: 387 additions & 0 deletions abi/XDEX.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,387 @@
{
"contractName": "XDEX",
"abi": [
{
"inputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "owner",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "spender",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "value",
"type": "uint256"
}
],
"name": "Approval",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "core",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "_core",
"type": "address"
}
],
"name": "SET_CORE",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "from",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "to",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "value",
"type": "uint256"
}
],
"name": "Transfer",
"type": "event"
},
{
"constant": true,
"inputs": [
{
"internalType": "address",
"name": "owner",
"type": "address"
},
{
"internalType": "address",
"name": "spender",
"type": "address"
}
],
"name": "allowance",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"internalType": "address",
"name": "spender",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "approve",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"internalType": "address",
"name": "account",
"type": "address"
}
],
"name": "balanceOf",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "core",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "decimals",
"outputs": [
{
"internalType": "uint8",
"name": "",
"type": "uint8"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"internalType": "address",
"name": "spender",
"type": "address"
},
{
"internalType": "uint256",
"name": "subtractedValue",
"type": "uint256"
}
],
"name": "decreaseAllowance",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"internalType": "address",
"name": "spender",
"type": "address"
},
{
"internalType": "uint256",
"name": "addedValue",
"type": "uint256"
}
],
"name": "increaseAllowance",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "name",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "symbol",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "totalSupply",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "transfer",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"internalType": "address",
"name": "sender",
"type": "address"
},
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "transferFrom",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"internalType": "address",
"name": "_core",
"type": "address"
}
],
"name": "setCore",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"internalType": "address",
"name": "account",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "mint",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "burnForSelf",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
}
]
}
149 changes: 67 additions & 82 deletions contracts/FarmMaster.sol
Original file line number Diff line number Diff line change
@@ -4,8 +4,9 @@ import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
import "@openzeppelin/contracts/math/SafeMath.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";

import "./XDEX.sol";
import "./XStream.sol";
import "./XdexStream.sol";

// FarmMaster is the master of xDefi Farms.
contract FarmMaster is ReentrancyGuard {
@@ -80,7 +81,7 @@ contract FarmMaster is ReentrancyGuard {
XDEX public xdex;

// The Halflife Protocol
XStream public stream;
XdexStream public stream;

// The main voting pool id
uint256 public votingPoolId;
@@ -142,7 +143,7 @@ contract FarmMaster is ReentrancyGuard {
uint256 indexed amount
);

event CoreTransferred(address indexed _core, address indexed _coreNew);
event SetCore(address indexed _core, address indexed _coreNew);

/**
* @dev Throws if the msg.sender unauthorized.
@@ -162,12 +163,12 @@ contract FarmMaster is ReentrancyGuard {

constructor(
XDEX _xdex,
XStream _stream,
address _stream,
uint256 _startBlock,
address _core
) public {
xdex = _xdex;
stream = _stream;
stream = XdexStream(_stream);
startBlock = _startBlock;
core = _core;
}
@@ -194,9 +195,8 @@ contract FarmMaster is ReentrancyGuard {
if (_withUpdate) {
massUpdatePools();
}
uint256 _lastRewardBlock = block.number > startBlock
? block.number
: startBlock;
uint256 _lastRewardBlock =
block.number > startBlock ? block.number : startBlock;

totalXFactor = totalXFactor.add(_lpFactor);

@@ -240,12 +240,13 @@ contract FarmMaster is ReentrancyGuard {

totalXFactor = totalXFactor.add(_lpFactor);

LpTokenInfo memory lpTokenInfo = LpTokenInfo({
lpToken: _lpToken,
lpTokenType: _lpTokenType,
lpFactor: _lpFactor,
lpAccPerShare: 0
});
LpTokenInfo memory lpTokenInfo =
LpTokenInfo({
lpToken: _lpToken,
lpTokenType: _lpTokenType,
lpFactor: _lpFactor,
lpAccPerShare: 0
});
poolInfo[_pid].poolFactor = pool.poolFactor.add(_lpFactor);
poolInfo[_pid].LpTokenInfos.push(lpTokenInfo);

@@ -295,8 +296,8 @@ contract FarmMaster is ReentrancyGuard {
amounts = new uint256[](length);
for (uint256 i = 0; i < length; i++) {
lpTokens[i] = address(pool.LpTokenInfos[i].lpToken);
UserInfo memory user = poolInfo[_pid].LpTokenInfos[i]
.userInfo[_user];
UserInfo memory user =
poolInfo[_pid].LpTokenInfos[i].userInfo[_user];
amounts[i] = user.amount;
}
}
@@ -316,10 +317,10 @@ contract FarmMaster is ReentrancyGuard {
PoolInfo storage pool = poolInfo[_pid];
uint256 index = _getLpIndexInPool(_pid, _lpToken);
//update poolFactor and totalXFactor
uint256 poolFactorNew = pool
.poolFactor
.sub(pool.LpTokenInfos[index].lpFactor)
.add(_lpFactor);
uint256 poolFactorNew =
pool.poolFactor.sub(pool.LpTokenInfos[index].lpFactor).add(
_lpFactor
);
pool.LpTokenInfos[index].lpFactor = _lpFactor;

totalXFactor = totalXFactor.sub(poolInfo[_pid].poolFactor).add(
@@ -351,10 +352,8 @@ contract FarmMaster is ReentrancyGuard {
}

PoolInfo storage pool = poolInfo[_pid];
(uint256 poolReward, , ) = getXCountToReward(
pool.lastRewardBlock,
block.number
);
(uint256 poolReward, , ) =
getXCountToReward(pool.lastRewardBlock, block.number);
poolReward = poolReward.mul(pool.poolFactor).div(totalXFactor);

uint256 totalLpSupply = 0;
@@ -365,9 +364,8 @@ contract FarmMaster is ReentrancyGuard {
continue;
}
totalLpSupply = totalLpSupply.add(lpSupply);
uint256 lpReward = poolReward.mul(lpInfo.lpFactor).div(
pool.poolFactor
);
uint256 lpReward =
poolReward.mul(lpInfo.lpFactor).div(pool.poolFactor);
pool.LpTokenInfos[i].lpAccPerShare = lpInfo.lpAccPerShare.add(
lpReward.mul(1e12).div(lpSupply)
);
@@ -394,8 +392,8 @@ contract FarmMaster is ReentrancyGuard {
uint256 totalPending = 0;
if (totalXFactor == 0 || pool.poolFactor == 0) {
for (uint256 i = 0; i < pool.LpTokenInfos.length; i++) {
UserInfo memory user = poolInfo[_pid].LpTokenInfos[i]
.userInfo[_user];
UserInfo memory user =
poolInfo[_pid].LpTokenInfos[i].userInfo[_user];
totalPending = totalPending.add(
user
.amount
@@ -408,10 +406,8 @@ contract FarmMaster is ReentrancyGuard {
return totalPending;
}

(uint256 xdexReward, , ) = getXCountToReward(
pool.lastRewardBlock,
block.number
);
(uint256 xdexReward, , ) =
getXCountToReward(pool.lastRewardBlock, block.number);

uint256 poolReward = xdexReward.mul(pool.poolFactor).div(totalXFactor);

@@ -422,15 +418,14 @@ contract FarmMaster is ReentrancyGuard {
continue;
}
if (block.number > pool.lastRewardBlock) {
uint256 lpReward = poolReward.mul(lpInfo.lpFactor).div(
pool.poolFactor
);
uint256 lpReward =
poolReward.mul(lpInfo.lpFactor).div(pool.poolFactor);
lpInfo.lpAccPerShare = lpInfo.lpAccPerShare.add(
lpReward.mul(1e12).div(lpSupply)
);
}
UserInfo memory user = poolInfo[_pid].LpTokenInfos[i]
.userInfo[_user];
UserInfo memory user =
poolInfo[_pid].LpTokenInfos[i].userInfo[_user];
totalPending = totalPending.add(
user.amount.mul(lpInfo.lpAccPerShare).div(1e12).sub(
user.rewardDebt
@@ -453,29 +448,27 @@ contract FarmMaster is ReentrancyGuard {
uint256 index = _getLpIndexInPool(_pid, _lpToken);
updatePool(_pid);

UserInfo storage user = poolInfo[_pid].LpTokenInfos[index].userInfo[msg
.sender];
UserInfo storage user =
poolInfo[_pid].LpTokenInfos[index].userInfo[msg.sender];

if (user.amount > 0) {
uint256 pending = user
.amount
.mul(pool.LpTokenInfos[index].lpAccPerShare)
.div(1e12)
.sub(user.rewardDebt);
uint256 pending =
user
.amount
.mul(pool.LpTokenInfos[index].lpAccPerShare)
.div(1e12)
.sub(user.rewardDebt);

if (pending > 0) {
//create the stream or add funds to stream
(bool hasVotingStream, bool hasNormalStream) = stream.hasStream(
msg.sender
);
(bool hasVotingStream, bool hasNormalStream) =
stream.hasStream(msg.sender);

if (_pid == votingPoolId) {
if (hasVotingStream) {
//add funds
uint256 streamId = stream.getStreamId(
msg.sender,
StreamTypeVoting
);
uint256 streamId =
stream.getStreamId(msg.sender, StreamTypeVoting);
require(streamId > 0, "not valid stream id");

xdex.approve(address(stream), pending);
@@ -484,10 +477,8 @@ contract FarmMaster is ReentrancyGuard {
} else {
if (hasNormalStream) {
//add funds
uint256 streamId = stream.getStreamId(
msg.sender,
StreamTypeNormal
);
uint256 streamId =
stream.getStreamId(msg.sender, StreamTypeNormal);
require(streamId > 0, "not valid stream id");

xdex.approve(address(stream), pending);
@@ -502,9 +493,8 @@ contract FarmMaster is ReentrancyGuard {
}

//if it is the first deposit
(bool hasVotingStream, bool hasNormalStream) = stream.hasStream(
msg.sender
);
(bool hasVotingStream, bool hasNormalStream) =
stream.hasStream(msg.sender);

//create the stream for First Deposit Bonus
if (_pid == votingPoolId) {
@@ -561,32 +551,30 @@ contract FarmMaster is ReentrancyGuard {
uint256 index = _getLpIndexInPool(_pid, _lpToken);
updatePool(_pid);

UserInfo storage user = poolInfo[_pid].LpTokenInfos[index].userInfo[msg
.sender];
UserInfo storage user =
poolInfo[_pid].LpTokenInfos[index].userInfo[msg.sender];
require(user.amount >= _amount, "withdraw: _amount not good");

uint256 pending = user
.amount
.mul(pool.LpTokenInfos[index].lpAccPerShare)
.div(1e12)
.sub(user.rewardDebt);
uint256 pending =
user
.amount
.mul(pool.LpTokenInfos[index].lpAccPerShare)
.div(1e12)
.sub(user.rewardDebt);

if (pending > 0) {
//create the stream or add funds to stream
(bool hasVotingStream, bool hasNormalStream) = stream.hasStream(
msg.sender
);
(bool hasVotingStream, bool hasNormalStream) =
stream.hasStream(msg.sender);

/* Approve the Stream contract to spend. */
xdex.approve(address(stream), pending);

if (_pid == votingPoolId) {
if (hasVotingStream) {
//add fund
uint256 streamId = stream.getStreamId(
msg.sender,
StreamTypeVoting
);
uint256 streamId =
stream.getStreamId(msg.sender, StreamTypeVoting);
require(streamId > 0, "not valid stream id");

xdex.approve(address(stream), pending);
@@ -595,10 +583,8 @@ contract FarmMaster is ReentrancyGuard {
} else {
if (hasNormalStream) {
//add fund
uint256 streamId = stream.getStreamId(
msg.sender,
StreamTypeNormal
);
uint256 streamId =
stream.getStreamId(msg.sender, StreamTypeNormal);
require(streamId > 0, "not valid stream id");

xdex.approve(address(stream), pending);
@@ -750,13 +736,13 @@ contract FarmMaster is ReentrancyGuard {
}

function setCore(address _core) public onlyCore {
emit SetCore(core, _core);
core = _core;
emit CoreTransferred(core, _core);
}

function setSAFU(address _safu) public onlyCore {
SAFU = _safu;
emit SetSAFU(_safu);
SAFU = _safu;
}

// The index in storage starts with 1, then need sub(1)
@@ -765,9 +751,8 @@ contract FarmMaster is ReentrancyGuard {
view
returns (uint256)
{
uint256 index = lpIndexInPool[keccak256(
abi.encodePacked(_pid, _lpToken)
)];
uint256 index =
lpIndexInPool[keccak256(abi.encodePacked(_pid, _lpToken))];
require(index > 0, "deposit the lp token which not exist");
return --index;
}
174 changes: 28 additions & 146 deletions contracts/XStream.sol → contracts/XdexStream.sol
Original file line number Diff line number Diff line change
@@ -1,80 +1,38 @@
pragma solidity 0.5.17;

import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "./interfaces/IXHalfLife.sol";

import "./XDEX.sol";

interface IXHalflife {
function createStream(
address recipient,
uint256 depositAmount,
uint256 startBlock,
uint256 kBlock,
uint256 unlockRatio
) external returns (uint256);

function isStream(uint256 streamId) external view returns (bool);

function getStream(uint256 streamId)
external
view
returns (
address sender,
address recipient,
uint256 depositAmount,
uint256 startBlock,
uint256 kBlock,
uint256 remaining,
uint256 withdrawable,
uint256 unlockRatio,
uint256 lastRewardBlock
);

function fundStream(uint256 streamId, uint256 amount)
external
returns (bool);

function withdrawFromStream(uint256 streamId, uint256 amount)
external
returns (bool);

function balanceOf(uint256 streamId)
external
view
returns (uint256 withdrawable, uint256 remaining);

function cancelStream(uint256 streamId) external returns (bool);
}

contract XStream is ReentrancyGuard {
contract XdexStream is ReentrancyGuard {
uint256 constant ONE = 10**18;
uint256 constant onePercent = 10**16;

// The XDEX TOKEN!
XDEX public _xdex;

// Should be FarmMaster Contract
address public core;
//The XDEX Token!
address public xdex;
address public xdexFarmMaster;

/**
* @notice An interface of XHalfLife, the contract responsible for creating, withdrawing from and cancelling streams.
* @notice An interface of XHalfLife, the contract responsible for creating, funding and withdrawing from streams.
* No one could cancle the xdex resward stream except the recipient, because the stream sender is this contract.
*/
IXHalflife public halflife;
IXHalfLife public halflife;

struct LockStream {
address depositor;
bool isEntity;
uint256 streamId;
}

//unlock ratio for both Voting and Normal Pool
uint256 constant unlockRatio = onePercent / 10; //0.1%

//funds from Voting Pool
//unlock k block for Voting Pool
uint256 constant unlockKBlocksV = 1800;
// key: recipient, value: Locked Stream
mapping(address => LockStream) private votingStreams;

//funds from Normal Pool
//funds for Normal Pool
uint256 constant unlockKBlocksN = 40;
// key: recipient, value: Locked Stream
mapping(address => LockStream) private normalStreams;
@@ -86,8 +44,10 @@ contract XStream is ReentrancyGuard {
modifier lockStreamExists(address who, uint256 streamType) {
bool found = false;
if (streamType == 0) {
//voting stream
found = votingStreams[who].isEntity;
} else if (streamType == 1) {
//normal stream
found = normalStreams[who].isEntity;
}

@@ -103,43 +63,14 @@ contract XStream is ReentrancyGuard {
_;
}

/**
* @dev Throws if the msg.sender unauthorized.
*/
modifier onlyCore() {
require(msg.sender == core, "Not authorized, only core");
_;
}

event Create(
address indexed sender,
address indexed recipient,
uint256 indexed streamId,
uint256 streamType,
uint256 depositAmount,
uint256 startBlock
);

event Withdraw(
address indexed withdrawer,
uint256 indexed streamId,
uint256 indexed amount,
uint256 streamType,
bool result
);

event Fund(
address indexed sender,
uint256 indexed streamId,
uint256 indexed amount
);

event CoreTransferred(address indexed _core, address indexed _coreNew);

constructor(XDEX _xdexToken, address _halflife) public {
_xdex = _xdexToken;
halflife = IXHalflife(_halflife);
core = msg.sender;
constructor(
address _xdex,
address _halfLife,
address _farmMaster
) public {
xdex = _xdex;
halflife = IXHalfLife(_halfLife);
xdexFarmMaster = _farmMaster;
}

/**
@@ -185,9 +116,9 @@ contract XStream is ReentrancyGuard {
external
nonReentrant
validStreamType(streamType)
onlyCore
returns (uint256 streamId)
{
require(msg.sender == xdexFarmMaster, "only farmMaster could create");
require(recipient != address(0), "stream to the zero address");
require(recipient != address(this), "stream to the contract itself");
require(recipient != msg.sender, "stream to the caller");
@@ -213,12 +144,13 @@ contract XStream is ReentrancyGuard {
}

/* Approve the XHalflife contract to spend. */
_xdex.approve(address(halflife), depositAmount);
IERC20(xdex).approve(address(halflife), depositAmount);

/* Transfer the tokens to this contract. */
_xdex.transferFrom(msg.sender, address(this), depositAmount);
IERC20(xdex).transferFrom(msg.sender, address(this), depositAmount);

streamId = halflife.createStream(
xdex,
recipient,
depositAmount,
startBlock,
@@ -239,15 +171,6 @@ contract XStream is ReentrancyGuard {
streamId: streamId
});
}

emit Create(
msg.sender,
recipient,
streamId,
streamType,
depositAmount,
startBlock
);
}

/**
@@ -262,52 +185,11 @@ contract XStream is ReentrancyGuard {
require(amount > 0, "amount is zero");

/* Approve the XHalflife contract to spend. */
_xdex.approve(address(halflife), amount);
IERC20(xdex).approve(address(halflife), amount);

/* Transfer the tokens to this contract. */
_xdex.transferFrom(msg.sender, address(this), amount);
IERC20(xdex).transferFrom(msg.sender, address(this), amount);

result = halflife.fundStream(streamId, amount);

emit Fund(msg.sender, streamId, amount);
}

/**
* @notice Withdraw from the votingStream or normalStream; `msg.sender` must be `recipient`
* @param streamType The type of stream: 0 is votingStream, 1 is normalStream;
* @param amount Withdraw amount
*/
function withdraw(uint256 streamType, uint256 amount)
external
validStreamType(streamType)
returns (bool result)
{
uint256 streamId = 0;
if (streamType == 0) {
require(
votingStreams[msg.sender].isEntity,
"senders votingStream not exist"
);
streamId = votingStreams[msg.sender].streamId;
} else if (streamType == 1) {
require(
normalStreams[msg.sender].isEntity,
"senders normalStream not exist"
);
streamId = normalStreams[msg.sender].streamId;
}

(, address recipient, , , , , , , ) = halflife.getStream(streamId);
require(msg.sender == recipient, "stream: user must be stream recipient");

result = halflife.withdrawFromStream(streamId, amount);

emit Withdraw(msg.sender, streamId, amount, streamType, result);
}

// core: Should be FarmMaster Contract
function setCore(address _core) public onlyCore {
core = _core;
emit CoreTransferred(core, _core);
}
}
53 changes: 53 additions & 0 deletions contracts/interfaces/IXHalfLife.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
pragma solidity 0.5.17;

interface IXHalfLife {
function createStream(
address token,
address recipient,
uint256 depositAmount,
uint256 startBlock,
uint256 kBlock,
uint256 unlockRatio
) external returns (uint256);

function createEtherStream(
address recipient,
uint256 startBlock,
uint256 kBlock,
uint256 unlockRatio
) external payable returns (uint256);

function getStream(uint256 streamId)
external
view
returns (
address sender,
address recipient,
address token,
uint256 depositAmount,
uint256 startBlock,
uint256 kBlock,
uint256 remaining,
uint256 withdrawable,
uint256 unlockRatio,
uint256 lastRewardBlock
);

function fundStream(uint256 streamId, uint256 amount)
external
payable
returns (bool);

function balanceOf(uint256 streamId)
external
view
returns (uint256 withdrawable, uint256 remaining);

function withdrawFromStream(uint256 streamId, uint256 amount)
external
returns (bool);

function cancelStream(uint256 streamId) external returns (bool);

function getVersion() external pure returns (bytes32);
}
File renamed without changes.

0 comments on commit 1ca90e7

Please sign in to comment.