def refund() -> bool: """ If the atomic swap didn't occur in time, refunds the cryptocurrency that was deposited in this smart contract :return: whether enough time has passed and the cryptocurrencies were refunded :rtype: bool """ if get_time > get(START_TIME).to_int() + LOCK_TIME: # Checking if OWNER transferred to this smart contract funded_crypto = get(FUNDED_PREFIX + OWNER).to_int() if funded_crypto != 0: call_contract(UInt160(get(TOKEN_PREFIX + OWNER)), 'transfer', [executing_script_hash, get(ADDRESS_PREFIX + OWNER), get(AMOUNT_PREFIX + OWNER)]) # Checking if OTHER_PERSON transferred to this smart contract funded_crypto = get(FUNDED_PREFIX + OTHER_PERSON).to_int() if funded_crypto != 0: call_contract(UInt160(get(TOKEN_PREFIX + OTHER_PERSON)), 'transfer', [executing_script_hash, get(ADDRESS_PREFIX + OTHER_PERSON), get(AMOUNT_PREFIX + OTHER_PERSON)]) put(FUNDED_PREFIX + OWNER, 0) put(FUNDED_PREFIX + OTHER_PERSON, 0) put(NOT_INITIALIZED, True) put(START_TIME, 0) return True return False
def cancel_pool(pool_id: UInt256): creator_on_storage = get(POOL_OWNER_KEY + pool_id) if len(creator_on_storage) == 0: raise Exception("Pool doesn't exist.") creator = UInt160(creator_on_storage) if not check_witness(creator): raise Exception('No authorization.') if len(get(POOL_RESULT_KEY + pool_id)) > 0: raise Exception('Pool is finished already') executing_contract = executing_script_hash # refund players bets_key_prefix = POOL_BET_KEY + pool_id bet = find(bets_key_prefix) while bet.next(): result_pair: List[bytes] = bet.value storage_key = result_pair[0] account = UInt160(storage_key[len(bets_key_prefix):]) transfer_gas(executing_contract, account, PRICE_IN_GAS) # set result put(POOL_RESULT_KEY + pool_id, serialize('Cancelled by owner'))
def refund() -> bool: """ If the atomic swap didn't occur in time, refunds the cryptocurrency that was deposited in this smart contract :return: whether enough time has passed and the cryptocurrencies were refunded :rtype: bool """ if runtime.time > storage.get(START_TIME).to_int() + LOCK_TIME: # Checking if PERSON_A transferred to this smart contract funded_crypto = storage.get(FUNDED_PREFIX + PERSON_A).to_int() if funded_crypto != 0: call_contract(UInt160( storage.get(TOKEN_PREFIX + PERSON_A)), 'transfer', [ runtime.executing_script_hash, UInt160(storage.get(ADDRESS_PREFIX + PERSON_A)), storage.get(AMOUNT_PREFIX + PERSON_A).to_int(), None ]) # Checking if PERSON_B transferred to this smart contract funded_crypto = storage.get(FUNDED_PREFIX + PERSON_B).to_int() if funded_crypto != 0: call_contract(UInt160( storage.get(TOKEN_PREFIX + PERSON_B)), 'transfer', [ runtime.executing_script_hash, storage.get(ADDRESS_PREFIX + PERSON_B), storage.get(AMOUNT_PREFIX + PERSON_B).to_int(), None ]) storage.put(FUNDED_PREFIX + PERSON_A, 0) storage.put(FUNDED_PREFIX + PERSON_B, 0) storage.put(NOT_INITIALIZED, True) storage.put(START_TIME, 0) return True return False
def withdraw(secret: str) -> bool: """ Deposits the contract's cryptocurrency into the owner and other_person addresses as long as they both transferred to this contract and there is some time remaining :param secret: the private key that unlocks the transaction :type secret: str :return: whether the transfers were successful :rtype: bool """ # Checking if OWNER and OTHER_PERSON transferred to this smart contract funded_owner = get(FUNDED_PREFIX + OWNER).to_int() funded_other_person = get(FUNDED_PREFIX + OTHER_PERSON).to_int() if verify() and not refund() and hash160(secret) == get(SECRET_HASH) and funded_owner != 0 and funded_other_person != 0: put(FUNDED_PREFIX + OWNER, 0) put(FUNDED_PREFIX + OTHER_PERSON, 0) put(NOT_INITIALIZED, True) put(START_TIME, 0) call_contract(UInt160(get(TOKEN_PREFIX + OTHER_PERSON)), 'transfer', [executing_script_hash, get(ADDRESS_PREFIX + OWNER), get(AMOUNT_PREFIX + OTHER_PERSON), '']) call_contract(UInt160(get(TOKEN_PREFIX + OWNER)), 'transfer', [executing_script_hash, get(ADDRESS_PREFIX + OTHER_PERSON), get(AMOUNT_PREFIX + OWNER), '']) return True return False
def withdraw(secret: str) -> bool: """ Deposits the contract's cryptocurrency into the person_a and person_b addresses as long as they both transferred to this contract and there is some time remaining :param secret: the private key that unlocks the transaction :type secret: str :return: whether the transfers were successful :rtype: bool """ # Checking if PERSON_A and PERSON_B transferred to this smart contract funded_person_a = storage.get(FUNDED_PREFIX + PERSON_A).to_int() funded_person_b = storage.get(FUNDED_PREFIX + PERSON_B).to_int() if verify() and not refund() and hash160(secret) == storage.get( SECRET_HASH) and funded_person_a != 0 and funded_person_b != 0: storage.put(FUNDED_PREFIX + PERSON_A, 0) storage.put(FUNDED_PREFIX + PERSON_B, 0) storage.put(NOT_INITIALIZED, True) storage.put(START_TIME, 0) call_contract(UInt160(storage.get(TOKEN_PREFIX + PERSON_B)), 'transfer', [ runtime.executing_script_hash, storage.get(ADDRESS_PREFIX + PERSON_A), storage.get(AMOUNT_PREFIX + PERSON_B), None ]) call_contract(UInt160(storage.get(TOKEN_PREFIX + PERSON_A)), 'transfer', [ runtime.executing_script_hash, storage.get(ADDRESS_PREFIX + PERSON_B), storage.get(AMOUNT_PREFIX + PERSON_A), None ]) return True return False
def swap_tokens(amount_in: int, amount_out_min: int, token_in: UInt160, user_address: UInt160) -> int: """ Swaps two tokens with a small fee in the process. :param amount_in: the amount of tokens that the user is trying to swap :type amount_in: int :param amount_out_min: the minimum amount of tokens that the user wants to receive :type amount_out_min: int :param token_in: the address of the token that the user is trying to use in the swap :type token_in: UInt160 :param user_address: the user's address :type user_address: UInt160 :return: the amount of tokens that the user received from the swap :rtype: int """ # this verification exists thanks to a limitation in the TestEngine, it's returning None when using calling_script_hash # using just `user_address = calling_script hash` should be enough if calling_script_hash is not None: # TODO: remove the verification when the TestEngine starts sending a calling script hash user_address = calling_script_hash else: assert check_witness(user_address) assert check_witness(user_address) assert token_in == UInt160(get(TOKEN_A)) or token_in == UInt160(get(TOKEN_B)) # Verifies if the user is trying to swap token_a or token_b and set the variables accordingly if token_in == UInt160(get(TOKEN_A)): reserve_token_in = get(SUPPLY_KEY + TOKEN_A).to_int() reserve_token_out = get(SUPPLY_KEY + TOKEN_B).to_int() amount_token_a_in = amount_in amount_token_b_in = 0 else: reserve_token_in = get(SUPPLY_KEY + TOKEN_B).to_int() reserve_token_out = get(SUPPLY_KEY + TOKEN_A).to_int() amount_token_a_in = 0 amount_token_b_in = amount_in # Calculates the amount of tokens the user will receive amount_in_fee = amount_in * (1000 - FEE) amount_out = amount_in_fee * reserve_token_out // (reserve_token_in * 1000 + amount_in_fee) assert amount_out >= amount_out_min # Checks if the user allowed enough tokens amount_allowed = call_contract(token_in, 'allowance', [user_address, executing_script_hash]) if isinstance(amount_allowed, int): assert amount_allowed >= amount_in else: abort() call_contract(token_in, 'transfer_from', [executing_script_hash, user_address, executing_script_hash, amount_in, None]) if amount_token_a_in != 0: swap(0, amount_out, user_address) else: swap(amount_out, 0, user_address) return amount_out
def mint(user_address: UInt160) -> int: """ Mints AMM tokens, this function will be called by `add_liquidity()`. It's best practice to separate `add_liquidity` and `mint` into different contracts, `add_liquidity` should be in a Router, while `mint` should be in another smart contract, however, since this is just an example, they both are in this same smart contract. :param user_address: the address of the user that wants to add liquidity to the pool :type user_address: UInt160 :return: the amount of liquidity tokens that were minted :rtype: int :raise AssertionError: raised if the liquidity ends up being equal or less than 0 """ # reserve_token_a and reserve_token_b are the amount of token_a and token_b tokens that the smart contract has saved in the # storage, it's not the actual amount that is in the balance, because the amount is not updated after transferring # the token_a and token_b tokens, it will be update only after minting reserve_token_a = get(SUPPLY_KEY + TOKEN_A).to_int() reserve_token_b = get(SUPPLY_KEY + TOKEN_B).to_int() # balance_token_a and balance_token_b are the actual amount that are in the balance of this smart contract balance_token_a = call_contract(UInt160(get(TOKEN_A)), 'balanceOf', [executing_script_hash]) balance_token_b = call_contract(UInt160(get(TOKEN_B)), 'balanceOf', [executing_script_hash]) liquidity: int if isinstance(balance_token_a, int) and isinstance(balance_token_b, int): # amount_token_a and amount_token_b are the quantity of tokens that were deposited in the balance of this smart contract amount_token_a = balance_token_a - reserve_token_a amount_token_b = balance_token_b - reserve_token_b total_supply = get(SUPPLY_KEY).to_int() # if there are no AMM tokens, then the quantity of AMM tokens that will be minted are calculated multiplying # amount_token_a and amount_token_b if total_supply == 0: liquidity = sqrt(amount_token_b * amount_token_a) # if the pool is not empty then the amount of AMM tokens that will be minted are calculated the way shown below else: liquidity = min(amount_token_a * total_supply // reserve_token_a, amount_token_b * total_supply // reserve_token_b) assert liquidity > 0 # updates the total supply of AMM tokens put(SUPPLY_KEY, total_supply + liquidity) # change the amount of liquidity the user has put(user_address, get(user_address).to_int() + liquidity) on_transfer(None, user_address, liquidity) update(balance_token_a, balance_token_b) on_mint(user_address, amount_token_a, amount_token_b) else: abort() return liquidity
def swap(amount_token_a_out: int, amount_token_b_out: int, user_address: UInt160): """ Swaps one token with another, this function will be called by `swap_tokens`. It's best practice to separate `swap_tokens` and `swap` into different contracts, `swap_tokens` should be in a Router, while `swap` should be in another smart contract, however, since this is just an example, they both are in this same smart contract. :param amount_token_a_out: the amount of token_a that will be given to the user :type amount_token_a_out: int :param amount_token_b_out: the amount of token_b that will be given to the user :type amount_token_b_out: int :param user_address: the user's address :type user_address: UInt160 :raise AssertionError: raised if the amount_token_a_out and amount_token_b_out are equal or less than zero, if the amount the user is going to receive is greater than the amount in the reserve, if the smart contract didn't receive any token from the user, or if the constant k after the swap ends up being lower than the one at the beginning """ assert amount_token_a_out > 0 or amount_token_b_out > 0 reserve_token_a = get(SUPPLY_KEY + TOKEN_A).to_int() reserve_token_b = get(SUPPLY_KEY + TOKEN_B).to_int() assert amount_token_a_out < reserve_token_a and amount_token_b_out < reserve_token_b if amount_token_a_out > 0: call_contract(UInt160(get(TOKEN_A)), 'transfer', [executing_script_hash, user_address, amount_token_a_out, None]) if amount_token_b_out > 0: call_contract(UInt160(get(TOKEN_B)), 'transfer', [executing_script_hash, user_address, amount_token_b_out, None]) # balance_token_a and balance_token_b are the actual amount that are in the balance of this smart contract balance_token_a = call_contract(UInt160(get(TOKEN_A)), 'balanceOf', [executing_script_hash]) balance_token_b = call_contract(UInt160(get(TOKEN_B)), 'balanceOf', [executing_script_hash]) if isinstance(balance_token_a, int) and isinstance(balance_token_b, int): amount_token_a_in = balance_token_a - (reserve_token_a - amount_token_a_out) if balance_token_a > reserve_token_a - amount_token_a_out else 0 amount_token_b_in = balance_token_b - (reserve_token_b - amount_token_b_out) if balance_token_b > reserve_token_b - amount_token_b_out else 0 assert amount_token_a_in > 0 or amount_token_b_in > 0 balance_token_a_adjusted = balance_token_a * 1000 - amount_token_a_in * FEE balance_token_b_adjusted = balance_token_b * 1000 - amount_token_b_in * FEE constant_k_new = balance_token_a_adjusted * balance_token_b_adjusted constant_k_old = reserve_token_a * 1000 * reserve_token_b * 1000 assert constant_k_new >= constant_k_old update(balance_token_a, balance_token_b) on_swap(user_address, amount_token_a_in, amount_token_b_in, amount_token_a_out, amount_token_b_out) else: abort()
def _deploy(data: Any, upgrade: bool): """ The contracts initial entry point, on deployment. """ if upgrade: return if get(DEPLOYED).to_bool(): abort() tx = cast(Transaction, script_container) #DEBUG_START #custom owner for tests if tx.sender is None: owner = UInt160(b'\x96Wl\x0e**\x1c!\xc4\xac^\xbd)31\x15%A\x1f@') #DEBUG_END put(DEPLOYED, True) put(PAUSED, False) put(TOKEN_COUNT, 0) put(MINT_FEE, MINT_FEE_ON_DEPLOY) auth: List[UInt160] = [] auth.append(tx.sender) serialized = serialize(auth) put(AUTH_ADDRESSES, serialized) wl: List[UInt160] = [] wl.append(tx.sender) wl_serialized = serialize(auth) put(WL_ADDRESSES, wl_serialized)
def deploy() -> bool: # placeholders for testing put(FEE_RECEIVER_KEY, UInt160()) feesMap.put(GAS, 10) feesMap.put(NEO, 20) return True
class Nep17: _hash = UInt160( b'\x70\x2e\x5c\xc9\x8a\x79\xa6\x21\xfb\x5e\x75\xbe\x1a\xf9\x44\xe1\x84\x9f\xf1\x21' ) @classmethod def symbol(cls) -> str: return cast(str, call_contract(cls._hash, 'symbol')) @classmethod def decimals(cls) -> int: return cast(int, call_contract(cls._hash, 'decimals')) @classmethod def total_supply(cls) -> int: return cast(int, call_contract(cls._hash, 'totalSupply')) @classmethod def balance_of(cls, account: UInt160) -> int: return cast(int, call_contract(cls._hash, 'balanceOf', [account])) @classmethod def transfer(cls, from_address: UInt160, to_address: UInt160, amount: int, data: Any) -> bool: return cast( bool, call_contract(cls._hash, 'transfer', [from_address, to_address, amount, data]))
def test_boa2_runtime_test(self): path = self.get_contract_path('RuntimeBoa2Test.py') engine = TestEngine() new_block = engine.increase_block() result = self.run_smart_contract(engine, path, 'main', 'time', 1) self.assertEqual(new_block.timestamp, result) from boa3.builtin.type import UInt160 result = self.run_smart_contract(engine, path, 'main', 'check_witness', UInt160(bytes(20))) self.assertEqual(False, result) result = self.run_smart_contract(engine, path, 'main', 'log', 'hello') self.assertEqual(True, result) result = self.run_smart_contract(engine, path, 'main', 'notify', 1234) self.assertEqual(True, result) event_notifications = engine.get_events(event_name=Interop.Notify.name) self.assertEqual(1, len(event_notifications)) self.assertEqual((1234, ), event_notifications[0].arguments) result = self.run_smart_contract(engine, path, 'main', 'get_trigger', 1234) self.assertEqual(TriggerType.APPLICATION, result)
def __init__(self): self.hash: UInt256 = UInt256() self.version: int = 0 self.nonce: int = 0 self.sender: UInt160 = UInt160() self.system_fee: int = 0 self.network_fee: int = 0 self.valid_until_block: int = 0 self.script: bytes = b''
def __init__(self): self.hash: UInt256 = UInt256() self.version: int = 0 self.previous_hash: UInt256 = UInt256() self.merkle_root: UInt256 = UInt256() self.timestamp: int = 0 self.index: int = 0 self.primary_index: int = 0 self.next_consensus: UInt160 = UInt160() self.transaction_count: int = 0
def get_notifications(script_hash: UInt160 = UInt160()) -> List[Notification]: """ This method gets current invocation notifications from specific 'script_hash' :param script_hash: must have 20 bytes, but if it's all zero 0000...0000 it refers to all existing notifications (like a * wildcard) :type script_hash: UInt160 :return: It will return an array of all matched notifications :rtype: List[Notification] """ pass
def burn(liquidity: int, user_address: UInt160) -> List[int]: """ Burns AMM tokens, this function will be called by `remove_liquidity()`. It's best practice to separate `remove_liquidity` and `mint` into different contracts, `add_liquidity` should be in a Router, while `burn` should be in another smart contract, however, since this is just an example, they both are in this same smart contract. :param liquidity: how many AMM tokens will be removed from the pool :type liquidity: int :param user_address: the address of the user that wants to remove liquidity of the pool :type user_address: int :return: at index 0 and 1, the amount of token_a and token_b tokens that were transferred, respectively :rtype: list :raise AssertionError: raised if amount_token_a or amount_token_b is equal or less than zero """ # balance_token_a and balance_token_b are the actual amount that are in the balance of this smart contract balance_token_a = call_contract(UInt160(get(TOKEN_A)), 'balanceOf', [executing_script_hash]) balance_token_b = call_contract(UInt160(get(TOKEN_B)), 'balanceOf', [executing_script_hash]) amount_token_a: int = 0 amount_token_b: int = 0 if isinstance(balance_token_a, int) and isinstance(balance_token_b, int): total_supply = get(SUPPLY_KEY).to_int() # amount_token_a and amount_token_b are the amount that will be transferred to the user after burning the liquidity amount_token_a = liquidity * balance_token_a // total_supply amount_token_b = liquidity * balance_token_b // total_supply assert amount_token_a > 0 and amount_token_b > 0 # changing the user balance after burning the liquidity put(user_address, balanceOf(user_address) - liquidity) # update the amount of AMM tokens in this smart contract put(SUPPLY_KEY, total_supply - liquidity) on_transfer(user_address, None, liquidity) call_contract(UInt160(get(TOKEN_A)), 'transfer', [executing_script_hash, user_address, amount_token_a, None]) call_contract(UInt160(get(TOKEN_B)), 'transfer', [executing_script_hash, user_address, amount_token_b, None]) balance_token_a = call_contract(UInt160(get(TOKEN_A)), 'balanceOf', [executing_script_hash]) balance_token_b = call_contract(UInt160(get(TOKEN_B)), 'balanceOf', [executing_script_hash]) if isinstance(balance_token_a, int) and isinstance(balance_token_b, int): update(balance_token_a, balance_token_b) on_burn(user_address, amount_token_a, amount_token_b) else: abort() else: abort() return [amount_token_a, amount_token_b]
def finish_pool(pool_id: UInt256, winner_options: List[str]): creator = get(POOL_OWNER_KEY + pool_id) if len(creator) == 0: raise Exception("Pool doesn't exist.") if not check_witness(creator): raise Exception('No authorization.') if len(get(POOL_RESULT_KEY + pool_id)) > 0: raise Exception('Pool is finished already') if len(winner_options) == 0: raise Exception('At least one winner is required') # validate all winner options are valid options winner_options: List[str] = remove_duplicates(winner_options) pool_options: List[str] = deserialize(get(POOL_OPTIONS_KEY + pool_id)) for option in winner_options: if option not in pool_options: raise Exception('Invalid option for this pool') winners: List[UInt160] = [] # get winner players bets_key_prefix = POOL_BET_KEY + pool_id bet = find(bets_key_prefix) while bet.next(): result_pair = bet.value storage_key = cast(bytes, result_pair[0]) account_bet = cast(str, result_pair[1]) if account_bet in winner_options: address = storage_key[len(bets_key_prefix):] account = UInt160(address) winners.append(account) # distribute the prizes if len(winners) > 0: total_stake = get(POOL_TOTAL_STAKE_KEY + pool_id).to_int() prize_per_winner = total_stake // len(winners) executing_contract = executing_script_hash for winner in winners: transfer_gas(executing_contract, winner, prize_per_winner) # set result put(POOL_RESULT_KEY + pool_id, serialize(winner_options))
def owner_of(token_id: ByteString) -> UInt160: """ Get the owner of the specified token. The parameter token_id SHOULD be a valid NFT ID (64 bytes maximum). :param token_id: the id of a token :type token_id: str """ assert len(token_id) <= 64 owner = UInt160() token_bytes = storage.get(account_prefix_key + token_id) if len(token_bytes) != 0: token = cast(NFT, deserialize(token_bytes)) owner = token.owner return owner
:type message: str """ pass def trigger() -> TriggerType: """ Return the smart contract trigger type. :return: a value that represents the contract trigger type. :rtype: TriggerType """ pass executing_script_hash: UInt160 = UInt160() calling_script_hash: UInt160 = UInt160() get_time: int = 0 gas_left: int = 0 get_platform: str = '' invocation_counter: int = 0 entry_script_hash: UInt160 = UInt160() def get_notifications(script_hash: UInt160 = UInt160()) -> List[Notification]: """ This method gets current invocation notifications from specific 'script_hash' :param script_hash: must have 20 bytes, but if it's all zero 0000...0000 it refers to all existing notifications (like a * wildcard) :type script_hash: UInt160
def __init__(self): self.script_hash: UInt160 = UInt160() self.event_name: str = '' self.state: tuple = ()
@metadata def manifest_metadata() -> NeoMetadata: meta = NeoMetadata() meta.author = 'The Four Blessings of the Apocalypse (COZ)' meta.email = '*****@*****.**' meta.description = 'This smart contract represents one of the core resources for the game, stone.' meta.version = "v0.0.1" return meta # --------------------------------- # CONTRACT GLOBALS # --------------------------------- ACCOUNT_PREFIX = b'a' ADMIN = UInt160(b'\x8cfQ\x01Rb2\x0f\xc6Ez\xebzP\xe9\xa5\xa1\xa4\xa1\xdd') TOKEN_DECIMALS = 0 TOKEN_PREFIX = b't' TOKEN_SYMBOL = 'DSTONE' TOTAL_SUPPLY = b's' # --------------------------------- # EVENTS # --------------------------------- on_transfer = Nep17TransferEvent # --------------------------------- # Methods # ---------------------------------
def uint160(arg: bytes) -> bytes: return UInt160(arg)
def main() -> int: return Policy.is_blocked(UInt160(), UInt160())
:raise Exception: raised if the nef or the manifest are not a valid smart contract. """ pass def update_contract(nef_file: bytes, manifest: bytes): """ Updates the executing smart contract given the script and the manifest :param nef_file: the new smart contract's compiled nef :type nef_file: bytes :param manifest: the new smart contract's manifest :type manifest: bytes :raise Exception: raised if the nef and the manifest are not a valid smart contract or the new contract is the same as the old one. """ pass def destroy_contract(): """ Destroy the executing smart contract """ pass NEO: UInt160 = UInt160() # not real value GAS: UInt160 = UInt160() # not real value
@metadata def manifest_metadata() -> NeoMetadata: """ Defines this smart contract's metadata information """ meta = NeoMetadata() return meta # ------------------------------------------- # VARIABLES SETTINGS # ------------------------------------------- OWNER = UInt160() OTHER_PERSON: bytes = b'person b' ADDRESS_PREFIX: bytes = b'address' AMOUNT_PREFIX: bytes = b'amount' TOKEN_PREFIX: bytes = b'token' FUNDED_PREFIX: bytes = b'funded' # Number of seconds that need to pass before refunding the contract LOCK_TIME = 15 * 1 NOT_INITIALIZED: bytes = b'not initialized' START_TIME: bytes = b'start time' SECRET_HASH: bytes = b'secret hash' DEPLOYED: bytes = b'deployed'
def __init__(self): self.id: int = 0 self.update_counter: int = 0 self.hash: UInt160 = UInt160() self.script: bytes = bytes() self.manifest: Dict[str, Any] = {}
def uint160(arg: str) -> UInt160: return UInt160(arg)
def get_owner_of(tokenId: bytes) -> UInt160: key = mk_token_key(tokenId) debug(['get_owner_of: ', key, tokenId]) owner = get(key) return UInt160(owner)
# ------------------------------------------- # Storage Key Prefixes # ------------------------------------------- KYC_WHITELIST_PREFIX = b'KYCWhitelistApproved' TOKEN_TOTAL_SUPPLY_PREFIX = b'TokenTotalSupply' TRANSFER_ALLOWANCE_PREFIX = b'TransferAllowancePrefix_' # ------------------------------------------- # TOKEN SETTINGS # ------------------------------------------- # Script hash of the contract owner TOKEN_OWNER = UInt160() # Symbol of the Token TOKEN_SYMBOL = 'ICO' # Number of decimal places TOKEN_DECIMALS = 8 # Initial Supply of tokens in the system TOKEN_INITIAL_SUPPLY = 10_000_000 * 10**TOKEN_DECIMALS # 10m total supply * 10^8 (decimals) # ------------------------------------------- # Events # ------------------------------------------- on_transfer = Nep17TransferEvent
def create_multisig_account(m: int, pub_keys: List[ECPoint]) -> UInt160: """ Calculates corresponding multisig account script hash for the given public keys. :param m: the minimum number of correct signatures need to be provided in order for the verification to pass. :type m: int :param pub_keys: the public keys of the account :type pub_keys: List[ECPoint] :return: the hash of the corresponding account :rtype: UInt160 """ pass NEO: UInt160 = UInt160() """ NEO's token script hash. :meta hide-value: """ GAS: UInt160 = UInt160() """ GAS' token script hash. :meta hide-value: """