Compare commits

...

6 Commits

Author SHA1 Message Date
lash
6f44c8304f
Add seal test interface 2023-06-08 08:05:10 +01:00
lash
993d52ecab
Rename writer test contract 2023-06-06 18:15:07 +01:00
lash
02aa54f653
Add writer test contract 2023-06-06 18:12:06 +01:00
lash
360a288d77
Bump version 2023-06-06 17:57:29 +01:00
lash
ef3ee7caf0
Add minter and burner python interface and test code 2023-06-06 17:56:45 +01:00
lash
220b8afbeb
Add capped interface, python interface and test for capped, expire 2023-06-06 14:46:55 +01:00
58 changed files with 1196 additions and 8 deletions

View File

@ -6,7 +6,7 @@ INPUTS = $(wildcard solidity/*.sol)
OUTPUTS_JSON = $(patsubst %.sol, %.json, $(INPUTS))
OUTPUTS_INTERFACE = $(patsubst %.sol, %.interface, $(INPUTS))
OUTPUTS = $(OUTPUTS_JSON) $(OUTPUTS_INTERFACE)
PREFIX = /usr/local/share/cic/solidity/abi
PREFIX = $(DESTDIR)/usr/local/share/cic/solidity/abi
#%.abi.json: $(wildcard *.sol)
# install -vDm0644 $@ $(PREFIX)/$@
@ -44,4 +44,7 @@ readme:
make -C doc/texinfo readme
pandoc -f docbook -t gfm doc/texinfo/build/docbook.xml > README.md
python:
make -C python
.PHONY: clean install

View File

@ -1 +1 @@
include *requirements.txt
include *requirements.txt solidity/* LICENSE README*

17
python/Makefile Normal file
View File

@ -0,0 +1,17 @@
INPUTS = $(wildcard solidity/*.sol)
OUTPUTS = $(patsubst %.sol, %.bin, $(INPUTS))
all: outs package
.SUFFIXES: .sol .bin
solidity:
.sol.bin:
solc $(basename $@).sol --evm-version=byzantium --bin | awk 'NR>3' > $@
truncate -s -1 $@
outs: $(OUTPUTS)
package:
python setup.py sdist

View File

@ -0,0 +1 @@
from .burn import EthBurner

33
python/eth_burner/burn.py Normal file
View File

@ -0,0 +1,33 @@
# external imports
from chainlib.eth.tx import TxFormat
from chainlib.eth.tx import TxFactory
from chainlib.jsonrpc import JSONRPCRequest
from chainlib.eth.constant import ZERO_ADDRESS
from chainlib.eth.contract import ABIContractEncoder
from chainlib.eth.contract import ABIContractType
from chainlib.eth.contract import abi_decode_single
from hexathon import add_0x
class EthBurner(TxFactory):
def burn(self, contract_address, sender_address, value, tx_format=TxFormat.JSONRPC):
enc = ABIContractEncoder()
enc.method('burn')
enc.typ(ABIContractType.UINT256)
enc.uint256(value)
data = enc.get()
tx = self.template(sender_address, contract_address, use_nonce=True)
tx = self.set_code(tx, data)
tx = self.finalize(tx, tx_format)
return tx
def burn_all(self, contract_address, sender_address, tx_format=TxFormat.JSONRPC):
enc = ABIContractEncoder()
enc.method('burn')
data = enc.get()
tx = self.template(sender_address, contract_address, use_nonce=True)
tx = self.set_code(tx, data)
tx = self.finalize(tx, tx_format)
return tx

View File

@ -0,0 +1 @@
from .interface import TestEthBurnerInterface

View File

@ -0,0 +1,53 @@
# standard imports
import os
import logging
import datetime
# external imports
from chainlib.eth.unittest.ethtester import EthTesterCase
from chainlib.connection import RPCConnection
from chainlib.eth.nonce import RPCNonceOracle
from chainlib.eth.tx import receipt
from chainlib.eth.tx import TxFactory
from chainlib.eth.tx import TxFormat
from chainlib.eth.contract import ABIContractEncoder
from chainlib.eth.contract import ABIContractType
# local imports
from eth_burner import EthBurner
script_dir = os.path.dirname(os.path.realpath(__file__))
contract_dir = os.path.join(script_dir, '..', '..', 'solidity')
logg = logging.getLogger(__name__)
class TestEthBurner(EthTesterCase):
def setUp(self):
super(TestEthBurner, self).setUp()
self.conn = RPCConnection.connect(self.chain_spec, 'default')
nonce_oracle = RPCNonceOracle(self.accounts[0], self.conn)
f = open(os.path.join(contract_dir, 'BurnerTest.bin'))
code = f.read()
f.close()
txf = TxFactory(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
tx = txf.template(self.accounts[0], None, use_nonce=True)
self.initial_supply = 1024
enc = ABIContractEncoder()
enc = ABIContractEncoder()
enc.uint256(self.initial_supply)
args = enc.get()
tx = txf.set_code(tx, code + args)
(tx_hash_hex, o) = txf.build(tx)
self.conn.do(o)
o = receipt(tx_hash_hex)
r = self.conn.do(o)
self.assertEqual(r['status'], 1)
self.address = r['contract_address']
logg.debug('published burner test contract with hash {}'.format(r))

View File

@ -0,0 +1,19 @@
# external imports
from chainlib.eth.tx import receipt
from chainlib.eth.nonce import RPCNonceOracle
# local imports
from eth_burner import EthBurner
class TestEthBurnerInterface:
def test_supply(self):
self.alice = self.accounts[1]
nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
c = EthBurner(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
(tx_hash, o) = c.burn(self.address, self.accounts[0], int(self.initial_supply / 2))
self.rpc.do(o)
o = receipt(tx_hash)
r = self.rpc.do(o)
self.assertEqual(r['status'],1)

View File

@ -0,0 +1 @@
from .capped import EthCapped

View File

@ -0,0 +1,22 @@
# external imports
from chainlib.eth.tx import TxFormat
from chainlib.eth.tx import TxFactory
from chainlib.jsonrpc import JSONRPCRequest
from chainlib.eth.constant import ZERO_ADDRESS
from chainlib.eth.contract import ABIContractEncoder
from chainlib.eth.contract import ABIContractType
from hexathon import add_0x
class EthCapped(TxFactory):
def max_supply(self, contract_address, sender_address=ZERO_ADDRESS, id_generator=None):
j = JSONRPCRequest(id_generator)
o = j.template()
o['method'] = 'eth_call'
enc = ABIContractEncoder()
enc.method('maxSupply')
data = add_0x(enc.get())
tx = self.template(sender_address, contract_address)
tx = self.set_code(tx, data)
o['params'].append(self.normalize(tx))
return o

View File

@ -0,0 +1 @@
from .interface import TestEthCappedInterface

View File

@ -0,0 +1,64 @@
# standard imports
import os
import logging
# external imports
from chainlib.eth.unittest.ethtester import EthTesterCase
from chainlib.connection import RPCConnection
from chainlib.eth.nonce import RPCNonceOracle
from chainlib.eth.tx import receipt
from chainlib.eth.tx import TxFactory
from chainlib.eth.tx import TxFormat
from chainlib.eth.contract import ABIContractEncoder
from chainlib.eth.contract import ABIContractType
script_dir = os.path.dirname(os.path.realpath(__file__))
contract_dir = os.path.join(script_dir, '..', '..', 'solidity')
logg = logging.getLogger(__name__)
class TestEthCapped(EthTesterCase):
def setUp(self):
super(TestEthCapped, self).setUp()
self.set_method = None
self.conn = RPCConnection.connect(self.chain_spec, 'default')
nonce_oracle = RPCNonceOracle(self.accounts[0], self.conn)
f = open(os.path.join(contract_dir, 'CappedTest.bin'))
code = f.read()
f.close()
txf = TxFactory(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
tx = txf.template(self.accounts[0], None, use_nonce=True)
self.max_supply_value = 1024
enc = ABIContractEncoder()
enc.uint256(self.max_supply_value)
args = enc.get()
tx = txf.set_code(tx, code + args)
(tx_hash_hex, o) = txf.build(tx)
self.conn.do(o)
o = receipt(tx_hash_hex)
r = self.conn.do(o)
self.assertEqual(r['status'], 1)
self.address = r['contract_address']
logg.debug('published capped test contract with hash {}'.format(r))
def set_max_supply(self, contract_address, sender_address, v, tx_format=TxFormat.JSONRPC):
nonce_oracle = RPCNonceOracle(self.accounts[0], self.conn)
txf = TxFactory(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
enc = ABIContractEncoder()
enc.method('setMaxSupply')
enc.typ(ABIContractType.UINT256)
enc.uint256(v)
data = enc.get()
tx = txf.template(sender_address, contract_address, use_nonce=True)
tx = txf.set_code(tx, data)
tx = txf.finalize(tx, tx_format)
return tx

View File

@ -0,0 +1,38 @@
# external imports
from chainlib.eth.tx import receipt
# local imports
from eth_capped import EthCapped
class TestEthCappedInterface:
def __init__(self):
self.set_method = None
self.max_supply_value = 0
def test_supply(self):
if self.max_supply_value == 0:
return
c = EthCapped(self.chain_spec)
o = c.max_supply(self.address, sender_address=self.accounts[0])
r = self.rpc.do(o)
self.assertEqual(self.max_supply_value, int(r, 16))
def test_supply_change(self):
if self.set_method == None:
return
self.max_supply_value = 2048
(tx_hash_hex, o) = self.set_method(self.address, self.accounts[0], self.max_supply_value)
self.rpc.do(o)
o = receipt(tx_hash_hex)
r = self.conn.do(o)
self.assertEqual(r['status'], 1)
c = EthCapped(self.chain_spec)
o = c.max_supply(self.address, sender_address=self.accounts[0])
r = self.rpc.do(o)
self.assertEqual(self.max_supply_value, int(r, 16))

View File

@ -0,0 +1 @@
from .expire import EthExpire

View File

@ -0,0 +1,37 @@
# external imports
from chainlib.eth.tx import TxFormat
from chainlib.eth.tx import TxFactory
from chainlib.jsonrpc import JSONRPCRequest
from chainlib.eth.constant import ZERO_ADDRESS
from chainlib.eth.contract import ABIContractEncoder
from chainlib.eth.contract import ABIContractType
from chainlib.eth.contract import abi_decode_single
from hexathon import add_0x
class EthExpire(TxFactory):
def apply_expiry(self, method, contract_address, sender_address, tx_format=TxFormat.JSONRPC):
enc = ABIContractEncoder()
enc.method('applyExpiry')
data = enc.get()
tx = self.template(sender_address, contract_address, use_nonce=True)
tx = self.set_code(tx, data)
tx = self.finalize(tx, tx_format)
return tx
def expires(self, contract_address, sender_address=ZERO_ADDRESS, id_generator=None):
j = JSONRPCRequest(id_generator)
o = j.template()
o['method'] = 'eth_call'
enc = ABIContractEncoder()
enc.method('expires')
data = add_0x(enc.get())
tx = self.template(sender_address, contract_address)
tx = self.set_code(tx, data)
o['params'].append(self.normalize(tx))
return o
def parse_expires(self, v):
return abi_decode_single(ABIContractType.UINT256, v)

View File

@ -0,0 +1 @@
from .interface import TestEthExpireInterface

View File

@ -0,0 +1,64 @@
# standard imports
import os
import logging
import datetime
# external imports
from chainlib.eth.unittest.ethtester import EthTesterCase
from chainlib.connection import RPCConnection
from chainlib.eth.nonce import RPCNonceOracle
from chainlib.eth.tx import receipt
from chainlib.eth.tx import TxFactory
from chainlib.eth.tx import TxFormat
from chainlib.eth.contract import ABIContractEncoder
from chainlib.eth.contract import ABIContractType
script_dir = os.path.dirname(os.path.realpath(__file__))
contract_dir = os.path.join(script_dir, '..', '..', 'solidity')
logg = logging.getLogger(__name__)
class TestEthExpire(EthTesterCase):
def setUp(self):
super(TestEthExpire, self).setUp()
self.conn = RPCConnection.connect(self.chain_spec, 'default')
nonce_oracle = RPCNonceOracle(self.accounts[0], self.conn)
f = open(os.path.join(contract_dir, 'ExpireTest.bin'))
code = f.read()
f.close()
txf = TxFactory(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
tx = txf.template(self.accounts[0], None, use_nonce=True)
date_expire = datetime.datetime.utcnow() + datetime.timedelta(seconds=10000)
self.expire = int(date_expire.timestamp())
enc = ABIContractEncoder()
enc.uint256(self.expire)
args = enc.get()
tx = txf.set_code(tx, code + args)
(tx_hash_hex, o) = txf.build(tx)
self.conn.do(o)
o = receipt(tx_hash_hex)
r = self.conn.do(o)
self.assertEqual(r['status'], 1)
self.address = r['contract_address']
logg.debug('published expire test contract with hash {}'.format(r))
def set_expiry(self, contract_address, sender_address, v, tx_format=TxFormat.JSONRPC):
nonce_oracle = RPCNonceOracle(self.accounts[0], self.conn)
txf = TxFactory(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
enc = ABIContractEncoder()
enc.method('setExpiry')
enc.typ(ABIContractType.UINT256)
enc.uint256(v)
data = enc.get()
tx = txf.template(sender_address, contract_address, use_nonce=True)
tx = txf.set_code(tx, data)
tx = txf.finalize(tx, tx_format)
return tx

View File

@ -0,0 +1,37 @@
# external imports
from chainlib.eth.tx import receipt
# local imports
from eth_expire import EthExpire
class TestEthExpireInterface:
def __init__(self):
self.set_method = None
def test_expire(self):
if self.expire == 0:
return
c = EthExpire(self.chain_spec)
o = c.expires(self.address, sender_address=self.accounts[0])
r = self.rpc.do(o)
self.assertEqual(self.expire, int(r, 16))
def test_expire_change(self):
if self.set_method == None:
return
self.expire += 43200
(tx_hash_hex, o) = self.set_method(self.address, self.accounts[0], self.expire)
self.rpc.do(o)
o = receipt(tx_hash_hex)
r = self.conn.do(o)
self.assertEqual(r['status'], 1)
c = EthExpire(self.chain_spec)
o = c.expires(self.address, sender_address=self.accounts[0])
r = self.rpc.do(o)
self.assertEqual(self.expire, int(r, 16))

View File

@ -0,0 +1 @@
from .minter import EthMinter

View File

@ -0,0 +1,25 @@
# external imports
from chainlib.eth.tx import TxFormat
from chainlib.eth.tx import TxFactory
from chainlib.jsonrpc import JSONRPCRequest
from chainlib.eth.constant import ZERO_ADDRESS
from chainlib.eth.contract import ABIContractEncoder
from chainlib.eth.contract import ABIContractType
from chainlib.eth.contract import abi_decode_single
from hexathon import add_0x
class EthMinter(TxFactory):
def mint_to(self, contract_address, sender_address, recipient_address, value, tx_format=TxFormat.JSONRPC):
enc = ABIContractEncoder()
enc.method('mintTo')
enc.typ(ABIContractType.ADDRESS)
enc.typ(ABIContractType.UINT256)
enc.address(recipient_address)
enc.uint256(value)
data = enc.get()
tx = self.template(sender_address, contract_address, use_nonce=True)
tx = self.set_code(tx, data)
tx = self.finalize(tx, tx_format)
return tx

View File

@ -0,0 +1 @@
from .interface import TestEthMinterInterface

View File

@ -0,0 +1,51 @@
# standard imports
import os
import logging
import datetime
# external imports
from chainlib.eth.unittest.ethtester import EthTesterCase
from chainlib.connection import RPCConnection
from chainlib.eth.nonce import RPCNonceOracle
from chainlib.eth.tx import receipt
from chainlib.eth.tx import TxFactory
from chainlib.eth.tx import TxFormat
from chainlib.eth.contract import ABIContractEncoder
from chainlib.eth.contract import ABIContractType
# local imports
from eth_minter import EthMinter
script_dir = os.path.dirname(os.path.realpath(__file__))
contract_dir = os.path.join(script_dir, '..', '..', 'solidity')
logg = logging.getLogger(__name__)
class TestEthMinter(EthTesterCase):
def setUp(self):
super(TestEthMinter, self).setUp()
self.conn = RPCConnection.connect(self.chain_spec, 'default')
nonce_oracle = RPCNonceOracle(self.accounts[0], self.conn)
f = open(os.path.join(contract_dir, 'MinterTest.bin'))
code = f.read()
f.close()
txf = TxFactory(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
tx = txf.template(self.accounts[0], None, use_nonce=True)
self.initial_supply = 1024
enc = ABIContractEncoder()
args = enc.get()
tx = txf.set_code(tx, code + args)
(tx_hash_hex, o) = txf.build(tx)
self.conn.do(o)
o = receipt(tx_hash_hex)
r = self.conn.do(o)
self.assertEqual(r['status'], 1)
self.address = r['contract_address']
logg.debug('published minter test contract with hash {}'.format(r))

View File

@ -0,0 +1,19 @@
# external imports
from chainlib.eth.tx import receipt
from chainlib.eth.nonce import RPCNonceOracle
# local imports
from eth_minter import EthMinter
class TestEthMinterInterface:
def test_supply(self):
self.alice = self.accounts[1]
nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
c = EthMinter(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
(tx_hash, o) = c.mint_to(self.address, self.accounts[0], self.alice, self.initial_supply)
self.rpc.do(o)
o = receipt(tx_hash)
r = self.rpc.do(o)
self.assertEqual(r['status'],1)

View File

@ -0,0 +1 @@
from .seal import EthSeal

32
python/eth_seal/seal.py Normal file
View File

@ -0,0 +1,32 @@
# external imports
from chainlib.eth.tx import TxFormat
from chainlib.eth.tx import TxFactory
from chainlib.jsonrpc import JSONRPCRequest
from chainlib.eth.constant import ZERO_ADDRESS
from chainlib.eth.contract import ABIContractEncoder
from chainlib.eth.contract import ABIContractType
from chainlib.eth.contract import abi_decode_single
from hexathon import add_0x
class EthSeal(TxFactory):
def __noarg(self, method, contract_address, sender_address=ZERO_ADDRESS, id_generator=None):
j = JSONRPCRequest(id_generator)
o = j.template()
o['method'] = 'eth_call'
enc = ABIContractEncoder()
enc.method(method)
data = add_0x(enc.get())
tx = self.template(sender_address, contract_address)
tx = self.set_code(tx, data)
o['params'].append(self.normalize(tx))
return o
def max_seal_state(self, contract_address, sender_address=ZERO_ADDRESS, id_generator=None):
return self.__noarg('maxSealState', contract_address, sender_address=sender_address, id_generator=id_generator)
def seal_state(self, contract_address, sender_address=ZERO_ADDRESS, id_generator=None):
return self.__noarg('sealState', contract_address, sender_address=sender_address, id_generator=id_generator)

View File

@ -0,0 +1 @@
from .interface import TestEthSealInterface

View File

@ -0,0 +1,60 @@
# standard imports
import os
import logging
# external imports
from chainlib.eth.unittest.ethtester import EthTesterCase
from chainlib.connection import RPCConnection
from chainlib.eth.nonce import RPCNonceOracle
from chainlib.eth.tx import receipt
from chainlib.eth.tx import TxFactory
from chainlib.eth.tx import TxFormat
from chainlib.eth.contract import ABIContractEncoder
from chainlib.eth.contract import ABIContractType
script_dir = os.path.dirname(os.path.realpath(__file__))
contract_dir = os.path.join(script_dir, '..', '..', 'solidity')
logg = logging.getLogger(__name__)
class TestEthSeal(EthTesterCase):
def setUp(self):
super(TestEthSeal, self).setUp()
self.set_method = None
self.conn = RPCConnection.connect(self.chain_spec, 'default')
nonce_oracle = RPCNonceOracle(self.accounts[0], self.conn)
f = open(os.path.join(contract_dir, 'SealTest.bin'))
code = f.read()
f.close()
txf = TxFactory(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
tx = txf.template(self.accounts[0], None, use_nonce=True)
self.max_seal_state = 7
tx = txf.set_code(tx, code)
(tx_hash_hex, o) = txf.build(tx)
self.conn.do(o)
o = receipt(tx_hash_hex)
r = self.conn.do(o)
self.assertEqual(r['status'], 1)
self.address = r['contract_address']
logg.debug('published seal test contract with hash {}'.format(r))
def seal(self, contract_address, sender_address, v, tx_format=TxFormat.JSONRPC):
nonce_oracle = RPCNonceOracle(self.accounts[0], self.conn)
txf = TxFactory(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
enc = ABIContractEncoder()
enc.method('seal')
enc.typ(ABIContractType.UINT256)
enc.uint256(v)
data = enc.get()
tx = txf.template(sender_address, contract_address, use_nonce=True)
tx = txf.set_code(tx, data)
tx = txf.finalize(tx, tx_format)
return tx

View File

@ -0,0 +1,21 @@
# external imports
from chainlib.eth.tx import receipt
# local imports
from eth_seal import EthSeal
class TestEthSealInterface:
def __init__(self):
self.set_method = None
self.max_seal_state = 0
def test_supply(self):
if self.max_seal_state == 0:
return
c = EthSeal(self.chain_spec)
o = c.max_seal_state(self.address, sender_address=self.accounts[0])
r = self.rpc.do(o)
self.assertEqual(self.max_seal_state, int(r, 16))

View File

@ -0,0 +1 @@
from .interface import *

View File

@ -0,0 +1,44 @@
# external imports
from chainlib.eth.tx import TxFormat
from chainlib.eth.tx import TxFactory
from chainlib.jsonrpc import JSONRPCRequest
from chainlib.eth.constant import ZERO_ADDRESS
from chainlib.eth.contract import ABIContractEncoder
from chainlib.eth.contract import ABIContractType
from hexathon import add_0x
class EthWriter(TxFactory):
def __single_address_method(self, method, contract_address, sender_address, address, tx_format=TxFormat.JSONRPC):
enc = ABIContractEncoder()
enc.method(method)
enc.typ(ABIContractType.ADDRESS)
enc.address(address)
data = enc.get()
tx = self.template(sender_address, contract_address, use_nonce=True)
tx = self.set_code(tx, data)
tx = self.finalize(tx, tx_format)
return tx
def add_writer(self, contract_address, sender_address, address, tx_format=TxFormat.JSONRPC):
return self.__single_address_method('addWriter', contract_address, sender_address, address, tx_format)
def delete_writer(self, contract_address, sender_address, address, tx_format=TxFormat.JSONRPC):
return self.__single_address_method('deleteWriter', contract_address, sender_address, address, tx_format)
def is_writer(self, contract_address, address, sender_address=ZERO_ADDRESS, id_generator=None):
j = JSONRPCRequest(id_generator)
o = j.template()
o['method'] = 'eth_call'
enc = ABIContractEncoder()
enc.method('isWriter')
enc.typ(ABIContractType.ADDRESS)
enc.address(address)
data = add_0x(enc.get())
tx = self.template(sender_address, contract_address)
tx = self.set_code(tx, data)
o['params'].append(self.normalize(tx))
return o

View File

@ -0,0 +1 @@
from .interface import TestEthWriterInterface

View File

@ -0,0 +1,58 @@
# standard imports
import os
import logging
# external imports
from chainlib.eth.unittest.ethtester import EthTesterCase
from chainlib.connection import RPCConnection
from chainlib.eth.nonce import RPCNonceOracle
from chainlib.eth.tx import receipt
from chainlib.eth.tx import TxFactory
from chainlib.eth.tx import TxFormat
from chainlib.eth.contract import ABIContractEncoder
from chainlib.eth.contract import ABIContractType
# local imports
from eth_writer import EthWriter
script_dir = os.path.dirname(os.path.realpath(__file__))
contract_dir = os.path.join(script_dir, '..', '..', 'solidity')
logg = logging.getLogger(__name__)
class TestEthWriter(EthTesterCase):
def setUp(self):
super(TestEthWriter, self).setUp()
self.set_method = None
self.conn = RPCConnection.connect(self.chain_spec, 'default')
nonce_oracle = RPCNonceOracle(self.accounts[0], self.conn)
f = open(os.path.join(contract_dir, 'WriterTest.bin'))
code = f.read()
f.close()
txf = TxFactory(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
tx = txf.template(self.accounts[0], None, use_nonce=True)
tx = txf.set_code(tx, code)
(tx_hash_hex, o) = txf.build(tx)
self.conn.do(o)
o = receipt(tx_hash_hex)
r = self.conn.do(o)
self.assertEqual(r['status'], 1)
self.address = r['contract_address']
self.contracts['writer'] = self.address
self.roles['publisher'] = self.accounts[0]
self.roles['writer'] = self.accounts[1]
logg.debug('published writer test contract with hash {}'.format(r))
c = EthWriter(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
(tx_hash, o) = c.add_writer(self.address, self.accounts[0], self.accounts[0])
self.rpc.do(o)
o = receipt(tx_hash)
r = self.rpc.do(o)
self.assertEqual(r['status'], 1)

View File

@ -0,0 +1,45 @@
# external imports
from chainlib.eth.unittest.ethtester import EthTesterCase
from chainlib.connection import RPCConnection
from chainlib.eth.nonce import RPCNonceOracle
from chainlib.eth.tx import receipt
# local imports
from eth_writer import EthWriter
class TestEthWriterInterface:
def test_add_delete(self):
writer_contract_address = self.contracts['writer']
publisher_address = self.roles.get('publisher')
writer_account = self.roles['writer']
nonce_oracle = RPCNonceOracle(self.publisher, conn=self.conn)
c = EthWriter(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
o = c.is_writer(writer_contract_address, publisher_address, sender_address=publisher_address)
r = self.rpc.do(o)
self.assertEqual(int(r, 16), 1)
self.alice = self.accounts[1]
(tx_hash, o) = c.add_writer(writer_contract_address, publisher_address, writer_account)
self.rpc.do(o)
o = receipt(tx_hash)
r = self.rpc.do(o)
self.assertEqual(r['status'], 1)
o = c.is_writer(writer_contract_address, writer_account, sender_address=publisher_address)
r = self.rpc.do(o)
self.assertEqual(int(r, 16), 1)
self.alice = self.accounts[1]
(tx_hash, o) = c.delete_writer(writer_contract_address, publisher_address, writer_account)
self.rpc.do(o)
o = receipt(tx_hash)
r = self.rpc.do(o)
self.assertEqual(r['status'], 1)
o = c.is_writer(writer_contract_address, self.alice, sender_address=publisher_address)
r = self.rpc.do(o)
self.assertEqual(int(r, 16), 0)

View File

@ -1 +1 @@
chainlib-eth~=0.4.7
chainlib-eth~=0.4.24

15
python/run_tests.sh Executable file
View File

@ -0,0 +1,15 @@
#!/bin/bash
export PYTHONPATH=${PYTHONPATH}:.
>&2 echo "using pythonpath $PYTHONPATH"
set -e
set -x
for f in `ls tests/*.py`; do
python $f
if [ $? -gt 0 ]; then
exit 1
fi
done
set +x
set +e

View File

@ -1,6 +1,6 @@
[metadata]
name = cic-contracts
version = 0.2.0
version = 0.3.0
description = CIC network smart contract interfaces
author = Louis Holbrook
author_email = dev@holbrook.no
@ -26,6 +26,8 @@ licence_files =
[options]
include_package_data = True
python_requires = >= 3.6
python_requires = >= 3.7
packages =
cic_contracts
eth_capped
eth_expire

View File

@ -0,0 +1 @@
608060405234801561001057600080fd5b5060405161070438038061070483398181016040528101906100329190610081565b8060008190555080600281905550506100ae565b600080fd5b6000819050919050565b61005e8161004b565b811461006957600080fd5b50565b60008151905061007b81610055565b92915050565b60006020828403121561009757610096610046565b5b60006100a58482850161006c565b91505092915050565b610647806100bd6000396000f3fe608060405234801561001057600080fd5b506004361061007f576000357c01000000000000000000000000000000000000000000000000000000009004806301ffc9a71461008457806342966c68146100b457806344d17187146100e457806344df8e7014610100578063a2309ff81461011e578063d89135cd1461013c575b600080fd5b61009e60048036038101906100999190610353565b61015a565b6040516100ab919061039b565b60405180910390f35b6100ce60048036038101906100c991906103ec565b61020a565b6040516100db919061039b565b60405180910390f35b6100fe60048036038101906100f991906104dc565b61021f565b005b61010861022f565b604051610115919061055f565b60405180910390f35b610126610241565b604051610133919061055f565b60405180910390f35b610144610247565b604051610151919061055f565b60405180910390f35b60006301ffc9a77c010000000000000000000000000000000000000000000000000000000002827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916036101ae5760019050610205565b63bc4babdd7c010000000000000000000000000000000000000000000000000000000002827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916036102005760019050610205565b600090505b919050565b60006102158261024d565b5060019050919050565b6102288361020a565b5050505050565b600061023c60005461024d565b905090565b60005481565b60015481565b6000808260025461025e91906105a9565b101561026957600080fd5b816001600082825461027b91906105dd565b92505081905550816002600082825461029491906105a9565b925050819055503373ffffffffffffffffffffffffffffffffffffffff167fcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca5836040516102e1919061055f565b60405180910390a2819050919050565b600080fd5b600080fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b610330816102fb565b811461033b57600080fd5b50565b60008135905061034d81610327565b92915050565b600060208284031215610369576103686102f1565b5b60006103778482850161033e565b91505092915050565b60008115159050919050565b61039581610380565b82525050565b60006020820190506103b0600083018461038c565b92915050565b6000819050919050565b6103c9816103b6565b81146103d457600080fd5b50565b6000813590506103e6816103c0565b92915050565b600060208284031215610402576104016102f1565b5b6000610410848285016103d7565b91505092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061044482610419565b9050919050565b61045481610439565b811461045f57600080fd5b50565b6000813590506104718161044b565b92915050565b600080fd5b600080fd5b600080fd5b60008083601f84011261049c5761049b610477565b5b8235905067ffffffffffffffff8111156104b9576104b861047c565b5b6020830191508360018202830111156104d5576104d4610481565b5b9250929050565b600080600080606085870312156104f6576104f56102f1565b5b600061050487828801610462565b9450506020610515878288016103d7565b935050604085013567ffffffffffffffff811115610536576105356102f6565b5b61054287828801610486565b925092505092959194509250565b610559816103b6565b82525050565b60006020820190506105746000830184610550565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006105b4826103b6565b91506105bf836103b6565b92508282039050818111156105d7576105d661057a565b5b92915050565b60006105e8826103b6565b91506105f3836103b6565b925082820190508082111561060b5761060a61057a565b5b9291505056fea2646970667358221220cf04ca2f9a9ef1aee6a7109799862035ae01e772554ee9c71f0ca5243159197164736f6c63430008130033

View File

@ -0,0 +1,50 @@
pragma solidity >=0.6.3;
// Author: Louis Holbrook <dev@holbrook.no> 0826EDA1702D1E87C6E2875121D2E7BB88C2A746
// SPDX-License-Identifier: AGPL-3.0-or-later
contract MinterTest {
uint256 public totalMinted;
uint256 public totalBurned;
uint256 balance;
event Burn(address indexed _burner, uint256 _burned);
constructor(uint256 _mintValue) {
totalMinted = _mintValue;
balance = _mintValue;
}
function burn(address _from, uint256 _value, bytes calldata _data) public {
_from;
_data;
burn(_value);
}
function burn(uint256 _value) public returns (bool) {
burnCore(_value);
return true;
}
function burnCore(uint256 _value) internal returns(uint256) {
require(balance - _value >= 0);
totalBurned += _value;
balance -= _value;
emit Burn(msg.sender, _value);
return _value;
}
function burn() public returns (uint256) {
return burnCore(totalMinted);
}
function supportsInterface(bytes4 _sum) public pure returns (bool) {
if (_sum == 0x01ffc9a7) { // EIP165
return true;
}
if (_sum == 0xbc4babdd) { // Burner
return true;
}
return false;
}
}

View File

@ -0,0 +1 @@
608060405234801561001057600080fd5b506040516104003803806104008339818101604052810190610032919061007a565b80600081905550506100a7565b600080fd5b6000819050919050565b61005781610044565b811461006257600080fd5b50565b6000815190506100748161004e565b92915050565b6000602082840312156100905761008f61003f565b5b600061009e84828501610065565b91505092915050565b61034a806100b66000396000f3fe608060405234801561001057600080fd5b506004361061005e576000357c01000000000000000000000000000000000000000000000000000000009004806301ffc9a7146100635780636f8b44b014610093578063d5abeb01146100af575b600080fd5b61007d60048036038101906100789190610224565b6100cd565b60405161008a919061026c565b60405180910390f35b6100ad60048036038101906100a891906102bd565b61017d565b005b6100b76101c1565b6040516100c491906102f9565b60405180910390f35b60006301ffc9a77c010000000000000000000000000000000000000000000000000000000002827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916036101215760019050610178565b63869f75947c010000000000000000000000000000000000000000000000000000000002827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916036101735760019050610178565b600090505b919050565b6000547f9722adea12ab7ef86fc45b88f0e0b567639e8dddaae60261e08c03d747fbbfe6826040516101af91906102f9565b60405180910390a28060008190555050565b60005481565b600080fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b610201816101cc565b811461020c57600080fd5b50565b60008135905061021e816101f8565b92915050565b60006020828403121561023a576102396101c7565b5b60006102488482850161020f565b91505092915050565b60008115159050919050565b61026681610251565b82525050565b6000602082019050610281600083018461025d565b92915050565b6000819050919050565b61029a81610287565b81146102a557600080fd5b50565b6000813590506102b781610291565b92915050565b6000602082840312156102d3576102d26101c7565b5b60006102e1848285016102a8565b91505092915050565b6102f381610287565b82525050565b600060208201905061030e60008301846102ea565b9291505056fea2646970667358221220f6bc26e7c6827142ccee8c0cadc8cb76d33712a68eacd67b69e4f8108aa2b59064736f6c63430008130033

View File

@ -0,0 +1,29 @@
pragma solidity >=0.6.3;
// Author: Louis Holbrook <dev@holbrook.no> 0826EDA1702D1E87C6E2875121D2E7BB88C2A746
// SPDX-License-Identifier: AGPL-3.0-or-later
contract CappedTest {
event Cap(uint256 indexed _oldCap, uint256 _newCap);
uint256 public maxSupply;
constructor(uint256 _supply) {
maxSupply = _supply;
}
function setMaxSupply(uint256 _supply) public {
emit Cap(maxSupply, _supply);
maxSupply = _supply;
}
function supportsInterface(bytes4 _sum) public pure returns (bool) {
if (_sum == 0x01ffc9a7) { // EIP165
return true;
}
if (_sum == 0x869f7594) { // Capped
return true;
}
return false;
}
}

View File

@ -0,0 +1 @@
608060405234801561001057600080fd5b506040516105143803806105148339818101604052810190610032919061007a565b80600081905550506100a7565b600080fd5b6000819050919050565b61005781610044565b811461006257600080fd5b50565b6000815190506100748161004e565b92915050565b6000602082840312156100905761008f61003f565b5b600061009e84828501610065565b91505092915050565b61045e806100b66000396000f3fe608060405234801561001057600080fd5b5060043610610069576000357c01000000000000000000000000000000000000000000000000000000009004806301cceb381461006e57806301ffc9a71461008a5780635f408c04146100ba578063b1cb0db3146100d8575b600080fd5b610088600480360381019061008391906102df565b6100f6565b005b6100a4600480360381019061009f9190610364565b610162565b6040516100b191906103ac565b60405180910390f35b6100c2610212565b6040516100cf91906103e3565b60405180910390f35b6100e061029e565b6040516100ed919061040d565b60405180910390f35b600160009054906101000a900460ff161561011057600080fd5b600054811161011e57600080fd5b6000547ff5bd6cb27a0006b5ea8618058a0d84719695cb6d984f4840bc1a54ca12ae4b7c82604051610150919061040d565b60405180910390a28060008190555050565b60006301ffc9a77c010000000000000000000000000000000000000000000000000000000002827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916036101b6576001905061020d565b63841a0e947c010000000000000000000000000000000000000000000000000000000002827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191603610208576001905061020d565b600090505b919050565b6000600160009054906101000a900460ff1615610232576001905061029b565b600054421015610245576000905061029b565b60018060006101000a81548160ff0219169083151502179055507ff80dbaea4785589e52984ca36a31de106adc77759539a5c7d92883bf49692fe94260405161028e919061040d565b60405180910390a1600190505b90565b60005481565b600080fd5b6000819050919050565b6102bc816102a9565b81146102c757600080fd5b50565b6000813590506102d9816102b3565b92915050565b6000602082840312156102f5576102f46102a4565b5b6000610303848285016102ca565b91505092915050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b6103418161030c565b811461034c57600080fd5b50565b60008135905061035e81610338565b92915050565b60006020828403121561037a576103796102a4565b5b60006103888482850161034f565b91505092915050565b60008115159050919050565b6103a681610391565b82525050565b60006020820190506103c1600083018461039d565b92915050565b600060ff82169050919050565b6103dd816103c7565b82525050565b60006020820190506103f860008301846103d4565b92915050565b610407816102a9565b82525050565b600060208201905061042260008301846103fe565b9291505056fea264697066735822122008d6e0c184036b44d56435108c0e081869b445ea32edbcd7035807691a26a11264736f6c63430008130033

View File

@ -0,0 +1,47 @@
pragma solidity >=0.6.3;
// Author: Louis Holbrook <dev@holbrook.no> 0826EDA1702D1E87C6E2875121D2E7BB88C2A746
// SPDX-License-Identifier: AGPL-3.0-or-later
contract ExpireTest {
uint256 public expires;
bool expired;
event Expired(uint256 _timestamp);
event ExpiryChange(uint256 indexed _oldTimestamp, uint256 _newTimestamp);
constructor(uint256 _timestamp) {
expires = _timestamp;
}
function setExpiry(uint256 _timestamp) public {
require(!expired);
require(_timestamp > expires);
emit ExpiryChange(expires, _timestamp);
expires = _timestamp;
}
function applyExpiry() public returns(uint8) {
if (expired) {
return 1;
}
if (block.timestamp < expires) {
return 0;
}
expired = true;
emit Expired(block.timestamp);
return 1;
}
function supportsInterface(bytes4 _sum) public pure returns (bool) {
if (_sum == 0x01ffc9a7) { // EIP165
return true;
}
if (_sum == 0x841a0e94) { // Expire
return true;
}
return false;
}
}

View File

@ -0,0 +1 @@
608060405234801561001057600080fd5b50610653806100206000396000f3fe608060405234801561001057600080fd5b5060043610610074576000357c01000000000000000000000000000000000000000000000000000000009004806301ffc9a714610079578063449a52f8146100a95780638832e6e3146100d957806394d008ef146100f5578063e3d670d714610111575b600080fd5b610093600480360381019061008e9190610353565b610141565b6040516100a0919061039b565b60405180910390f35b6100c360048036038101906100be919061044a565b6101f1565b6040516100d0919061039b565b60405180910390f35b6100f360048036038101906100ee91906104ef565b6102b7565b005b61010f600480360381019061010a91906104ef565b6102c8565b005b61012b60048036038101906101269190610563565b6102d9565b604051610138919061059f565b60405180910390f35b60006301ffc9a77c010000000000000000000000000000000000000000000000000000000002827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19160361019557600190506101ec565b635878bcf47c010000000000000000000000000000000000000000000000000000000002827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916036101e757600190506101ec565b600090505b919050565b6000816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825461024191906105e9565b925050819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fab8530f87dc9b59234c4623bf917212bb2536d647574c8e7e5da92c2ede0c9f8846040516102a5919061059f565b60405180910390a36001905092915050565b6102c184846101f1565b5050505050565b6102d284846101f1565b5050505050565b60006020528060005260406000206000915090505481565b600080fd5b600080fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b610330816102fb565b811461033b57600080fd5b50565b60008135905061034d81610327565b92915050565b600060208284031215610369576103686102f1565b5b60006103778482850161033e565b91505092915050565b60008115159050919050565b61039581610380565b82525050565b60006020820190506103b0600083018461038c565b92915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006103e1826103b6565b9050919050565b6103f1816103d6565b81146103fc57600080fd5b50565b60008135905061040e816103e8565b92915050565b6000819050919050565b61042781610414565b811461043257600080fd5b50565b6000813590506104448161041e565b92915050565b60008060408385031215610461576104606102f1565b5b600061046f858286016103ff565b925050602061048085828601610435565b9150509250929050565b600080fd5b600080fd5b600080fd5b60008083601f8401126104af576104ae61048a565b5b8235905067ffffffffffffffff8111156104cc576104cb61048f565b5b6020830191508360018202830111156104e8576104e7610494565b5b9250929050565b60008060008060608587031215610509576105086102f1565b5b6000610517878288016103ff565b945050602061052887828801610435565b935050604085013567ffffffffffffffff811115610549576105486102f6565b5b61055587828801610499565b925092505092959194509250565b600060208284031215610579576105786102f1565b5b6000610587848285016103ff565b91505092915050565b61059981610414565b82525050565b60006020820190506105b46000830184610590565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006105f482610414565b91506105ff83610414565b9250828201905080821115610617576106166105ba565b5b9291505056fea2646970667358221220a5a810b6de36b1154b4b2d37d08d4e8a5fe442c870cd58cdba0d86a13da3dda964736f6c63430008130033

View File

@ -0,0 +1,35 @@
pragma solidity >=0.6.3;
// Author: Louis Holbrook <dev@holbrook.no> 0826EDA1702D1E87C6E2875121D2E7BB88C2A746
// SPDX-License-Identifier: AGPL-3.0-or-later
contract MinterTest {
mapping (address => uint256) public balance;
event Mint(address indexed _minter, address indexed _beneficiary, uint256 _value);
function mintTo(address _beneficiary, uint256 _value) public returns (bool) {
balance[_beneficiary] += _value;
emit Mint(msg.sender, _beneficiary, _value);
return true;
}
function mint(address _beneficiary, uint256 _value, bytes calldata _data) public {
_data;
mintTo(_beneficiary, _value);
}
function safeMint(address _beneficiary, uint256 _value, bytes calldata _data) public {
_data;
mintTo(_beneficiary, _value);
}
function supportsInterface(bytes4 _sum) public pure returns (bool) {
if (_sum == 0x01ffc9a7) { // EIP165
return true;
}
if (_sum == 0x5878bcf4) { // Minter
return true;
}
return false;
}
}

View File

@ -0,0 +1 @@
6080604052600760015534801561001557600080fd5b50610355806100256000396000f3fe608060405234801561001057600080fd5b5060043610610069576000357c01000000000000000000000000000000000000000000000000000000009004806301ffc9a71461006e57806318cbbcfc1461009e57806331a5995d146100bc57806386fe212d146100da575b600080fd5b6100886004803603810190610083919061022f565b6100f6565b6040516100959190610277565b60405180910390f35b6100a66101a6565b6040516100b391906102ab565b60405180910390f35b6100c46101ac565b6040516100d191906102ab565b60405180910390f35b6100f460048036038101906100ef91906102f2565b6101b2565b005b60006301ffc9a77c010000000000000000000000000000000000000000000000000000000002827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19160361014a57600190506101a1565b630d7491f87c010000000000000000000000000000000000000000000000000000000002827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19160361019c57600190506101a1565b600090505b919050565b60015481565b60005481565b60015481106101c057600080fd5b80600080828254179250508190555050565b600080fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b61020c816101d7565b811461021757600080fd5b50565b60008135905061022981610203565b92915050565b600060208284031215610245576102446101d2565b5b60006102538482850161021a565b91505092915050565b60008115159050919050565b6102718161025c565b82525050565b600060208201905061028c6000830184610268565b92915050565b6000819050919050565b6102a581610292565b82525050565b60006020820190506102c0600083018461029c565b92915050565b6102cf81610292565b81146102da57600080fd5b50565b6000813590506102ec816102c6565b92915050565b600060208284031215610308576103076101d2565b5b6000610316848285016102dd565b9150509291505056fea26469706673582212208356fec8f4fc7719bf58ea1be5e22cf56cadb8367918f5b4e0a90cad23396bb064736f6c63430008130033

View File

@ -0,0 +1,25 @@
pragma solidity >=0.6.12;
// Author: Louis Holbrook <dev@holbrook.no> 0826EDA1702D1E87C6E2875121D2E7BB88C2A746
// SPDX-License-Identifier: AGPL-3.0-or-later
contract SealTest {
event SealStateChange(bool indexed _final, uint256 _sealState);
uint256 public sealState;
uint256 public maxSealState = 7;
function seal(uint256 _bits) public {
require(_bits < maxSealState);
sealState |= _bits;
}
function supportsInterface(bytes4 _sum) public pure returns (bool) {
if (_sum == 0x01ffc9a7) { // EIP165
return true;
}
if (_sum == 0x0d7491f8) { // Capped
return true;
}
return false;
}
}

View File

@ -0,0 +1 @@
608060405234801561001057600080fd5b506104da806100206000396000f3fe608060405234801561001057600080fd5b5060043610610069576000357c01000000000000000000000000000000000000000000000000000000009004806301ffc9a71461006e5780632b29ba231461009e5780635ae06f7e146100ce578063da2824a8146100fe575b600080fd5b6100886004803603810190610083919061038c565b61012e565b60405161009591906103d4565b60405180910390f35b6100b860048036038101906100b3919061044d565b6101de565b6040516100c591906103d4565b60405180910390f35b6100e860048036038101906100e3919061044d565b6101fe565b6040516100f591906103d4565b60405180910390f35b6101186004803603810190610113919061044d565b610296565b60405161012591906103d4565b60405180910390f35b60006301ffc9a77c010000000000000000000000000000000000000000000000000000000002827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19160361018257600190506101d9565b63abe1f1f57c010000000000000000000000000000000000000000000000000000000002827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916036101d457600190506101d9565b600090505b919050565b60006020528060005260406000206000915054906101000a900460ff1681565b6000806000808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055507f9002f14780245e47491e7a2caae4712e7cea2e298e4e76c6916845145b90a51c826040516102859190610489565b60405180910390a160019050919050565b600060016000808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055507f6ff3aa2ea7b53070f6d9d07a445d338d89e8edef44250ffa8be19f53910d4a2e8260405161031e9190610489565b60405180910390a160019050919050565b600080fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b61036981610334565b811461037457600080fd5b50565b60008135905061038681610360565b92915050565b6000602082840312156103a2576103a161032f565b5b60006103b084828501610377565b91505092915050565b60008115159050919050565b6103ce816103b9565b82525050565b60006020820190506103e960008301846103c5565b92915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061041a826103ef565b9050919050565b61042a8161040f565b811461043557600080fd5b50565b60008135905061044781610421565b92915050565b6000602082840312156104635761046261032f565b5b600061047184828501610438565b91505092915050565b6104838161040f565b82525050565b600060208201905061049e600083018461047a565b9291505056fea26469706673582212206bef2d3402160122da272241da7b2729136d4bc1e4399f01ddd8c8a7d3b93cdd64736f6c63430008130033

View File

@ -0,0 +1,33 @@
pragma solidity >=0.6.3;
// Author: Louis Holbrook <dev@holbrook.no> 0826EDA1702D1E87C6E2875121D2E7BB88C2A746
// SPDX-License-Identifier: AGPL-3.0-or-later
contract WriterTest {
mapping (address => bool ) public isWriter;
event WriterAdded(address _writer);
event WriterDeleted(address _writer);
function addWriter(address _writer) public returns (bool) {
isWriter[_writer] = true;
emit WriterAdded(_writer);
return true;
}
function deleteWriter(address _writer) public returns (bool) {
isWriter[_writer] = false;
emit WriterDeleted(_writer);
return true;
}
function supportsInterface(bytes4 _sum) public pure returns (bool) {
if (_sum == 0x01ffc9a7) { // EIP165
return true;
}
if (_sum == 0xabe1f1f5) { // Writer
return true;
}
return false;
}
}

View File

@ -1,2 +1,4 @@
eth_tester==0.5.0b3
py-evm==0.3.0a20
eth-erc20~=0.7.4
eth-interface~=0.1.2

View File

@ -0,0 +1,29 @@
# standard imports
import unittest
import logging
import os
from chainlib.eth.nonce import RPCNonceOracle
from chainlib.eth.tx import receipt
from eth_erc20 import ERC20
from giftable_erc20_token import GiftableToken
from eth_interface.unittest import TestERC165
# local imports
from eth_burner import EthBurner
from eth_burner.unittest import TestEthBurnerInterface
from eth_burner.unittest.base import TestEthBurner
logging.basicConfig(level=logging.DEBUG)
logg = logging.getLogger()
class TestBurnerBase(TestEthBurner, TestEthBurnerInterface, TestERC165):
def setUp(self):
super(TestBurnerBase, self).setUp()
self.add_interface_check('bc4babdd')
if __name__ == '__main__':
unittest.main()

View File

@ -0,0 +1,30 @@
# standard imports
import unittest
import logging
import os
from chainlib.eth.nonce import RPCNonceOracle
from chainlib.eth.tx import receipt
from eth_erc20 import ERC20
from giftable_erc20_token import GiftableToken
from eth_interface.unittest import TestERC165
# local imports
from eth_capped import EthCapped
from eth_capped.unittest import TestEthCappedInterface
from eth_capped.unittest.base import TestEthCapped
logging.basicConfig(level=logging.DEBUG)
logg = logging.getLogger()
class TestCappedBase(TestEthCapped, TestEthCappedInterface, TestERC165):
def setUp(self):
super(TestCappedBase, self).setUp()
self.add_interface_check('869f7594')
self.set_method = self.set_max_supply
if __name__ == '__main__':
unittest.main()

View File

@ -0,0 +1,30 @@
# standard imports
import unittest
import logging
import os
from chainlib.eth.nonce import RPCNonceOracle
from chainlib.eth.tx import receipt
from eth_erc20 import ERC20
from giftable_erc20_token import GiftableToken
from eth_interface.unittest import TestERC165
# local imports
from eth_expire import EthExpire
from eth_expire.unittest import TestEthExpireInterface
from eth_expire.unittest.base import TestEthExpire
logging.basicConfig(level=logging.DEBUG)
logg = logging.getLogger()
class TestExpireBase(TestEthExpire, TestEthExpireInterface, TestERC165):
def setUp(self):
super(TestExpireBase, self).setUp()
self.add_interface_check('841a0e94')
self.set_method = self.set_expiry
if __name__ == '__main__':
unittest.main()

View File

@ -0,0 +1,29 @@
# standard imports
import unittest
import logging
import os
from chainlib.eth.nonce import RPCNonceOracle
from chainlib.eth.tx import receipt
from eth_erc20 import ERC20
from giftable_erc20_token import GiftableToken
from eth_interface.unittest import TestERC165
# local imports
from eth_minter import EthMinter
from eth_minter.unittest import TestEthMinterInterface
from eth_minter.unittest.base import TestEthMinter
logging.basicConfig(level=logging.DEBUG)
logg = logging.getLogger()
class TestMinterBase(TestEthMinter, TestEthMinterInterface, TestERC165):
def setUp(self):
super(TestMinterBase, self).setUp()
self.add_interface_check('5878bcf4')
if __name__ == '__main__':
unittest.main()

30
python/tests/test_seal.py Normal file
View File

@ -0,0 +1,30 @@
# standard imports
import unittest
import logging
import os
from chainlib.eth.nonce import RPCNonceOracle
from chainlib.eth.tx import receipt
from eth_erc20 import ERC20
from giftable_erc20_token import GiftableToken
from eth_interface.unittest import TestERC165
# local imports
from eth_seal import EthSeal
from eth_seal.unittest import TestEthSealInterface
from eth_seal.unittest.base import TestEthSeal
logging.basicConfig(level=logging.DEBUG)
logg = logging.getLogger()
class TestSealBase(TestEthSeal, TestEthSealInterface, TestERC165):
def setUp(self):
super(TestSealBase, self).setUp()
self.add_interface_check('0d7491f8')
self.set_method = self.seal
if __name__ == '__main__':
unittest.main()

View File

@ -0,0 +1,29 @@
# standard imports
import unittest
import logging
import os
from chainlib.eth.nonce import RPCNonceOracle
from chainlib.eth.tx import receipt
from eth_erc20 import ERC20
from giftable_erc20_token import GiftableToken
from eth_interface.unittest import TestERC165
# local imports
from eth_writer import EthWriter
from eth_writer.unittest import TestEthWriterInterface
from eth_writer.unittest.base import TestEthWriter
logging.basicConfig(level=logging.DEBUG)
logg = logging.getLogger()
class TestWriterBase(TestEthWriter, TestEthWriterInterface, TestERC165):
def setUp(self):
super(TestWriterBase, self).setUp()
self.add_interface_check('abe1f1f5')
if __name__ == '__main__':
unittest.main()

View File

@ -12,10 +12,11 @@ interface IBurner {
function burn(address _from, uint256 _amount, bytes calldata _data) external;
// Burn given amount of tokens held by signer.
function burn(uint256 _burn) external returns (bool);
function burn(uint256 _amount) external returns (bool);
// Burn all tokens held by signer.
function burn() external returns (bool);
// Returns the amount of tokens burned.
function burn() external returns (uint256);
// Total amount of tokens that have been burned.
function totalBurned() external returns (uint256);

12
solidity/Capped.sol Normal file
View File

@ -0,0 +1,12 @@
pragma solidity >=0.6.12;
// Author: Louis Holbrook <dev@holbrook.no> 0826EDA1702D1E87C6E2875121D2E7BB88C2A746
// SPDX-License-Identifier: AGPL-3.0-or-later
// File-version: 1
interface ICapped {
// Supply limit is changed.
event Cap(uint256 indexed _oldCap, uint256 _newCap);
// Return the supply limit.
function maxSupply() external returns(uint256);
}

View File

@ -18,5 +18,5 @@ interface IWriter {
function deleteWriter(address _writer) external returns (bool);
// Check whether the given address is a writer.
function isWriter(address _writer) external returns (bool);
function isWriter(address _writer) external view returns (bool);
}