Skip to content

Instantly share code, notes, and snippets.

@hal0x2328
Last active August 4, 2019 00:22
Show Gist options
  • Save hal0x2328/3237fd9f61132cea6b6dd43899947753 to your computer and use it in GitHub Desktop.
Save hal0x2328/3237fd9f61132cea6b6dd43899947753 to your computer and use it in GitHub Desktop.
NEP-11 implementation
"""NEO NEP-11 Non-Fungible Token Smart Contract Template
Author: Joe Stewart
Email: hal0x2328@splyse.tech
Version: 3.0
Date: August 3 2019
License: MIT
Example test using neo-local:
neo> sc build_run /smart-contracts/nft_template.py test 0710 05 True False False name []
Compile and import with neo-python using neo-local:
neo> sc build /smart-contracts/nft_template.py
neo> sc deploy /smart-contracts/nft_template.avm 0710 05 True False False
"""
from boa.builtins import concat
from boa.interop.Neo.Action import RegisterAction
from boa.interop.Neo.Blockchain import GetContract
from boa.interop.Neo.Iterator import Iterator
from boa.interop.Neo.Runtime import CheckWitness, GetTrigger, Notify, Serialize, Deserialize
from boa.interop.Neo.Storage import GetContext, Get, Put, Delete, Find
from boa.interop.Neo.TriggerType import Application, Verification
from boa.interop.System.ExecutionEngine import GetCallingScriptHash
# This is the script hash of the address for the owner of the contract
# This can be found in ``neo-python`` with the wallet open,
# use ``wallet`` command
TOKEN_CONTRACT_OWNER = b'\x1c\xc9\xc0\\\xef\xff\xe6\xcd\xd7\xb1\x82\x81j\x91R\xec!\x8d.\xc0'
TOKEN_NAME = 'Neo NEP-11 Non-Fungible Token Template'
TOKEN_SYMBOL = 'NFT'
TOKEN_DECIMALS = 0
TOKEN_CIRC_KEY = b'in_circulation'
# Smart Contract Event Notifications
OnTransfer = RegisterAction('transfer', 'addr_from', 'addr_to', 'amount', 'token_id')
OnError = RegisterAction('error', 'message')
# common errors
ARG_ERROR = 'incorrect arg length'
INVALID_ADDRESS_ERROR = 'invalid address'
PERMISSION_ERROR = 'incorrect permission'
TOKEN_DNE_ERROR = 'token does not exist'
def Main(operation, args):
trigger = GetTrigger()
if trigger == Verification():
assert CheckWitness(TOKEN_CONTRACT_OWNER), PERMISSION_ERROR
return True
elif trigger == Application():
ctx = GetContext()
if operation == 'name':
return TOKEN_NAME
elif operation == 'symbol':
return TOKEN_SYMBOL
elif operation == 'supportedStandards':
return Serialize(['NEP-10','NEP-11'])
elif operation == 'totalSupply':
return Get(ctx, TOKEN_CIRC_KEY)
elif operation == 'decimals':
return TOKEN_DECIMALS
elif operation == 'ownerOf':
assert len(args) == 1, ARG_ERROR
token = get_token(ctx, args[0])
return token['owner']
elif operation == 'balanceOf':
assert len(args) == 1, ARG_ERROR
assert len(args[0]) == 20, INVALID_ADDRESS_ERROR
token_iter = Find(ctx, args[0])
count = 0
while token_iter.next():
count += 1
return count
elif operation == 'tokensOf':
assert len(args) == 1, ARG_ERROR
assert len(args[0]) == 20, INVALID_ADDRESS_ERROR
return Find(ctx, args[0])
elif operation == 'properties':
assert len(args) == 1, ARG_ERROR
token = get_token(ctx, args[0])
return token['properties']
elif operation == 'transfer':
assert len(args) == 2, ARG_ERROR
t_to = args[0]
t_id = args[1]
assert len(t_to) == 20, INVALID_ADDRESS_ERROR
token = get_token(ctx, args[0])
t_owner = token['owner']
assert CheckWitness(t_owner), PERMISSION_ERROR
token['owner'] = t_to;
Delete(ctx, concat(t_owner, t_id))
Put(ctx, concat(t_owner, t_id), t_id)
OnTransfer(t_owner, t_to, 1, t_id)
return save_token(ctx, t_id, token)
elif operation == 'mintToken':
assert CheckWitness(TOKEN_CONTRACT_OWNER), PERMISSION_ERROR
assert len(args) == 4, ARG_ERROR
t_circ = Get(ctx, TOKEN_CIRC_KEY)
t_circ += 1
assert len(args[0]) == 20, INVALID_ADDRESS_ERROR
assert args[1], 'missing token id'
assert args[2], 'missing properties'
assert args[3], 'missing owner'
t_id = args[1]
t = Get(ctx, concat('token/', t_id))
assert not t, 'token already exists'
token = {}
token['id'] = t_id
token['properties'] = args[2]
token['owner'] = args[3]
Put(ctx, concat(token['owner'], t_id), t_id)
Put(ctx, TOKEN_CIRC_KEY, t_circ) # update total supply
OnTransfer('', token['owner'], 1, t_id)
return save_token(ctx, t_id, token)
AssertionError('unknown operation')
def get_token(ctx, token_id):
data = Get(ctx, concat('token/', token_id))
assert len(data) > 0, TOKEN_DNE_ERROR
obj = Deserialize(data)
return obj
def save_token(ctx, token_id, token):
data = Serialize(token)
Put(ctx, concat('token/', token_id), token)
return True
def AssertionError(msg):
OnError(msg) # for neo-cli ApplicationLog
raise Exception(msg)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment