/
ico_template.py
274 lines (197 loc) · 7.59 KB
/
ico_template.py
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
"""
NEX ICO Template
===================================
Author: Thomas Saunders
Email: tom@neonexchange.org
Date: Dec 11 2017
Narrative Updates:
Author: Brian Lenz
Email: brian@narrative.network
Date: Jan 27 2018
"""
from boa.blockchain.vm.Neo.Runtime import GetTrigger, CheckWitness, Notify
from boa.blockchain.vm.Neo.TriggerType import Application, Verification
from nrve.common.storage import StorageAPI
from nrve.common.txio import Attachments,get_asset_attachments
from nrve.token.nrvetoken import Token
from nrve.token.nep5 import NEP5Handler
from nrve.token.crowdsale import Crowdsale
def Main(operation, args):
"""
:param operation: str The name of the operation to perform
:param args: list A list of arguments along with the operation
:return:
bytearray: The result of the operation
"""
trigger = GetTrigger()
token = Token()
# This is used in the Verification portion of the contract
# To determine whether a transfer of system assets (NEO/Gas) involving
# This contract's address can proceed
if trigger == Verification:
storage = StorageAPI()
owner = storage.get(token.owner_key)
if owner:
# If the invoker is the owner of this contract, proceed
if CheckWitness(owner):
return True
else:
# check original_owner if not deployed yet (i.e. no owner in storage)
if CheckWitness(token.original_owner):
return True
# Otherwise, we need to lookup the assets and determine
# If attachments of assets is ok
attachments = get_asset_attachments() # type:Attachments
crowdsale = Crowdsale()
# the exchange will be allowed if the number of tokens to convert to is greater than zero.
# zero indicates that there is a reason this contribution will not be allowed
return crowdsale.check_and_calculate_tokens(token, attachments, storage, True) > 0
elif trigger == Application:
if operation != None:
nep = NEP5Handler()
for op in nep.get_methods():
if operation == op:
return nep.handle_nep51(operation, args, token)
if operation == 'deploy':
return deploy(token)
if operation == 'circulation':
storage = StorageAPI()
return token.get_circulation(storage)
sale = Crowdsale()
if operation == 'mintTokens':
return sale.exchange(token)
if operation == 'crowdsale_register':
return sale.kyc_register(args, token)
if operation == 'crowdsale_deregister':
return sale.kyc_deregister(args, token)
if operation == 'crowdsale_status':
return sale.kyc_status(args)
if operation == 'crowdsale_available':
return token.crowdsale_available_amount()
if operation == 'transfer_presale_tokens':
return sale.transfer_presale_tokens(token, args)
if operation == 'transfer_team_tokens':
return sale.transfer_team_tokens(token, args)
if operation == 'transfer_company_tokens':
return sale.transfer_company_tokens(token, args)
if operation == 'mint_rewards_tokens':
return sale.mint_rewards_tokens(token, args)
if operation == 'change_owner':
new_owner = args[0]
return change_owner(token, new_owner)
if operation == 'accept_owner':
return accept_owner(token)
if operation == 'cancel_change_owner':
return cancel_change_owner(token)
if operation == 'start_public_sale':
return sale.start_public_sale(token)
if operation == 'pause_sale':
return pause_sale(token)
if operation == 'resume_sale':
return resume_sale(token)
return 'unknown operation'
return False
def deploy(token: Token):
"""
:param token: Token The token to deploy
:return:
bool: Whether the operation was successful
"""
if not CheckWitness(token.original_owner):
print("Must be original_owner to deploy")
return False
storage = StorageAPI()
# can only deploy once, so if we already have an owner, no-op
if storage.get(token.owner_key):
return False
# mark the current owner, which can be changed later
storage.put(token.owner_key, token.original_owner)
return True
def change_owner(token: Token, new_owner):
"""
Record a transfer request to a new owner. The new owner must accept the request via accept_owner
:param token: Token The token to change the owner for
:param new_owner: the new owner of the contract
:return:
bool: Whether the operation was successful
"""
storage = StorageAPI()
owner = storage.get(token.owner_key)
if not owner:
print("Must deploy before changing owner")
return False
if not CheckWitness(owner):
print("Must be owner to change owner")
return False
# setup the new owner. will need to be accepted by the new owner in order to finalize
storage.put(token.new_owner_key, new_owner)
return True
def cancel_change_owner(token: Token):
"""
Cancel a pending ownership transfer request
:param token: Token The token to cancel the ownership transfer for
:return:
bool: Whether the operation was successful
"""
storage = StorageAPI()
new_owner = storage.get(token.new_owner_key)
if not new_owner:
print("Can't cancel_change_owner unless an owner change is already pending")
return False
owner = storage.get(token.owner_key)
if not CheckWitness(owner):
print("Must be owner to cancel change_owner")
return False
# delete the new owner to cancel the transfer.
storage.delete(token.new_owner_key)
return True
def accept_owner(token: Token):
"""
Change the owner of this smart contract who will be able to perform protected operations
:param token: Token The token to change the owner for
:return:
bool: Whether the operation was successful
"""
storage = StorageAPI()
new_owner = storage.get(token.new_owner_key)
if not new_owner:
print("Must call change_owner before accept_owner")
return False
if not CheckWitness(new_owner):
print("Must be new_owner to accept owner")
return False
# setup the new owner.
storage.put(token.owner_key, new_owner)
# now that it's accepted, make the change official by removing the pending new_owner
storage.delete(token.new_owner_key)
return True
def pause_sale(token: Token):
"""
Pause the sale
:param token: Token The token of the sale to pause
:return:
bool: Whether the operation was successful
"""
storage = StorageAPI()
owner = storage.get(token.owner_key)
if not CheckWitness(owner):
print("Must be owner to pause sale")
return False
# mark the sale as paused
storage.put(token.sale_paused_key, True)
return True
def resume_sale(token: Token):
"""
Resume the sale
:param token: Token The token of the sale to resume
:return:
bool: Whether the operation was successful
"""
storage = StorageAPI()
owner = storage.get(token.owner_key)
if not CheckWitness(owner):
print("Must be owner to resume sale")
return False
# mark the sale as active
storage.delete(token.sale_paused_key)
return True