Add capped interface, python interface and test for capped, expire
This commit is contained in:
parent
c10d2c46f1
commit
220b8afbeb
5
Makefile
5
Makefile
@ -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
|
||||
|
@ -1 +1 @@
|
||||
include *requirements.txt
|
||||
include *requirements.txt solidity/* LICENSE README*
|
||||
|
17
python/Makefile
Normal file
17
python/Makefile
Normal 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
|
1
python/eth_capped/__init__.py
Normal file
1
python/eth_capped/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
from .capped import EthCapped
|
22
python/eth_capped/capped.py
Normal file
22
python/eth_capped/capped.py
Normal 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
|
1
python/eth_capped/unittest/__init__.py
Normal file
1
python/eth_capped/unittest/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
from .interface import TestEthCappedInterface
|
67
python/eth_capped/unittest/base.py
Normal file
67
python/eth_capped/unittest/base.py
Normal file
@ -0,0 +1,67 @@
|
||||
# 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_capped import EthCapped
|
||||
|
||||
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
|
38
python/eth_capped/unittest/interface.py
Normal file
38
python/eth_capped/unittest/interface.py
Normal 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))
|
1
python/eth_expire/__init__.py
Normal file
1
python/eth_expire/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
from .expire import EthExpire
|
37
python/eth_expire/expire.py
Normal file
37
python/eth_expire/expire.py
Normal 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)
|
1
python/eth_expire/unittest/__init__.py
Normal file
1
python/eth_expire/unittest/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
from .interface import TestEthExpireInterface
|
69
python/eth_expire/unittest/base.py
Normal file
69
python/eth_expire/unittest/base.py
Normal file
@ -0,0 +1,69 @@
|
||||
# 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_capped import EthCapped
|
||||
|
||||
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.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, '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
|
37
python/eth_expire/unittest/interface.py
Normal file
37
python/eth_expire/unittest/interface.py
Normal 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))
|
1
python/eth_writer/__init__.py
Normal file
1
python/eth_writer/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
from .interface import *
|
44
python/eth_writer/interface.py
Normal file
44
python/eth_writer/interface.py
Normal 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
|
1
python/eth_writer/unittest/__init__.py
Normal file
1
python/eth_writer/unittest/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
from .base import TestEthWriterInterface
|
45
python/eth_writer/unittest/base.py
Normal file
45
python/eth_writer/unittest/base.py
Normal 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)
|
@ -1 +1 @@
|
||||
chainlib-eth~=0.4.7
|
||||
chainlib-eth~=0.4.24
|
||||
|
15
python/run_tests.sh
Executable file
15
python/run_tests.sh
Executable 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
|
@ -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
|
||||
|
1
python/solidity/CappedTest.bin
Normal file
1
python/solidity/CappedTest.bin
Normal file
@ -0,0 +1 @@
|
||||
608060405234801561001057600080fd5b506040516104003803806104008339818101604052810190610032919061007a565b80600081905550506100a7565b600080fd5b6000819050919050565b61005781610044565b811461006257600080fd5b50565b6000815190506100748161004e565b92915050565b6000602082840312156100905761008f61003f565b5b600061009e84828501610065565b91505092915050565b61034a806100b66000396000f3fe608060405234801561001057600080fd5b506004361061005e576000357c01000000000000000000000000000000000000000000000000000000009004806301ffc9a7146100635780636f8b44b014610093578063d5abeb01146100af575b600080fd5b61007d60048036038101906100789190610224565b6100cd565b60405161008a919061026c565b60405180910390f35b6100ad60048036038101906100a891906102bd565b61017d565b005b6100b76101c1565b6040516100c491906102f9565b60405180910390f35b60006301ffc9a77c010000000000000000000000000000000000000000000000000000000002827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916036101215760019050610178565b63869f75947c010000000000000000000000000000000000000000000000000000000002827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916036101735760019050610178565b600090505b919050565b6000547f9722adea12ab7ef86fc45b88f0e0b567639e8dddaae60261e08c03d747fbbfe6826040516101af91906102f9565b60405180910390a28060008190555050565b60005481565b600080fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b610201816101cc565b811461020c57600080fd5b50565b60008135905061021e816101f8565b92915050565b60006020828403121561023a576102396101c7565b5b60006102488482850161020f565b91505092915050565b60008115159050919050565b61026681610251565b82525050565b6000602082019050610281600083018461025d565b92915050565b6000819050919050565b61029a81610287565b81146102a557600080fd5b50565b6000813590506102b781610291565b92915050565b6000602082840312156102d3576102d26101c7565b5b60006102e1848285016102a8565b91505092915050565b6102f381610287565b82525050565b600060208201905061030e60008301846102ea565b9291505056fea2646970667358221220f6bc26e7c6827142ccee8c0cadc8cb76d33712a68eacd67b69e4f8108aa2b59064736f6c63430008130033
|
29
python/solidity/CappedTest.sol
Normal file
29
python/solidity/CappedTest.sol
Normal 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;
|
||||
}
|
||||
}
|
1
python/solidity/ExpireTest.bin
Normal file
1
python/solidity/ExpireTest.bin
Normal file
@ -0,0 +1 @@
|
||||
608060405234801561001057600080fd5b506040516105143803806105148339818101604052810190610032919061007a565b80600081905550506100a7565b600080fd5b6000819050919050565b61005781610044565b811461006257600080fd5b50565b6000815190506100748161004e565b92915050565b6000602082840312156100905761008f61003f565b5b600061009e84828501610065565b91505092915050565b61045e806100b66000396000f3fe608060405234801561001057600080fd5b5060043610610069576000357c01000000000000000000000000000000000000000000000000000000009004806301cceb381461006e57806301ffc9a71461008a5780635f408c04146100ba578063b1cb0db3146100d8575b600080fd5b610088600480360381019061008391906102df565b6100f6565b005b6100a4600480360381019061009f9190610364565b610162565b6040516100b191906103ac565b60405180910390f35b6100c2610212565b6040516100cf91906103e3565b60405180910390f35b6100e061029e565b6040516100ed919061040d565b60405180910390f35b600160009054906101000a900460ff161561011057600080fd5b600054811161011e57600080fd5b6000547ff5bd6cb27a0006b5ea8618058a0d84719695cb6d984f4840bc1a54ca12ae4b7c82604051610150919061040d565b60405180910390a28060008190555050565b60006301ffc9a77c010000000000000000000000000000000000000000000000000000000002827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916036101b6576001905061020d565b63841a0e947c010000000000000000000000000000000000000000000000000000000002827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191603610208576001905061020d565b600090505b919050565b6000600160009054906101000a900460ff1615610232576001905061029b565b600054421015610245576000905061029b565b60018060006101000a81548160ff0219169083151502179055507ff80dbaea4785589e52984ca36a31de106adc77759539a5c7d92883bf49692fe94260405161028e919061040d565b60405180910390a1600190505b90565b60005481565b600080fd5b6000819050919050565b6102bc816102a9565b81146102c757600080fd5b50565b6000813590506102d9816102b3565b92915050565b6000602082840312156102f5576102f46102a4565b5b6000610303848285016102ca565b91505092915050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b6103418161030c565b811461034c57600080fd5b50565b60008135905061035e81610338565b92915050565b60006020828403121561037a576103796102a4565b5b60006103888482850161034f565b91505092915050565b60008115159050919050565b6103a681610391565b82525050565b60006020820190506103c1600083018461039d565b92915050565b600060ff82169050919050565b6103dd816103c7565b82525050565b60006020820190506103f860008301846103d4565b92915050565b610407816102a9565b82525050565b600060208201905061042260008301846103fe565b9291505056fea26469706673582212200ea18a383a2b4a17a3ce884a7787899f37d703ede95cd1ba000e15710432f90b64736f6c63430008130033
|
47
python/solidity/ExpireTest.sol
Normal file
47
python/solidity/ExpireTest.sol
Normal 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) { // Capped
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -1,2 +1,4 @@
|
||||
eth_tester==0.5.0b3
|
||||
py-evm==0.3.0a20
|
||||
eth-erc20~=0.7.4
|
||||
eth-interface~=0.1.2
|
||||
|
30
python/tests/test_capped.py
Normal file
30
python/tests/test_capped.py
Normal 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()
|
30
python/tests/test_expire.py
Normal file
30
python/tests/test_expire.py
Normal 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()
|
12
solidity/Capped.sol
Normal file
12
solidity/Capped.sol
Normal 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);
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user