Skip to content

Commit 5e1295c

Browse files
authored
token: erc20 transfers (#195)
* refactor: context notation * token: remove the non-standard callback and make it behave like standard ERC20 * token: add minting tests
1 parent 80a5b57 commit 5e1295c

15 files changed

+408
-444
lines changed

.soliumignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
node_modules
22
contracts/Staking.sol
33
contracts/Migrations.sol
4-
contracts/DisputeManager.sol
54
contracts/bancor
65
contracts/openzeppelin
76
contracts/MultiSigWallet.sol

contracts/Curation.sol

Lines changed: 30 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -154,33 +154,37 @@ contract Curation is Governed, BancorFormula {
154154
}
155155

156156
/**
157-
* @dev Accept tokens
158-
* @notice Receive Graph tokens
159-
* @param _from Token holder's address
160-
* @param _value Amount of Graph Tokens
161-
* @param _data Extra data payload
162-
* @return true if token transfer is processed
157+
* @dev Assign Graph Tokens received from staking to the subgraph reserve
158+
* @param _subgraphID Subgraph where funds should be allocated as reserves
159+
* @param _tokens Amount of Graph Tokens to add to reserves
163160
*/
164-
function tokensReceived(
165-
address _from,
166-
uint256 _value,
167-
bytes calldata _data
168-
) external returns (bool) {
169-
// Make sure the token is the caller of this function
170-
require(msg.sender == address(token), "Caller is not the GRT token contract");
171-
172-
// Decode subgraphID
173-
bytes32 subgraphID = _data.slice(0, 32).toBytes32(0);
174-
175-
// Transfers from staking means we are assigning fees to reserves
176-
if (_from == staking) {
177-
_collect(subgraphID, _value);
178-
return true;
179-
}
161+
function collect(bytes32 _subgraphID, uint256 _tokens) external {
162+
require(msg.sender == staking, "Caller must be the staking contract");
163+
164+
// Transfer tokens to collect from staking to this contract
165+
require(
166+
token.transferFrom(staking, address(this), _tokens),
167+
"Cannot transfer tokens to collect"
168+
);
169+
// Collect tranferred tokens and assign to subgraph reserves
170+
_collect(_subgraphID, _tokens);
171+
}
172+
173+
/**
174+
* @dev Called by a curator to deposit Graph Tokens in exchange for shares of a subgraph
175+
* @param _subgraphID Subgraph ID where the curator is staking Graph Tokens
176+
* @param _tokens Amount of Graph Tokens to stake
177+
*/
178+
function stake(bytes32 _subgraphID, uint256 _tokens) external {
179+
address curator = msg.sender;
180180

181-
// Any other source address means they are staking tokens for shares
182-
_stake(_from, subgraphID, _value);
183-
return true;
181+
// Transfer tokens from the curator to this contract
182+
require(
183+
token.transferFrom(curator, address(this), _tokens),
184+
"Cannot transfer tokens to stake"
185+
);
186+
// Stake transferred tokens to subgraph
187+
_stake(curator, _subgraphID, _tokens);
184188
}
185189

186190
/**
@@ -351,8 +355,8 @@ contract Curation is Governed, BancorFormula {
351355

352356
/**
353357
* @dev Deposit Graph Tokens in exchange for shares of a subgraph
354-
* @param _subgraphID Subgraph ID where the curator is staking Graph Tokens
355358
* @param _curator Address of staking party
359+
* @param _subgraphID Subgraph ID where the curator is staking Graph Tokens
356360
* @param _tokens Amount of Graph Tokens to stake
357361
*/
358362
function _stake(

contracts/DisputeManager.sol

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -280,23 +280,23 @@ contract DisputeManager is Governed {
280280
}
281281

282282
/**
283-
* @dev Accept tokens
284-
* @notice Receive Graph tokens
285-
* @param _from Token sender address
286-
* @param _value Amount of Graph Tokens
287-
* @param _data Extra data payload
283+
* @dev Create a dispute for the arbitrator to resolve.
284+
* This function is called by a fisherman and will need to `_deposit` at
285+
* least `minimumDeposit` GRT tokens.
286+
* @param _attestationData Attestation bytes submitted by the fisherman
287+
* @param _deposit Amount of tokens staked as deposit
288288
*/
289-
function tokensReceived(address _from, uint256 _value, bytes calldata _data)
290-
external
291-
returns (bool)
289+
function createDispute(bytes calldata _attestationData, uint256 _deposit) external
292290
{
293-
// Make sure the token is the caller of this function
294-
require(msg.sender == address(token), "Caller is not the GRT token contract");
295-
296-
// Create a dispute using the received attestation
297-
_createDispute(_data, _from, _value);
291+
address fisherman = msg.sender;
298292

299-
return true;
293+
// Transfer tokens to deposit from fisherman to this contract
294+
require(
295+
token.transferFrom(fisherman, address(this), _deposit),
296+
"Cannot transfer tokens to deposit"
297+
);
298+
// Create a dispute using the received attestation and deposit
299+
_createDispute(fisherman, _deposit, _attestationData);
300300
}
301301

302302
/**
@@ -392,7 +392,7 @@ contract DisputeManager is Governed {
392392
* @param _fisherman Creator of dispute
393393
* @param _deposit Amount of tokens staked as deposit
394394
*/
395-
function _createDispute(bytes memory _attestationData, address _fisherman, uint256 _deposit) private {
395+
function _createDispute(address _fisherman, uint256 _deposit, bytes memory _attestationData) private {
396396
// Check attestation data length
397397
require(_attestationData.length == ATTESTATION_SIZE_BYTES, "Attestation must be 161 bytes long");
398398

contracts/GraphToken.sol

Lines changed: 48 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,94 +1,100 @@
11
pragma solidity ^0.6.4;
22
pragma experimental ABIEncoderV2;
33

4-
/*
5-
* @title GraphToken contract
6-
*
7-
*/
8-
94
import "./Governed.sol";
5+
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
106
import "@openzeppelin/contracts/token/ERC20/ERC20Burnable.sol";
11-
import "@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol";
127

138

14-
// NOTE: This is based off of ERC777TokensRecipient interface, but does not fully implement it
15-
interface TokenReceiver {
16-
function tokensReceived(address _from, uint256 _amount, bytes calldata _data)
17-
external
18-
returns (bool);
19-
}
20-
9+
/**
10+
* @title GraphToken contract
11+
* @dev This is the implementation of the ERC20 Graph Token.
12+
*/
13+
contract GraphToken is Governed, ERC20, ERC20Burnable {
14+
// -- State --
2115

22-
contract GraphToken is Governed, ERC20Detailed, ERC20Burnable {
2316
mapping(address => bool) private _minters;
2417

2518
// -- Events --
19+
2620
event MinterAdded(address indexed account);
2721
event MinterRemoved(address indexed account);
2822

2923
modifier onlyMinter() {
30-
require(isMinter(msg.sender) || msg.sender == governor, "Only minter can call");
24+
require(isMinter(msg.sender), "Only minter can call");
3125
_;
3226
}
3327

34-
/*
35-
* @dev Init Graph Token contract
36-
* @param _governor <address> Address of the multisig contract as Governor of this contract
37-
* @param _initialSupply <uint256> Initial supply of Graph Tokens
28+
/**
29+
* @dev Graph Token Contract Constructor
30+
* @param _governor Owner address of this contract
31+
* @param _initialSupply Initial supply of GRT
3832
*/
3933
constructor(address _governor, uint256 _initialSupply)
4034
public
41-
ERC20Detailed("Graph Token", "GRT", 18)
35+
ERC20("Graph Token", "GRT")
4236
Governed(_governor)
4337
{
44-
// Governor is initially the sole treasurer
45-
_addMinter(_governor);
46-
4738
// The Governor has the initial supply of tokens
4839
_mint(_governor, _initialSupply);
40+
// The Governor is the default minter
41+
_addMinter(_governor);
4942
}
5043

44+
/**
45+
* @dev Add a new minter
46+
* @param _account Address of the minter
47+
*/
5148
function addMinter(address _account) external onlyGovernor {
5249
_addMinter(_account);
5350
}
5451

52+
/**
53+
* @dev Remove a minter
54+
* @param _account Address of the minter
55+
*/
5556
function removeMinter(address _account) external onlyGovernor {
5657
_removeMinter(_account);
5758
}
5859

59-
function isMinter(address _account) public view returns (bool) {
60-
return _minters[_account];
61-
}
62-
60+
/**
61+
* @dev Renounce to be a minter
62+
*/
6363
function renounceMinter() external {
6464
_removeMinter(msg.sender);
6565
}
6666

67-
function mint(address _account, uint256 _amount) external onlyMinter returns (bool) {
68-
_mint(_account, _amount);
69-
return true;
67+
/**
68+
* @dev Mint new tokens
69+
* @param _to Address to send the newly minted tokens
70+
* @param _amount Amount of tokens to mint
71+
*/
72+
function mint(address _to, uint256 _amount) external onlyMinter {
73+
_mint(_to, _amount);
7074
}
7175

72-
/*
73-
* @dev Transfer Graph tokens to the Staking interface
74-
* @notice Interacts with Staking contract
75-
* @notice Overriding `transfer` was not working with web3.js so we renamed to `transferToTokenReceiver`
76+
/**
77+
* @dev Return if the `_account` is a minter or not
78+
* @param _account Address to check
79+
* @return True if the `_account` is minter
7680
*/
77-
function transferToTokenReceiver(address _to, uint256 _amount, bytes memory _data)
78-
public
79-
returns (bool success)
80-
{
81-
assert(super.transfer(_to, _amount)); // Handle basic transfer functionality
82-
// @imp 08 Have staking contract receive the token and handle the data
83-
assert(TokenReceiver(_to).tokensReceived(msg.sender, _amount, _data));
84-
success = true;
81+
function isMinter(address _account) public view returns (bool) {
82+
return _minters[_account];
8583
}
8684

85+
/**
86+
* @dev Add a new minter
87+
* @param _account Address of the minter
88+
*/
8789
function _addMinter(address _account) internal {
8890
_minters[_account] = true;
8991
emit MinterAdded(_account);
9092
}
9193

94+
/**
95+
* @dev Remove a minter
96+
* @param _account Address of the minter
97+
*/
9298
function _removeMinter(address _account) internal {
9399
_minters[_account] = false;
94100
emit MinterRemoved(_account);

0 commit comments

Comments
 (0)