def Main(operation, args): trigger = GetTrigger() token = Token() if trigger == Verification: is_owner = CheckWitness(token.owner) if is_owner: return True attachments = get_asset_attachments() storage = StorageAPI() crowdsale = Crowdsale() return crowdsale.can_exchange(token, attachments, storage, True) 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_status': return sale.kyc_status(args) if operation == 'crowdsale_available': return token.crowdsale_available_amount() return 'unknown operation' return False
def exchange(self, token: Token): attachments = get_asset_attachments() storage = StorageAPI() can_exchange = self.can_exchange(token, attachments, storage, False) if not can_exchange: print("Cannot exchange value") if attachments.neo_attached > 0: OnRefund(attachments.sender_addr, attachments.neo_attached) return False current_balance = storage.get(attachments.sender_addr) exchanged_tokens = attachments.neo_attached * token.tokens_per_neo / 100000000 new_total = exchanged_tokens + current_balance storage.put(attachments.sender_addr, new_total) token.add_to_circulation(exchanged_tokens, storage) OnTransfer(attachments.receiver_addr, attachments.sender_addr, exchanged_tokens) return True
def kyc_register(self, args, token:Token): """ :param args:List Eine Liste der Adressen die zu registrieren sind :param token:Token Ein Token Objekt mit Ihren ICO Einstellungen :return: int: Die Nummer der Adressen die mit KYC registriert werden """ ok_count = 0 if CheckWitness(token.owner): for address in args: if len(address) == 20: storage = StorageAPI() kyc_storage_key = concat(self.kyc_key, address) storage.put(kyc_storage_key, True) OnKYCRegister(address) ok_count += 1 return ok_count
def crowdfunding_get_members(crowdfunding_address): storage = StorageAPI() crowdfunding_meta_key = storage.get_crowdfunding_members_key( crowdfunding_address) print(crowdfunding_meta_key) # Check if this address or crowdfunding_meta already exists addresses = storage.get(crowdfunding_meta_key) if len(addresses) == 0: print("Error: address does not belong to a crowdfunding") return False n = len(addresses) num_addresses = n / 20 msg = ["Crowdfunding found. Members:", num_addresses] Notify(msg) address_list = [] i = 0 while i < num_addresses: addr = addresses[0:20] addresses = addresses[20:] address_list.append(addr) i += 1 return address_list
def kyc_register(self, args, token: Token): """ :param args:list a list of addresses to register :param token:Token A token object with your ICO settings :return: int: The number of addresses to register for KYC """ ok_count = 0 if CheckWitness(token.owner): for address in args: if len(address) == 20: storage = StorageAPI() kyc_storage_key = concat(self.kyc_key, address) storage.put(kyc_storage_key, True) OnKYCRegister(address) ok_count += 1 return ok_count
def AddOracle(self, args): storage = StorageAPI() isValidOwner = self.ValidateOwner() if isValidOwner == False: return False isValidLength = ValidateArgsLength(args, 1) if isValidLength == False: return False oracleID = args[0] oracleKey = concat(self.oracle_prefix, oracleID) isOracle = storage.get(oracleKey) if isOracle == True: Log("Address is already an oracle") return False oracleCount = storage.get(self.oracle_count_key) newCount = oracleCount + 1 storage.put(oracleKey, True) storage.put(self.oracle_count_key, newCount) OnOracleAdded(oracleID, newCount) return True
def PlaceBet(self, args, sender): storage = StorageAPI() user = GetUser(storage, sender, True) if user.isUser == False: return False isValidLength = ValidateArgsLength(args, 5) if isValidLength == False: return False isValidBet = self.ValidateNewBet(user, args) if isValidBet == False: return False bet = InitialiseNewBet(storage, args) user.RemoveFromBalance(storage, bet.betAmount) storage.put(bet.betAmountKey, bet.betAmount) storage.put(bet.unmatchedAmountKey, bet.returnAmount) storage.put(bet.betMakerKey, sender) storage.put(bet.statusKey, "valid") OnBetAdded(bet.betID, sender, args, bet.betIndex) return True
def handle_nep51(self, operation, args, token: Token): # these first 3 don't require get ctx if operation == 'name': return token.name elif operation == 'decimals': return token.decimals elif operation == 'symbol': return token.symbol storage = StorageAPI() arg_error = 'Incorrect Arg Length' if operation == 'totalSupply': return storage.get(token.in_circulation_key) elif operation == 'balanceOf': if len(args) == 1: account = args[0] return storage.get(account) return arg_error elif operation == 'transfer': if len(args) == 3: t_from = args[0] t_to = args[1] t_amount = args[2] return self.do_transfer(storage, t_from, t_to, t_amount) return arg_error elif operation == 'transferFrom': if len(args) == 3: t_from = args[0] t_to = args[1] t_amount = args[2] return self.do_transfer_from(storage, t_from, t_to, t_amount) return arg_error elif operation == 'approve': if len(args) == 3: t_owner = args[0] t_spender = args[1] t_amount = args[2] return self.do_approve(storage, t_owner, t_spender, t_amount) return arg_error elif operation == 'allowance': if len(args) == 2: t_owner = args[0] t_spender = args[1] return self.do_allowance(storage, t_owner, t_spender) return arg_error return False
def level_of(address): """ Return the level of the user who owns the address. """ storage = StorageAPI() level_key = storage.get_level_key(address) stored_level = storage.get(level_key) return stored_level
def is_crowdfunding_address(crowdfunding_address): storage = StorageAPI() crowdfunding_meta_key = storage.get_crowdfunding_members_key( crowdfunding_address) addresses = storage.get(crowdfunding_meta_key) if len(addresses) == 0: return False return True
def calculate_can_exchange(self, token: Token, amount: int, address, verify_only: bool): """ Perform custom token exchange calculations here. :param token:Token The token settings for the sale :param amount:int Number of tokens to convert from asset to tokens :param address:bytearray The address to mint the tokens to :return: bool: Whether or not an address can exchange a specified amount """ height = GetHeight() storage = StorageAPI() current_in_circulation = storage.get(token.in_circulation_key) new_amount = current_in_circulation + amount if new_amount > token.total_supply: print("amount greater than total supply") return False print("trying to calculate height????") if height < token.block_sale_start: print("sale not begun yet") return False # if we are in free round, any amount if height > token.limited_round_end: print("Free for all, accept as much as possible") return True # check amount in limited round if amount <= token.max_exchange_limited_round: # check if they have already exchanged in the limited round r1key = concat(address, self.limited_round_key) has_exchanged = storage.get(r1key) # if not, then save the exchange for limited round if not has_exchanged: # note that this method can be invoked during the Verification trigger, so we have the # verify_only param to avoid the Storage.Put during the read-only Verification trigger. # this works around a "method Neo.Storage.Put not found in ->" error in InteropService.py # since Verification is read-only and thus uses a StateReader, not a StateMachine if not verify_only: storage.put(r1key, True) return True print("already exchanged in limited round") return False print("too much for limited round") return False
def level_up(address): """ Loop up the level of the owner of address. Then raise it by 1, put it back into storage and return the new value. """ storage = StorageAPI() level_key = storage.get_level_key(address) level = level_of(level_key) new_level = level + 1 storage.put(level_key, new_level) return new_level
def crowdsale_available_amount(self): """ :return: int Der Betrag der Tokens der für den Crowdsale Verkauf übrig ist """ storage = StorageAPI() in_circ = storage.get(self.in_circulation_key) available = self.total_supply - in_circ return available
def kyc_status(self, args): storage = StorageAPI() if len(args) > 0: addr = args[0] kyc_storage_key = concat(self.kyc_key, addr) return storage.get(kyc_storage_key) return False
def crowdsale_available_amount(self): """ :return: int The amount of tokens left for sale in the crowdsale """ storage = StorageAPI() in_circ = storage.get(self.in_circulation_key) available = self.total_supply - in_circ return available
def calculate_can_exchange(self, token: Token, amount: int, address): """ Führt benutzerdefinierte Token exchange Kalkulationen aus. :param token:Token Die Token Einstellungen für den Verkauf :param amount:int Nummer der Tokens die von Asset zu Tokens konvertiert werden :param address:bytearray Die Adresse wo die Tokens erzeugt werden sollen :return: bool: Ob eine Adresse einen bestimmten Betrag tauschen kann oder nicht """ height = GetHeight() storage = StorageAPI() current_in_circulation = storage.get(token.in_circulation_key) new_amount = current_in_circulation + amount if new_amount > token.total_supply: # print("amount greater than total supply") return False if height < token.block_sale_start: # print("sale not begun yet") return False # Ob wir in einer freien Runde sind, jeder Betrag if height > token.limited_round_end: # print("Free for all, accept as much as possible") return True # Überprüfe Betrag in einer limitierten Runde if amount <= token.max_exchange_limited_round: # Überprüfe ob die Adresse bereits in einer limitierten Runde teilgenommen haben r1key = concat(address, self.limited_round_key) has_exchanged = storage.get(r1key) # falls nicht, dann sichere den exchange für die limitierte Runde if not has_exchanged: storage.put(r1key, True) return True print("already exchanged in limited round") return False print("too much for limited round") return False
def calculate_can_exchange(self, token: Token, amount: int, address): """ Perform custom token exchange calculations here. :param token:Token The token settings for the sale :param amount:int Number of tokens to convert from asset to tokens :param address:bytearray The address to mint the tokens to :return: bool: Whether or not an address can exchange a specified amount """ height = GetHeight() storage = StorageAPI() current_in_circulation = storage.get(token.in_circulation_key) new_amount = current_in_circulation + amount if new_amount > token.total_supply: print("amount greater than total supply") return False print("trying to calculate height????") if height < token.block_sale_start: print("sale not begun yet") return False # if we are in free round, any amount if height > token.limited_round_end: print("Free for all, accept as much as possible") return True # check amount in limited round if amount <= token.max_exchange_limited_round: # check if they have already exchanged in the limited round r1key = concat(address, self.limited_round_key) has_exchanged = storage.get(r1key) # if not, then save the exchange for limited round if not has_exchanged: storage.put(r1key, True) return True print("already exchanged in limited round") return False print("too much for limited round") return False
def UpdateEventOutcome(self, args, oracleID): storage = StorageAPI() isValidSender = self.ValidateOracle(storage, oracleID) if isValidSender == False: return False isValidLength = ValidateArgsLength(args, 2) if isValidLength == False: return False eventID = args[0] outcome = args[1] eventKey = concat(self.event_prefix, eventID) event = storage.get(eventKey) if event != "active": msg1 = concat("Cannot update event: ", eventID) msg2 = concat(", Event state is currently: ", event) msg = concat(msg1, msg2) Log(msg) return False oracleSuffix = concat(self.outcome_oracle_prefix, oracleID) countSuffix = concat(self.outcome_count_prefix, outcome) oracleKey = concat(eventKey, oracleSuffix) countKey = concat(eventKey, countSuffix) reachedConsensus = self.CheckEventConsensus(storage, oracleKey, countKey) if reachedConsensus == False: OnEventOutcomeConsensus(eventID, oracleID) else: if outcome == "void": storage.put(eventKey, "void") else: outcomeKey = concat(eventKey, "/outcome") storage.put(outcomeKey, outcome) storage.put(eventKey, "finished") OnEventOutcomeConfirmed(eventID, outcome, oracleID) return True
def exchange(self, token: Token): """ :param token:Token The token object with NEP5/sale settings :return: bool: Whether the exchange was successful """ attachments = get_asset_attachments() # type: Attachments storage = StorageAPI() # this looks up whether the exchange can proceed can_exchange = self.can_exchange(token, attachments, storage, False) if not can_exchange: print("Cannot exchange value") # This should only happen in the case that there are a lot of TX on the final # block before the total amount is reached. An amount of TX will get through # the verification phase because the total amount cannot be updated during that phase # because of this, there should be a process in place to manually refund tokens if attachments.neo_attached > 0: OnRefund(attachments.sender_addr, attachments.neo_attached) # if you want to exchange gas instead of neo, use this #if attachments.gas_attached > 0: # OnRefund(attachments.sender_addr, attachments.gas_attached) return False # lookup the current balance of the address current_balance = storage.get(attachments.sender_addr) # calculate the amount of tokens the attached neo will earn exchanged_tokens = attachments.neo_attached * token.tokens_per_neo / 100000000 # if you want to exchange gas instead of neo, use this # exchanged_tokens += attachments.gas_attached * token.tokens_per_gas / 100000000 # add it to the the exchanged tokens and persist in storage new_total = exchanged_tokens + current_balance storage.put(attachments.sender_addr, new_total) # update the in circulation amount token.add_to_circulation(exchanged_tokens, storage) # dispatch transfer event OnTransfer(attachments.receiver_addr, attachments.sender_addr, exchanged_tokens) return True
def deploy(token: Token): if not CheckWitness(token.owner): print("Must be owner to deploy") return False storage = StorageAPI() if not storage.get('initialized'): storage.put('initialized', 1) storage.put(token.owner, token.initial_amount) token.add_to_circulation(token.initial_amount, storage) return True return False
def InitialiseContract(self): storage = StorageAPI() isValidOwner = self.ValidateOwner() if isValidOwner == False: return False isInitialised = storage.get(self.admin_init_key) if isInitialised: Log("Contract has already been initialised") return False storage.put(self.admin_init_key, True) return True
def crowdfunding_create(args): """ args: 0: crowdfunding address 1..n: member addresses """ print("Create a crowdfunding") storage = StorageAPI() crowdfunding_address = args[0] crowdfunding_meta_key = storage.get_crowdfunding_members_key( crowdfunding_address) print(crowdfunding_meta_key) # Check for minimum number of arguments nargs = len(args) if nargs < 3: print( "Error: need at least 3 arguments: (1) crowdfunding address, (2+3) member addresses" ) return False # Check if this address or crowdfunding_meta already exists balance = storage.get(crowdfunding_address) if len(balance) > 0: print("Error: address is already in use") return False meta = storage.get(crowdfunding_meta_key) if len(meta) > 0: print("Error: crowdfunding is already setup") return False # Build list of addresses to store in meta key print("Build list of addresses") nargs = len(args) member_addresses = args[1] print(member_addresses) i = 2 while i < nargs: member_address = args[i] print(member_address) i += 1 member_addresses = concat(member_addresses, member_address) storage.put(crowdfunding_meta_key, member_addresses) print("Created the crowdfunding with those member addresses") print(member_addresses)
def AddEvent(self, args, oracleID): storage = StorageAPI() isValidSender = self.ValidateOracle(storage, oracleID) if isValidSender == False: return False isValidLength = ValidateArgsLength(args, 7) if isValidLength == False: return False eventID = CreateEventID(args) eventKey = concat(self.event_prefix, eventID) event = storage.get(eventKey) if event == False: _ = StoreEventDetails(storage, eventKey, args) event = "pending" OnNewEventAdded(eventID, oracleID, args) if event == "pending": oracleKey = concat(eventKey, oracleID) countKey = concat(eventKey, "/count") reachedConsensus = self.CheckEventConsensus( storage, oracleKey, countKey) if reachedConsensus == False: OnNewEventConsensus(eventID, oracleID) else: storage.put(eventKey, "active") OnNewEventConfirmed(eventID, oracleID) return True else: msg1 = concat("Consensus has finished for: ", eventID) msg2 = concat(", Event state is currently: ", event) msg = concat(msg1, msg2) Log(msg) return False
def exchange(self, token: Token): """ :param token:Token Das Token Objekt mit NEP5/sale Einstellungen :return: bool: Ob der exchange erfolgreich war """ attachments = get_asset_attachments() # type: Attachments storage = StorageAPI() # Dies überprüft ob der exchange ausgeführt werden kann can_exchange = self.can_exchange(token, attachments, storage) if not can_exchange: print("Cannot exchange value") # Dies sollte nur passieren im Fall das viele TX auf dem Final Block sind bevor # der total amount erreicht ist. Nur eine Teilmenge der TX wird durch die Verification # Phase kommen und da die Gesamtmenge während dieser Phase nicht erhöht werden kann, # sollte es einen Prozess zur manuellen Erstattung der Tokens geben. OnRefund(attachments.sender_addr, attachments.neo_attached) return False # Suche den aktuellen Kontostand einer Adresse current_balance = storage.get(attachments.sender_addr) # Kalkuliere den Wert an Tokens die die angehängten NEO Wert sind exchanged_tokens = attachments.neo_attached * token.tokens_per_neo / 100000000 # Wenn Sie anstatt Neo, Gas verwenden wollen benutzen Sie dies hier # exchanged_tokens += attachments.gas_attached * token.tokens_per_gas / 100000000 # Fügen Sie die erhaltenen Tokens zu dem Persisten Storage hinzu new_total = exchanged_tokens + current_balance storage.put(attachments.sender_addr, new_total) # Updaten Sie den im Umlauf befindenden Wert token.add_to_circulation(exchanged_tokens, storage) # Dispatch Transfer Event OnTransfer(attachments.receiver_addr, attachments.sender_addr, exchanged_tokens) return True
def reward_user(address): """ Raise the user level corresponding to address and reward him/her. """ token = Token() if not CheckWitness(token.owner): print("Must be owner to reward") return False nep = NEP5Handler() storage = StorageAPI() level = level_up( address ) ### you might wanna just set this constant for debugging purposes reward = calculate_reward(level) success = nep.do_transfer(storage, token.owner, address, reward) return success
def kyc_status(self, args): """ Gets the KYC Status of an address :param args:list a list of arguments :return: bool: Returns the kyc status of an address """ storage = StorageAPI() if len(args) > 0: addr = args[0] kyc_storage_key = concat(self.kyc_key, addr) return storage.get(kyc_storage_key) return False
def kyc_status(self, args): """ Gibt den KYC Status einer Adresse aus :param args:list Eine Liste mit Argumenten :return: bool: Gibt den KYC Status einer Adresse aus """ storage = StorageAPI() if len(args) > 0: addr = args[0] kyc_storage_key = concat(self.kyc_key, addr) return storage.get(kyc_storage_key) return False
def calculate_reward(address): """ Apply the calculation function for the user reward. """ storage = StorageAPI() level_key = storage.get_level_key(address) level = level_of(address) bonus_factor = 1 if level > 1: bonus_factor = 2 if level > 3: bonus_factor = 5 if level > 9: bonus_factor = 20 basic_reward = 100000000 reward = basic_reward * bonus_factor return reward
def kyc_register(self, args, token: Token): ok_count = 0 if CheckWitness(token.owner): for address in args: if len(address) == 20: storage = StorageAPI() kyc_storage_key = concat(self.kyc_key, address) storage.put(kyc_storage_key, True) OnKYCRegister(address) ok_count += 1 return ok_count
def InitialiseContract(self): storage = StorageAPI() isValidOwner = self.ValidateOwner() if isValidOwner == False: return False isInitialised = storage.get(self.admin_init_key) if isInitialised: Log("Contract has already been initialised") return False oracleKey = concat(self.oracle_prefix, self.OWNER) storage.put(oracleKey, True) storage.put(self.oracle_count_key, 1) storage.put(self.oracle_consensus_key, 70) storage.put(self.admin_init_key, True) return True