Specificatii tehnice

Interfata contractului:

1
interface cMDL_v1 {
2
// User actions
3
function claimEmissionForUser(address account, uint256 nonce, uint8 v, bytes32 r, bytes32 s) external onlyMint;
4
function register(address account, uint256 id) external onlyMint;
5
function reRegisterAccount(address account, uint256 id) external onlyMint;
6
function blockAccount(uint256 id) public onlyMint;
7
function unBlockAccount(uint256 id) public onlyMint;
8
9
// Parameters
10
function changeEmissionParameters(uint256 emissionAmount_, uint256 emissionPeriod_) external onlyOperator returns (bool success);
11
function changeOperatorAccount(address operatorAccount_) external onlyOperator returns (bool success);
12
function changeMintAccount(address mintAccount_) external onlyOperator;
13
function setProxyContract(address contractAddress, bool isProxy) external onlyOperator;
14
function changeBurnFee(uint256 burnFee_) external onlyOperator;
15
function changeTxFee(uint256 txFee_) external onlyOperator;
16
17
// Public
18
function isRegistered(address account) public view returns (bool registered);
19
20
// Core functions ERC20
21
function transfer(address _to, uint256 _value) public returns (bool success);
22
function signedTransfer(address _to, uint256 _value, address _account, uint256 nonce, uint8 v, bytes32 r, bytes32 s) public returns (bool success);
23
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success);
24
function approve(address _spender, uint256 _value) public returns (bool success);
25
function burn(uint256 _value) public returns (bool success);
26
}
Copied!

Codul contractului:

1
pragma solidity ^0.4.19;
2
3
4
// The cMDL Token Contract
5
contract cMDL_v1 {
6
7
/** Paramaeters **/
8
// Core
9
uint256 public emissionAmount; // amount of cMDLs distributed to each account during the emissionPeriod
10
uint256 public emissionPeriod; // number of blocks between emissions
11
uint256 public emissionParametersChangePeriod = 40320; // number of blocks between emission parameters change
12
13
// Burn Fees
14
uint256 public burnFee; // the burn fee proportion deducted from each cMDL transfer (1 = 1e18, 0.001 (0.1%) = 1e15 etc)
15
16
// Operator
17
address public operatorAccount; // account that changes the mintAccount and can block/unblock accounts, operator account also distributes Rinkeby ETH to all accounts to allow for free transfers
18
address public mintAccount; // account that is allowed to mint initial payments
19
20
21
// Transaction Fees
22
uint256 public maxTxFee = 1e16; // maximum transaction fee 1%
23
uint256 public txFee; // the transaction fee proportion deducted from each cMDL transfer (1 = 1e18, 0.001 (0.1%) = 1e15 etc)
24
25
26
27
28
/** Events **/
29
// Parameters
30
event emissionParametersChanged(uint256 newEmissionAmount, uint256 newEmissionPeriod); // fired when emission parameters are changed
31
event operatorChanged(address indexed newOperatorAccount); // fired when operatorAccount is modified
32
event mintAccountChanged(address indexed newMintAccount); // fired when mint account is changed
33
event chargedProposalFee(address indexed account, uint256 fee); // fired when a proposal fee is charged
34
35
// Operator
36
event registered(uint256 indexed id, address account); // fired when a new account is registered
37
event userBlocked(uint256 indexed id, bool blocked); // fired when an account is blocked or unblocked
38
event userSetInactive(address account); // fired when an account is marked as inactive
39
40
// User
41
event claimed(address indexed account, uint256 amount); // fired on each emission claim performed by user
42
43
// Burn fee
44
event burnFeeChanged(uint256 newBurnFee); // fired when the burnFee is changed
45
46
// Transaction Fees
47
event txFeeChanged(uint256 newTxFee); // fired when the taxProportion is changed
48
49
50
51
/**
52
* cMDL Functions
53
* */
54
55
/** Emission Functionality **/
56
// Internal parameters
57
mapping (uint256 => uint256) public lastEmissionClaimBlock; // mapping of user FB ids and their respective last emission claim blocks
58
mapping (address => uint256) public balance; // holds
59
mapping (uint256 => address) public accounts; // mapping of ID numbers (eg. Facebook UID) to account addresses
60
mapping (address => uint256) public ids; // inverse mapping of accounts
61
mapping (uint256 => bool) public blocked; // keeps list of accounts blocked for emissions
62
mapping (address => bool) public proxyContract; // mapping of proxy contracts, funds sent to these contracts dont have a burn fee or tx fee
63
mapping (bytes32 => bool) public claimedHashes; // mapping of claim hashes that have been already used
64
mapping (bytes32 => bool) public transferred; // mapping of used transfer hashes
65
66
uint256 public lastEmissionParameterChange; // the block number when the emission parameters were changed last time
67
68
69
70
71
/** User Functions **/
72
enum SignatureType {
73
/* 0 */RECURRING_PAYMENT_CREATE,
74
/* 1 */RECURRING_PAYMENT_CANCEL
75
}
76
77
// Claim emission function called by the holder once each emission period
78
// function claimEmission() external {
79
// releaseEmission(msg.sender);
80
// }
81
82
// Claim emission function called by the mint account on behalf of the user
83
function claimEmissionForUser(address account, uint256 nonce, uint8 v, bytes32 r, bytes32 s) external onlyMint {
84
bytes32 claimHash = keccak256(this, account, nonce);
85
require(ecrecover(keccak256("\x19Ethereum Signed Message:\n32", claimHash), v, r, s) == account, "cMDL Error: invalid signature");
86
require(!claimedHashes[claimHash], "cMDL Error: claim hash already used");
87
88
releaseEmission(account);
89
}
90
91
// Perform emission
92
function releaseEmission(address account) internal {
93
require(ids[account] > 0, "cMDL Error: account not registered");
94
require(safeSub(block.number, lastEmissionClaimBlock[ids[account]]) > emissionPeriod, "cMDL Error: emission period did not pass yet");
95
//require(safeAdd(totalSupply, emissionAmount) <= maxSupply, "cMDL Error: max supply reached");
96
97
require(!blocked[ids[account]], "cMDL Error: account blocked");
98
99
balanceOf[account] = safeAdd(balanceOf[account], emissionAmount);
100
101
lastEmissionClaimBlock[ids[account]] = block.number;
102
totalSupply = safeAdd(totalSupply, emissionAmount);
103
104
emit claimed(account, emissionAmount);
105
emit Transfer(address(0), account, emissionAmount);
106
}
107
108
109
110
/** Operator Functions **/
111
// Register participant
112
function register(address account, uint256 id) external onlyMint {
113
require(ids[account] == 0, "cMDL Error: account already registered");
114
require(mintAccount != account, "cMDL Error: cannot mint to mintAccount");
115
116
accounts[id] = account;
117
ids[account] = id;
118
119
emit registered(id, account);
120
121
allocateEmission(account, id);
122
}
123
124
function allocateEmission(address account, uint256 id) internal returns (uint256) {
125
// if (safeAdd(totalSupply, emissionAmount) > maxSupply) {
126
// return 0;
127
// }
128
129
balanceOf[account] = safeAdd(balanceOf[account], emissionAmount);
130
lastEmissionClaimBlock[id] = block.number;
131
132
totalSupply = safeAdd(totalSupply, emissionAmount);
133
134
emit claimed(account, emissionAmount);
135
emit Transfer(address(0), account, emissionAmount);
136
137
return emissionAmount;
138
}
139
140
function reRegisterAccount(address account, uint256 id) external onlyMint {
141
require(ids[account] == 0, "cMDL Error: address already used for another account");
142
require(accounts[id] != address(0), "cMDL Error: account not registered");
143
144
145
ids[account] = id;
146
accounts[id] = account;
147
148
emit registered(id, account);
149
}
150
151
// Block account, prevents account from claimin emissions
152
function blockAccount(uint256 id) public onlyMint {
153
blocked[id] = true;
154
emit userBlocked(id, true);
155
}
156
157
// Unblock account, removes block from account
158
function unBlockAccount(uint256 id) public onlyMint {
159
blocked[id] = false;
160
emit userBlocked(id, false);
161
}
162
163
164
165
166
167
168
169
170
171
172
/** Parameter Functionality **/
173
// the function called by the operator to change the cMDL emission parameters
174
function changeEmissionParameters(uint256 emissionAmount_, uint256 emissionPeriod_) external onlyOperator returns (bool success) {
175
//require(emissionAmount_ < safeMul(emissionAmount, 1328)/1000 && emissionAmount_ > safeMul(emissionAmount, 618)/1000, "cMDL Error: emissionSize out of bounds");
176
require(lastEmissionParameterChange < safeSub(block.number, emissionParametersChangePeriod), "cMDL Error: emission parameters cannot be changed yet");
177
//require(emissionPeriod_ >= emissionPeriod, "cMDL Error: emission period can only be increased");
178
179
emissionAmount = emissionAmount_;
180
emissionPeriod = emissionPeriod_;
181
182
lastEmissionParameterChange = block.number;
183
184
emit emissionParametersChanged(emissionAmount, emissionPeriod);
185
return true;
186
}
187
188
// function called by the operator to change the cMDL operatorAccount
189
function changeOperatorAccount(address operatorAccount_) external onlyOperator returns (bool success) {
190
operatorAccount = operatorAccount_;
191
192
emit operatorChanged(operatorAccount);
193
return true;
194
}
195
196
// function called by the operatorAccount to change the mint account address
197
function changeMintAccount(address mintAccount_) external onlyOperator {
198
mintAccount = mintAccount_;
199
200
emit mintAccountChanged(mintAccount);
201
}
202
203
// function called to set a contract as a proxy contract by the operatorAccount
204
function setProxyContract(address contractAddress, bool isProxy) external onlyOperator {
205
proxyContract[contractAddress] = isProxy;
206
}
207
208
209
/** Transaction Burn Fee Functionality **/
210
// Transaction burn fee is the fee taken during each transfer from the transferred amount and burnt.
211
// This is necessary to combat inflation, through the burn fee, the total supply of cMDL is decreased
212
// as the transferred volume increases
213
214
// the function called by the operator to change the burnFee
215
function changeBurnFee(uint256 burnFee_) external onlyOperator {
216
require(burnFee_ < 5e16, "cMDL Error: burn fee cannot be higher than 5%");
217
218
burnFee = burnFee_;
219
emit burnFeeChanged(burnFee);
220
}
221
222
223
224
225
/** Transaction Fee Functionality **/
226
// Transaction fee account is the account receiving the transaction fee from each cMDL transfer
227
// This functionality is optional to mitigate network congestion that could lead to high network fees
228
// Can also be used to collect additional taxes from users
229
// Transaction fee is paid by the receiver
230
231
// the function called by the operator to change the txFee
232
function changeTxFee(uint256 txFee_) external onlyOperator {
233
require(txFee_ < maxTxFee, "cMDL Error: txFee cannot be higher than maxTxFee");
234
235
txFee = txFee_;
236
emit txFeeChanged(txFee);
237
}
238
239
240
241
242
/** Internal Functionality **/
243
244
/** Constructor **/
245
// Constructor function, called once when deploying the contract
246
constructor(
247
string memory name_,
248
string memory symbol_,
249
250
uint256 initialEmissionAmount,
251
uint256 initialEmissionPeriod,
252
uint256 initialBurnFee,
253
uint256 initialTxFee,
254
255
address initialOperatorAccount,
256
address initialMintAccount
257
) public
258
{
259
name = name_;
260
symbol = symbol_;
261
262
emissionAmount = initialEmissionAmount;
263
emissionPeriod = initialEmissionPeriod;
264
burnFee = initialBurnFee;
265
txFee = initialTxFee;
266
267
operatorAccount = initialOperatorAccount;
268
mintAccount = initialMintAccount;
269
}
270
271
272
273
274
/** Modifiers **/
275
// a modifier that allows only the mintAccount to access a function
276
modifier onlyMint {
277
require(msg.sender == mintAccount || msg.sender == operatorAccount, "cMDL Error: accesses denied");
278
_;
279
}
280
281
// a modifier that allows only the operatorAccount to access a function
282
modifier onlyOperator {
283
require(msg.sender == operatorAccount, "cMDL Error: accesses denied");
284
_;
285
}
286
287
288
/** Helpers **/
289
// Returns the smaller of two values
290
function min(uint a, uint b) private pure returns (uint) {
291
return a < b ? a : b;
292
}
293
294
// Returns the largest of the two values
295
function max(uint a, uint b) private pure returns (uint) {
296
return a > b ? a : b;
297
}
298
299
300
// Returns true if the account is registered
301
function isRegistered(address account) public view returns (bool registered)
302
{
303
if (lastEmissionClaimBlock[ids[account]] > 0)
304
{
305
return true;
306
}
307
else
308
{
309
return false;
310
}
311
}
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
/** ERC20 Implementation
327
* https://eips.ethereum.org/EIPS/eip-20
328
**/
329
string public name;
330
string public symbol;
331
uint8 public decimals = 18;
332
uint256 public totalSupply = 0;
333
334
mapping (address => uint256) public balanceOf; // keeps the balances of all accounts
335
mapping (address => mapping (address => uint256)) public allowance; // keeps allowences for all accounts (implementation of the ERC20 interface)
336
337
// This generates a public event on the blockchain that will notify clients
338
event Transfer(address indexed from, address indexed to, uint256 value); // This generates a public event on the blockchain that will notify clients (ERC20 interface)
339
340
// This generates a public event on the blockchain that will notify clients
341
event Approval(address indexed _owner, address indexed _spender, uint256 _value);
342
343
// This notifies clients about the amount burnt
344
event Burn(address indexed from, uint256 value);
345
346
/**
347
* Internal transfer, only can be called by this contract
348
*/
349
function _transfer(address _from, address _to, uint _value) internal {
350
// Prevent transfer to 0x0 address. Use burn() instead
351
require(address(_to) != address(0));
352
353
uint256 burnFeeAmount = safeMul(_value, burnFee)/1e18;
354
uint256 txFeeAmount = safeMul(_value, txFee)/1e18;
355
356
if (proxyContract[_to])
357
{
358
burnFeeAmount = 0;
359
txFeeAmount = 0;
360
}
361
362
// Subtract from the sender
363
balanceOf[_from] = safeSub(balanceOf[_from], safeAdd(_value, txFeeAmount));
364
balanceOf[_to] = safeAdd(balanceOf[_to], _value);
365
balanceOf[operatorAccount] = safeAdd(balanceOf[operatorAccount], txFeeAmount);
366
burnForUser(_to, burnFeeAmount);
367
368
emit Transfer(_from, _to, _value);
369
}
370
371
/**
372
* Transfer tokens
373
*
374
* Send `_value` tokens to `_to` from your account
375
*
376
* @param _to The address of the recipient
377
* @param _value the amount to send
378
*/
379
function transfer(address _to, uint256 _value) public returns (bool success) {
380
_transfer(msg.sender, _to, _value);
381
return true;
382
}
383
384
/**
385
* Signed Transfer
386
*
387
* Send `_value` tokens to `_to` from `_account`
388
*
389
* @param _to The address of the recipient
390
* @param _value the amount to send
391
*/
392
function signedTransfer(address _to, uint256 _value, address _account, uint256 nonce, uint8 v, bytes32 r, bytes32 s) public returns (bool success) {
393
bytes32 transferHash = keccak256(this, _account, _to, _value, nonce);
394
require(ecrecover(keccak256("\x19Ethereum Signed Message:\n32", transferHash), v, r, s) == _account, "cMDL Error: invalid signature");
395
require(!transferred[transferHash], "cMDL Error: transfer hash already used");
396
397
transferred[transferHash] = true;
398
399
_transfer(_account, _to, _value);
400
return true;
401
}
402
403
/**
404
* Transfer tokens from other address
405
*
406
* Send `_value` tokens to `_to` on behalf of `_from`
407
*
408
* @param _from The address of the sender
409
* @param _to The address of the recipient
410
* @param _value the amount to send
411
*/
412
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) {
413
require(_value <= allowance[_from][msg.sender]); // Check allowance
414
allowance[_from][msg.sender] -= _value;
415
_transfer(_from, _to, _value);
416
return true;
417
}
418
419
/**
420
* Set allowance for other address
421
*
422
* Allows `_spender` to spend no more than `_value` tokens on your behalf
423
*
424
* @param _spender The address authorized to spend
425
* @param _value the max amount they can spend
426
*/
427
function approve(address _spender, uint256 _value) public
428
returns (bool success) {
429
allowance[msg.sender][_spender] = _value;
430
emit Approval(msg.sender, _spender, _value);
431
return true;
432
}
433
434
/**
435
* Destroy tokens
436
*
437
* Remove `_value` tokens from the system irreversibly
438
*
439
* @param _value the amount of money to burn
440
*/
441
function burn(uint256 _value) public returns (bool success) {
442
require(balanceOf[msg.sender] >= _value); // Check if the sender has enough
443
balanceOf[msg.sender] -= _value; // Subtract from the sender
444
totalSupply -= _value; // Updates totalSupply
445
emit Burn(msg.sender, _value);
446
return true;
447
}
448
449
/**
450
* Destroy tokens
451
*
452
* Remove `_value` tokens from the system irreversibly
453
*
454
* @param _value the amount of money to burn
455
*/
456
function burnForUser(address account, uint256 _value) internal returns (bool success) {
457
require(balanceOf[account] >= _value); // Check if the sender has enough
458
balanceOf[account] -= _value; // Subtract from the sender
459
totalSupply -= _value; // Updates totalSupply
460
//emit Burn(account, _value);
461
return true;
462
}
463
464
465
466
/** Safe Math **/
467
468
// Safe Multiply Function - prevents integer overflow
469
function safeMul(uint a, uint b) internal pure returns (uint) {
470
uint c = a * b;
471
assert(a == 0 || c / a == b);
472
return c;
473
}
474
475
// Safe Subtraction Function - prevents integer overflow
476
function safeSub(uint a, uint b) internal pure returns (uint) {
477
assert(b <= a);
478
return a - b;
479
}
480
481
// Safe Addition Function - prevents integer overflow
482
function safeAdd(uint a, uint b) internal pure returns (uint) {
483
uint c = a + b;
484
assert(c>=a && c>=b);
485
return c;
486
}
487
}
Copied!
Last modified 1yr ago