commit ccc616a1dc8505f37406722a4a11a554ed7075e1
parent 902d4d790ed35f61e7a1ab2ac596e9961e0dddb7
Author: lash <dev@holbrook.no>
Date: Thu, 27 Jul 2023 18:10:48 +0100
Add python harness
Diffstat:
12 files changed, 176 insertions(+), 0 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -0,0 +1,7 @@
+__pycache__
+*.pyc
+*.egg-info
+dist/
+build/
+solidity/*.json
+solidity/*.bin
diff --git a/python/erc20_limiter/__init__.py b/python/erc20_limiter/__init__.py
@@ -0,0 +1 @@
+from .limiter import Limiter
diff --git a/python/erc20_limiter/data/Limiter.bin b/python/erc20_limiter/data/Limiter.bin
@@ -0,0 +1 @@
+608060405234801561001057600080fd5b506102c6806100206000396000f3fe608060405234801561001057600080fd5b5060043610610053576000357c010000000000000000000000000000000000000000000000000000000090048063237786131461005857806336db43b514610088575b600080fd5b610072600480360381019061006d91906101b0565b6100a4565b60405161007f9190610209565b60405180910390f35b6100a2600480360381019061009d9190610250565b6100c9565b005b6000602052816000526040600020602052806000526040600020600091509150505481565b806000808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061017d82610152565b9050919050565b61018d81610172565b811461019857600080fd5b50565b6000813590506101aa81610184565b92915050565b600080604083850312156101c7576101c661014d565b5b60006101d58582860161019b565b92505060206101e68582860161019b565b9150509250929050565b6000819050919050565b610203816101f0565b82525050565b600060208201905061021e60008301846101fa565b92915050565b61022d816101f0565b811461023857600080fd5b50565b60008135905061024a81610224565b92915050565b600080604083850312156102675761026661014d565b5b60006102758582860161019b565b92505060206102868582860161023b565b915050925092905056fea2646970667358221220b0b99ecbbe087d46a73d112695aeff90259e3319f10106bab0b8330733dbea4364736f6c63430008130033
+\ No newline at end of file
diff --git a/python/erc20_limiter/data/Limiter.json b/python/erc20_limiter/data/Limiter.json
@@ -0,0 +1 @@
+[{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"limitOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"setLimit","outputs":[],"stateMutability":"nonpayable","type":"function"}]
diff --git a/python/erc20_limiter/data/Limiter.metadata.json b/python/erc20_limiter/data/Limiter.metadata.json
@@ -0,0 +1 @@
+{"compiler":{"version":"0.8.19+commit.7dd6d404"},"language":"Solidity","output":{"abi":[{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"limitOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"setLimit","outputs":[],"stateMutability":"nonpayable","type":"function"}],"devdoc":{"kind":"dev","methods":{},"version":1},"userdoc":{"kind":"user","methods":{},"version":1}},"settings":{"compilationTarget":{"Limiter.sol":"Limiter"},"evmVersion":"byzantium","libraries":{},"metadata":{"bytecodeHash":"ipfs"},"optimizer":{"enabled":false,"runs":200},"remappings":[]},"sources":{"Limiter.sol":{"keccak256":"0x24351d76034fded7d12ba485309035752a6c960c49e0079c3ad22eaeb11dad9d","license":"AGPL-3.0-or-later","urls":["bzz-raw://2982f178296a2675687b4b65110529f439cd2bcb837579e9658bbf913a978d0b","dweb:/ipfs/Qmf6g95sC1RaRZ6DJ6w2yDnBRoDPFKGid73yefj1pv4jsM"]}},"version":1}
diff --git a/python/erc20_limiter/data/__init__.py b/python/erc20_limiter/data/__init__.py
@@ -0,0 +1,3 @@
+import os
+
+data_dir = os.path.realpath(os.path.dirname(__file__))
diff --git a/python/erc20_limiter/limiter.py b/python/erc20_limiter/limiter.py
@@ -0,0 +1,91 @@
+# standard imports
+import logging
+import os
+import enum
+
+# external imports
+from chainlib.eth.constant import ZERO_ADDRESS
+from chainlib.eth.constant import ZERO_CONTENT
+from chainlib.eth.contract import (
+ ABIContractEncoder,
+ ABIContractDecoder,
+ ABIContractType,
+ abi_decode_single,
+)
+from chainlib.eth.jsonrpc import to_blockheight_param
+from chainlib.eth.error import RequestMismatchException
+from chainlib.eth.tx import (
+ TxFactory,
+ TxFormat,
+)
+from chainlib.jsonrpc import JSONRPCRequest
+from chainlib.block import BlockSpec
+from hexathon import (
+ add_0x,
+ strip_0x,
+)
+from chainlib.eth.cli.encode import CLIEncoder
+
+# local imports
+from erc20_limiter.data import data_dir
+
+logg = logging.getLogger()
+
+
+class Limiter(TxFactory):
+
+ __abi = None
+ __bytecode = None
+
+ def constructor(self, sender_address, tx_format=TxFormat.JSONRPC, version=None):
+ code = self.cargs(version=version)
+ tx = self.template(sender_address, None, use_nonce=True)
+ tx = self.set_code(tx, code)
+ return self.finalize(tx, tx_format)
+
+
+ @staticmethod
+ def cargs(version=None):
+ code = Limiter.bytecode(version=version)
+ enc = ABIContractEncoder()
+ args = enc.get()
+ code += args
+ logg.debug('constructor code: ' + args)
+ return code
+
+
+ @staticmethod
+ def gas(code=None):
+ return 4000000
+
+
+ @staticmethod
+ def abi():
+ if Limiter.__abi == None:
+ f = open(os.path.join(data_dir, 'Limiter.json'), 'r')
+ Limiter.__abi = json.load(f)
+ f.close()
+ return Limiter.__abi
+
+
+ @staticmethod
+ def bytecode(version=None):
+ if Limiter.__bytecode == None:
+ f = open(os.path.join(data_dir, 'Limiter.bin'))
+ Limiter.__bytecode = f.read()
+ f.close()
+ return Limiter.__bytecode
+
+
+ def set_limit(self, contract_address, sender_address, token_address, limit, tx_format=TxFormat.JSONRPC, id_generator=None):
+ enc = ABIContractEncoder()
+ enc.method('setLimit')
+ enc.typ(ABIContractType.ADDRESS)
+ enc.typ(ABIContractType.UINT256)
+ enc.address(token_address)
+ enc.uint256(limit)
+ data = add_0x(enc.get())
+ tx = self.template(sender_address, contract_address, use_nonce=True)
+ tx = self.set_code(tx, data)
+ tx = self.finalize(tx, tx_format, id_generator=id_generator)
+ return tx
diff --git a/python/erc20_limiter/unittest/__init__.py b/python/erc20_limiter/unittest/__init__.py
@@ -0,0 +1 @@
+from .base import *
diff --git a/python/erc20_limiter/unittest/base.py b/python/erc20_limiter/unittest/base.py
@@ -0,0 +1,35 @@
+# standard imports
+import logging
+import time
+
+# 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.address import to_checksum_address
+from chainlib.eth.block import block_latest
+
+# local imports
+from erc20_limiter import Limiter
+
+logg = logging.getLogger(__name__)
+
+class TestLimiter(EthTesterCase):
+
+ def setUp(self):
+ super(TestLimiter, self).setUp()
+ self.conn = RPCConnection.connect(self.chain_spec, 'default')
+ self.publish_limiter()
+
+
+ def publish_limiter(self):
+ nonce_oracle = RPCNonceOracle(self.accounts[0], conn=self.conn)
+ c = Limiter(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
+ (tx_hash, o) = c.constructor(self.accounts[0])
+ self.rpc.do(o)
+ o = receipt(tx_hash)
+ r = self.rpc.do(o)
+ self.assertEqual(r['status'], 1)
+ self.address = to_checksum_address(r['contract_address'])
+ logg.debug('published limiter on address {} with hash {}'.format(self.address, tx_hash))
diff --git a/python/requirements.txt b/python/requirements.txt
@@ -0,0 +1 @@
+chainlib-eth~=0.4.22
diff --git a/python/test_requirements.txt b/python/test_requirements.txt
@@ -0,0 +1,3 @@
+eth_tester==0.5.0b3
+py-evm==0.3.0a20
+eth-interface==0.1.1
diff --git a/python/tests/test_base.py b/python/tests/test_base.py
@@ -0,0 +1,30 @@
+# standard imports
+import unittest
+import logging
+
+# external imports
+from chainlib.eth.nonce import RPCNonceOracle
+from chainlib.eth.tx import receipt
+
+# local imports
+from erc20_limiter import Limiter
+from erc20_limiter.unittest import TestLimiter
+
+logging.basicConfig(level=logging.DEBUG)
+logg = logging.getLogger()
+
+
+class TestLimiterBase(TestLimiter):
+
+ def test_limit(self):
+ nonce_oracle = RPCNonceOracle(self.accounts[0], conn=self.conn)
+ c = Limiter(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
+ (tx_hash, o) = c.set_limit(self.address, self.accounts[0], '2c26b46b68ffc68ff99b453c1d30413413422d70', 256)
+ self.rpc.do(o)
+ o = receipt(tx_hash)
+ r = self.rpc.do(o)
+ self.assertEqual(r['status'], 1)
+
+
+if __name__ == '__main__':
+ unittest.main()