-
Notifications
You must be signed in to change notification settings - Fork 98
/
Copy path0x6531f133e6deebe7f2dce5a0441aa7ef330b4e53-TIME-TIME.sol
1212 lines (1113 loc) · 40 KB
/
0x6531f133e6deebe7f2dce5a0441aa7ef330b4e53-TIME-TIME.sol
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
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
pragma solidity ^0.4.4;
contract Owned {
address public contractOwner;
address public pendingContractOwner;
function Owned() {
contractOwner = msg.sender;
}
modifier onlyContractOwner() {
if (contractOwner == msg.sender) {
_;
}
}
/**
* Prepares ownership pass.
*
* Can only be called by current owner.
*
* @param _to address of the next owner.
*
* @return success.
*/
function changeContractOwnership(address _to) onlyContractOwner() returns(bool) {
pendingContractOwner = _to;
return true;
}
/**
* Finalize ownership pass.
*
* Can only be called by pending owner.
*
* @return success.
*/
function claimContractOwnership() returns(bool) {
if (pendingContractOwner != msg.sender) {
return false;
}
contractOwner = pendingContractOwner;
delete pendingContractOwner;
return true;
}
}
contract Emitter {
function emitTransfer(address _from, address _to, bytes32 _symbol, uint _value, string _reference);
function emitIssue(bytes32 _symbol, uint _value, address _by);
function emitRevoke(bytes32 _symbol, uint _value, address _by);
function emitOwnershipChange(address _from, address _to, bytes32 _symbol);
function emitApprove(address _from, address _spender, bytes32 _symbol, uint _value);
function emitRecovery(address _from, address _to, address _by);
function emitError(bytes32 _message);
}
contract Proxy {
function emitTransfer(address _from, address _to, uint _value);
function emitApprove(address _from, address _spender, uint _value);
}
/**
* @title ChronoBank Platform.
*
* The official ChronoBank assets platform powering TIME and LHT tokens, and possibly
* other unknown tokens needed later.
* Platform uses EventsHistory contract to keep events, so that in case it needs to be redeployed
* at some point, all the events keep appearing at the same place.
*
* Every asset is meant to be used through a proxy contract. Only one proxy contract have access
* rights for a particular asset.
*
* Features: transfers, allowances, supply adjustments, lost wallet access recovery.
*
* Note: all the non constant functions return false instead of throwing in case if state change
* didn't happen yet.
*/
contract ChronoBankPlatform is Owned {
// Structure of a particular asset.
struct Asset {
uint owner; // Asset's owner id.
uint totalSupply; // Asset's total supply.
string name; // Asset's name, for information purposes.
string description; // Asset's description, for information purposes.
bool isReissuable; // Indicates if asset have dynamic of fixed supply.
uint8 baseUnit; // Proposed number of decimals.
mapping(uint => Wallet) wallets; // Holders wallets.
}
// Structure of an asset holder wallet for particular asset.
struct Wallet {
uint balance;
mapping(uint => uint) allowance;
}
// Structure of an asset holder.
struct Holder {
address addr; // Current address of the holder.
mapping(address => bool) trust; // Addresses that are trusted with recovery proocedure.
}
// Iterable mapping pattern is used for holders.
uint public holdersCount;
mapping(uint => Holder) public holders;
// This is an access address mapping. Many addresses may have access to a single holder.
mapping(address => uint) holderIndex;
// Asset symbol to asset mapping.
mapping(bytes32 => Asset) public assets;
// Asset symbol to asset proxy mapping.
mapping(bytes32 => address) public proxies;
// Should use interface of the emitter, but address of events history.
Emitter public eventsHistory;
/**
* Emits Error event with specified error message.
*
* Should only be used if no state changes happened.
*
* @param _message error message.
*/
function _error(bytes32 _message) internal {
eventsHistory.emitError(_message);
}
/**
* Sets EventsHstory contract address.
*
* Can be set only once, and only by contract owner.
*
* @param _eventsHistory EventsHistory contract address.
*
* @return success.
*/
function setupEventsHistory(address _eventsHistory) onlyContractOwner() returns(bool) {
if (address(eventsHistory) != 0) {
return false;
}
eventsHistory = Emitter(_eventsHistory);
return true;
}
/**
* Emits Error if called not by asset owner.
*/
modifier onlyOwner(bytes32 _symbol) {
if (isOwner(msg.sender, _symbol)) {
_;
} else {
_error("Only owner: access denied");
}
}
/**
* Emits Error if called not by asset proxy.
*/
modifier onlyProxy(bytes32 _symbol) {
if (proxies[_symbol] == msg.sender) {
_;
} else {
_error("Only proxy: access denied");
}
}
/**
* Emits Error if _from doesn't trust _to.
*/
modifier checkTrust(address _from, address _to) {
if (isTrusted(_from, _to)) {
_;
} else {
_error("Only trusted: access denied");
}
}
/**
* Check asset existance.
*
* @param _symbol asset symbol.
*
* @return asset existance.
*/
function isCreated(bytes32 _symbol) constant returns(bool) {
return assets[_symbol].owner != 0;
}
/**
* Returns asset decimals.
*
* @param _symbol asset symbol.
*
* @return asset decimals.
*/
function baseUnit(bytes32 _symbol) constant returns(uint8) {
return assets[_symbol].baseUnit;
}
/**
* Returns asset name.
*
* @param _symbol asset symbol.
*
* @return asset name.
*/
function name(bytes32 _symbol) constant returns(string) {
return assets[_symbol].name;
}
/**
* Returns asset description.
*
* @param _symbol asset symbol.
*
* @return asset description.
*/
function description(bytes32 _symbol) constant returns(string) {
return assets[_symbol].description;
}
/**
* Returns asset reissuability.
*
* @param _symbol asset symbol.
*
* @return asset reissuability.
*/
function isReissuable(bytes32 _symbol) constant returns(bool) {
return assets[_symbol].isReissuable;
}
/**
* Returns asset owner address.
*
* @param _symbol asset symbol.
*
* @return asset owner address.
*/
function owner(bytes32 _symbol) constant returns(address) {
return holders[assets[_symbol].owner].addr;
}
/**
* Check if specified address has asset owner rights.
*
* @param _owner address to check.
* @param _symbol asset symbol.
*
* @return owner rights availability.
*/
function isOwner(address _owner, bytes32 _symbol) constant returns(bool) {
return isCreated(_symbol) && (assets[_symbol].owner == getHolderId(_owner));
}
/**
* Returns asset total supply.
*
* @param _symbol asset symbol.
*
* @return asset total supply.
*/
function totalSupply(bytes32 _symbol) constant returns(uint) {
return assets[_symbol].totalSupply;
}
/**
* Returns asset balance for a particular holder.
*
* @param _holder holder address.
* @param _symbol asset symbol.
*
* @return holder balance.
*/
function balanceOf(address _holder, bytes32 _symbol) constant returns(uint) {
return _balanceOf(getHolderId(_holder), _symbol);
}
/**
* Returns asset balance for a particular holder id.
*
* @param _holderId holder id.
* @param _symbol asset symbol.
*
* @return holder balance.
*/
function _balanceOf(uint _holderId, bytes32 _symbol) constant returns(uint) {
return assets[_symbol].wallets[_holderId].balance;
}
/**
* Returns current address for a particular holder id.
*
* @param _holderId holder id.
*
* @return holder address.
*/
function _address(uint _holderId) constant returns(address) {
return holders[_holderId].addr;
}
/**
* Sets Proxy contract address for a particular asset.
*
* Can be set only once for each asset, and only by contract owner.
*
* @param _address Proxy contract address.
* @param _symbol asset symbol.
*
* @return success.
*/
function setProxy(address _address, bytes32 _symbol) onlyContractOwner() returns(bool) {
if (proxies[_symbol] != 0x0) {
return false;
}
proxies[_symbol] = _address;
return true;
}
/**
* Transfers asset balance between holders wallets.
*
* @param _fromId holder id to take from.
* @param _toId holder id to give to.
* @param _value amount to transfer.
* @param _symbol asset symbol.
*/
function _transferDirect(uint _fromId, uint _toId, uint _value, bytes32 _symbol) internal {
assets[_symbol].wallets[_fromId].balance -= _value;
assets[_symbol].wallets[_toId].balance += _value;
}
/**
* Transfers asset balance between holders wallets.
*
* Performs sanity checks and takes care of allowances adjustment.
*
* @param _fromId holder id to take from.
* @param _toId holder id to give to.
* @param _value amount to transfer.
* @param _symbol asset symbol.
* @param _reference transfer comment to be included in a Transfer event.
* @param _senderId transfer initiator holder id.
*
* @return success.
*/
function _transfer(uint _fromId, uint _toId, uint _value, bytes32 _symbol, string _reference, uint _senderId) internal returns(bool) {
// Should not allow to send to oneself.
if (_fromId == _toId) {
_error("Cannot send to oneself");
return false;
}
// Should have positive value.
if (_value == 0) {
_error("Cannot send 0 value");
return false;
}
// Should have enough balance.
if (_balanceOf(_fromId, _symbol) < _value) {
_error("Insufficient balance");
return false;
}
// Should have enough allowance.
if (_fromId != _senderId && _allowance(_fromId, _senderId, _symbol) < _value) {
_error("Not enough allowance");
return false;
}
_transferDirect(_fromId, _toId, _value, _symbol);
// Adjust allowance.
if (_fromId != _senderId) {
assets[_symbol].wallets[_fromId].allowance[_senderId] -= _value;
}
// Internal Out Of Gas/Throw: revert this transaction too;
// Call Stack Depth Limit reached: n/a after HF 4;
// Recursive Call: safe, all changes already made.
eventsHistory.emitTransfer(_address(_fromId), _address(_toId), _symbol, _value, _reference);
_proxyTransferEvent(_fromId, _toId, _value, _symbol);
return true;
}
/**
* Transfers asset balance between holders wallets.
*
* Can only be called by asset proxy.
*
* @param _to holder address to give to.
* @param _value amount to transfer.
* @param _symbol asset symbol.
* @param _reference transfer comment to be included in a Transfer event.
* @param _sender transfer initiator address.
*
* @return success.
*/
function proxyTransferWithReference(address _to, uint _value, bytes32 _symbol, string _reference, address _sender) onlyProxy(_symbol) returns(bool) {
return _transfer(getHolderId(_sender), _createHolderId(_to), _value, _symbol, _reference, getHolderId(_sender));
}
/**
* Ask asset Proxy contract to emit ERC20 compliant Transfer event.
*
* @param _fromId holder id to take from.
* @param _toId holder id to give to.
* @param _value amount to transfer.
* @param _symbol asset symbol.
*/
function _proxyTransferEvent(uint _fromId, uint _toId, uint _value, bytes32 _symbol) internal {
if (proxies[_symbol] != 0x0) {
// Internal Out Of Gas/Throw: revert this transaction too;
// Call Stack Depth Limit reached: n/a after HF 4;
// Recursive Call: safe, all changes already made.
Proxy(proxies[_symbol]).emitTransfer(_address(_fromId), _address(_toId), _value);
}
}
/**
* Returns holder id for the specified address.
*
* @param _holder holder address.
*
* @return holder id.
*/
function getHolderId(address _holder) constant returns(uint) {
return holderIndex[_holder];
}
/**
* Returns holder id for the specified address, creates it if needed.
*
* @param _holder holder address.
*
* @return holder id.
*/
function _createHolderId(address _holder) internal returns(uint) {
uint holderId = holderIndex[_holder];
if (holderId == 0) {
holderId = ++holdersCount;
holders[holderId].addr = _holder;
holderIndex[_holder] = holderId;
}
return holderId;
}
/**
* Issues new asset token on the platform.
*
* Tokens issued with this call go straight to contract owner.
* Each symbol can be issued only once, and only by contract owner.
*
* @param _symbol asset symbol.
* @param _value amount of tokens to issue immediately.
* @param _name name of the asset.
* @param _description description for the asset.
* @param _baseUnit number of decimals.
* @param _isReissuable dynamic or fixed supply.
*
* @return success.
*/
function issueAsset(bytes32 _symbol, uint _value, string _name, string _description, uint8 _baseUnit, bool _isReissuable) onlyContractOwner() returns(bool) {
// Should have positive value if supply is going to be fixed.
if (_value == 0 && !_isReissuable) {
_error("Cannot issue 0 value fixed asset");
return false;
}
// Should not be issued yet.
if (isCreated(_symbol)) {
_error("Asset already issued");
return false;
}
uint holderId = _createHolderId(msg.sender);
assets[_symbol] = Asset(holderId, _value, _name, _description, _isReissuable, _baseUnit);
assets[_symbol].wallets[holderId].balance = _value;
// Internal Out Of Gas/Throw: revert this transaction too;
// Call Stack Depth Limit reached: n/a after HF 4;
// Recursive Call: safe, all changes already made.
eventsHistory.emitIssue(_symbol, _value, _address(holderId));
return true;
}
/**
* Issues additional asset tokens if the asset have dynamic supply.
*
* Tokens issued with this call go straight to asset owner.
* Can only be called by asset owner.
*
* @param _symbol asset symbol.
* @param _value amount of additional tokens to issue.
*
* @return success.
*/
function reissueAsset(bytes32 _symbol, uint _value) onlyOwner(_symbol) returns(bool) {
// Should have positive value.
if (_value == 0) {
_error("Cannot reissue 0 value");
return false;
}
Asset asset = assets[_symbol];
// Should have dynamic supply.
if (!asset.isReissuable) {
_error("Cannot reissue fixed asset");
return false;
}
// Resulting total supply should not overflow.
if (asset.totalSupply + _value < asset.totalSupply) {
_error("Total supply overflow");
return false;
}
uint holderId = getHolderId(msg.sender);
asset.wallets[holderId].balance += _value;
asset.totalSupply += _value;
// Internal Out Of Gas/Throw: revert this transaction too;
// Call Stack Depth Limit reached: n/a after HF 4;
// Recursive Call: safe, all changes already made.
eventsHistory.emitIssue(_symbol, _value, _address(holderId));
_proxyTransferEvent(0, holderId, _value, _symbol);
return true;
}
/**
* Destroys specified amount of senders asset tokens.
*
* @param _symbol asset symbol.
* @param _value amount of tokens to destroy.
*
* @return success.
*/
function revokeAsset(bytes32 _symbol, uint _value) returns(bool) {
// Should have positive value.
if (_value == 0) {
_error("Cannot revoke 0 value");
return false;
}
Asset asset = assets[_symbol];
uint holderId = getHolderId(msg.sender);
// Should have enough tokens.
if (asset.wallets[holderId].balance < _value) {
_error("Not enough tokens to revoke");
return false;
}
asset.wallets[holderId].balance -= _value;
asset.totalSupply -= _value;
// Internal Out Of Gas/Throw: revert this transaction too;
// Call Stack Depth Limit reached: n/a after HF 4;
// Recursive Call: safe, all changes already made.
eventsHistory.emitRevoke(_symbol, _value, _address(holderId));
_proxyTransferEvent(holderId, 0, _value, _symbol);
return true;
}
/**
* Passes asset ownership to specified address.
*
* Only ownership is changed, balances are not touched.
* Can only be called by asset owner.
*
* @param _symbol asset symbol.
* @param _newOwner address to become a new owner.
*
* @return success.
*/
function changeOwnership(bytes32 _symbol, address _newOwner) onlyOwner(_symbol) returns(bool) {
Asset asset = assets[_symbol];
uint newOwnerId = _createHolderId(_newOwner);
// Should pass ownership to another holder.
if (asset.owner == newOwnerId) {
_error("Cannot pass ownership to oneself");
return false;
}
address oldOwner = _address(asset.owner);
asset.owner = newOwnerId;
// Internal Out Of Gas/Throw: revert this transaction too;
// Call Stack Depth Limit reached: n/a after HF 4;
// Recursive Call: safe, all changes already made.
eventsHistory.emitOwnershipChange(oldOwner, _address(newOwnerId), _symbol);
return true;
}
/**
* Check if specified holder trusts an address with recovery procedure.
*
* @param _from truster.
* @param _to trustee.
*
* @return trust existance.
*/
function isTrusted(address _from, address _to) constant returns(bool) {
return holders[getHolderId(_from)].trust[_to];
}
/**
* Trust an address to perform recovery procedure for the caller.
*
* @param _to trustee.
*
* @return success.
*/
function trust(address _to) returns(bool) {
uint fromId = _createHolderId(msg.sender);
// Should trust to another address.
if (fromId == getHolderId(_to)) {
_error("Cannot trust to oneself");
return false;
}
// Should trust to yet untrusted.
if (isTrusted(msg.sender, _to)) {
_error("Already trusted");
return false;
}
holders[fromId].trust[_to] = true;
return true;
}
/**
* Revoke trust to perform recovery procedure from an address.
*
* @param _to trustee.
*
* @return success.
*/
function distrust(address _to) checkTrust(msg.sender, _to) returns(bool) {
holders[getHolderId(msg.sender)].trust[_to] = false;
return true;
}
/**
* Perform recovery procedure.
*
* This function logic is actually more of an addAccess(uint _holderId, address _to).
* It grants another address access to recovery subject wallets.
* Can only be called by trustee of recovery subject.
*
* @param _from holder address to recover from.
* @param _to address to grant access to.
*
* @return success.
*/
function recover(address _from, address _to) checkTrust(_from, msg.sender) returns(bool) {
// Should recover to previously unused address.
if (getHolderId(_to) != 0) {
_error("Should recover to new address");
return false;
}
// We take current holder address because it might not equal _from.
// It is possible to recover from any old holder address, but event should have the current one.
address from = holders[getHolderId(_from)].addr;
holders[getHolderId(_from)].addr = _to;
holderIndex[_to] = getHolderId(_from);
// Internal Out Of Gas/Throw: revert this transaction too;
// Call Stack Depth Limit reached: revert this transaction too;
// Recursive Call: safe, all changes already made.
eventsHistory.emitRecovery(from, _to, msg.sender);
return true;
}
/**
* Sets asset spending allowance for a specified spender.
*
* Note: to revoke allowance, one needs to set allowance to 0.
*
* @param _spenderId holder id to set allowance for.
* @param _value amount to allow.
* @param _symbol asset symbol.
* @param _senderId approve initiator holder id.
*
* @return success.
*/
function _approve(uint _spenderId, uint _value, bytes32 _symbol, uint _senderId) internal returns(bool) {
// Asset should exist.
if (!isCreated(_symbol)) {
_error("Asset is not issued");
return false;
}
// Should allow to another holder.
if (_senderId == _spenderId) {
_error("Cannot approve to oneself");
return false;
}
assets[_symbol].wallets[_senderId].allowance[_spenderId] = _value;
// Internal Out Of Gas/Throw: revert this transaction too;
// Call Stack Depth Limit reached: revert this transaction too;
// Recursive Call: safe, all changes already made.
eventsHistory.emitApprove(_address(_senderId), _address(_spenderId), _symbol, _value);
if (proxies[_symbol] != 0x0) {
// Internal Out Of Gas/Throw: revert this transaction too;
// Call Stack Depth Limit reached: n/a after HF 4;
// Recursive Call: safe, all changes already made.
Proxy(proxies[_symbol]).emitApprove(_address(_senderId), _address(_spenderId), _value);
}
return true;
}
/**
* Sets asset spending allowance for a specified spender.
*
* Can only be called by asset proxy.
*
* @param _spender holder address to set allowance to.
* @param _value amount to allow.
* @param _symbol asset symbol.
* @param _sender approve initiator address.
*
* @return success.
*/
function proxyApprove(address _spender, uint _value, bytes32 _symbol, address _sender) onlyProxy(_symbol) returns(bool) {
return _approve(_createHolderId(_spender), _value, _symbol, _createHolderId(_sender));
}
/**
* Returns asset allowance from one holder to another.
*
* @param _from holder that allowed spending.
* @param _spender holder that is allowed to spend.
* @param _symbol asset symbol.
*
* @return holder to spender allowance.
*/
function allowance(address _from, address _spender, bytes32 _symbol) constant returns(uint) {
return _allowance(getHolderId(_from), getHolderId(_spender), _symbol);
}
/**
* Returns asset allowance from one holder to another.
*
* @param _fromId holder id that allowed spending.
* @param _toId holder id that is allowed to spend.
* @param _symbol asset symbol.
*
* @return holder to spender allowance.
*/
function _allowance(uint _fromId, uint _toId, bytes32 _symbol) constant internal returns(uint) {
return assets[_symbol].wallets[_fromId].allowance[_toId];
}
/**
* Prforms allowance transfer of asset balance between holders wallets.
*
* Can only be called by asset proxy.
*
* @param _from holder address to take from.
* @param _to holder address to give to.
* @param _value amount to transfer.
* @param _symbol asset symbol.
* @param _reference transfer comment to be included in a Transfer event.
* @param _sender allowance transfer initiator address.
*
* @return success.
*/
function proxyTransferFromWithReference(address _from, address _to, uint _value, bytes32 _symbol, string _reference, address _sender) onlyProxy(_symbol) returns(bool) {
return _transfer(getHolderId(_from), _createHolderId(_to), _value, _symbol, _reference, getHolderId(_sender));
}
}
contract ChronoBankAsset {
function __transferWithReference(address _to, uint _value, string _reference, address _sender) returns(bool);
function __transferFromWithReference(address _from, address _to, uint _value, string _reference, address _sender) returns(bool);
function __approve(address _spender, uint _value, address _sender) returns(bool);
function __process(bytes _data, address _sender) payable {
throw;
}
}
contract ERC20 {
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed from, address indexed spender, uint256 value);
function totalSupply() constant returns (uint256 supply);
function balanceOf(address _owner) constant returns (uint256 balance);
function transfer(address _to, uint256 _value) returns (bool success);
function transferFrom(address _from, address _to, uint256 _value) returns (bool success);
function approve(address _spender, uint256 _value) returns (bool success);
function allowance(address _owner, address _spender) constant returns (uint256 remaining);
}
contract ChronoBankAssetProxy is ERC20 {
// Assigned platform, immutable.
ChronoBankPlatform public chronoBankPlatform;
// Assigned symbol, immutable.
bytes32 smbl;
// Assigned name, immutable.
string public name;
string public symbol;
/**
* Sets platform address, assigns symbol and name.
*
* Can be set only once.
*
* @param _chronoBankPlatform platform contract address.
* @param _symbol assigned symbol.
* @param _name assigned name.
*
* @return success.
*/
function init(ChronoBankPlatform _chronoBankPlatform, string _symbol, string _name) returns(bool) {
if (address(chronoBankPlatform) != 0x0) {
return false;
}
chronoBankPlatform = _chronoBankPlatform;
symbol = _symbol;
smbl = stringToBytes32(_symbol);
name = _name;
return true;
}
function stringToBytes32(string memory source) returns (bytes32 result) {
assembly {
result := mload(add(source, 32))
}
}
/**
* Only platform is allowed to call.
*/
modifier onlyChronoBankPlatform() {
if (msg.sender == address(chronoBankPlatform)) {
_;
}
}
/**
* Only current asset owner is allowed to call.
*/
modifier onlyAssetOwner() {
if (chronoBankPlatform.isOwner(msg.sender, smbl)) {
_;
}
}
/**
* Returns asset implementation contract for current caller.
*
* @return asset implementation contract.
*/
function _getAsset() internal returns(ChronoBankAsset) {
return ChronoBankAsset(getVersionFor(msg.sender));
}
/**
* Returns asset total supply.
*
* @return asset total supply.
*/
function totalSupply() constant returns(uint) {
return chronoBankPlatform.totalSupply(smbl);
}
/**
* Returns asset balance for a particular holder.
*
* @param _owner holder address.
*
* @return holder balance.
*/
function balanceOf(address _owner) constant returns(uint) {
return chronoBankPlatform.balanceOf(_owner, smbl);
}
/**
* Returns asset allowance from one holder to another.
*
* @param _from holder that allowed spending.
* @param _spender holder that is allowed to spend.
*
* @return holder to spender allowance.
*/
function allowance(address _from, address _spender) constant returns(uint) {
return chronoBankPlatform.allowance(_from, _spender, smbl);
}
/**
* Returns asset decimals.
*
* @return asset decimals.
*/
function decimals() constant returns(uint8) {
return chronoBankPlatform.baseUnit(smbl);
}
/**
* Transfers asset balance from the caller to specified receiver.
*
* @param _to holder address to give to.
* @param _value amount to transfer.
*
* @return success.
*/
function transfer(address _to, uint _value) returns(bool) {
return _transferWithReference(_to, _value, "");
}
/**
* Transfers asset balance from the caller to specified receiver adding specified comment.
*
* @param _to holder address to give to.
* @param _value amount to transfer.
* @param _reference transfer comment to be included in a platform's Transfer event.
*
* @return success.
*/
function transferWithReference(address _to, uint _value, string _reference) returns(bool) {
return _transferWithReference(_to, _value, _reference);
}
/**
* Resolves asset implementation contract for the caller and forwards there arguments along with
* the caller address.
*
* @return success.
*/
function _transferWithReference(address _to, uint _value, string _reference) internal returns(bool) {
return _getAsset().__transferWithReference(_to, _value, _reference, msg.sender);
}
/**
* Performs transfer call on the platform by the name of specified sender.
*
* Can only be called by asset implementation contract assigned to sender.
*
* @param _to holder address to give to.
* @param _value amount to transfer.
* @param _reference transfer comment to be included in a platform's Transfer event.
* @param _sender initial caller.
*
* @return success.
*/
function __transferWithReference(address _to, uint _value, string _reference, address _sender) onlyAccess(_sender) returns(bool) {
return chronoBankPlatform.proxyTransferWithReference(_to, _value, smbl, _reference, _sender);
}
/**
* Prforms allowance transfer of asset balance between holders.
*
* @param _from holder address to take from.
* @param _to holder address to give to.
* @param _value amount to transfer.
*
* @return success.
*/
function transferFrom(address _from, address _to, uint _value) returns(bool) {
return _transferFromWithReference(_from, _to, _value, "");
}
/**
* Prforms allowance transfer of asset balance between holders adding specified comment.
*
* @param _from holder address to take from.
* @param _to holder address to give to.
* @param _value amount to transfer.
* @param _reference transfer comment to be included in a platform's Transfer event.
*
* @return success.
*/
function transferFromWithReference(address _from, address _to, uint _value, string _reference) returns(bool) {
return _transferFromWithReference(_from, _to, _value, _reference);
}
/**
* Resolves asset implementation contract for the caller and forwards there arguments along with
* the caller address.
*
* @return success.
*/
function _transferFromWithReference(address _from, address _to, uint _value, string _reference) internal returns(bool) {
return _getAsset().__transferFromWithReference(_from, _to, _value, _reference, msg.sender);
}
/**
* Performs allowance transfer call on the platform by the name of specified sender.
*
* Can only be called by asset implementation contract assigned to sender.
*
* @param _from holder address to take from.
* @param _to holder address to give to.
* @param _value amount to transfer.
* @param _reference transfer comment to be included in a platform's Transfer event.
* @param _sender initial caller.
*
* @return success.
*/
function __transferFromWithReference(address _from, address _to, uint _value, string _reference, address _sender) onlyAccess(_sender) returns(bool) {
return chronoBankPlatform.proxyTransferFromWithReference(_from, _to, _value, smbl, _reference, _sender);
}
/**
* Sets asset spending allowance for a specified spender.
*
* @param _spender holder address to set allowance to.
* @param _value amount to allow.
*
* @return success.
*/
function approve(address _spender, uint _value) returns(bool) {
return _approve(_spender, _value);
}