Add seal logic and tests
This commit is contained in:
parent
1f0dc0aa5f
commit
3353733405
File diff suppressed because one or more lines are too long
@ -13,7 +13,7 @@ from chainlib.eth.constant import ZERO_ADDRESS
|
|||||||
|
|
||||||
class ExpiryContract(TxFactory):
|
class ExpiryContract(TxFactory):
|
||||||
|
|
||||||
def set_expires_period(self, contract_address, sender_address, expire_timestamp, tx_format=TxFormat.JSONRPC):
|
def set_expire_period(self, contract_address, sender_address, expire_timestamp, tx_format=TxFormat.JSONRPC):
|
||||||
enc = ABIContractEncoder()
|
enc = ABIContractEncoder()
|
||||||
enc.method('setExpirePeriod')
|
enc.method('setExpirePeriod')
|
||||||
enc.typ(ABIContractType.UINT256)
|
enc.typ(ABIContractType.UINT256)
|
||||||
|
@ -1,15 +1,38 @@
|
|||||||
|
# standard imports
|
||||||
|
import enum
|
||||||
|
|
||||||
# external imports
|
# external imports
|
||||||
|
from chainlib.eth.constant import ZERO_ADDRESS
|
||||||
|
from chainlib.jsonrpc import JSONRPCRequest
|
||||||
from chainlib.eth.tx import (
|
from chainlib.eth.tx import (
|
||||||
TxFactory,
|
TxFactory,
|
||||||
TxFormat,
|
TxFormat,
|
||||||
)
|
)
|
||||||
from chainlib.eth.contract import (
|
from chainlib.eth.contract import (
|
||||||
ABIContractEncoder,
|
ABIContractEncoder,
|
||||||
|
ABIContractType,
|
||||||
|
abi_decode_single,
|
||||||
)
|
)
|
||||||
|
from hexathon import (
|
||||||
|
add_0x,
|
||||||
|
)
|
||||||
|
|
||||||
|
class ContractState(enum.IntEnum):
|
||||||
|
MINTER_STATE = 1
|
||||||
|
SINK_STATE = 2
|
||||||
|
EXPIRY_STATE = 4
|
||||||
|
CAP_STATE = 8
|
||||||
|
|
||||||
|
CONTRACT_SEAL_STATE_MAX = 0
|
||||||
|
|
||||||
|
for v in dir(ContractState):
|
||||||
|
if len(v) > 6 and v[-6:] == '_STATE':
|
||||||
|
CONTRACT_SEAL_STATE_MAX += getattr(ContractState, v).value
|
||||||
|
|
||||||
|
|
||||||
class SealedContract(TxFactory):
|
class SealedContract(TxFactory):
|
||||||
|
|
||||||
def set_state(self, contract_address, sender_address, seal, tx_format=TxFormat.JSONRPC):
|
def seal(self, contract_address, sender_address, seal, tx_format=TxFormat.JSONRPC):
|
||||||
enc = ABIContractEncoder()
|
enc = ABIContractEncoder()
|
||||||
enc.method('seal')
|
enc.method('seal')
|
||||||
enc.typ(ABIContractType.UINT256)
|
enc.typ(ABIContractType.UINT256)
|
||||||
@ -19,3 +42,25 @@ class SealedContract(TxFactory):
|
|||||||
tx = self.set_code(tx, data)
|
tx = self.set_code(tx, data)
|
||||||
tx = self.finalize(tx, tx_format)
|
tx = self.finalize(tx, tx_format)
|
||||||
return tx
|
return tx
|
||||||
|
|
||||||
|
|
||||||
|
def is_sealed(self, contract_address, v, sender_address=ZERO_ADDRESS, id_generator=None):
|
||||||
|
j = JSONRPCRequest(id_generator)
|
||||||
|
o = j.template()
|
||||||
|
o['method'] = 'eth_call'
|
||||||
|
enc = ABIContractEncoder()
|
||||||
|
enc.method('isSealed')
|
||||||
|
enc.typ(ABIContractType.UINT256)
|
||||||
|
enc.uint256(v)
|
||||||
|
data = add_0x(enc.get())
|
||||||
|
tx = self.template(sender_address, contract_address)
|
||||||
|
tx = self.set_code(tx, data)
|
||||||
|
o['params'].append(self.normalize(tx))
|
||||||
|
o['params'].append('latest')
|
||||||
|
o = j.finalize(o)
|
||||||
|
return o
|
||||||
|
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def parse_is_sealed(self, v):
|
||||||
|
return abi_decode_single(ABIContractType.BOOLEAN, v)
|
||||||
|
@ -430,6 +430,18 @@ class DemurrageToken(ERC20, SealedContract, ExpiryContract):
|
|||||||
return o
|
return o
|
||||||
|
|
||||||
|
|
||||||
|
def set_sink_address(self, contract_address, sender_address, address, tx_format=TxFormat.JSONRPC):
|
||||||
|
enc = ABIContractEncoder()
|
||||||
|
enc.method('setSinkAddress')
|
||||||
|
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 apply_demurrage(self, contract_address, sender_address, limit=0, tx_format=TxFormat.JSONRPC):
|
def apply_demurrage(self, contract_address, sender_address, limit=0, tx_format=TxFormat.JSONRPC):
|
||||||
if limit == 0:
|
if limit == 0:
|
||||||
return self.transact_noarg('applyDemurrage', contract_address, sender_address)
|
return self.transact_noarg('applyDemurrage', contract_address, sender_address)
|
||||||
|
@ -39,5 +39,8 @@ done
|
|||||||
# ERC20_DEMURRAGE_TOKEN_TEST_MODE=$m python tests/test_redistribution.py
|
# ERC20_DEMURRAGE_TOKEN_TEST_MODE=$m python tests/test_redistribution.py
|
||||||
#done
|
#done
|
||||||
|
|
||||||
|
python tests/test_expiry.py
|
||||||
|
python tests/test_seal.py
|
||||||
|
|
||||||
set +e
|
set +e
|
||||||
set +x
|
set +x
|
||||||
|
@ -37,7 +37,7 @@ class TestExpire(TestDemurrageDefault):
|
|||||||
(tx_hash, o) = c.mint_to(self.address, self.accounts[0], self.accounts[i+1], mint_amount)
|
(tx_hash, o) = c.mint_to(self.address, self.accounts[0], self.accounts[i+1], mint_amount)
|
||||||
r = self.rpc.do(o)
|
r = self.rpc.do(o)
|
||||||
|
|
||||||
(tx_hash, o) = c.set_expires_period(self.address, self.accounts[0], 2)
|
(tx_hash, o) = c.set_expire_period(self.address, self.accounts[0], 2)
|
||||||
r = self.rpc.do(o)
|
r = self.rpc.do(o)
|
||||||
o = receipt(tx_hash)
|
o = receipt(tx_hash)
|
||||||
r = self.rpc.do(o)
|
r = self.rpc.do(o)
|
||||||
|
164
python/tests/test_seal.py
Normal file
164
python/tests/test_seal.py
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
# standard imports
|
||||||
|
import os
|
||||||
|
import unittest
|
||||||
|
import json
|
||||||
|
import logging
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
# external imports
|
||||||
|
from chainlib.eth.constant import ZERO_ADDRESS
|
||||||
|
from chainlib.eth.nonce import RPCNonceOracle
|
||||||
|
from chainlib.eth.tx import receipt
|
||||||
|
from chainlib.eth.block import (
|
||||||
|
block_latest,
|
||||||
|
block_by_number,
|
||||||
|
)
|
||||||
|
|
||||||
|
# local imports
|
||||||
|
from erc20_demurrage_token import DemurrageToken
|
||||||
|
from erc20_demurrage_token.seal import ContractState
|
||||||
|
from erc20_demurrage_token.seal import CONTRACT_SEAL_STATE_MAX
|
||||||
|
|
||||||
|
# test imports
|
||||||
|
from erc20_demurrage_token.unittest import TestDemurrageDefault
|
||||||
|
|
||||||
|
logging.basicConfig(level=logging.DEBUG)
|
||||||
|
logg = logging.getLogger()
|
||||||
|
|
||||||
|
testdir = os.path.dirname(__file__)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class TestSeal(TestDemurrageDefault):
|
||||||
|
|
||||||
|
def test_seal_dup(self):
|
||||||
|
nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
|
||||||
|
c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
|
||||||
|
|
||||||
|
(tx_hash, o) = c.seal(self.address, self.accounts[0], 1)
|
||||||
|
r = self.rpc.do(o)
|
||||||
|
o = receipt(tx_hash)
|
||||||
|
r = self.rpc.do(o)
|
||||||
|
self.assertEqual(r['status'], 1)
|
||||||
|
|
||||||
|
(tx_hash, o) = c.seal(self.address, self.accounts[0], 1)
|
||||||
|
r = self.rpc.do(o)
|
||||||
|
o = receipt(tx_hash)
|
||||||
|
r = self.rpc.do(o)
|
||||||
|
self.assertEqual(r['status'], 0)
|
||||||
|
|
||||||
|
|
||||||
|
def test_seal_all(self):
|
||||||
|
nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
|
||||||
|
c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
|
||||||
|
|
||||||
|
(tx_hash, o) = c.seal(self.address, self.accounts[0], CONTRACT_SEAL_STATE_MAX)
|
||||||
|
r = self.rpc.do(o)
|
||||||
|
o = receipt(tx_hash)
|
||||||
|
r = self.rpc.do(o)
|
||||||
|
self.assertEqual(r['status'], 1)
|
||||||
|
|
||||||
|
o = c.is_sealed(self.address, 0, sender_address=self.accounts[0])
|
||||||
|
r = self.rpc.do(o)
|
||||||
|
self.assertTrue(c.parse_is_sealed(r))
|
||||||
|
|
||||||
|
|
||||||
|
def test_seal_minter(self):
|
||||||
|
nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
|
||||||
|
c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
|
||||||
|
|
||||||
|
(tx_hash, o) = c.add_minter(self.address, self.accounts[0], self.accounts[1])
|
||||||
|
r = self.rpc.do(o)
|
||||||
|
o = receipt(tx_hash)
|
||||||
|
r = self.rpc.do(o)
|
||||||
|
self.assertEqual(r['status'], 1)
|
||||||
|
|
||||||
|
(tx_hash, o) = c.seal(self.address, self.accounts[0], ContractState.MINTER_STATE)
|
||||||
|
r = self.rpc.do(o)
|
||||||
|
o = receipt(tx_hash)
|
||||||
|
r = self.rpc.do(o)
|
||||||
|
self.assertEqual(r['status'], 1)
|
||||||
|
|
||||||
|
(tx_hash, o) = c.add_minter(self.address, self.accounts[0], self.accounts[2])
|
||||||
|
r = self.rpc.do(o)
|
||||||
|
o = receipt(tx_hash)
|
||||||
|
r = self.rpc.do(o)
|
||||||
|
self.assertEqual(r['status'], 0)
|
||||||
|
|
||||||
|
o = c.is_sealed(self.address, ContractState.MINTER_STATE, sender_address=self.accounts[0])
|
||||||
|
r = self.rpc.do(o)
|
||||||
|
self.assertTrue(c.parse_is_sealed(r))
|
||||||
|
|
||||||
|
|
||||||
|
def test_seal_expiry(self):
|
||||||
|
nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
|
||||||
|
c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
|
||||||
|
|
||||||
|
(tx_hash, o) = c.set_expire_period(self.address, self.accounts[0], 10)
|
||||||
|
r = self.rpc.do(o)
|
||||||
|
o = receipt(tx_hash)
|
||||||
|
r = self.rpc.do(o)
|
||||||
|
self.assertEqual(r['status'], 1)
|
||||||
|
|
||||||
|
(tx_hash, o) = c.set_expire_period(self.address, self.accounts[0], 20)
|
||||||
|
r = self.rpc.do(o)
|
||||||
|
o = receipt(tx_hash)
|
||||||
|
r = self.rpc.do(o)
|
||||||
|
self.assertEqual(r['status'], 1)
|
||||||
|
|
||||||
|
(tx_hash, o) = c.seal(self.address, self.accounts[0], ContractState.EXPIRY_STATE)
|
||||||
|
r = self.rpc.do(o)
|
||||||
|
o = receipt(tx_hash)
|
||||||
|
r = self.rpc.do(o)
|
||||||
|
self.assertEqual(r['status'], 1)
|
||||||
|
|
||||||
|
(tx_hash, o) = c.set_expire_period(self.address, self.accounts[0], 21)
|
||||||
|
r = self.rpc.do(o)
|
||||||
|
o = receipt(tx_hash)
|
||||||
|
r = self.rpc.do(o)
|
||||||
|
self.assertEqual(r['status'], 0)
|
||||||
|
|
||||||
|
o = c.is_sealed(self.address, ContractState.EXPIRY_STATE, sender_address=self.accounts[0])
|
||||||
|
r = self.rpc.do(o)
|
||||||
|
self.assertTrue(c.parse_is_sealed(r))
|
||||||
|
|
||||||
|
|
||||||
|
def test_seal_set_sink_address(self):
|
||||||
|
nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
|
||||||
|
c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
|
||||||
|
|
||||||
|
(tx_hash, o) = c.set_sink_address(self.address, self.accounts[0], self.accounts[3])
|
||||||
|
r = self.rpc.do(o)
|
||||||
|
o = receipt(tx_hash)
|
||||||
|
r = self.rpc.do(o)
|
||||||
|
self.assertEqual(r['status'], 1)
|
||||||
|
|
||||||
|
(tx_hash, o) = c.set_sink_address(self.address, self.accounts[0], self.accounts[4])
|
||||||
|
r = self.rpc.do(o)
|
||||||
|
o = receipt(tx_hash)
|
||||||
|
r = self.rpc.do(o)
|
||||||
|
self.assertEqual(r['status'], 1)
|
||||||
|
|
||||||
|
(tx_hash, o) = c.seal(self.address, self.accounts[0], ContractState.SINK_STATE)
|
||||||
|
r = self.rpc.do(o)
|
||||||
|
o = receipt(tx_hash)
|
||||||
|
r = self.rpc.do(o)
|
||||||
|
self.assertEqual(r['status'], 1)
|
||||||
|
|
||||||
|
(tx_hash, o) = c.set_sink_address(self.address, self.accounts[0], self.accounts[5])
|
||||||
|
r = self.rpc.do(o)
|
||||||
|
o = receipt(tx_hash)
|
||||||
|
r = self.rpc.do(o)
|
||||||
|
self.assertEqual(r['status'], 0)
|
||||||
|
|
||||||
|
o = c.is_sealed(self.address, ContractState.SINK_STATE, sender_address=self.accounts[0])
|
||||||
|
r = self.rpc.do(o)
|
||||||
|
self.assertTrue(c.parse_is_sealed(r))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
|
|
||||||
|
|
@ -155,7 +155,7 @@ contract DemurrageTokenSingleCap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function seal(uint256 _state) public returns(uint256) {
|
function seal(uint256 _state) public returns(uint256) {
|
||||||
require(_state < 8, 'ERR_INVALID_STATE');
|
require(_state < 16, 'ERR_INVALID_STATE');
|
||||||
require(_state & sealState == 0, 'ERR_ALREADY_LOCKED');
|
require(_state & sealState == 0, 'ERR_ALREADY_LOCKED');
|
||||||
sealState |= _state;
|
sealState |= _state;
|
||||||
emit SealStateChange(sealState);
|
emit SealStateChange(sealState);
|
||||||
|
Reference in New Issue
Block a user