1
+ pragma solidity ^ 0.4.17 ;
2
+ contract TicketPro
3
+ {
4
+ mapping (address => bytes32 []) inventory;
5
+ uint16 ticketIndex = 0 ; //to track mapping in tickets
6
+ address organiser;
7
+ address paymaster;
8
+ uint numOfTransfers = 0 ;
9
+ string public name;
10
+ string public symbol;
11
+ uint8 public constant decimals = 0 ; //no decimals as tickets cannot be split
12
+
13
+ event Transfer (address indexed _to , uint16 [] _indices );
14
+ event TransferFrom (address indexed _from , address indexed _to , uint16 [] _indices );
15
+ event Trade (address indexed seller , uint16 [] ticketIndices , uint8 v , bytes32 r , bytes32 s );
16
+ event PassTo (uint16 [] ticketIndices , uint8 v , bytes32 r , bytes32 s , address indexed recipient );
17
+
18
+ modifier organiserOnly ()
19
+ {
20
+ if (msg .sender != organiser) revert ();
21
+ else _;
22
+ }
23
+
24
+ modifier payMasterOnly ()
25
+ {
26
+ if (msg .sender != paymaster) revert ();
27
+ else _;
28
+ }
29
+
30
+ function () public { revert (); } //should not send any ether directly
31
+
32
+
33
+ constructor (
34
+ bytes32 [] tickets ,
35
+ string nameOfContract ,
36
+ string symbolForContract ,
37
+ address organiserAddr ,
38
+ address paymasterAddr ,
39
+ address recipientAddr ) public
40
+ {
41
+ name = nameOfContract;
42
+ symbol = symbolForContract;
43
+ organiser = organiserAddr;
44
+ paymaster = paymasterAddr;
45
+ inventory[recipientAddr] = tickets;
46
+ }
47
+
48
+ function getDecimals () public pure returns (uint )
49
+ {
50
+ return decimals;
51
+ }
52
+
53
+ // example: 0, [3, 4], 27, "0x9CAF1C785074F5948310CD1AA44CE2EFDA0AB19C308307610D7BA2C74604AE98", "0x23D8D97AB44A2389043ECB3C1FB29C40EC702282DB6EE1D2B2204F8954E4B451"
54
+ // price is encoded in the server and the msg.value is added to the message digest,
55
+ // if the message digest is thus invalid then either the price or something else in the message is invalid
56
+ function trade (uint256 expiry ,
57
+ uint16 [] ticketIndices ,
58
+ uint8 v ,
59
+ bytes32 r ,
60
+ bytes32 s ) public payable
61
+ {
62
+ //checks expiry timestamp,
63
+ //if fake timestamp is added then message verification will fail
64
+ require (expiry > block .timestamp || expiry == 0 );
65
+
66
+ bytes32 message = encodeMessage (msg .value , expiry, ticketIndices);
67
+ address seller = ecrecover (message, v, r, s);
68
+
69
+ for (uint i = 0 ; i < ticketIndices.length ; i++ )
70
+ { // transfer each individual tickets in the ask order
71
+ uint16 index = ticketIndices[i];
72
+ assert (inventory[seller][index] != bytes32 (0 )); // 0 means ticket gone.
73
+ inventory[msg .sender ].push (inventory[seller][index]);
74
+ // 0 means ticket gone.
75
+ delete inventory[seller][index];
76
+ }
77
+ seller.transfer (msg .value );
78
+
79
+ emit Trade (seller, ticketIndices, v, r, s);
80
+ }
81
+
82
+ function loadNewTickets (bytes32 [] tickets ) public organiserOnly
83
+ {
84
+ for (uint i = 0 ; i < tickets.length ; i++ )
85
+ {
86
+ inventory[organiser].push (tickets[i]);
87
+ }
88
+ }
89
+
90
+ function passTo (uint256 expiry ,
91
+ uint16 [] ticketIndices ,
92
+ uint8 v ,
93
+ bytes32 r ,
94
+ bytes32 s ,
95
+ address recipient ) public payMasterOnly
96
+ {
97
+ require (expiry > block .timestamp || expiry == 0 );
98
+ bytes32 message = encodeMessage (0 , expiry, ticketIndices);
99
+ address giver = ecrecover (message, v, r, s);
100
+ for (uint i = 0 ; i < ticketIndices.length ; i++ )
101
+ {
102
+ uint16 index = ticketIndices[i];
103
+ //needs to use revert as all changes should be reversed
104
+ //if the user doesnt't hold all the tickets
105
+ assert (inventory[giver][index] != bytes32 (0 ));
106
+ bytes32 ticket = inventory[giver][index];
107
+ inventory[recipient].push (ticket);
108
+ delete inventory[giver][index];
109
+ }
110
+
111
+ emit PassTo (ticketIndices, v, r, s, recipient);
112
+ }
113
+
114
+ //must also sign in the contractAddress
115
+ function encodeMessage (uint value , uint expiry , uint16 [] ticketIndices )
116
+ internal view returns (bytes32 )
117
+ {
118
+ bytes memory message = new bytes (84 + ticketIndices.length * 2 );
119
+ address contractAddress = getContractAddress ();
120
+ for (uint i = 0 ; i < 32 ; i++ )
121
+ { // convert bytes32 to bytes[32]
122
+ // this adds the price to the message
123
+ message[i] = byte (bytes32 (value << (8 * i)));
124
+ }
125
+
126
+ for (i = 0 ; i < 32 ; i++ )
127
+ {
128
+ message[i + 32 ] = byte (bytes32 (expiry << (8 * i)));
129
+ }
130
+
131
+ for (i = 0 ; i < 20 ; i++ )
132
+ {
133
+ message[64 + i] = byte (bytes20 (bytes20 (contractAddress) << (8 * i)));
134
+ }
135
+
136
+ for (i = 0 ; i < ticketIndices.length ; i++ )
137
+ {
138
+ // convert int[] to bytes
139
+ message[84 + i * 2 ] = byte (ticketIndices[i] >> 8 );
140
+ message[84 + i * 2 + 1 ] = byte (ticketIndices[i]);
141
+ }
142
+
143
+ return keccak256 (message);
144
+ }
145
+
146
+ function name () public view returns (string )
147
+ {
148
+ return name;
149
+ }
150
+
151
+ function symbol () public view returns (string )
152
+ {
153
+ return symbol;
154
+ }
155
+
156
+ function getAmountTransferred () public view returns (uint )
157
+ {
158
+ return numOfTransfers;
159
+ }
160
+
161
+ function balanceOf (address _owner ) public view returns (bytes32 [])
162
+ {
163
+ return inventory[_owner];
164
+ }
165
+
166
+ function myBalance () public view returns (bytes32 []){
167
+ return inventory[msg .sender ];
168
+ }
169
+
170
+ function transfer (address _to , uint16 [] ticketIndices ) public
171
+ {
172
+ for (uint i = 0 ; i < ticketIndices.length ; i++ )
173
+ {
174
+ uint index = uint (ticketIndices[i]);
175
+ assert (inventory[msg .sender ][index] != bytes32 (0 ));
176
+ //pushes each element with ordering
177
+ inventory[_to].push (inventory[msg .sender ][index]);
178
+ delete inventory[msg .sender ][index];
179
+ }
180
+ emit Transfer (_to, ticketIndices);
181
+ }
182
+
183
+ function transferFrom (address _from , address _to , uint16 [] ticketIndices )
184
+ organiserOnly public
185
+ {
186
+ for (uint i = 0 ; i < ticketIndices.length ; i++ )
187
+ {
188
+ uint index = uint (ticketIndices[i]);
189
+ assert (inventory[_from][index] != bytes32 (0 ));
190
+ //pushes each element with ordering
191
+ inventory[_to].push (inventory[msg .sender ][index]);
192
+ delete inventory[_from][index];
193
+ }
194
+
195
+ emit TransferFrom (_from, _to, ticketIndices);
196
+ }
197
+
198
+ function endContract () public organiserOnly
199
+ {
200
+ selfdestruct (organiser);
201
+ }
202
+
203
+ function isStormBirdContract () public pure returns (bool )
204
+ {
205
+ return true ;
206
+ }
207
+
208
+ function getContractAddress () public view returns (address )
209
+ {
210
+ return this ;
211
+ }
212
+
213
+ }
0 commit comments