Beispiel #1
0
def na_alias_data(alias, args):
    """
    :param alias:
    \n:param args [type]:
    \n:returns alias data as array if success or None if failed:
    \nif sub_nas defined passes call to sub_nas otherwise
    we try to get alias data
    """

    if len(args) > 0:
        alias_type = args[0]
    else:
        alias_type = 0

    stored_alias = init_alias(alias,alias_type)

    if alias_exists(stored_alias) :
        stored_alias = alias_load(stored_alias)
        if not alias_expired(stored_alias):
            data = alias_get_data(stored_alias)
            Notify(data)
            return data
    msg = concat("Alias ", alias)
    msg = concat(msg, " not found or expired.")
    Notify(msg)
    return return_value(False,msg)
Beispiel #2
0
def SetSubdomain(domain_name, subdomain):
    msg = concat("SetSubdomain: ", domain_name, subdomain)
    Notify(msg)
    context = GetContext()
    owner = Get(context, domain_name)

    if stringCompare(subdomain):
        Notify("Domain has incorrect char inside")
        return False

    if not owner:
        Notify("Domain is not yet registered")
        return False

    if not CheckWitness(owner):
        Notify("Sender is not the owner, cannot set subdomain")
        return False

    domain = concat(subdomain, ".")
    domain = concat(domain, domain_name)

    Put(context, domain, owner)

    msg2 = [domain, "is owned by ", owner]
    Notify(msg2)
    return True
def register_delegator(context, args):
    if not CheckWitness(OWNER):
        Notify(ILLEGAL_CALL)
        return False

    delegator = args[0]
    name = args[1]

    if len(delegator) != 20:
        Notify(INVALID_ADDRESS)
        return False

    if not name:
        Notify(MISSING_DELEGATOR_NAME)
        return False

    if Get(context, delegator):
        Notify(ALREADY_EXISTING_DELEGATOR)
        return False

    Notify(['[REGISTER-DELEGATOR] delegator:', delegator, 'name:', name])

    Put(context, delegator, name)

    return True
Beispiel #4
0
def Main():

    # pobieramy kontekst storage'u dla danego kontraktu
    # każdy kontrakt ma własny obszar storage
    context = GetContext()

    # klucz
    item_key = 'moj-klucz'

    # pobieramy wartość za pomocą klucza
    item_value = Get(context, item_key)

    msg = ['Wartosc odczytana ze storage:', item_value]
    Notify(msg)

    # w przypadku gdy para klucz-wartość nie są zapisane
    # próba pobrania wartości za pomocą nie istniejącego w storage klucza
    # zwróci wartość pustego ciągu bajtów b''
    if len(item_value) == 0:
        Notify('Klucz nie istnieje w storage, ustawiam wartosc na 1')
        item_value = 1

    else:
        Notify("Klucz juz jest w storage, zwiększam wartosc o 1.")
        item_value += 1

    # zapisanie wartości pod kluczem
    Put(context, item_key, item_value)

    msg = ["Nowa wartosc zapisana do storage:", item_value]
    Notify(msg)

    return item_value
Beispiel #5
0
def RegisterFarmContract(FarmContract_name, OwnerNeoAddress, Farmer_id,
                         Buyer_id, Project_id, Contract_id, Balance, Status,
                         Other_data):
    msg = concat("RegisterFarmContract: ", FarmContract_name)
    msg2 = concat(msg, OwnerNeoAddress)
    Notify(msg2)

    storage_key = concat(FarmContract_name, OwnerNeoAddress)

    if not CheckWitness(OwnerNeoAddress):
        Notify("Owner argument is not the same as the person who registered")
        return False

    context = GetContext()
    exists = getRegistry(context, storage_key)
    if exists:
        Notify("Contract is already registered")
        return False

    raw_data = [
        Farmer_id, Buyer_id, Project_id, Contract_id, Balance, Status,
        Other_data
    ]
    farm_contract_info_serialised = serialize_array(raw_data)

    putRegistry(context, storage_key, farm_contract_info_serialised)
    return True
Beispiel #6
0
def Main():

    m = bytearray(b'\x01\x02\x03\x04\x05\x06\x07\x08')

    # this is a test to see if slice notation without specifying an end
    # is functional
#    s1 = m[2:] # it is not

    # without specifying beginning it is:
    s2 = m[:4]

    j = 2
    k = 4

    s3 = m[j:k]

    Notify(s3)

    s4 = m[get_slice_start():get_slice_end()]

    Notify(s4)

    ind = [1, 3, 4, 5]

    s6 = m[get_slice_start():ind[2]]

    Notify(s6)

    res = concat(s6, concat(s4, concat(s2, s3)))

    Notify(res)

    return res
Beispiel #7
0
def buyCat(from_acc, animal, amount):
    if not CheckWitness(from_acc):
        Notify("Not the owner, can't buy")
        return False

    tmplist = Get(ctx, from_acc + "CAT")
    if len(tmplist) != 0:
        delist = Deserialize(tmplist)
        Notify(delist)
        delist.append(animal)
        Notify(delist)
        Put(ctx, from_acc + "CAT", Serialize(delist))
    else:
        Put(ctx, from_acc + "CAT", Serialize([animal]))
        Notify(Serialize([animal]))

    current_balance = Get(ctx, from_acc)
    if current_balance <= amount:
        Notify("Insufficient funds")
        return False
    to_balance = Get(ctx, TOKEN_OWNER)
    to_balance += amount
    Put(ctx, TOKEN_OWNER, to_balance)
    current_balance -= amount
    if current_balance != 0:
        Put(ctx, from_acc, current_balance)
    else:
        Delete(ctx, from_acc)
    OnTransfer(from_acc, TOKEN_OWNER, amount)
    return True
Beispiel #8
0
def Main(operation, args):

    trigger = GetTrigger()

    if trigger == Verification():
        is_owner = CheckWitness(CONTRACT_OWNER)
        if is_owner:
            return True
        else:
            return False
    elif trigger == Application():
        sender = args[0]
        authorized = CheckWitness(sender)
        """
            Make sure that invoker is valid
        """
        if not authorized:
            Notify("Not authorized")
            return False
        Log("test")
        Notify(len(args))
        """
            query operations    
        """
        if operation == "sendMessage" and len(args) == 4:
            Notify("In operation sendMessage")
            return sendMessage(args)
        else:
            return False
    return False
Beispiel #9
0
def InsertCharacter(attrList):

    ID_TIP_KEY = "id-tip-key"

    Notify("Calling InsertCharacterByAttrList")
    context = GetContext()

    # Make sure that it can be converted correctly
    character = ConvertFromList(attrList)

    nextId = Get(context, ID_TIP_KEY)
    if not nextId:
        Notify("id-tip-key is not set")
        nextId = 0
    else:
        Notify("id-tip-key is set")

    nextId = nextId + 1

    serialized = Serialize(attrList)
    Notify(serialized)

    Put(context, nextId, serialized)
    Put(context, ID_TIP_KEY, nextId)

    return nextId
Beispiel #10
0
def TransferFarmContract(FarmContract_name, OwnerNeoAddress, to_address):
    msg = concat("TransferFarmContract: ", FarmContract_name)
    msg2 = concat(msg, OwnerNeoAddress)
    Notify(msg2)

    storage_key = concat(FarmContract_name, OwnerNeoAddress)

    context = GetContext()
    Owner = Get(context, storage_key)
    if not Owner:
        Notify("This farm contract is not yet registered")
        return False

    if not CheckWitness(Owner):
        Notify(
            "This person is not the Owner, Farm Contract ownership cannot be Transfered"
        )
        return False

    if not len(to_address) != 34:
        Notify("Invalid new owner neo address. Must be exactly 34 characters")
        return False

    putRegistry(context, storage_key, to_address)
    return True
def set_webpage(adr, webpage):
    msg = concat("Change webpage for: ", adr)
    Notify(msg)
    termsba = Get(ctx, adr)
    if not termsba:
        Notify("Partnership for address is not yet created")
        return False
    serterms = deserialize_bytearray(termsba)
    currency = serterms[0]
    flatfees_struc = serterms[1]
    partnership_struc = serterms[2]

    terms = [currency, flatfees_struc, partnership_struc, webpage]
    serterms = serialize_array(terms)
    Put(ctx, adr, serterms)

    msg = concat("Webpage updated:", " ")
    a = concat("Address : ", adr)
    msg = concat(msg, a)
    c = concat(", Currency : ", currency)
    msg = concat(msg, c)
    d = concat(", Flatfee Structure : ", flatfees_struc)
    msg = concat(msg, d)
    e = concat(", Partnership Structure: ", partnership_struc)
    msg = concat(msg, e)
    f = concat(", Webpage: ", webpage)
    msg = concat(msg, f)
    Notify(msg)
    return True
def Main(op, args):
    context = GetContext()

    if op == 'registerDelegator':
        if len(args) == 2:
            return register_delegator(context, args)
        else:
            Notify(ARG_ERROR)
            return False
    elif op == 'registerWallet':
        if len(args) == 1:
            return register_wallet(context, args)
        else:
            Notify(ARG_ERROR)
            return False
    elif op == 'verifyClaim':
        if len(args) == 1:
            delegator = GetEntryScriptHash()
            return verify_claim(context, delegator, args)
        else:
            Notify(ARG_ERROR)
            return False
    else:
        Notify(INVALID_OPERATION)
        return False
Beispiel #13
0
def Main():
    context = GetContext()

    # This is the storage key we use in this example
    item_key = 'test-storage-key'

    # Try to get a value for this key from storage
    item_value = Get(context, item_key)
    msg = ["Value read from storage:", item_value]
    Notify(msg)

    if len(item_value) == 0:
        Notify("Storage key not yet set. Setting to 1")
        item_value = 1

    else:
        Notify("Storage key already set. Incrementing by 1")
        item_value += 1

    # Store the new value
    Put(context, item_key, item_value)
    msg = ["New value written into storage:", item_value]
    Notify(msg)

    return item_value
Beispiel #14
0
def transfer(t_from, t_to, amount):
    ctx = GetContext()

    assert len(t_from) == 20, "Invalid from address"
    assert len(t_to) == 20, "Invalid to address"

    if t_from == t_to:
        Notify("Transferring to self. Nothing changes.")
        return True

    from_val = Get(ctx, t_from)
    if from_val == amount:
        Delete(ctx, t_from)
    else:
        difference = from_val - amount
        Put(ctx, t_from, difference)
    if from_val < amount:
        return False

    to_value = Get(ctx, t_to)
    to_total = to_value + amount
    Put(ctx, t_to, to_total)
    Notify("Transfer successful.")

    return True
Beispiel #15
0
def addMessage(party, direction, message, partySecond, time):
    context = GetContext()
    partyHelper = concat(direction, 'latest')
    partyLast = concat(party, partyHelper)
    lastIndex = Get(context, partyLast)
    if lastIndex == '':
        # No last Index, set first (1)
        newLastIndex = 1
    else:
        # Increment last index
        newLastIndex = lastIndex + 1
    Notify(concat('lastindex +1: ', newLastIndex))
    # Set new last index
    Put(context, partyLast, newLastIndex)
    Notify(concat('put partyLast: ', partyLast))
    # Set message for index
    partyHelper2 = concat(direction, newLastIndex)
    partyMessageId = concat(party, partyHelper2)
    # Create message with header and body
    # header contains partySecond (sender / receiver) and time
    # body contains message
    # messageData = [partySecond,time,message]
    messageData = [message, time, partySecond]
    messageTemp = Serialize(messageData)
    Put(context, partyMessageId, messageTemp)
    Notify(concat('pt msg: ', messageTemp))
    return True
Beispiel #16
0
def RegisterDomain(domain_name, owner):
    msg = concat("RegisterDomain: ", domain_name)
    Notify(msg)
    '''
    Check if the domain contain .
    if ture then return false
    '''
    if stringCompare(domain_name):
        Notify("Domain has incorrect char inside")
        return False

    if not CheckWitness(owner):
        Notify("Owner argument is not the same as the sender")
        return False

    context = GetContext()
    exists = Get(context, domain_name)
    if exists:
        Notify("Domain is already registered")
        return False

    Put(context, domain_name, owner)
    msg2 = [domain_name, "is owned by ", owner]
    Notify(msg2)
    return True
Beispiel #17
0
def na_query(alias, args):
    """
    :param alias:
    \n:param args [type]:
    \n:returns alias target if success or False if failed:
    \nif sub_nas defined passes call to sub_nas otherwise
    we try to query alias target
    """
    if len(args) > 0:
        alias_type = args[0]
    else:
        alias_type = 0

    stored_alias = init_alias(alias,alias_type)
    
    if alias_exists(stored_alias):
        stored_alias = alias_load(stored_alias)
        if not alias_expired(stored_alias):
            target = alias_get_target(stored_alias)
            msg = concat("Query resolved: ", target)
            Notify(msg)
            QueryAliasEvent(alias, alias_type, target)
            return target

    msg = concat("Alias ", alias)
    msg = concat(msg, " not found or expired.")
    Notify(msg)
    return return_value(False,msg)
Beispiel #18
0
def give_user_gas(ad_id, reciever_id, reciever_ad_count):

    reciever_info = list(length=5)
    ad_data = list(length=8)

    ad_id = args[0]
    reciever_id = args[1]
    reciever_ad_count = args[2]
    if reciever_ad_count < 1:
        return 'User did not view any ads'

        ad_data = deserialize_bytearray(Get(ctx, ad_id))
        ad_gas_amount = ad_data[7]
        reciever_info = Get(ctx, reciever_id)
        ad_gas_amount = ad_gas_amount / 2
        reciever_info[3] = ad_gas_amount
        reciever_info[4] = reciever_info[4] + 1
        Delete(ctx, reciever_id)
        data_serialized = serialize_array(reciever_info)

        Put(ctx, reciever_id, data_serialized)
        if transfer:
            Notify(' Transaction approved')
            update_gas = update_gas(ad_id, ad_gas_amount)
            if update_gas:
                Notify("Gas amount on acc updated ")
                return True
    return False
Beispiel #19
0
def register_provider(context, args):
    if not CheckWitness(OWNER):
        Notify(ILLEGAL_CALL)
        return False

    name = args[0]
    provider = args[1]

    if not name:
        Notify(MISSING_PROVIDER_NAME)
        return False

    if len(provider) != 20:
        Notify(INVALID_ADDRESS)
        return False

    if Get(context, name):
        Notify(ALREADY_EXISTING_PROVIDER)
        return False

    Notify(['[REGISTER-PROVIDER] name:', name, 'provider:', provider])

    Put(context, name, provider)

    return True
def create_verification_request(source_address, target_address):
    """
    The target user is doing this!
    :param target_address:
    :param source_address:
    :return:
    """

    msg = concat("Target users requests verification from ", source_address)
    Notify(msg)

    # if not CheckWitness(target_address):
    #     Notify("target_address argument is not the same as the tx sender")
    #     return False

    context = GetContext()
    key = _build_verification_request_key(source_address, target_address)
    result = Get(context, key)

    if not result:
        msg = concat("Verification request has been created for source ",
                     source_address)
        Notify(msg)
        Put(context, key, PENDING_STATUS)
        return True

    Notify(
        "Verification has already been started or completed for this source target combination"
    )
    return False
Beispiel #21
0
def remove_token_from_owners_list(ctx, t_owner, t_id):
    """Removes a token from owner's list of tokens

    :param StorageContext ctx: current store context
    :param byte[] t_owner: token owner
    :param bytes t_id: token id
    :return: token removal success
    :rtype: bool
    """
    length = Get(ctx, t_owner)  # get how many tokens this owner owns
    # this should be impossible, but just in case, leaving it here
    if len(length) == b'\x00':
        Notify('owner has no tokens')
        return False

    # if Delete returns True, that means the token was
    # successfully deleted and we should decrement the owner's balance.
    # otherwise, the token didn't exist/didn't belong to the owner,
    # so Delete returns False in that case.
    if Delete(ctx, concat(t_owner, t_id)):
        new_balance = length - 1
        if new_balance > 0:
            Put(ctx, t_owner, new_balance)
        else:
            Delete(ctx, t_owner)

        Log("removed token from owner's list and decremented owner's balance")
        return True

    Notify("token not found in owner's list")
    return False
Beispiel #22
0
def removeQuestionId(questionId):
    Notify("[!] Remove QuestionID to all_question_ids object")
    serial = Get(GetContext(), get_all_ids)
    all_question_ids = Deserialize(serial)
    all_question_ids.remove(questionId)
    new_serial = Serialize(all_question_ids)
    Put(GetContext(), get_all_ids, new_serial)
    Notify("[!] Removed QuestionID from all_question_ids object")
Beispiel #23
0
def removePostId(postId):
    Notify("[!] Remove PostID to all_posts object")
    serial = Get(GetContext(), get_all_ids)
    all_posts = Deserialize(serial)
    all_posts.remove(postId)
    new_serial = Serialize(all_posts)
    Put(GetContext(), get_all_ids, new_serial)
    Notify("[!] Removed PostID from all_posts object")
Beispiel #24
0
def addQuestionId(questionId, question):
    Notify("[!] Add QuestionID to all_question_ids object")
    serial = Get(GetContext(), get_all_ids)
    all_question_ids = Deserialize(serial)
    all_question_ids[questionId] = question
    new_serial = Serialize(all_question_ids)
    Put(GetContext(), get_all_ids, new_serial)
    Notify("[!] Added QuestionID to all_question_ids object")
Beispiel #25
0
def addPostId(postId, title):
    Notify("[!] Add PostID to all_posts object")
    serial = Get(GetContext(), get_all_ids)
    all_posts = Deserialize(serial)
    all_posts[postId] = title
    new_serial = Serialize(all_posts)
    Put(GetContext(), get_all_ids, new_serial)
    Notify("[!] Added PostID to all_posts object")
def unFollow(ctx, uid, uFAddr, index_a, index_b):
    """
    Unfollow another user

    Args:
        uid -> unique user id
        uFAddr -> to-follow script hash
        index_a -> Index of iterated storage of uid, for the following of fUid
        index_b -> Index of iterated storage of FUid, for the follow of uid
    """
    uFUid = isRegistered(ctx, uFAddr)
    if not uFUid == False:
        if uFUid == uid:
            Notify("User cannot unfollow himself")
            return False
        if isFollowing(ctx, uid, uFUid):
            #User has to be follower, respecitve follower has to be followed by user
            a_temp = GetThree(ctx, uid, ".following.", index_a)
            a_temp_d = Deserialize(a_temp)
            b_temp = GetThree(ctx, uFUid, ".followers.", index_b)
            b_temp_d = Deserialize(b_temp)
            if a_temp_d[0] == uFUid and b_temp_d[0] == uid:
                # Count unfollowing += 1 for uid
                ##a_save = Get(ctx, uid)
                ##a_save_d = Deserialize(a_save)
                ##a_count = a_save_d[8]
                ##aa_count = a_count + 1
                ##a_save_d[8] = aa_count
                ##a_save_s = Serialize(a_save_d)
                ##Put(ctx, uid, a_save_s)
                updateAccCount(ctx, uid, 8, False)

                # Count unfollowed += 1 for uFUid
                ##b_save = Get(ctx, uFUid)
                ##b_save_d = Deserialize(b_save)
                ##b_count = b_save_d[7]
                ##bb_count = b_count + 1
                ##b_save_d[7] = bb_count
                ##b_save_s = Serialize(b_save_d)
                ##Put(ctx, uFUid, b_save_s)
                updateAccCount(ctx, uFUid, 7, False)

                # Mark index as unfollowed for uid
                PutThree(ctx, uid, ".following.", index_a, "unfollowing")
                # Mark index as unfollowed for uFUid
                PutThree(ctx, uFUid, ".followers.", index_b, "unfollowed")

                #Set follow indicator = false
                PutThree(ctx, uid, ".followcheck.", uFUid, False)

                OnUnfollow(uid, uFUid)
                return True
            Notify("Following and Follower indexes do not match")
            return False
        Notify("User is not following.")
        return False
    Notify("User to unfollow not registered")
    return False
Beispiel #27
0
def addPostId(postId):
    check_allPostIds()
    Notify("[!] Add PostID to all_posts object")
    serial = Get(GetContext(), get_all_ids)
    all_posts = Deserialize(serial)
    all_posts.append(postId)
    new_serial = Serialize(all_posts)
    Put(GetContext(), get_all_ids, new_serial)
    Notify("[!] Added PostID to all_posts object")
Beispiel #28
0
def do_mint_token(ctx, args):
    """Mints a new NFT token; stores it's properties, URI info, and
    owner on the blockchain; updates the totalSupply

    :param StorageContext ctx: current store context
    :param list args:
        0: byte[] t_owner: token owner
        1: byte[] t_properties: token's read only data
        2: bytes t_uri: token's uri
        3: extra_arg (optional): extra arg to be passed to a smart
            contract
    :return: mint success
    :rtype: bool
    """
    t_id = Get(ctx, TOKEN_CIRC_KEY)
    # the int 0 is represented as b'' in neo-boa, this caused bugs
    # throughout my code
    # This is the reason why token id's start at 1 instead
    t_id += 1

    # this should never already exist
    if len(Get(ctx, t_id)) == 20:
        Notify('token already exists')
        return False

    t_owner = args[0]
    if len(t_owner) != 20:
        Notify(INVALID_ADDRESS_ERROR)
        return False

    t_properties = args[1]
    if len(t_properties) == b'\x00':
        Notify('missing properties data string')
        return False

    t_uri = args[2]

    if GetContract(t_owner):
        contract_args = [t_owner, t_id]
        if len(args) == 4:  # append optional extra arg
            contract_args.append(args[3])

        success = transfer_to_smart_contract(ctx, GetExecutingScriptHash(),
                                             contract_args, True)
        if success is False:
            return False

    Put(ctx, t_id, t_owner)  # update token's owner
    Put(ctx, concat('properties/', t_id), t_properties)
    Put(ctx, concat('uri/', t_id), t_uri)
    add_token_to_owners_list(ctx, t_owner, t_id)
    Put(ctx, TOKEN_CIRC_KEY, t_id)  # update total supply

    # Log this minting event
    OnMint(t_owner, 1)
    OnNFTMint(t_owner, t_id)
    return True
Beispiel #29
0
def do_tokens_of_owner(ctx, t_owner, start_index):
    """This method returns ten of the owner's tokens starting at the
    given index. The index is used for paginating through the results.
    Pagination is needed for the situation where the owner's dict of
    tokens could be quite large.

    For example, the specified owner could have 100,000 tokens out
    of 1,000,000 minted tokens.
    In such a scenario, returning the full list of token id's would
    be quite expensive and could possibly be too large to return anyway.
    Hence, @hal0x2328 recognized the need to paginate the
    data in such a scenario. So, if we know that this user has a
    balanceOf() 100,000 tokens and we want to get their 10 most recent
    tokens, then our call would be like so:
    `testinvoke {my_hash} tokensOfOwner [{owner address string}, 999990]`
    The results would look something like:
        [{'type': 'ByteArray',
        'value':
        '82060007746f6b656e2f010001010007746f6b656e2f020001020007746f6b656e2f030001030007746f6b656e2f040001040007746f6b656e2f050001050007746f6b656e2f06000106''}]

    :param StorageContext ctx: current store context
    :param byte[] t_owner: token owner
    :param bytes start_index: the index to start searching through the
        owner's tokens
    :return: dict of tokens
    :rtype: bool or dict
    """
    if len(t_owner) != 20:
        Notify(INVALID_ADDRESS_ERROR)
        return False

    if len(start_index) == b'\x00':
        start_index = b'\x01'  # token id's cannot go below 1

    start_key = concat(t_owner, start_index)
    count = 0
    token_dict = {}
    token_iter = Find(ctx, t_owner)
    # while loop explained: keep looping through the owner's list
    # of tokens until 10 have been found beginning at the starting
    # index.
    # if statement explained: once a key has been found matching
    # my search key (or of greater value),
    # update the dictionary, increment the counter,
    # and disregard trying to find a matching key thereafter.
    # (once a key has been found matching my search key
    # (or greater), just get everything afterward while count < 10)
    while token_iter.next() and (count < 10):
        if (token_iter.Key >= start_key) or (count > 0):
            token_dict[concat('token/', token_iter.Value)] = token_iter.Value
            count += 1

    if len(token_dict) >= 1:
        return token_dict

    Notify(TOKEN_DNE_ERROR)
    return False
Beispiel #30
0
def do_approve(ctx, caller, t_receiver, t_id, revoke):
    """Approve a token to eventually be transferred to the t_receiver

    :param StorageContext ctx: current store context
    :param byte[] caller: calling script hash
    :param byte[] t_receiver: address of the future token owner
    :param bytes t_id: int: token id
    :param bytes revoke: set to 1 to revoke previous approval
    :return: approval success
    :rtype: bool
    """
    if len(t_receiver) != 20:
        Notify(INVALID_ADDRESS_ERROR)
        return False

    if len(revoke) == b'\x00':
        revoke = b'\x00'

    t_owner = Get(ctx, t_id)
    if len(t_owner) != 20:
        Notify(TOKEN_DNE_ERROR)
        return False

    if t_owner == t_receiver:
        Notify('approved spend to self')
        return True

    is_token_owner = CheckWitness(t_owner)
    if is_token_owner and GetEntryScriptHash() != caller:
        Notify('third party script is bouncing the signature to us')
        return False
    # if token owner is a smart contract and is the calling
    # script hash, continue
    elif GetContract(t_owner) and t_owner == caller:
        is_token_owner = True

    if is_token_owner:
        approval_key = concat('approved/', t_id)
        # revoke previous approval if revoke != 0
        if revoke != b'\x00':
            Delete(ctx, approval_key)
            # log the revoking of previous approvals
            OnApprove(t_owner, t_receiver, b'\x00')
            OnNFTApprove(t_owner, '', t_id)
            return True

        # approve this transfer
        Put(ctx, approval_key, concat(t_owner, t_receiver))

        # Log this approval event
        OnApprove(t_owner, t_receiver, 1)
        OnNFTApprove(t_owner, t_receiver, t_id)
        return True

    Notify(PERMISSION_ERROR)
    return False