-
Notifications
You must be signed in to change notification settings - Fork 558
Expand file tree
/
Copy pathSecurityToken.sol
More file actions
216 lines (191 loc) · 8.41 KB
/
SecurityToken.sol
File metadata and controls
216 lines (191 loc) · 8.41 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
/**
* This smart contract code is Copyright 2018, 2019 TokenMarket Ltd. For more information see https://tokenmarket.net
* Licensed under the Apache License, version 2.0: https://github.com/TokenMarketNet/ico/blob/master/LICENSE.txt
* NatSpec is used intentionally to cover also other than public functions.
* Solidity 0.4.18 is intentionally used: it's stable, and our framework is
* based on that.
*/
pragma solidity ^0.4.18;
import "./CheckpointToken.sol";
import "./ERC20SnapshotMixin.sol";
import "./ERC865.sol";
import "./AnnouncementInterface.sol";
import "../Recoverable.sol";
import "zeppelin/contracts/math/SafeMath.sol";
import "zeppelin/contracts/ownership/rbac/RBAC.sol";
/**
* @author TokenMarket / Ville Sundell <ville at tokenmarket.net>
*/
contract SecurityToken is CheckpointToken, RBAC, Recoverable, ERC865, ERC20SnapshotMixin {
using SafeMath for uint256; // We use only uint256 for safety reasons (no boxing)
string public constant ROLE_ANNOUNCE = "announce()";
string public constant ROLE_FORCE = "forceTransfer()";
string public constant ROLE_ISSUE = "issueTokens()";
string public constant ROLE_BURN = "burnTokens()";
string public constant ROLE_INFO = "setTokenInformation()";
string public constant ROLE_SETVERIFIER = "setTransactionVerifier()";
string public constant ROLE_CHECKPOINT = "checkpoint()";
/// @dev Version string telling the token is TM-01, and its version:
string public version = 'TM-01 0.3';
/// @dev URL where you can get more information about the security
/// (for example company website or investor interface):
string public url;
/** SecurityToken specific events **/
/// @dev This is emitted when new tokens are created:
event Issued(address indexed to, uint256 value);
/// @dev This is emitted when tokens are burned from token's own stash:
event Burned(address indexed burner, uint256 value);
/// @dev This is emitted upon forceful transfer of tokens by the Board:
event Forced(address indexed from, address indexed to, uint256 value);
/// @dev This is emitted when new announcements (like dividends, voting, etc.) are issued by the Board:
event Announced(address indexed announcement, uint256 indexed announcementType, bytes32 indexed announcementName, bytes32 announcementURI, uint256 announcementHash);
/// @dev This is emitted when token information is changed:
event UpdatedTokenInformation(string newName, string newSymbol, string newUrl);
/// @dev This is emitted when transaction verifier (the contract which would check KYC, etc.):
event UpdatedTransactionVerifier(address newVerifier);
/// @dev This is emitted when a new checkpoint (snapshot) is created
event Checkpointed(uint256 checkpointID);
/// @dev Address list of Announcements (see "interface Announcement").
/// Announcements are things like votings, dividends, or any kind of
/// smart contract:
address[] public announcements;
/// @dev For performance reasons, we also maintain address based mapping of
/// Announcements:
mapping(address => uint256) public announcementsByAddress;
/**
* @dev Contructor to create SecurityToken, and subsequent CheckpointToken.
*
* CheckpointToken will be created with hardcoded 18 decimals.
*
* @param _name Initial name of the token
* @param _symbol Initial symbol of the token
*/
function SecurityToken(string _name, string _symbol, string _url) CheckpointToken(_name, _symbol, 18) public {
url = _url;
addRole(msg.sender, ROLE_ANNOUNCE);
addRole(msg.sender, ROLE_FORCE);
addRole(msg.sender, ROLE_ISSUE);
addRole(msg.sender, ROLE_BURN);
addRole(msg.sender, ROLE_INFO);
addRole(msg.sender, ROLE_SETVERIFIER);
addRole(msg.sender, ROLE_CHECKPOINT);
}
/**
* @dev Function to announce Announcements.
*
* Announcements can be for instance for dividend sharing, voting, or
* just for general announcements.
*
* Instead of storing the announcement details, we just broadcast them as an
* event, and store only the address.
*
* @param announcement Address of the Announcement
*/
function announce(Announcement announcement) external onlyRole(ROLE_ANNOUNCE) {
announcements.push(announcement);
announcementsByAddress[address(announcement)] = announcements.length;
Announced(address(announcement), announcement.announcementType(), announcement.announcementName(), announcement.announcementURI(), announcement.announcementHash());
}
/**
* @dev Function to forcefully transfer tokens from A to B by board decission
*
* This must be implemented carefully, since this is a very critical part
* to ensure investor safety.
*
* This is intended to be called by the BAC (The Board).
* The BAC must have the RBAC role ROLE_FORCE.
*
* @param from Address of the account to confisticate the tokens from
* @param to Address to deposit the confisticated token to
* @param value amount of tokens to be confisticated
*/
function forceTransfer(address from, address to, uint256 value) external onlyRole(ROLE_FORCE) {
transferInternal(from, to, value);
Forced(from, to, value);
}
/**
* @dev Issue new tokens to the board by a board decission
*
* Issue new tokens. This is intended to be called by the BAC (The Board).
* The BAC must have the RBAC role ROLE_ISSUE.
*
* @param value Token amount to issue
*/
function issueTokens(uint256 value) external onlyRole(ROLE_ISSUE) {
address issuer = msg.sender;
uint256 blackHoleBalance = balanceOf(address(0));
uint256 totalSupplyNow = totalSupply();
setCheckpoint(tokenBalances[address(0)], blackHoleBalance.add(value));
transferInternal(address(0), issuer, value);
setCheckpoint(tokensTotal, totalSupplyNow.add(value));
Issued(issuer, value);
}
/**
* @dev Burn tokens from contract's own balance by a board decission
*
* Burn tokens from contract's own balance to prevent accidental burnings.
* This is intended to be called by the BAC (The Board).
* The BAC must have the RBAC role ROLE_BURN.
*
* @param value Token amount to burn from this contract's balance
*/
function burnTokens(uint256 value) external onlyRole(ROLE_BURN) {
address burner = address(this);
uint256 burnerBalance = balanceOf(burner);
uint256 totalSupplyNow = totalSupply();
transferInternal(burner, address(0), value);
setCheckpoint(tokenBalances[address(0)], burnerBalance.sub(value));
setCheckpoint(tokensTotal, totalSupplyNow.sub(value));
Burned(burner, value);
}
/**
* @dev Permissioned users (The Board, BAC) can update token information here.
*
* It is often useful to conceal the actual token association, until
* the token operations, like central issuance or reissuance have been completed.
*
* This function allows the token owner to rename the token after the operations
* have been completed and then point the audience to use the token contract.
*
* The BAC must have the RBAC role ROLE_INFO.
*
* @param _name New name of the token
* @param _symbol New symbol of the token
* @param _url New URL of the token
*/
function setTokenInformation(string _name, string _symbol, string _url) external onlyRole(ROLE_INFO) {
name = _name;
symbol = _symbol;
url = _url;
UpdatedTokenInformation(name, symbol, url);
}
/**
* @dev Set transaction verifier
*
* This sets a SecurityTransferAgent to be used as a transaction verifier for
* each transfer. This is implemented for possible regulatory requirements.
*
* @param newVerifier Address of the SecurityTransferAgent used as verifier
*/
function setTransactionVerifier(SecurityTransferAgent newVerifier) external onlyRole(ROLE_SETVERIFIER) {
transactionVerifier = newVerifier;
UpdatedTransactionVerifier(newVerifier);
}
/**
* @dev Create a checkpoint for current token holdings
*
* Checkpoint enables the auxiliarly contracts to query token holdings on
* a pre-defined checkpoint.
*
* In addition to our own Checkpointed() event, it will emit Snapshot(), which
* is compatible with Zeppelin's ERC20Snapshot. This is to enable future block
* explorers to be aware of our checkpoint functionality.
*
* @return ID number of the newly created checkpoint (an incrementing integer)
*/
function checkpoint() external onlyRole(ROLE_CHECKPOINT) returns (uint256 checkpointID) {
checkpointID = createCheckpoint();
emit Snapshot(checkpointID);
emit Checkpointed(checkpointID);
}
}