eth-token-index

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

commit f8466066f1b1ed91a778983af050cfc5992cd001
Author: nolash <dev@holbrook.no>
Date:   Mon,  4 Oct 2021 16:24:51 +0200

initial commit, factored out from eth-address-index

Diffstat:
A.gitignore | 4++++
Apython/MANIFEST.in | 1+
Apython/eth_token_index/__init__.py | 4++++
Apython/eth_token_index/data/ERC20.json | 1+
Apython/eth_token_index/data/GiftableToken.bin | 2++
Apython/eth_token_index/data/GiftableToken.json | 1+
Apython/eth_token_index/data/TokenUniqueSymbolIndex.bin | 2++
Apython/eth_token_index/data/TokenUniqueSymbolIndex.json | 1+
Apython/eth_token_index/index.py | 147+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Apython/eth_token_index/runnable/add.py | 89+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Apython/eth_token_index/runnable/deploy.py | 69+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Apython/eth_token_index/runnable/list.py | 100+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Apython/requirements.txt | 5+++++
Apython/setup.cfg | 45+++++++++++++++++++++++++++++++++++++++++++++
Apython/setup.py | 25+++++++++++++++++++++++++
Apython/test_requirements.txt | 2++
Apython/tests/test_tokenindex.py | 78++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asolidity/Makefile | 11+++++++++++
Asolidity/TokenUniqueSymbolIndex.sol | 105+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
19 files changed, 692 insertions(+), 0 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -0,0 +1,4 @@ +*.egg-info +build +*.pyc +__pycache__ diff --git a/python/MANIFEST.in b/python/MANIFEST.in @@ -0,0 +1 @@ +include **/data/*.json **/data/*.bin *requirements.txt diff --git a/python/eth_token_index/__init__.py b/python/eth_token_index/__init__.py @@ -0,0 +1,4 @@ +from .index import ( + TokenUniqueSymbolIndex, + to_identifier, + ) diff --git a/python/eth_token_index/data/ERC20.json b/python/eth_token_index/data/ERC20.json @@ -0,0 +1 @@ +[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_owner","type":"address"},{"indexed":true,"internalType":"address","name":"_spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"_value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_from","type":"address"},{"indexed":true,"internalType":"address","name":"_to","type":"address"},{"indexed":false,"internalType":"uint256","name":"_value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_spender","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}] diff --git a/python/eth_token_index/data/GiftableToken.bin b/python/eth_token_index/data/GiftableToken.bin @@ -0,0 +1 @@ +60806040523480156200001157600080fd5b506040516200120338038062001203833981810160405260608110156200003757600080fd5b81019080805160405193929190846401000000008211156200005857600080fd5b838201915060208201858111156200006f57600080fd5b82518660018202830111640100000000821117156200008d57600080fd5b8083526020830192505050908051906020019080838360005b83811015620000c3578082015181840152602081019050620000a6565b50505050905090810190601f168015620000f15780820380516001836020036101000a031916815260200191505b50604052602001805160405193929190846401000000008211156200011557600080fd5b838201915060208201858111156200012c57600080fd5b82518660018202830111640100000000821117156200014a57600080fd5b8083526020830192505050908051906020019080838360005b838110156200018057808201518184015260208101905062000163565b50505050905090810190601f168015620001ae5780820380516001836020036101000a031916815260200191505b5060405260200180519060200190929190505050336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555082600290805190602001906200021a929190620002af565b50816003908051906020019062000233929190620002af565b5080600460006101000a81548160ff021916908360ff16021790555060018060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff02191690831515021790555050505062000365565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282620002e7576000855562000333565b82601f106200030257805160ff191683800117855562000333565b8280016001018555821562000333579182015b828111156200033257825182559160200191906001019062000315565b5b50905062000342919062000346565b5090565b5b808211156200036157600081600090555060010162000347565b5090565b610e8e80620003756000396000f3fe608060405234801561001057600080fd5b50600436106100b45760003560e01c806355b6ed5c1161007157806355b6ed5c146102bd57806370a082311461033557806395d89b411461038d578063983b2d5614610410578063a0712d681461046a578063a9059cbb146104ae576100b4565b806306fdde03146100b9578063095ea7b31461013c57806318160ddd146101a057806323b872dd146101be5780633092afd514610242578063313ce5671461029c575b600080fd5b6100c1610512565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156101015780820151818401526020810190506100e6565b50505050905090810190601f16801561012e5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6101886004803603604081101561015257600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506105b0565b60405180821515815260200191505060405180910390f35b6101a86106ab565b6040518082815260200191505060405180910390f35b61022a600480360360608110156101d457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506106b1565b60405180821515815260200191505060405180910390f35b6102846004803603602081101561025857600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506109a8565b60405180821515815260200191505060405180910390f35b6102a4610a9a565b604051808260ff16815260200191505060405180910390f35b61031f600480360360408110156102d357600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610aad565b6040518082815260200191505060405180910390f35b6103776004803603602081101561034b57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610ad2565b6040518082815260200191505060405180910390f35b610395610aea565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156103d55780820151818401526020810190506103ba565b50505050905090810190601f1680156104025780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6104526004803603602081101561042657600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610b88565b60405180821515815260200191505060405180910390f35b6104966004803603602081101561048057600080fd5b8101908080359060200190929190505050610c43565b60405180821515815260200191505060405180910390f35b6104fa600480360360408110156104c457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610d01565b60405180821515815260200191505060405180910390f35b60028054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156105a85780601f1061057d576101008083540402835291602001916105a8565b820191906000526020600020905b81548152906001019060200180831161058b57829003601f168201915b505050505081565b600081600760003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040518082815260200191505060405180910390a36001905092915050565b60055481565b600081600760008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054101561073c57600080fd5b81600660008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054101561078857600080fd5b81600760008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205403600760008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555081600660008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254039250508190555081600660008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055503373ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167f5f7542858008eeb041631f30e6109ae94b83a58e9a58261dd2c42c508850f939856040518082815260200191505060405180910390a4600190509392505050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161480610a3057508173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b610a3957600080fd5b6000600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff02191690831515021790555060019050919050565b600460009054906101000a900460ff1681565b6007602052816000526040600020602052806000526040600020600091509150505481565b60066020528060005260406000206000915090505481565b60038054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610b805780601f10610b5557610100808354040283529160200191610b80565b820191906000526020600020905b815481529060010190602001808311610b6357829003601f168201915b505050505081565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610be357600080fd5b60018060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff02191690831515021790555060019050919050565b6000600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16610c9b57600080fd5b81600660003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508160056000828254019250508190555060019050919050565b600081600660003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541015610d4f57600080fd5b81600660003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254039250508190555081600660008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a3600190509291505056fea2646970667358221220decedd646f4686c330f11369f5c7b4908d8940d20f00c85711890c5f75172d8764736f6c63430007050033 +\ No newline at end of file diff --git a/python/eth_token_index/data/GiftableToken.json b/python/eth_token_index/data/GiftableToken.json @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"uint8","name":"_decimals","type":"uint8"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_owner","type":"address"},{"indexed":true,"internalType":"address","name":"_spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"_value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_from","type":"address"},{"indexed":true,"internalType":"address","name":"_to","type":"address"},{"indexed":false,"internalType":"uint256","name":"_value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_from","type":"address"},{"indexed":true,"internalType":"address","name":"_to","type":"address"},{"indexed":true,"internalType":"address","name":"_spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"_value","type":"uint256"}],"name":"TransferFrom","type":"event"},{"inputs":[{"internalType":"address","name":"_minter","type":"address"}],"name":"addMinter","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"allowances","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_spender","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"mint","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_minter","type":"address"}],"name":"removeMinter","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}] diff --git a/python/eth_token_index/data/TokenUniqueSymbolIndex.bin b/python/eth_token_index/data/TokenUniqueSymbolIndex.bin @@ -0,0 +1 @@ +608060405234801561001057600080fd5b50336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600360009080600181540180825580915050600190039060005260206000200160009091909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550611021806100c46000396000f3fe608060405234801561001057600080fd5b50600436106100bb576000357c0100000000000000000000000000000000000000000000000000000000900480637ef50298116100835780637ef502981461018c5780638da5cb5b146101bc578063bb34534c146101da578063e2095c071461020a578063f2fde38b1461023a576100bb565b806301ffc9a7146100c05780630a3b0a4f146100f05780630cbb0f83146101205780634420e4861461013e57806379ba50971461016e575b600080fd5b6100da60048036038101906100d59190610b9c565b61026a565b6040516100e79190610ccf565b60405180910390f35b61010a60048036038101906101059190610b15565b610415565b6040516101179190610ccf565b60405180910390f35b610128610427565b6040516101359190610cea565b60405180910390f35b61015860048036038101906101539190610b15565b610440565b6040516101659190610ccf565b60405180910390f35b610176610709565b6040516101839190610ccf565b60405180910390f35b6101a660048036038101906101a19190610b42565b6108ab565b6040516101b39190610cea565b60405180910390f35b6101c46108c3565b6040516101d19190610cb4565b60405180910390f35b6101f460048036038101906101ef9190610b42565b6108e7565b6040516102019190610cb4565b60405180910390f35b610224600480360381019061021f9190610c12565b610947565b6040516102319190610cb4565b60405180910390f35b610254600480360381019061024f9190610b15565b61099b565b6040516102619190610ccf565b60405180910390f35b600063cbdb05c77c010000000000000000000000000000000000000000000000000000000002827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614156102bf5760019050610410565b63bb34534c7c010000000000000000000000000000000000000000000000000000000002827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614156103125760019050610410565b6301ffc9a77c010000000000000000000000000000000000000000000000000000000002827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614156103655760019050610410565b639493f8b27c010000000000000000000000000000000000000000000000000000000002827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614156103b85760019050610410565b6337a47be47c010000000000000000000000000000000000000000000000000000000002827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916141561040b5760019050610410565b600090505b919050565b600061042082610440565b9050919050565b6000600160038054905061043b9190610dc7565b905090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461049b57600080fd5b60606000806000808673ffffffffffffffffffffffffffffffffffffffff166040516024016040516020818303038152906040527f95d89b41000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505060405161054a9190610c9d565b6000604051808303816000865af19150503d8060008114610587576040519150601f19603f3d011682016040523d82523d6000602084013e61058c565b606091505b50915091508161059b57600080fd5b808060200190518101906105af9190610bc9565b94506002856040516105c19190610c9d565b602060405180830381855afa1580156105de573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052508101906106019190610b6f565b9350600260008581526020019081526020016000205492506000831461062657600080fd5b60038054905060026000868152602001908152602001600020819055506003879080600181540180825580915050600190039060005260206000200160009091909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060016003805490506106b89190610dc7565b8773ffffffffffffffffffffffffffffffffffffffff167f9cc987676e7d63379f176ea50df0ae8d2d9d1141d1231d4ce15b5965f73c943060405160405180910390a3600195505050505050919050565b600080600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461076657600080fd5b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff166000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506000600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35090565b60026020528060005260406000206000915090505481565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600080600260008481526020019081526020016000205490506003818154811061091457610913610f0c565b5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16915050919050565b600060036001836109589190610d71565b8154811061096957610968610f0c565b5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050919050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146109f657600080fd5b81600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550919050565b6000610a4f610a4a84610d2a565b610d05565b905082815260208101848484011115610a6b57610a6a610f6f565b5b610a76848285610e79565b509392505050565b600081359050610a8d81610f8f565b92915050565b600081359050610aa281610fa6565b92915050565b600081519050610ab781610fa6565b92915050565b600081359050610acc81610fbd565b92915050565b600082601f830112610ae757610ae6610f6a565b5b8151610af7848260208601610a3c565b91505092915050565b600081359050610b0f81610fd4565b92915050565b600060208284031215610b2b57610b2a610f79565b5b6000610b3984828501610a7e565b91505092915050565b600060208284031215610b5857610b57610f79565b5b6000610b6684828501610a93565b91505092915050565b600060208284031215610b8557610b84610f79565b5b6000610b9384828501610aa8565b91505092915050565b600060208284031215610bb257610bb1610f79565b5b6000610bc084828501610abd565b91505092915050565b600060208284031215610bdf57610bde610f79565b5b600082015167ffffffffffffffff811115610bfd57610bfc610f74565b5b610c0984828501610ad2565b91505092915050565b600060208284031215610c2857610c27610f79565b5b6000610c3684828501610b00565b91505092915050565b610c4881610dfb565b82525050565b610c5781610e0d565b82525050565b6000610c6882610d5b565b610c728185610d66565b9350610c82818560208601610e79565b80840191505092915050565b610c9781610e6f565b82525050565b6000610ca98284610c5d565b915081905092915050565b6000602082019050610cc96000830184610c3f565b92915050565b6000602082019050610ce46000830184610c4e565b92915050565b6000602082019050610cff6000830184610c8e565b92915050565b6000610d0f610d20565b9050610d1b8282610eac565b919050565b6000604051905090565b600067ffffffffffffffff821115610d4557610d44610f3b565b5b610d4e82610f7e565b9050602081019050919050565b600081519050919050565b600081905092915050565b6000610d7c82610e6f565b9150610d8783610e6f565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff03821115610dbc57610dbb610edd565b5b828201905092915050565b6000610dd282610e6f565b9150610ddd83610e6f565b925082821015610df057610def610edd565b5b828203905092915050565b6000610e0682610e4f565b9050919050565b60008115159050919050565b6000819050919050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b60005b83811015610e97578082015181840152602081019050610e7c565b83811115610ea6576000848401525b50505050565b610eb582610f7e565b810181811067ffffffffffffffff82111715610ed457610ed3610f3b565b5b80604052505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b610f9881610dfb565b8114610fa357600080fd5b50565b610faf81610e19565b8114610fba57600080fd5b50565b610fc681610e23565b8114610fd157600080fd5b50565b610fdd81610e6f565b8114610fe857600080fd5b5056fea26469706673582212201cbc4bf05e3ed0bb6e627801ab4486f9b8d966bf2e342645a13008d6bfddb33b64736f6c63430008070033 +\ No newline at end of file diff --git a/python/eth_token_index/data/TokenUniqueSymbolIndex.json b/python/eth_token_index/data/TokenUniqueSymbolIndex.json @@ -0,0 +1 @@ +[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"addedAccount","type":"address"},{"indexed":true,"internalType":"uint256","name":"accountIndex","type":"uint256"}],"name":"AddressAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[],"name":"acceptOwnership","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"add","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_key","type":"bytes32"}],"name":"addressOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_idx","type":"uint256"}],"name":"entry","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"entryCount","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"}],"name":"register","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"registry","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","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/eth_token_index/index.py b/python/eth_token_index/index.py @@ -0,0 +1,147 @@ +# Author: Louis Holbrook <dev@holbrook.no> 0826EDA1702D1E87C6E2875121D2E7BB88C2A746 +# SPDX-License-Identifier: GPL-3.0-or-later +# File-version: 1 +# Description: Python interface to abi and bin files for faucet contracts + +# standard imports +import logging +import json +import os +import hashlib + +# external imports +from chainlib.eth.contract import ( + ABIContractEncoder, + ABIContractType, + abi_decode_single, + ) +from chainlib.eth.tx import ( + TxFactory, + TxFormat, + ) +from chainlib.jsonrpc import JSONRPCRequest +from chainlib.eth.constant import ZERO_ADDRESS +from hexathon import ( + add_0x, + ) + +logg = logging.getLogger(__name__) + +moddir = os.path.dirname(__file__) +datadir = os.path.join(moddir, 'data') + + +def to_identifier(s): + h = hashlib.new('sha256') + h.update(s.encode('utf-8')) + return h.digest().hex() + + +class TokenUniqueSymbolIndex(TxFactory): + + __abi = None + __bytecode = None + + + @staticmethod + def abi(): + if TokenUniqueSymbolIndex.__abi == None: + f = open(os.path.join(datadir, 'TokenUniqueSymbolIndex.json'), 'r') + TokenUniqueSymbolIndex.__abi = json.load(f) + f.close() + return TokenUniqueSymbolIndex.__abi + + + @staticmethod + def bytecode(): + if TokenUniqueSymbolIndex.__bytecode == None: + f = open(os.path.join(datadir, 'TokenUniqueSymbolIndex.bin')) + TokenUniqueSymbolIndex.__bytecode = f.read() + f.close() + return TokenUniqueSymbolIndex.__bytecode + + + @staticmethod + def gas(code=None): + return 1200000 + + + def constructor(self, sender_address): + code = TokenUniqueSymbolIndex.bytecode() + tx = self.template(sender_address, None, use_nonce=True) + tx = self.set_code(tx, code) + return self.build(tx) + + + def register(self, contract_address, sender_address, address, tx_format=TxFormat.JSONRPC): + enc = ABIContractEncoder() + enc.method('register') + 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 address_of(self, contract_address, token_symbol, sender_address=ZERO_ADDRESS, id_generator=None): + j = JSONRPCRequest(id_generator) + o = j.template() + o['method'] = 'eth_call' + enc = ABIContractEncoder() + enc.method('addressOf') + enc.typ(ABIContractType.BYTES32) + token_symbol_digest = to_identifier(token_symbol) + enc.bytes32(token_symbol_digest) + 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 = j.finalize(o) + return o + + + def entry(self, contract_address, idx, sender_address=ZERO_ADDRESS, id_generator=None): + j = JSONRPCRequest(id_generator) + o = j.template() + o['method'] = 'eth_call' + enc = ABIContractEncoder() + enc.method('entry') + enc.typ(ABIContractType.UINT256) + enc.uint256(idx) + 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 = j.finalize(o) + return o + + + def entry_count(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('entryCount') + 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 = j.finalize(o) + return o + + + @classmethod + def parse_address_of(self, v): + return abi_decode_single(ABIContractType.ADDRESS, v) + + + @classmethod + def parse_entry(self, v): + return abi_decode_single(ABIContractType.ADDRESS, v) + + + @classmethod + def parse_entry_count(self, v): + return abi_decode_single(ABIContractType.UINT256, v) diff --git a/python/eth_token_index/runnable/add.py b/python/eth_token_index/runnable/add.py @@ -0,0 +1,89 @@ +"""Adds a new token to the token symbol index + +.. moduleauthor:: Louis Holbrook <dev@holbrook.no> +.. pgp:: 0826EDA1702D1E87C6E2875121D2E7BB88C2A746 + +""" + +# standard imports +import sys +import os +import json +import argparse +import logging +import hashlib + +# external imports +import chainlib.eth.cli +from chainlib.chain import ChainSpec +from chainlib.eth.tx import receipt +from eth_erc20 import ERC20 +from chainlib.eth.address import to_checksum_address +from hexathon import add_0x + +# local imports +from eth_token_index import TokenUniqueSymbolIndex + +logging.basicConfig(level=logging.WARNING) +logg = logging.getLogger() + +arg_flags = chainlib.eth.cli.argflag_std_write | chainlib.eth.cli.Flag.EXEC +argparser = chainlib.eth.cli.ArgumentParser(arg_flags) +argparser.add_argument('token_address', type=str, help='Token address to add to index') +args = argparser.parse_args() + +extra_args = { + 'token_address': None, + } +config = chainlib.eth.cli.Config.from_args(args, arg_flags, extra_args=extra_args, default_fee_limit=TokenUniqueSymbolIndex.gas()) + +wallet = chainlib.eth.cli.Wallet() +wallet.from_config(config) + +rpc = chainlib.eth.cli.Rpc(wallet=wallet) +conn = rpc.connect_by_config(config) + +chain_spec = ChainSpec.from_chain_str(config.get('CHAIN_SPEC')) + + +def main(): + signer = rpc.get_signer() + signer_address = rpc.get_sender_address() + + gas_oracle = rpc.get_gas_oracle() + nonce_oracle = rpc.get_nonce_oracle() + + c = TokenUniqueSymbolIndex(chain_spec, signer=signer, gas_oracle=gas_oracle, nonce_oracle=nonce_oracle) + + token_address = to_checksum_address(config.get('_TOKEN_ADDRESS')) + if not config.true('_UNSAFE') and token_address != add_0x(config.get('_TOKEN_ADDRESS')): + raise ValueError('invalid checksum address for token_address') + + contract_address = to_checksum_address(config.get('_EXEC_ADDRESS')) + if not config.true('_UNSAFE') and contract_address != add_0x(config.get('_EXEC_ADDRESS')): + raise ValueError('invalid checksum address for contract') + + (tx_hash_hex, o) = c.register(contract_address, signer_address, token_address) + + if config.get('_RPC_SEND'): + conn.do(o) + if config.get('_WAIT'): + r = conn.wait(tx_hash_hex) + if r['status'] == 0: + sys.stderr.write('EVM revert while deploying contract. Wish I had more to tell you') + sys.exit(1) + + c = ERC20(chain_spec) + o = c.symbol(token_address) + r = conn.do(o) + token_symbol = ERC20.parse_symbol(r) + + logg.info('added token {} at {} to token index {}'.format(token_symbol, token_address, contract_address)) + + print(tx_hash_hex) + else: + print(o) + + +if __name__ == '__main__': + main() diff --git a/python/eth_token_index/runnable/deploy.py b/python/eth_token_index/runnable/deploy.py @@ -0,0 +1,69 @@ +"""Deploys the token symbol index + +.. moduleauthor:: Louis Holbrook <dev@holbrook.no> +.. pgp:: 0826EDA1702D1E87C6E2875121D2E7BB88C2A746 + +""" + +# standard imports +import sys +import os +import json +import argparse +import logging + +# external imports +import chainlib.eth.cli +from chainlib.chain import ChainSpec +from chainlib.eth.tx import receipt + +# local imports +from eth_token_index import TokenUniqueSymbolIndex + +logging.basicConfig(level=logging.WARNING) +logg = logging.getLogger() + +arg_flags = chainlib.eth.cli.argflag_std_write +argparser = chainlib.eth.cli.ArgumentParser(arg_flags) +args = argparser.parse_args() + +config = chainlib.eth.cli.Config.from_args(args, arg_flags, default_fee_limit=TokenUniqueSymbolIndex.gas()) + +wallet = chainlib.eth.cli.Wallet() +wallet.from_config(config) + +rpc = chainlib.eth.cli.Rpc(wallet=wallet) +conn = rpc.connect_by_config(config) + +chain_spec = ChainSpec.from_chain_str(config.get('CHAIN_SPEC')) + + +def main(): + signer = rpc.get_signer() + signer_address = rpc.get_sender_address() + + gas_oracle = rpc.get_gas_oracle() + nonce_oracle = rpc.get_nonce_oracle() + + c = TokenUniqueSymbolIndex(chain_spec, signer=signer, gas_oracle=gas_oracle, nonce_oracle=nonce_oracle) + + (tx_hash_hex, o) = c.constructor(signer_address) + if config.get('_RPC_SEND'): + conn.do(o) + if config.get('_WAIT'): + r = conn.wait(tx_hash_hex) + if r['status'] == 0: + sys.stderr.write('EVM revert while deploying contract. Wish I had more to tell you') + sys.exit(1) + # TODO: pass through translator for keys (evm tester uses underscore instead of camelcase) + address = r['contractAddress'] + + print(address) + else: + print(tx_hash_hex) + else: + print(o) + + +if __name__ == '__main__': + main() diff --git a/python/eth_token_index/runnable/list.py b/python/eth_token_index/runnable/list.py @@ -0,0 +1,100 @@ +"""Adds a new token to the token symbol index + +.. moduleauthor:: Louis Holbrook <dev@holbrook.no> +.. pgp:: 0826EDA1702D1E87C6E2875121D2E7BB88C2A746 + +""" + +# standard imports +import sys +import os +import json +import argparse +import logging +import hashlib + +# external imports +import chainlib.eth.cli +from chainlib.chain import ChainSpec +from eth_erc20 import ERC20 +from chainlib.eth.address import to_checksum_address +from hexathon import add_0x + +# local imports +from eth_token_index import TokenUniqueSymbolIndex + +logging.basicConfig(level=logging.WARNING) +logg = logging.getLogger() +default_format = 'terminal' + +script_dir = os.path.dirname(__file__) +data_dir = os.path.join(script_dir, '..', 'data') + +arg_flags = chainlib.eth.cli.argflag_std_write | chainlib.eth.cli.Flag.EXEC +argparser = chainlib.eth.cli.ArgumentParser(arg_flags) +argparser.add_argument('token_symbol', type=str, nargs='?', help='Token symbol to return address for') +args = argparser.parse_args() + +extra_args = { + 'token_symbol': None, + } +config = chainlib.eth.cli.Config.from_args(args, arg_flags, extra_args=extra_args, default_fee_limit=TokenUniqueSymbolIndex.gas()) + +#wallet = chainlib.eth.cli.Wallet() +#wallet.from_config(config) + +rpc = chainlib.eth.cli.Rpc() +conn = rpc.connect_by_config(config) + +chain_spec = ChainSpec.from_chain_str(config.get('CHAIN_SPEC')) + + +def out_element(e, w=sys.stdout): + if config.get('_RAW'): + w.write(e[1] + '\n') + else: + w.write(e[1] + '\t' + e[0] + '\n') + + +def element(ifc, conn, contract_address, token_symbol, w=sys.stdout): + o = ifc.address_of(contract_address, token_symbol) + r = conn.do(o) + a = ifc.parse_address_of(r) + out_element((token_symbol, a), w) + + +def ls(ifc, conn, contract_address, token_ifc, w=sys.stdout): + o = ifc.entry_count(contract_address) + r = conn.do(o) + count = ifc.parse_entry_count(r) + logg.debug('count {}'.format(count)) + + for i in range(count): + o = ifc.entry(contract_address, i) + r = conn.do(o) + token_address = ifc.parse_entry(r) + + o = token_ifc.symbol(token_address) + r = conn.do(o) + token_symbol = token_ifc.parse_symbol(r) + + element(ifc, conn, contract_address, token_symbol, w) + + +def main(): + token_ifc = ERC20(chain_spec) + ifc = TokenUniqueSymbolIndex(chain_spec) + + contract_address = to_checksum_address(config.get('_EXEC_ADDRESS')) + if not config.true('_UNSAFE') and contract_address != add_0x(config.get('_EXEC_ADDRESS')): + raise ValueError('invalid checksum address for contract') + + token_symbol = config.get('_TOKEN_SYMBOL') + if token_symbol != None: + element(ifc, conn, contract_address, token_symbol, sys.stdout) + else: + ls(ifc, conn, contract_address, token_ifc, sys.stdout) + + +if __name__ == '__main__': + main() diff --git a/python/requirements.txt b/python/requirements.txt @@ -0,0 +1,5 @@ +confini>=0.3.6rc3,<0.5.0 +crypto-dev-signer>=0.4.15rc2,<=0.4.15 +chainlib-eth>=0.0.9a13,<=0.1.0 +eth_erc20>=0.1.2a3,<=0.2.0 +eth-address-index>=0.2.4a1 diff --git a/python/setup.cfg b/python/setup.cfg @@ -0,0 +1,45 @@ +[metadata] +name = eth-token-index +version = 0.2.4a1 +description = Token symbol to address unique index +author = Louis Holbrook +author_email = dev@holbrook.no +url = https://gitlab.com/cicnet/eth-address-index +keywords = + ethereum +classifiers = + Programming Language :: Python :: 3 + Operating System :: OS Independent + Development Status :: 3 - Alpha + Environment :: No Input/Output (Daemon) + Intended Audience :: Developers + License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+) + Topic :: Internet + #Topic :: Blockchain :: EVM +license = GPL3 +licence_files = + LICENSE + +[options] +include_package_data = True +python_requires = >= 3.6 +packages = + eth_token_index + eth_token_index.runnable + +[options.extras_require] +testing = + eth-tester==0.5.0b2 + py-evm==0.3.0a20 + +[options.package_data] +* = + data/TokenUniqueSymbolIndex.bin + data/TokenUniqueSymbolIndex.json + data/ERC20.json + +[options.entry_points] +console_scripts = + eth-token-index-deploy = eth_token_index.runnable.deploy:main + eth-token-index-add = eth_token_index.runnable.add:main + eth-token-index-list = eth_token_index.runnable.list:main diff --git a/python/setup.py b/python/setup.py @@ -0,0 +1,25 @@ +from setuptools import setup + +requirements = [] +f = open('requirements.txt', 'r') +while True: + l = f.readline() + if l == '': + break + requirements.append(l.rstrip()) +f.close() + +test_requirements = [] +f = open('test_requirements.txt', 'r') +while True: + l = f.readline() + if l == '': + break + test_requirements.append(l.rstrip()) +f.close() + + +setup( + install_requires=requirements, + tests_require=test_requirements, + ) diff --git a/python/test_requirements.txt b/python/test_requirements.txt @@ -0,0 +1,2 @@ +eth-tester==0.5.0b3 +py-evm==0.3.0a20 diff --git a/python/tests/test_tokenindex.py b/python/tests/test_tokenindex.py @@ -0,0 +1,78 @@ +# standard imports +import os +import unittest +import json +import logging +import hashlib + +# external imports +from chainlib.eth.unittest.ethtester import EthTesterCase +from chainlib.eth.nonce import RPCNonceOracle +from chainlib.eth.tx import receipt +from giftable_erc20_token import GiftableToken +from chainlib.eth.tx import unpack +from hexathon import strip_0x +from chainlib.eth.contract import ABIContractEncoder + +# local imports +from eth_token_index.index import ( + TokenUniqueSymbolIndex, + to_identifier, + ) + +# test imports +from eth_address_declarator.declarator import Declarator +from eth_address_declarator.unittest import TestAddressDeclaratorBase + +logging.basicConfig(level=logging.DEBUG) +logg = logging.getLogger() + +testdir = os.path.dirname(__file__) + + +class TestTokenUniqueSymbolIndex(TestAddressDeclaratorBase): + + def setUp(self): + super(TestTokenUniqueSymbolIndex, self).setUp() + nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc) + c = TokenUniqueSymbolIndex(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle) + (tx_hash_hex, o) = c.constructor(self.accounts[0]) + self.rpc.do(o) + + o = receipt(tx_hash_hex) + r = self.rpc.do(o) + self.assertEqual(r['status'], 1) + + self.token_index_address = r['contract_address'] + + + def test_register(self): + nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc) + c = TokenUniqueSymbolIndex(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle) + + (tx_hash_hex, o) = c.register(self.token_index_address, self.accounts[0], self.foo_token_address) + self.rpc.do(o) + e = unpack(bytes.fromhex(strip_0x(o['params'][0])), self.chain_spec) + + o = receipt(tx_hash_hex) + r = self.rpc.do(o) + self.assertEqual(r['status'], 1) + + o = c.address_of(self.token_index_address, 'FOO', sender_address=self.accounts[0]) + r = self.rpc.do(o) + address = c.parse_address_of(r) + self.assertEqual(address, strip_0x(self.foo_token_address)) + + o = c.entry(self.token_index_address, 0, sender_address=self.accounts[0]) + r = self.rpc.do(o) + address = c.parse_entry(r) + self.assertEqual(address, strip_0x(self.foo_token_address)) + + o = c.entry_count(self.token_index_address, sender_address=self.accounts[0]) + r = self.rpc.do(o) + count = c.parse_entry_count(r) + self.assertEqual(count, 1) + + +if __name__ == '__main__': + unittest.main() diff --git a/solidity/Makefile b/solidity/Makefile @@ -0,0 +1,11 @@ +SOLC = /usr/bin/solc + +all: + $(SOLC) TokenUniqueSymbolIndex.sol --abi --evm-version byzantium | awk 'NR>3' > TokenUniqueSymbolIndex.json + $(SOLC) TokenUniqueSymbolIndex.sol --bin --evm-version byzantium | awk 'NR>3' > TokenUniqueSymbolIndex.bin + truncate -s -1 TokenUniqueSymbolIndex.bin + +install: all + cp -v TokenUniqueSymbolIndex.{json,bin} ../python/eth_token_index/data/ + +.PHONY: install diff --git a/solidity/TokenUniqueSymbolIndex.sol b/solidity/TokenUniqueSymbolIndex.sol @@ -0,0 +1,105 @@ +pragma solidity >0.6.11; + +// SPDX-License-Identifier: GPL-3.0-or-later + +contract TokenUniqueSymbolIndex { + + // EIP 173 + address public owner; + address newOwner; + + mapping ( bytes32 => uint256 ) public registry; + address[] tokens; + + event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); // EIP173 + event AddressAdded(address indexed addedAccount, uint256 indexed accountIndex); // AccountsIndex + + constructor() public { + owner = msg.sender; + tokens.push(address(0)); + } + + // Implements AccountsIndex + function entry(uint256 _idx) public view returns ( address ) { + return tokens[_idx + 1]; + } + + // Implements Registry + function addressOf(bytes32 _key) public view returns ( address ) { + uint256 idx; + + idx = registry[_key]; + return tokens[idx]; + } + + function register(address _token) public returns (bool) { + require(msg.sender == owner); + + bytes memory token_symbol; + bytes32 token_symbol_key; + uint256 idx; + + (bool _ok, bytes memory _r) = _token.call(abi.encodeWithSignature('symbol()')); + require(_ok); + + token_symbol = abi.decode(_r, (bytes)); + token_symbol_key = sha256(token_symbol); + + idx = registry[token_symbol_key]; + require(idx == 0); + + registry[token_symbol_key] = tokens.length; + tokens.push(_token); + emit AddressAdded(_token, tokens.length - 1); + return true; + } + + // Implements AccountsIndex + function add(address _token) public returns (bool) { + return register(_token); + } + + + // Implements AccountsIndex + function entryCount() public view returns ( uint256 ) { + return tokens.length - 1; + } + + // Implements EIP173 + function transferOwnership(address _newOwner) public returns (bool) { + require(msg.sender == owner); + newOwner = _newOwner; + } + + // Implements OwnedAccepter + function acceptOwnership() public returns (bool) { + address oldOwner; + + require(msg.sender == newOwner); + oldOwner = owner; + owner = newOwner; + newOwner = address(0); + emit OwnershipTransferred(oldOwner, owner); + } + + + // Implements EIP165 + function supportsInterface(bytes4 _sum) public pure returns (bool) { + if (_sum == 0xcbdb05c7) { // AccountsIndex + return true; + } + if (_sum == 0xbb34534c) { // Registry + return true; + } + if (_sum == 0x01ffc9a7) { // EIP165 + return true; + } + if (_sum == 0x9493f8b2) { // EIP173 + return true; + } + if (_sum == 0x37a47be4) { // OwnedAccepter + return true; + } + return false; + } +}