erc20-limiter

ERC20 balance limit registry
Log | Files | Refs | README

commit d1680b60e70e0449e51e68d8eb18f41c6d176313
parent ccc616a1dc8505f37406722a4a11a554ed7075e1
Author: lash <dev@holbrook.no>
Date:   Fri, 28 Jul 2023 10:47:00 +0100

Make limitOf external function, expose unittest fixture

Diffstat:
Mpython/erc20_limiter/data/Limiter.bin | 4++--
Mpython/erc20_limiter/data/Limiter.json | 2+-
Mpython/erc20_limiter/data/Limiter.metadata.json | 2+-
Mpython/erc20_limiter/limiter.py | 30++++++++++++++++++++++++++++--
Mpython/erc20_limiter/unittest/base.py | 7++++---
Msolidity/Limiter.sol | 45+++++++++++++++++++++++++++++++++++++++++++--
6 files changed, 79 insertions(+), 11 deletions(-)

diff --git a/python/erc20_limiter/data/Limiter.bin b/python/erc20_limiter/data/Limiter.bin @@ -1 +1 @@ -608060405234801561001057600080fd5b506102c6806100206000396000f3fe608060405234801561001057600080fd5b5060043610610053576000357c010000000000000000000000000000000000000000000000000000000090048063237786131461005857806336db43b514610088575b600080fd5b610072600480360381019061006d91906101b0565b6100a4565b60405161007f9190610209565b60405180910390f35b6100a2600480360381019061009d9190610250565b6100c9565b005b6000602052816000526040600020602052806000526040600020600091509150505481565b806000808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061017d82610152565b9050919050565b61018d81610172565b811461019857600080fd5b50565b6000813590506101aa81610184565b92915050565b600080604083850312156101c7576101c661014d565b5b60006101d58582860161019b565b92505060206101e68582860161019b565b9150509250929050565b6000819050919050565b610203816101f0565b82525050565b600060208201905061021e60008301846101fa565b92915050565b61022d816101f0565b811461023857600080fd5b50565b60008135905061024a81610224565b92915050565b600080604083850312156102675761026661014d565b5b60006102758582860161019b565b92505060206102868582860161023b565b915050925092905056fea2646970667358221220b0b99ecbbe087d46a73d112695aeff90259e3319f10106bab0b8330733dbea4364736f6c63430008130033 -\ No newline at end of file +608060405234801561001057600080fd5b50336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550610931806100606000396000f3fe608060405234801561001057600080fd5b506004361061007f576000357c01000000000000000000000000000000000000000000000000000000009004806301ffc9a71461008457806323778613146100b457806336db43b5146100e45780638da5cb5b14610100578063bdd554401461011e578063f2fde38b1461013a575b600080fd5b61009e60048036038101906100999190610633565b61016a565b6040516100ab919061067b565b60405180910390f35b6100ce60048036038101906100c991906106f4565b61021a565b6040516100db919061074d565b60405180910390f35b6100fe60048036038101906100f99190610794565b6102a1565b005b610108610326565b60405161011591906107e3565b60405180910390f35b610138600480360381019061013391906107fe565b61034a565b005b610154600480360381019061014f9190610851565b610494565b604051610161919061067b565b60405180910390f35b60006301ffc9a77c010000000000000000000000000000000000000000000000000000000002827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916036101be5760019050610215565b639493f8b27c010000000000000000000000000000000000000000000000000000000002827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916036102105760019050610215565b600090505b919050565b6000600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b80600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505050565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806103cf57508173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b61040e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610405906108db565b60405180910390fd5b80600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550505050565b60008060008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146104ef57600080fd5b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050826000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a36001915050919050565b600080fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b610610816105db565b811461061b57600080fd5b50565b60008135905061062d81610607565b92915050565b600060208284031215610649576106486105d6565b5b60006106578482850161061e565b91505092915050565b60008115159050919050565b61067581610660565b82525050565b6000602082019050610690600083018461066c565b92915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006106c182610696565b9050919050565b6106d1816106b6565b81146106dc57600080fd5b50565b6000813590506106ee816106c8565b92915050565b6000806040838503121561070b5761070a6105d6565b5b6000610719858286016106df565b925050602061072a858286016106df565b9150509250929050565b6000819050919050565b61074781610734565b82525050565b6000602082019050610762600083018461073e565b92915050565b61077181610734565b811461077c57600080fd5b50565b60008135905061078e81610768565b92915050565b600080604083850312156107ab576107aa6105d6565b5b60006107b9858286016106df565b92505060206107ca8582860161077f565b9150509250929050565b6107dd816106b6565b82525050565b60006020820190506107f860008301846107d4565b92915050565b600080600060608486031215610817576108166105d6565b5b6000610825868287016106df565b9350506020610836868287016106df565b92505060406108478682870161077f565b9150509250925092565b600060208284031215610867576108666105d6565b5b6000610875848285016106df565b91505092915050565b600082825260208201905092915050565b7f4552525f41585800000000000000000000000000000000000000000000000000600082015250565b60006108c560078361087e565b91506108d08261088f565b602082019050919050565b600060208201905081810360008301526108f4816108b8565b905091905056fea2646970667358221220637537cee91db8d40743b879190b927cde6e34eee8a9524863365ce11ec024c664736f6c63430008130033 +\ No newline at end of file diff --git a/python/erc20_limiter/data/Limiter.json b/python/erc20_limiter/data/Limiter.json @@ -1 +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"}] +[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_holder","type":"address"}],"name":"limitOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"setLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_holder","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"setLimitFor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"_sum","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"_newOwner","type":"address"}],"name":"transferOwnership","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}] diff --git a/python/erc20_limiter/data/Limiter.metadata.json b/python/erc20_limiter/data/Limiter.metadata.json @@ -1 +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} +{"compiler":{"version":"0.8.19+commit.7dd6d404"},"language":"Solidity","output":{"abi":[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_holder","type":"address"}],"name":"limitOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"setLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_holder","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"setLimitFor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"_sum","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"_newOwner","type":"address"}],"name":"transferOwnership","outputs":[{"internalType":"bool","name":"","type":"bool"}],"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":"0x5d2efe5fb5477abcc3f9ae9cb2f89caa2138ae71308f74e7860fea85999fd7c5","license":"AGPL-3.0-or-later","urls":["bzz-raw://3cc9ed399ceab3c64b147cafaa577351a943a442ab3d7fece036444c88d3800e","dweb:/ipfs/Qmd41uw2HGfXd1AvKGQAHsikjvopRPLidXBDQrx5zz6igT"]}},"version":1} diff --git a/python/erc20_limiter/limiter.py b/python/erc20_limiter/limiter.py @@ -77,15 +77,41 @@ class Limiter(TxFactory): return Limiter.__bytecode - def set_limit(self, contract_address, sender_address, token_address, limit, tx_format=TxFormat.JSONRPC, id_generator=None): + def set_limit(self, contract_address, sender_address, token_address, limit, holder_address=None, tx_format=TxFormat.JSONRPC, id_generator=None): enc = ABIContractEncoder() - enc.method('setLimit') + if holder_address != None: + enc.method('setLimitFor') enc.typ(ABIContractType.ADDRESS) + if holder_address != None: + enc.typ(ABIContractType.ADDRESS) enc.typ(ABIContractType.UINT256) enc.address(token_address) + if holder_address != None: + enc.address(holder_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 + + + def limit_of(self, contract_address, token_address, holder_address, sender_address=ZERO_ADDRESS, id_generator=None): + j = JSONRPCRequest(id_generator) + o = j.template() + o['method'] = 'eth_call' + enc = ABIContractEncoder() + enc.method('limitOf') + enc.typ(ABIContractType.ADDRESS) + enc.typ(ABIContractType.ADDRESS) + enc.address(token_address) + enc.address(holder_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)) + o['params'].append('latest') + o = j.finalize(o) + return o + + diff --git a/python/erc20_limiter/unittest/base.py b/python/erc20_limiter/unittest/base.py @@ -20,7 +20,7 @@ class TestLimiter(EthTesterCase): def setUp(self): super(TestLimiter, self).setUp() self.conn = RPCConnection.connect(self.chain_spec, 'default') - self.publish_limiter() + self.address = self.publish_limiter() def publish_limiter(self): @@ -31,5 +31,6 @@ class TestLimiter(EthTesterCase): 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)) + address = to_checksum_address(r['contract_address']) + logg.debug('published limiter on address {} with hash {}'.format(address, tx_hash)) + return address diff --git a/solidity/Limiter.sol b/solidity/Limiter.sol @@ -6,9 +6,50 @@ pragma solidity ^0.8.0; // Description: Registry of allowed ERC20 balance limits per-token and per-holder. contract Limiter { - mapping ( address => mapping ( address => uint256 ) ) public limitOf; + address public owner; + + mapping ( address => mapping ( address => uint256 ) ) limit; + + // EIP173 + event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); // EIP173 + + constructor() { + owner = msg.sender; + } + + function limitOf(address _token, address _holder) public view returns (uint256) { + return limit[_token][_holder]; + } function setLimit(address _token, uint256 _value) public { - limitOf[_token][msg.sender] = _value; + limit[_token][msg.sender] = _value; + } + + function setLimitFor(address _token, address _holder, uint256 _value) public { + require(msg.sender == owner || msg.sender == _holder, 'ERR_AXX'); + limit[_token][_holder] = _value; + } + + // Implements EIP173 + function transferOwnership(address _newOwner) public returns (bool) { + address oldOwner; + + require(msg.sender == owner); + oldOwner = owner; + owner = _newOwner; + + emit OwnershipTransferred(oldOwner, owner); + return true; + } + + // Implements EIP165 + function supportsInterface(bytes4 _sum) public pure returns (bool) { + if (_sum == 0x01ffc9a7) { // ERC165 + return true; + } + if (_sum == 0x9493f8b2) { // ERC173 + return true; + } + return false; } }