erc20-demurrage-token

ERC20 token with redistributed continual demurrage
Log | Files | Refs | README

commit 5dcf7287016630372971c32774e828449d87edb1
parent d6e71424f3aeb60309beffee5fc7264b36f4a16a
Author: nolash <dev@holbrook.no>
Date:   Sat,  5 Jun 2021 11:58:35 +0200

Add singlecap contract + runner for all test combos

Diffstat:
Mpython/erc20_demurrage_token/data/DemurrageTokenMultiCap.bin | 2++
Mpython/erc20_demurrage_token/data/DemurrageTokenMultiCap.json | 1+
Apython/erc20_demurrage_token/data/DemurrageTokenSingleCap.bin | 2++
Apython/erc20_demurrage_token/data/DemurrageTokenSingleCap.json | 1+
Mpython/erc20_demurrage_token/token.py | 12++++++++++++
Apython/test.sh | 29+++++++++++++++++++++++++++++
Mpython/tests/base.py | 50++++++++++++++++++++++++++++++++++++++++++++------
Mpython/tests/test_basic.py | 2+-
Apython/tests/test_cap.py | 67+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mpython/tests/test_single.py | 4++--
Msolidity/DemurrageTokenMultiCap.sol | 4++--
Asolidity/DemurrageTokenSingleCap.sol | 614+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msolidity/Makefile | 14++++++++++----
13 files changed, 787 insertions(+), 15 deletions(-)

diff --git a/python/erc20_demurrage_token/data/DemurrageTokenMultiCap.bin b/python/erc20_demurrage_token/data/DemurrageTokenMultiCap.bin @@ -0,0 +1 @@ +60e06040523480156200001157600080fd5b5060405162003d6c38038062003d6c833981810160405281019062000037919062000496565b33600360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506001600b6000600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff02191690831515021790555086600590805190602001906200010a9291906200032f565b508560069080519060200190620001239291906200032f565b508460ff166007819055504260808181525050603c836200014591906200076c565b60a08181525050620f42406d04ee2d6d415b85acef81000000006200016b91906200076c565b600260006101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055506001600260106101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055508360c0818152505060006200020a6000620f424060006001620002a3640100000000026401000000009004565b905060008190806001815401808255809150506001900390600052602060002001600090919091909150558160098190555082600d60006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508560ff16600a6200028f91906200062f565b600a819055505050505050505050620009b3565b60008073fffff00000000000000000000000000000000000608c60ff16869060020a021660010281179050710fffffffff00000000000000000000000000606860ff16879060020a0216600102811790506cffffffffffffffffff00000000602060ff16859060020a02166001028117905063ffffffff83166001028117905080915050949350505050565b8280546200033d906200084e565b90600052602060002090601f016020900481019282620003615760008555620003ad565b82601f106200037c57805160ff1916838001178555620003ad565b82800160010185558215620003ad579182015b82811115620003ac5782518255916020019190600101906200038f565b5b509050620003bc9190620003c0565b5090565b5b80821115620003db576000816000905550600101620003c1565b5090565b6000620003f6620003f0846200059e565b62000575565b9050828152602081018484840111156200040f57600080fd5b6200041c84828562000818565b509392505050565b600081519050620004358162000965565b92915050565b600082601f8301126200044d57600080fd5b81516200045f848260208601620003df565b91505092915050565b60008151905062000479816200097f565b92915050565b600081519050620004908162000999565b92915050565b600080600080600080600060e0888a031215620004b257600080fd5b600088015167ffffffffffffffff811115620004cd57600080fd5b620004db8a828b016200043b565b975050602088015167ffffffffffffffff811115620004f957600080fd5b620005078a828b016200043b565b96505060406200051a8a828b016200047f565b95505060606200052d8a828b0162000468565b9450506080620005408a828b0162000468565b93505060a0620005538a828b0162000424565b92505060c0620005668a828b0162000468565b91505092959891949750929550565b60006200058162000594565b90506200058f828262000884565b919050565b6000604051905090565b600067ffffffffffffffff821115620005bc57620005bb62000918565b5b620005c78262000947565b9050602081019050919050565b6000808291508390505b60018511156200062657808604811115620005fe57620005fd620008ba565b5b60018516156200060e5780820291505b80810290506200061e8562000958565b9450620005de565b94509492505050565b60006200063c8262000801565b9150620006498362000801565b9250620006787fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff848462000680565b905092915050565b60008262000692576001905062000765565b81620006a2576000905062000765565b8160018114620006bb5760028114620006c657620006fc565b600191505062000765565b60ff841115620006db57620006da620008ba565b5b8360020a915084821115620006f557620006f4620008ba565b5b5062000765565b5060208310610133831016604e8410600b8410161715620007365782820a90508381111562000730576200072f620008ba565b5b62000765565b620007458484846001620005d4565b925090508184048111156200075f576200075e620008ba565b5b81810290505b9392505050565b6000620007798262000801565b9150620007868362000801565b9250817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615620007c257620007c1620008ba565b5b828202905092915050565b6000620007da82620007e1565b9050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b600060ff82169050919050565b60005b83811015620008385780820151818401526020810190506200081b565b8381111562000848576000848401525b50505050565b600060028204905060018216806200086757607f821691505b602082108114156200087e576200087d620008e9565b5b50919050565b6200088f8262000947565b810181811067ffffffffffffffff82111715620008b157620008b062000918565b5b80604052505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000601f19601f8301169050919050565b6000600282049050919050565b6200097081620007cd565b81146200097c57600080fd5b50565b6200098a8162000801565b81146200099657600080fd5b50565b620009a4816200080b565b8114620009b057600080fd5b50565b60805160a05160c05161334a62000a2260003960008181610cd101528181610f2c015281816110bd01528181611def0152818161247101526124a90152600081816113bc01528181611d9d0152611e8a0152600081816113e801528181611eab0152611ef0015261334a6000f3fe608060405234801561001057600080fd5b5060043610610265576000357c0100000000000000000000000000000000000000000000000000000000900480636a2d094e11610158578063983b2d56116100d5578063e3ab207a11610099578063e3ab207a146107ec578063e54d63f71461081c578063e80952951461084c578063eda4e6d61461086a578063f2fde38b1461088857610265565b8063983b2d56146107205780639da7d8ba14610750578063a2119e2f14610780578063a9059cbb1461079e578063b470aade146107ce57610265565b806379ba50971161011c57806379ba50971461068a5780638da5cb5b146106a85780638f1df6bc146106c65780638f770ad0146106e457806395d89b411461070257610265565b80636a2d094e146105ac5780636d5055a6146105dc5780636ffa8a051461060c57806370a082311461063c578063731f237c1461066c57610265565b806331333487116101e6578063449a52f8116101aa578063449a52f8146104ce57806347a50517146104fe5780634abfbba21461052e578063573cc5071461055e5780636787a9be1461057c57610265565b806331333487146103f0578063313ce5671461042057806335b16eb81461043e57806340452d911461046e57806340fc89f51461049e57610265565b80631989c6a81161022d5780631989c6a814610324578063216ea5ec14610342578063229ba1971461037257806323b872dd146103905780633092afd5146103c057610265565b806301ffc9a71461026a57806306fdde031461029a578063095ea7b3146102b857806309f28f3c146102e857806318160ddd14610306575b600080fd5b610284600480360381019061027f9190612bf2565b6108b8565b6040516102919190612dc0565b60405180910390f35b6102a2610a63565b6040516102af9190612df6565b60405180910390f35b6102d260048036038101906102cd9190612b8d565b610af1565b6040516102df9190612dc0565b60405180910390f35b6102f0610c15565b6040516102fd9190612e78565b60405180910390f35b61030e610c37565b60405161031b9190612eae565b60405180910390f35b61032c610c3d565b6040516103399190612eae565b60405180910390f35b61035c60048036038101906103579190612c6d565b610c49565b6040516103699190612eae565b60405180910390f35b61037a610ccf565b6040516103879190612eae565b60405180910390f35b6103aa60048036038101906103a59190612b3e565b610cf3565b6040516103b79190612dc0565b60405180910390f35b6103da60048036038101906103d59190612b15565b610e1d565b6040516103e79190612dc0565b60405180910390f35b61040a60048036038101906104059190612c6d565b610f10565b6040516104179190612eae565b60405180910390f35b610428610fc1565b6040516104359190612eae565b60405180910390f35b61045860048036038101906104539190612b15565b610fc7565b6040516104659190612dc0565b60405180910390f35b61048860048036038101906104839190612c44565b6111ed565b6040516104959190612ddb565b60405180910390f35b6104b860048036038101906104b39190612bc9565b611211565b6040516104c59190612eae565b60405180910390f35b6104e860048036038101906104e39190612b8d565b611242565b6040516104f59190612dc0565b60405180910390f35b61051860048036038101906105139190612b15565b611360565b6040516105259190612eae565b60405180910390f35b61054860048036038101906105439190612c44565b6113b8565b6040516105559190612eae565b60405180910390f35b610566611418565b6040516105739190612eae565b60405180910390f35b61059660048036038101906105919190612c44565b61141e565b6040516105a39190612eae565b60405180910390f35b6105c660048036038101906105c19190612c44565b61148a565b6040516105d39190612eae565b60405180910390f35b6105f660048036038101906105f19190612b15565b6114ab565b6040516106039190612eae565b60405180910390f35b61062660048036038101906106219190612bc9565b611516565b6040516106339190612eae565b60405180910390f35b61065660048036038101906106519190612b15565b611549565b6040516106639190612eae565b60405180910390f35b61067461162a565b6040516106819190612dc0565b60405180910390f35b6106926117d8565b60405161069f9190612dc0565b60405180910390f35b6106b061197f565b6040516106bd9190612da5565b60405180910390f35b6106ce6119a5565b6040516106db9190612dc0565b60405180910390f35b6106ec611b5c565b6040516106f99190612eae565b60405180910390f35b61070a611b62565b6040516107179190612df6565b60405180910390f35b61073a60048036038101906107359190612b15565b611bf0565b6040516107479190612dc0565b60405180910390f35b61076a60048036038101906107659190612bc9565b611cad565b6040516107779190612eae565b60405180910390f35b610788611cd9565b6040516107959190612e78565b60405180910390f35b6107b860048036038101906107b39190612b8d565b611cfb565b6040516107c59190612dc0565b60405180910390f35b6107d6611d9b565b6040516107e39190612eae565b60405180910390f35b61080660048036038101906108019190612bc9565b611dbf565b6040516108139190612eae565b60405180910390f35b61083660048036038101906108319190612c6d565b611dd3565b6040516108439190612eae565b60405180910390f35b610854611e84565b6040516108619190612e78565b60405180910390f35b610872611eee565b60405161087f9190612eae565b60405180910390f35b6108a2600480360381019061089d9190612b15565b611f12565b6040516108af9190612dc0565b60405180910390f35b600063c6bb4b707c010000000000000000000000000000000000000000000000000000000002827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916141561090d5760019050610a5e565b63449a52f87c010000000000000000000000000000000000000000000000000000000002827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614156109605760019050610a5e565b6301ffc9a77c010000000000000000000000000000000000000000000000000000000002827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614156109b35760019050610a5e565b639493f8b27c010000000000000000000000000000000000000000000000000000000002827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161415610a065760019050610a5e565b6337a47be47c010000000000000000000000000000000000000000000000000000000002827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161415610a595760019050610a5e565b600090505b919050565b60058054610a709061310d565b80601f0160208091040260200160405190810160405280929190818152602001828054610a9c9061310d565b8015610ae95780601f10610abe57610100808354040283529160200191610ae9565b820191906000526020600020905b815481529060010190602001808311610acc57829003601f168201915b505050505081565b600080610afc6119a5565b50610b0633610fc7565b50610b108361141e565b905080600c60003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254610b9e9190612ee5565b925050819055508373ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92585604051610c029190612eae565b60405180910390a3600191505092915050565b600260009054906101000a90046fffffffffffffffffffffffffffffffff1681565b60085481565b60008080549050905090565b600080600080851415610c91576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c8890612e18565b60405180910390fd5b838510610c9d57600080fd5b8484610ca99190612f3b565b91508482610cb79190612f6c565b90508084610cc59190612ffa565b9250505092915050565b7f000000000000000000000000000000000000000000000000000000000000000081565b6000806000610d006119a5565b50610d0a33610fc7565b50610d148461141e565b915081600c60008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541015610d9f57600080fd5b610daa868684611fb4565b90508473ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef86604051610e099190612eae565b60405180910390a380925050509392505050565b6000600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161480610ea657503373ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16145b610eaf57600080fd5b6000600b60008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff02191690831515021790555060019050919050565b6000806000620f424091506d04ee2d6d415b85acef81000000007f0000000000000000000000000000000000000000000000000000000000000000610f559190612f3b565b905060005b84811015610f9c57620f42408284610f729190612f6c565b610f7c9190612f3b565b83610f879190612ffa565b92508080610f949061313f565b915050610f5a565b50620f42408583610fad9190612f6c565b610fb79190612f3b565b9250505092915050565b60075481565b600080600080600080600080610fdc896114ab565b915060008214806110065750610ff0611e84565b6fffffffffffffffffffffffffffffffff168210155b1561101b5760009750505050505050506111e8565b600060018361102a9190612ffa565b81548110611061577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b9060005260206000200154965061107787611211565b945060008514156110925760009750505050505050506111e8565b61109b87611cad565b95506110a687611516565b90506d04ee2d6d415b85acef8100000000620f42407f00000000000000000000000000000000000000000000000000000000000000006110e69190612f3b565b86886110f29190612f3b565b6110fc9190612f6c565b6111069190612f3b565b9350620f424081856111189190612f6c565b6111229190612f3b565b92506cffffffff00000000000000000019600102600160008b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254169250508190555061118c8984612058565b50818973ffffffffffffffffffffffffffffffffffffffff167f9a2a887706623ad3ff7fc85652deeceabe9fe1e00466c597972079ee91ea40d3856040516111d49190612eae565b60405180910390a360019750505050505050505b919050565b600081815481106111fd57600080fd5b906000526020600020016000915090505481565b6000606860ff16710fffffffff00000000000000000000000000836001900416908060020a82049150509050919050565b600080600b60003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1661129b57600080fd5b600954600854846112ac9190612ee5565b11156112b757600080fd5b6112bf6119a5565b5082905082600860008282546112d59190612ee5565b925050819055506112e68482612058565b508373ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fab8530f87dc9b59234c4623bf917212bb2536d647574c8e7e5da92c2ede0c9f8856040516113449190612eae565b60405180910390a36113546121b4565b50600191505092915050565b600068ffffffffffffffffff600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205460019004169050919050565b60007f0000000000000000000000000000000000000000000000000000000000000000826113e69190612f6c565b7f00000000000000000000000000000000000000000000000000000000000000006114119190612ee5565b9050919050565b600a5481565b6000600260009054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff16620f42406d04ee2d6d415b85acef81000000008461146f9190612f6c565b6114799190612f6c565b6114839190612f3b565b9050919050565b6000603c824261149a9190612ffa565b6114a49190612f3b565b9050919050565b6000604860ff166cffffffff000000000000000000600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546001900416908060020a82049150509050919050565b6000608c60ff1673fffff00000000000000000000000000000000000836001900416908060020a82049150509050919050565b60008060008061155885611360565b9250600260109054906101000a90046fffffffffffffffffffffffffffffffff16611581611e84565b61158b9190612fc6565b6fffffffffffffffffffffffffffffffff1690506115d9600260009054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff1682610f10565b6fffffffffffffffffffffffffffffffff169150620f42406d04ee2d6d415b85acef810000000061160a9190612f6c565b82846116169190612f6c565b6116209190612f3b565b9350505050919050565b600080600080600061163a611e84565b9350600260109054906101000a90046fffffffffffffffffffffffffffffffff16846116669190612fc6565b92506000836fffffffffffffffffffffffffffffffff1614156116905760009450505050506117d5565b600260009054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff1691506116df82846fffffffffffffffffffffffffffffffff16610f10565b600260006101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff16021790555083600260106101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff16021790555081836fffffffffffffffffffffffffffffffff16856fffffffffffffffffffffffffffffffff167fa0717e54e02bd9829db5e6e998aec0ae9de796b8d150a3cc46a92ab869697755600260009054906101000a90046fffffffffffffffffffffffffffffffff166040516117c49190612e93565b60405180910390a460019450505050505b90565b600080600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461183557600080fd5b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16600360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506000600460006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35090565b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008060008060008060008060008060006119be61229c565b995060006001028a14156119df5760009a5050505050505050505050611b59565b6119e88a611dbf565b97506001886119f79190612ee5565b9050611a02886113b8565b9150611a0c61162a565b50600260009054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff169450611a498261148a565b92506000831115611a7e576d04ee2d6d415b85acef8100000000611a6d8685611dd3565b611a779190612f3b565b9350611a9b565b6d04ee2d6d415b85acef810000000085611a989190612f3b565b93505b611aaa600085600854846123cc565b98506000899080600181540180825580915050600190039060005260206000200160009091909190915055611ade8a611211565b96506000871415611af957611af28a612458565b9550611b13565b611b0587600854610c49565b9550611b11868961264b565b505b7f55d243082e019fce4009ccea5368b92e436c17586a1e793c7deda16df4e5d67581604051611b429190612eae565b60405180910390a160019a50505050505050505050505b90565b60095481565b60068054611b6f9061310d565b80601f0160208091040260200160405190810160405280929190818152602001828054611b9b9061310d565b8015611be85780601f10611bbd57610100808354040283529160200191611be8565b820191906000526020600020905b815481529060010190602001808311611bcb57829003601f168201915b505050505081565b6000600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611c4c57600080fd5b6001600b60008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff02191690831515021790555060019050919050565b6000602060ff166cffffffffffffffffff00000000836001900416908060020a82049150509050919050565b600260109054906101000a90046fffffffffffffffffffffffffffffffff1681565b6000806000611d086119a5565b50611d1233610fc7565b50611d1c8461141e565b9150611d29338684611fb4565b90508473ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef86604051611d889190612eae565b60405180910390a3809250505092915050565b7f000000000000000000000000000000000000000000000000000000000000000081565b600063ffffffff8260019004169050919050565b6000806000620f424091506d04ee2d6d415b85acef81000000007f0000000000000000000000000000000000000000000000000000000000000000611e189190612f3b565b905060005b84811015611e5f57620f42408284611e359190612f6c565b611e3f9190612f3b565b83611e4a9190612ee5565b92508080611e579061313f565b915050611e1d565b50620f42408583611e709190612f6c565b611e7a9190612f3b565b9250505092915050565b600060017f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000042611ed59190612ffa565b611edf9190612f3b565b611ee99190612ee5565b905090565b7f000000000000000000000000000000000000000000000000000000000000000081565b6000600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611f6e57600080fd5b81600460006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550919050565b600080611fc18584612781565b50611fcc8484612058565b50611fd5611e84565b6fffffffffffffffffffffffffffffffff169050600a548310158015612003575080612000866114ab565b14155b801561203b57508373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1614155b1561204c5761204a85826128b2565b505b60019150509392505050565b600080600080600160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205460019004905060008514156120b957600093505050506121ae565b6120c286611360565b925084836120d09190612ee5565b91508273ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1611612140576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161213790612e58565b60405180910390fd5b68ffffffffffffffffff198116905068ffffffffffffffffff82168117905080600102600160008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550600193505050505b92915050565b600080600060016000805490506121cb9190612ffa565b81548110612202577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b90600052602060002001546001900490506cffffffffffffffffff000000001981169050602060ff166008549060020a0281179050806001026000600160008054905061224f9190612ffa565b81548110612286577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b9060005260206000200181905550600191505090565b60008060008060016000805490506122b49190612ffa565b815481106122eb577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b906000526020600020015491503073ffffffffffffffffffffffffffffffffffffffff1663e80952956040518163ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040160206040518083038186803b15801561235a57600080fd5b505afa15801561236e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123929190612c1b565b6fffffffffffffffffffffffffffffffff1690506123af82611dbf565b81116123c3576000600102925050506123c9565b81925050505b90565b60008073fffff00000000000000000000000000000000000608c60ff16869060020a021660010281179050710fffffffff00000000000000000000000000606860ff16879060020a0216600102811790506cffffffffffffffffff00000000602060ff16859060020a02166001028117905063ffffffff83166001028117905080915050949350505050565b600080600080600061246986611cad565b9350620f42407f00000000000000000000000000000000000000000000000000000000000000008561249b9190612f6c565b6124a59190612f3b565b91507f0000000000000000000000000000000000000000000000000000000000000000620f4240836124d79190612f6c565b6124e19190612f3b565b9050838110156125f9576124f486611dbf565b9250710fffffffff0000000000000000000000000019600102600060018561251c9190612ffa565b81548110612553577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b9060005260206000200160008282541692505081905550606860ff1660019060020a027f80000000000000000000000000000000000000000000000000000000000000001760010260006001856125aa9190612ffa565b815481106125e1577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b90600052602060002001600082825417925050819055505b61263e600d60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff166d04ee2d6d415b85acef8100000000846126399190612f3b565b612058565b5081945050505050919050565b600080600084141561266157600091505061277b565b7f800000000000000000000000000000000000000000000000000000000000000060010260006001856126949190612ffa565b815481106126cb577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b906000526020600020016000828254179250508190555061273b60006001856126f49190612ffa565b8154811061272b577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b9060005260206000200154611cad565b9050612774600d60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16858361276f9190612ffa565b612058565b5060019150505b92915050565b600080600080600160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205460019004905060008514156127e257600093505050506128ac565b6127eb86611360565b925084831015612830576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161282790612e38565b60405180910390fd5b848361283c9190612ffa565b915068ffffffffffffffffff198116905068ffffffffffffffffff82168117905080600102600160008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550600193505050505b92915050565b60006cffffffff00000000000000000019600102600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825416925050819055506cffffffff000000000000000000604860ff16839060020a0216600102600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254179250508190555061298361298e565b506001905092915050565b600080600080600060016000805490506129a89190612ffa565b815481106129df577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b9060005260206000200154925060016129f784611211565b612a019190612ee5565b905082600190049150710fffffffff000000000000000000000000001982169150710fffffffff00000000000000000000000000606860ff16829060020a0216821791508160010260006001600080549050612a5d9190612ffa565b81548110612a94577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b90600052602060002001819055506001935050505090565b600081359050612abb816132a1565b92915050565b600081359050612ad0816132b8565b92915050565b600081359050612ae5816132cf565b92915050565b600081519050612afa816132e6565b92915050565b600081359050612b0f816132fd565b92915050565b600060208284031215612b2757600080fd5b6000612b3584828501612aac565b91505092915050565b600080600060608486031215612b5357600080fd5b6000612b6186828701612aac565b9350506020612b7286828701612aac565b9250506040612b8386828701612b00565b9150509250925092565b60008060408385031215612ba057600080fd5b6000612bae85828601612aac565b9250506020612bbf85828601612b00565b9150509250929050565b600060208284031215612bdb57600080fd5b6000612be984828501612ac1565b91505092915050565b600060208284031215612c0457600080fd5b6000612c1284828501612ad6565b91505092915050565b600060208284031215612c2d57600080fd5b6000612c3b84828501612aeb565b91505092915050565b600060208284031215612c5657600080fd5b6000612c6484828501612b00565b91505092915050565b60008060408385031215612c8057600080fd5b6000612c8e85828601612b00565b9250506020612c9f85828601612b00565b9150509250929050565b612cb28161302e565b82525050565b612cc181613040565b82525050565b612cd08161304c565b82525050565b6000612ce182612ec9565b612ceb8185612ed4565b9350612cfb8185602086016130da565b612d0481613215565b840191505092915050565b6000612d1c601183612ed4565b9150612d2782613226565b602082019050919050565b6000612d3f600d83612ed4565b9150612d4a8261324f565b602082019050919050565b6000612d62600d83612ed4565b9150612d6d82613278565b602082019050919050565b612d8181613082565b82525050565b612d90816130c8565b82525050565b612d9f816130be565b82525050565b6000602082019050612dba6000830184612ca9565b92915050565b6000602082019050612dd56000830184612cb8565b92915050565b6000602082019050612df06000830184612cc7565b92915050565b60006020820190508181036000830152612e108184612cd6565b905092915050565b60006020820190508181036000830152612e3181612d0f565b9050919050565b60006020820190508181036000830152612e5181612d32565b9050919050565b60006020820190508181036000830152612e7181612d55565b9050919050565b6000602082019050612e8d6000830184612d78565b92915050565b6000602082019050612ea86000830184612d87565b92915050565b6000602082019050612ec36000830184612d96565b92915050565b600081519050919050565b600082825260208201905092915050565b6000612ef0826130be565b9150612efb836130be565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff03821115612f3057612f2f613188565b5b828201905092915050565b6000612f46826130be565b9150612f51836130be565b925082612f6157612f606131b7565b5b828204905092915050565b6000612f77826130be565b9150612f82836130be565b9250817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615612fbb57612fba613188565b5b828202905092915050565b6000612fd182613082565b9150612fdc83613082565b925082821015612fef57612fee613188565b5b828203905092915050565b6000613005826130be565b9150613010836130be565b92508282101561302357613022613188565b5b828203905092915050565b60006130398261309e565b9050919050565b60008115159050919050565b6000819050919050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b60006fffffffffffffffffffffffffffffffff82169050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b60006130d382613082565b9050919050565b60005b838110156130f85780820151818401526020810190506130dd565b83811115613107576000848401525b50505050565b6000600282049050600182168061312557607f821691505b60208210811415613139576131386131e6565b5b50919050565b600061314a826130be565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82141561317d5761317c613188565b5b600182019050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000601f19601f8301169050919050565b7f4552525f4e554d50415254535f5a45524f000000000000000000000000000000600082015250565b7f4552525f4f5645525350454e4400000000000000000000000000000000000000600082015250565b7f4552525f574f554c445752415000000000000000000000000000000000000000600082015250565b6132aa8161302e565b81146132b557600080fd5b50565b6132c18161304c565b81146132cc57600080fd5b50565b6132d881613056565b81146132e357600080fd5b50565b6132ef81613082565b81146132fa57600080fd5b50565b613306816130be565b811461331157600080fd5b5056fea2646970667358221220c5feb6b1114a2cab184be4920704db0d3d14a87b8c092f786f96263d39c1457b64736f6c63430008040033 +\ No newline at end of file diff --git a/python/erc20_demurrage_token/data/DemurrageTokenMultiCap.json b/python/erc20_demurrage_token/data/DemurrageTokenMultiCap.json @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"uint8","name":"_decimals","type":"uint8"},{"internalType":"uint256","name":"_taxLevelMinute","type":"uint256"},{"internalType":"uint256","name":"_periodMinutes","type":"uint256"},{"internalType":"address","name":"_defaultSinkAddress","type":"address"},{"internalType":"uint256","name":"_supplyCap","type":"uint256"}],"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":false,"internalType":"bytes32","name":"_foo","type":"bytes32"}],"name":"Debug","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_period","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"_periodCount","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"_oldAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_newAmount","type":"uint256"}],"name":"Decayed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_minter","type":"address"},{"indexed":true,"internalType":"address","name":"_beneficiary","type":"address"},{"indexed":false,"internalType":"uint256","name":"_value","type":"uint256"}],"name":"Mint","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"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_period","type":"uint256"}],"name":"Period","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_account","type":"address"},{"indexed":true,"internalType":"uint256","name":"_period","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_value","type":"uint256"}],"name":"Redistribution","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":[],"name":"acceptOwnership","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"accountPeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"actualPeriod","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_minter","type":"address"}],"name":"addMinter","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"applyDemurrage","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"applyRedistributionOnAccount","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","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":"_account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"baseBalanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"changePeriod","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_value","type":"uint256"},{"internalType":"uint256","name":"_period","type":"uint256"}],"name":"decayBy","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"demurrageAmount","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_target","type":"uint256"}],"name":"demurrageCycles","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"demurragePeriod","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_periodCount","type":"uint256"}],"name":"getPeriodTimeDelta","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_value","type":"uint256"},{"internalType":"uint256","name":"_period","type":"uint256"}],"name":"growBy","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minimumParticipantSpend","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_beneficiary","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"mintTo","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"periodDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"periodStart","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"redistributionCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"redistributions","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_numParts","type":"uint256"},{"internalType":"uint256","name":"_sumWhole","type":"uint256"}],"name":"remainder","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"_minter","type":"address"}],"name":"removeMinter","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"supplyCap","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":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"taxLevel","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"toBaseAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"redistribution","type":"bytes32"}],"name":"toRedistributionDemurrageModifier","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32","name":"redistribution","type":"bytes32"}],"name":"toRedistributionParticipants","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32","name":"redistribution","type":"bytes32"}],"name":"toRedistributionPeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32","name":"redistribution","type":"bytes32"}],"name":"toRedistributionSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","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"},{"inputs":[{"internalType":"address","name":"_newOwner","type":"address"}],"name":"transferOwnership","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}] diff --git a/python/erc20_demurrage_token/data/DemurrageTokenSingleCap.bin b/python/erc20_demurrage_token/data/DemurrageTokenSingleCap.bin @@ -0,0 +1 @@ +60e06040523480156200001157600080fd5b5060405162003a6638038062003a66833981810160405281019062000037919062000496565b33600360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506001600b6000600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff02191690831515021790555086600590805190602001906200010a9291906200032f565b508560069080519060200190620001239291906200032f565b508460ff166007819055504260808181525050603c836200014591906200076c565b60a08181525050620f42406d04ee2d6d415b85acef81000000006200016b91906200076c565b600260006101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055506001600260106101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055508360c0818152505060006200020a6000620f424060006001620002a3640100000000026401000000009004565b905060008190806001815401808255809150506001900390600052602060002001600090919091909150558160098190555082600d60006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508560ff16600a6200028f91906200062f565b600a819055505050505050505050620009b3565b60008073fffff00000000000000000000000000000000000608c60ff16869060020a021660010281179050710fffffffff00000000000000000000000000606860ff16879060020a0216600102811790506cffffffffffffffffff00000000602060ff16859060020a02166001028117905063ffffffff83166001028117905080915050949350505050565b8280546200033d906200084e565b90600052602060002090601f016020900481019282620003615760008555620003ad565b82601f106200037c57805160ff1916838001178555620003ad565b82800160010185558215620003ad579182015b82811115620003ac5782518255916020019190600101906200038f565b5b509050620003bc9190620003c0565b5090565b5b80821115620003db576000816000905550600101620003c1565b5090565b6000620003f6620003f0846200059e565b62000575565b9050828152602081018484840111156200040f57600080fd5b6200041c84828562000818565b509392505050565b600081519050620004358162000965565b92915050565b600082601f8301126200044d57600080fd5b81516200045f848260208601620003df565b91505092915050565b60008151905062000479816200097f565b92915050565b600081519050620004908162000999565b92915050565b600080600080600080600060e0888a031215620004b257600080fd5b600088015167ffffffffffffffff811115620004cd57600080fd5b620004db8a828b016200043b565b975050602088015167ffffffffffffffff811115620004f957600080fd5b620005078a828b016200043b565b96505060406200051a8a828b016200047f565b95505060606200052d8a828b0162000468565b9450506080620005408a828b0162000468565b93505060a0620005538a828b0162000424565b92505060c0620005668a828b0162000468565b91505092959891949750929550565b60006200058162000594565b90506200058f828262000884565b919050565b6000604051905090565b600067ffffffffffffffff821115620005bc57620005bb62000918565b5b620005c78262000947565b9050602081019050919050565b6000808291508390505b60018511156200062657808604811115620005fe57620005fd620008ba565b5b60018516156200060e5780820291505b80810290506200061e8562000958565b9450620005de565b94509492505050565b60006200063c8262000801565b9150620006498362000801565b9250620006787fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff848462000680565b905092915050565b60008262000692576001905062000765565b81620006a2576000905062000765565b8160018114620006bb5760028114620006c657620006fc565b600191505062000765565b60ff841115620006db57620006da620008ba565b5b8360020a915084821115620006f557620006f4620008ba565b5b5062000765565b5060208310610133831016604e8410600b8410161715620007365782820a90508381111562000730576200072f620008ba565b5b62000765565b620007458484846001620005d4565b925090508184048111156200075f576200075e620008ba565b5b81810290505b9392505050565b6000620007798262000801565b9150620007868362000801565b9250817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615620007c257620007c1620008ba565b5b828202905092915050565b6000620007da82620007e1565b9050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b600060ff82169050919050565b60005b83811015620008385780820151818401526020810190506200081b565b8381111562000848576000848401525b50505050565b600060028204905060018216806200086757607f821691505b602082108114156200087e576200087d620008e9565b5b50919050565b6200088f8262000947565b810181811067ffffffffffffffff82111715620008b157620008b062000918565b5b80604052505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000601f19601f8301169050919050565b6000600282049050919050565b6200097081620007cd565b81146200097c57600080fd5b50565b6200098a8162000801565b81146200099657600080fd5b50565b620009a4816200080b565b8114620009b057600080fd5b50565b60805160a05160c05161304b62000a1b60003960008181610cc701528181610f1801528181611c26015281816122a801526122e001526000818161123001528181611bd40152611cc101526000818161125c01528181611ce20152611d27015261304b6000f3fe608060405234801561001057600080fd5b5060043610610265576000357c0100000000000000000000000000000000000000000000000000000000900480636a2d094e11610158578063983b2d56116100d5578063e3ab207a11610099578063e3ab207a146107ec578063e54d63f71461081c578063e80952951461084c578063eda4e6d61461086a578063f2fde38b1461088857610265565b8063983b2d56146107205780639da7d8ba14610750578063a2119e2f14610780578063a9059cbb1461079e578063b470aade146107ce57610265565b806379ba50971161011c57806379ba50971461068a5780638da5cb5b146106a85780638f1df6bc146106c65780638f770ad0146106e457806395d89b411461070257610265565b80636a2d094e146105ac5780636d5055a6146105dc5780636ffa8a051461060c57806370a082311461063c578063731f237c1461066c57610265565b806331333487116101e6578063449a52f8116101aa578063449a52f8146104ce57806347a50517146104fe5780634abfbba21461052e578063573cc5071461055e5780636787a9be1461057c57610265565b806331333487146103f0578063313ce5671461042057806335b16eb81461043e57806340452d911461046e57806340fc89f51461049e57610265565b80631989c6a81161022d5780631989c6a814610324578063216ea5ec14610342578063229ba1971461037257806323b872dd146103905780633092afd5146103c057610265565b806301ffc9a71461026a57806306fdde031461029a578063095ea7b3146102b857806309f28f3c146102e857806318160ddd14610306575b600080fd5b610284600480360381019061027f91906128f3565b6108b8565b6040516102919190612ac1565b60405180910390f35b6102a2610a63565b6040516102af9190612af7565b60405180910390f35b6102d260048036038101906102cd919061288e565b610af1565b6040516102df9190612ac1565b60405180910390f35b6102f0610c0b565b6040516102fd9190612b79565b60405180910390f35b61030e610c2d565b60405161031b9190612baf565b60405180910390f35b61032c610c33565b6040516103399190612baf565b60405180910390f35b61035c6004803603810190610357919061296e565b610c3f565b6040516103699190612baf565b60405180910390f35b61037a610cc5565b6040516103879190612baf565b60405180910390f35b6103aa60048036038101906103a5919061283f565b610ce9565b6040516103b79190612ac1565b60405180910390f35b6103da60048036038101906103d59190612816565b610e09565b6040516103e79190612ac1565b60405180910390f35b61040a6004803603810190610405919061296e565b610efc565b6040516104179190612baf565b60405180910390f35b610428610fad565b6040516104359190612baf565b60405180910390f35b61045860048036038101906104539190612816565b610fb3565b6040516104659190612ac1565b60405180910390f35b61048860048036038101906104839190612945565b611061565b6040516104959190612adc565b60405180910390f35b6104b860048036038101906104b391906128ca565b611085565b6040516104c59190612baf565b60405180910390f35b6104e860048036038101906104e3919061288e565b6110b6565b6040516104f59190612ac1565b60405180910390f35b61051860048036038101906105139190612816565b6111d4565b6040516105259190612baf565b60405180910390f35b61054860048036038101906105439190612945565b61122c565b6040516105559190612baf565b60405180910390f35b61056661128c565b6040516105739190612baf565b60405180910390f35b61059660048036038101906105919190612945565b611292565b6040516105a39190612baf565b60405180910390f35b6105c660048036038101906105c19190612945565b6112fe565b6040516105d39190612baf565b60405180910390f35b6105f660048036038101906105f19190612816565b61131f565b6040516106039190612baf565b60405180910390f35b610626600480360381019061062191906128ca565b61138a565b6040516106339190612baf565b60405180910390f35b61065660048036038101906106519190612816565b6113bd565b6040516106639190612baf565b60405180910390f35b61067461149e565b6040516106819190612ac1565b60405180910390f35b61069261164c565b60405161069f9190612ac1565b60405180910390f35b6106b06117f3565b6040516106bd9190612aa6565b60405180910390f35b6106ce611819565b6040516106db9190612ac1565b60405180910390f35b6106ec61199d565b6040516106f99190612baf565b60405180910390f35b61070a6119a3565b6040516107179190612af7565b60405180910390f35b61073a60048036038101906107359190612816565b611a31565b6040516107479190612ac1565b60405180910390f35b61076a600480360381019061076591906128ca565b611aee565b6040516107779190612baf565b60405180910390f35b610788611b1a565b6040516107959190612b79565b60405180910390f35b6107b860048036038101906107b3919061288e565b611b3c565b6040516107c59190612ac1565b60405180910390f35b6107d6611bd2565b6040516107e39190612baf565b60405180910390f35b610806600480360381019061080191906128ca565b611bf6565b6040516108139190612baf565b60405180910390f35b6108366004803603810190610831919061296e565b611c0a565b6040516108439190612baf565b60405180910390f35b610854611cbb565b6040516108619190612b79565b60405180910390f35b610872611d25565b60405161087f9190612baf565b60405180910390f35b6108a2600480360381019061089d9190612816565b611d49565b6040516108af9190612ac1565b60405180910390f35b600063c6bb4b707c010000000000000000000000000000000000000000000000000000000002827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916141561090d5760019050610a5e565b63449a52f87c010000000000000000000000000000000000000000000000000000000002827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614156109605760019050610a5e565b6301ffc9a77c010000000000000000000000000000000000000000000000000000000002827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614156109b35760019050610a5e565b639493f8b27c010000000000000000000000000000000000000000000000000000000002827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161415610a065760019050610a5e565b6337a47be47c010000000000000000000000000000000000000000000000000000000002827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161415610a595760019050610a5e565b600090505b919050565b60058054610a7090612e0e565b80601f0160208091040260200160405190810160405280929190818152602001828054610a9c90612e0e565b8015610ae95780601f10610abe57610100808354040283529160200191610ae9565b820191906000526020600020905b815481529060010190602001808311610acc57829003601f168201915b505050505081565b600080610afc611819565b50610b0683611292565b905080600c60003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254610b949190612be6565b925050819055508373ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92585604051610bf89190612baf565b60405180910390a3600191505092915050565b600260009054906101000a90046fffffffffffffffffffffffffffffffff1681565b60085481565b60008080549050905090565b600080600080851415610c87576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c7e90612b19565b60405180910390fd5b838510610c9357600080fd5b8484610c9f9190612c3c565b91508482610cad9190612c6d565b90508084610cbb9190612cfb565b9250505092915050565b7f000000000000000000000000000000000000000000000000000000000000000081565b6000806000610cf6611819565b50610d0084611292565b915081600c60008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541015610d8b57600080fd5b610d96868684611deb565b90508473ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef86604051610df59190612baf565b60405180910390a380925050509392505050565b6000600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161480610e9257503373ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16145b610e9b57600080fd5b6000600b60008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff02191690831515021790555060019050919050565b6000806000620f424091506d04ee2d6d415b85acef81000000007f0000000000000000000000000000000000000000000000000000000000000000610f419190612c3c565b905060005b84811015610f8857620f42408284610f5e9190612c6d565b610f689190612c3c565b83610f739190612cfb565b92508080610f8090612e40565b915050610f46565b50620f42408583610f999190612c6d565b610fa39190612c3c565b9250505092915050565b60075481565b600080610fbf8361131f565b90506000811480610fe95750610fd3611cbb565b6fffffffffffffffffffffffffffffffff168110155b15610ff857600091505061105c565b6cffffffff00000000000000000019600102600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254169250508190555060019150505b919050565b6000818154811061107157600080fd5b906000526020600020016000915090505481565b6000606860ff16710fffffffff00000000000000000000000000836001900416908060020a82049150509050919050565b600080600b60003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1661110f57600080fd5b600954600854846111209190612be6565b111561112b57600080fd5b611133611819565b5082905082600860008282546111499190612be6565b9250508190555061115a8482611e8f565b508373ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fab8530f87dc9b59234c4623bf917212bb2536d647574c8e7e5da92c2ede0c9f8856040516111b89190612baf565b60405180910390a36111c8611feb565b50600191505092915050565b600068ffffffffffffffffff600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205460019004169050919050565b60007f00000000000000000000000000000000000000000000000000000000000000008261125a9190612c6d565b7f00000000000000000000000000000000000000000000000000000000000000006112859190612be6565b9050919050565b600a5481565b6000600260009054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff16620f42406d04ee2d6d415b85acef8100000000846112e39190612c6d565b6112ed9190612c6d565b6112f79190612c3c565b9050919050565b6000603c824261130e9190612cfb565b6113189190612c3c565b9050919050565b6000604860ff166cffffffff000000000000000000600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546001900416908060020a82049150509050919050565b6000608c60ff1673fffff00000000000000000000000000000000000836001900416908060020a82049150509050919050565b6000806000806113cc856111d4565b9250600260109054906101000a90046fffffffffffffffffffffffffffffffff166113f5611cbb565b6113ff9190612cc7565b6fffffffffffffffffffffffffffffffff16905061144d600260009054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff1682610efc565b6fffffffffffffffffffffffffffffffff169150620f42406d04ee2d6d415b85acef810000000061147e9190612c6d565b828461148a9190612c6d565b6114949190612c3c565b9350505050919050565b60008060008060006114ae611cbb565b9350600260109054906101000a90046fffffffffffffffffffffffffffffffff16846114da9190612cc7565b92506000836fffffffffffffffffffffffffffffffff161415611504576000945050505050611649565b600260009054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff16915061155382846fffffffffffffffffffffffffffffffff16610efc565b600260006101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff16021790555083600260106101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff16021790555081836fffffffffffffffffffffffffffffffff16856fffffffffffffffffffffffffffffffff167fa0717e54e02bd9829db5e6e998aec0ae9de796b8d150a3cc46a92ab869697755600260009054906101000a90046fffffffffffffffffffffffffffffffff166040516116389190612b94565b60405180910390a460019450505050505b90565b600080600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146116a957600080fd5b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16600360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506000600460006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35090565b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008060008060008060008060008060006118326120d3565b995060006001028a14156118535760009a505050505050505050505061199a565b61185c8a611bf6565b975060018861186b9190612be6565b90506118768861122c565b915061188061149e565b50600260009054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff1694506118bd826112fe565b925060008311156118f2576d04ee2d6d415b85acef81000000006118e18685611c0a565b6118eb9190612c3c565b935061190f565b6d04ee2d6d415b85acef81000000008561190c9190612c3c565b93505b61191e60008560085484612203565b985060008990806001815401808255809150506001900390600052602060002001600090919091909150556119528a61228f565b95507f55d243082e019fce4009ccea5368b92e436c17586a1e793c7deda16df4e5d675816040516119839190612baf565b60405180910390a160019a50505050505050505050505b90565b60095481565b600680546119b090612e0e565b80601f01602080910402602001604051908101604052809291908181526020018280546119dc90612e0e565b8015611a295780601f106119fe57610100808354040283529160200191611a29565b820191906000526020600020905b815481529060010190602001808311611a0c57829003601f168201915b505050505081565b6000600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611a8d57600080fd5b6001600b60008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff02191690831515021790555060019050919050565b6000602060ff166cffffffffffffffffff00000000836001900416908060020a82049150509050919050565b600260109054906101000a90046fffffffffffffffffffffffffffffffff1681565b6000806000611b49611819565b50611b5384611292565b9150611b60338684611deb565b90508473ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef86604051611bbf9190612baf565b60405180910390a3809250505092915050565b7f000000000000000000000000000000000000000000000000000000000000000081565b600063ffffffff8260019004169050919050565b6000806000620f424091506d04ee2d6d415b85acef81000000007f0000000000000000000000000000000000000000000000000000000000000000611c4f9190612c3c565b905060005b84811015611c9657620f42408284611c6c9190612c6d565b611c769190612c3c565b83611c819190612be6565b92508080611c8e90612e40565b915050611c54565b50620f42408583611ca79190612c6d565b611cb19190612c3c565b9250505092915050565b600060017f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000042611d0c9190612cfb565b611d169190612c3c565b611d209190612be6565b905090565b7f000000000000000000000000000000000000000000000000000000000000000081565b6000600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611da557600080fd5b81600460006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550919050565b600080611df88584612482565b50611e038484611e8f565b50611e0c611cbb565b6fffffffffffffffffffffffffffffffff169050600a548310158015611e3a575080611e378661131f565b14155b8015611e7257508373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1614155b15611e8357611e8185826125b3565b505b60019150509392505050565b600080600080600160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546001900490506000851415611ef05760009350505050611fe5565b611ef9866111d4565b92508483611f079190612be6565b91508273ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1611611f77576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611f6e90612b59565b60405180910390fd5b68ffffffffffffffffff198116905068ffffffffffffffffff82168117905080600102600160008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550600193505050505b92915050565b600080600060016000805490506120029190612cfb565b81548110612039577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b90600052602060002001546001900490506cffffffffffffffffff000000001981169050602060ff166008549060020a028117905080600102600060016000805490506120869190612cfb565b815481106120bd577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b9060005260206000200181905550600191505090565b60008060008060016000805490506120eb9190612cfb565b81548110612122577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b906000526020600020015491503073ffffffffffffffffffffffffffffffffffffffff1663e80952956040518163ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040160206040518083038186803b15801561219157600080fd5b505afa1580156121a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121c9919061291c565b6fffffffffffffffffffffffffffffffff1690506121e682611bf6565b81116121fa57600060010292505050612200565b81925050505b90565b60008073fffff00000000000000000000000000000000000608c60ff16869060020a021660010281179050710fffffffff00000000000000000000000000606860ff16879060020a0216600102811790506cffffffffffffffffff00000000602060ff16859060020a02166001028117905063ffffffff83166001028117905080915050949350505050565b60008060008060006122a086611aee565b9350620f42407f0000000000000000000000000000000000000000000000000000000000000000856122d29190612c6d565b6122dc9190612c3c565b91507f0000000000000000000000000000000000000000000000000000000000000000620f42408361230e9190612c6d565b6123189190612c3c565b9050838110156124305761232b86611bf6565b9250710fffffffff000000000000000000000000001960010260006001856123539190612cfb565b8154811061238a577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b9060005260206000200160008282541692505081905550606860ff1660019060020a027f80000000000000000000000000000000000000000000000000000000000000001760010260006001856123e19190612cfb565b81548110612418577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b90600052602060002001600082825417925050819055505b612475600d60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff166d04ee2d6d415b85acef8100000000846124709190612c3c565b611e8f565b5081945050505050919050565b600080600080600160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205460019004905060008514156124e357600093505050506125ad565b6124ec866111d4565b925084831015612531576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161252890612b39565b60405180910390fd5b848361253d9190612cfb565b915068ffffffffffffffffff198116905068ffffffffffffffffff82168117905080600102600160008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550600193505050505b92915050565b60006cffffffff00000000000000000019600102600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825416925050819055506cffffffff000000000000000000604860ff16839060020a0216600102600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254179250508190555061268461268f565b506001905092915050565b600080600080600060016000805490506126a99190612cfb565b815481106126e0577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b9060005260206000200154925060016126f884611085565b6127029190612be6565b905082600190049150710fffffffff000000000000000000000000001982169150710fffffffff00000000000000000000000000606860ff16829060020a021682179150816001026000600160008054905061275e9190612cfb565b81548110612795577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b90600052602060002001819055506001935050505090565b6000813590506127bc81612fa2565b92915050565b6000813590506127d181612fb9565b92915050565b6000813590506127e681612fd0565b92915050565b6000815190506127fb81612fe7565b92915050565b60008135905061281081612ffe565b92915050565b60006020828403121561282857600080fd5b6000612836848285016127ad565b91505092915050565b60008060006060848603121561285457600080fd5b6000612862868287016127ad565b9350506020612873868287016127ad565b925050604061288486828701612801565b9150509250925092565b600080604083850312156128a157600080fd5b60006128af858286016127ad565b92505060206128c085828601612801565b9150509250929050565b6000602082840312156128dc57600080fd5b60006128ea848285016127c2565b91505092915050565b60006020828403121561290557600080fd5b6000612913848285016127d7565b91505092915050565b60006020828403121561292e57600080fd5b600061293c848285016127ec565b91505092915050565b60006020828403121561295757600080fd5b600061296584828501612801565b91505092915050565b6000806040838503121561298157600080fd5b600061298f85828601612801565b92505060206129a085828601612801565b9150509250929050565b6129b381612d2f565b82525050565b6129c281612d41565b82525050565b6129d181612d4d565b82525050565b60006129e282612bca565b6129ec8185612bd5565b93506129fc818560208601612ddb565b612a0581612f16565b840191505092915050565b6000612a1d601183612bd5565b9150612a2882612f27565b602082019050919050565b6000612a40600d83612bd5565b9150612a4b82612f50565b602082019050919050565b6000612a63600d83612bd5565b9150612a6e82612f79565b602082019050919050565b612a8281612d83565b82525050565b612a9181612dc9565b82525050565b612aa081612dbf565b82525050565b6000602082019050612abb60008301846129aa565b92915050565b6000602082019050612ad660008301846129b9565b92915050565b6000602082019050612af160008301846129c8565b92915050565b60006020820190508181036000830152612b1181846129d7565b905092915050565b60006020820190508181036000830152612b3281612a10565b9050919050565b60006020820190508181036000830152612b5281612a33565b9050919050565b60006020820190508181036000830152612b7281612a56565b9050919050565b6000602082019050612b8e6000830184612a79565b92915050565b6000602082019050612ba96000830184612a88565b92915050565b6000602082019050612bc46000830184612a97565b92915050565b600081519050919050565b600082825260208201905092915050565b6000612bf182612dbf565b9150612bfc83612dbf565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff03821115612c3157612c30612e89565b5b828201905092915050565b6000612c4782612dbf565b9150612c5283612dbf565b925082612c6257612c61612eb8565b5b828204905092915050565b6000612c7882612dbf565b9150612c8383612dbf565b9250817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615612cbc57612cbb612e89565b5b828202905092915050565b6000612cd282612d83565b9150612cdd83612d83565b925082821015612cf057612cef612e89565b5b828203905092915050565b6000612d0682612dbf565b9150612d1183612dbf565b925082821015612d2457612d23612e89565b5b828203905092915050565b6000612d3a82612d9f565b9050919050565b60008115159050919050565b6000819050919050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b60006fffffffffffffffffffffffffffffffff82169050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b6000612dd482612d83565b9050919050565b60005b83811015612df9578082015181840152602081019050612dde565b83811115612e08576000848401525b50505050565b60006002820490506001821680612e2657607f821691505b60208210811415612e3a57612e39612ee7565b5b50919050565b6000612e4b82612dbf565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415612e7e57612e7d612e89565b5b600182019050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000601f19601f8301169050919050565b7f4552525f4e554d50415254535f5a45524f000000000000000000000000000000600082015250565b7f4552525f4f5645525350454e4400000000000000000000000000000000000000600082015250565b7f4552525f574f554c445752415000000000000000000000000000000000000000600082015250565b612fab81612d2f565b8114612fb657600080fd5b50565b612fc281612d4d565b8114612fcd57600080fd5b50565b612fd981612d57565b8114612fe457600080fd5b50565b612ff081612d83565b8114612ffb57600080fd5b50565b61300781612dbf565b811461301257600080fd5b5056fea2646970667358221220a834e180272e82901d4d69c10917674445b4deab2e2e9f57ccf712ba2a8f33d364736f6c63430008040033 +\ No newline at end of file diff --git a/python/erc20_demurrage_token/data/DemurrageTokenSingleCap.json b/python/erc20_demurrage_token/data/DemurrageTokenSingleCap.json @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"uint8","name":"_decimals","type":"uint8"},{"internalType":"uint256","name":"_taxLevelMinute","type":"uint256"},{"internalType":"uint256","name":"_periodMinutes","type":"uint256"},{"internalType":"address","name":"_defaultSinkAddress","type":"address"},{"internalType":"uint256","name":"_supplyCap","type":"uint256"}],"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":false,"internalType":"bytes32","name":"_foo","type":"bytes32"}],"name":"Debug","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_period","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"_periodCount","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"_oldAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_newAmount","type":"uint256"}],"name":"Decayed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_minter","type":"address"},{"indexed":true,"internalType":"address","name":"_beneficiary","type":"address"},{"indexed":false,"internalType":"uint256","name":"_value","type":"uint256"}],"name":"Mint","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"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_period","type":"uint256"}],"name":"Period","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_account","type":"address"},{"indexed":true,"internalType":"uint256","name":"_period","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_value","type":"uint256"}],"name":"Redistribution","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":[],"name":"acceptOwnership","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"accountPeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"actualPeriod","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_minter","type":"address"}],"name":"addMinter","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"applyDemurrage","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"applyRedistributionOnAccount","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","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":"_account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"baseBalanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"changePeriod","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_value","type":"uint256"},{"internalType":"uint256","name":"_period","type":"uint256"}],"name":"decayBy","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"demurrageAmount","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_target","type":"uint256"}],"name":"demurrageCycles","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"demurragePeriod","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_periodCount","type":"uint256"}],"name":"getPeriodTimeDelta","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_value","type":"uint256"},{"internalType":"uint256","name":"_period","type":"uint256"}],"name":"growBy","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minimumParticipantSpend","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_beneficiary","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"mintTo","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"periodDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"periodStart","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"redistributionCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"redistributions","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_numParts","type":"uint256"},{"internalType":"uint256","name":"_sumWhole","type":"uint256"}],"name":"remainder","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"_minter","type":"address"}],"name":"removeMinter","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"supplyCap","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":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"taxLevel","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"toBaseAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"redistribution","type":"bytes32"}],"name":"toRedistributionDemurrageModifier","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32","name":"redistribution","type":"bytes32"}],"name":"toRedistributionParticipants","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32","name":"redistribution","type":"bytes32"}],"name":"toRedistributionPeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32","name":"redistribution","type":"bytes32"}],"name":"toRedistributionSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","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"},{"inputs":[{"internalType":"address","name":"_newOwner","type":"address"}],"name":"transferOwnership","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}] diff --git a/python/erc20_demurrage_token/token.py b/python/erc20_demurrage_token/token.py @@ -46,6 +46,7 @@ class DemurrageToken(ERC20): 'MultiNocap', 'SingleNocap', 'MultiCap', + 'SingleCap', ] def constructor(self, sender_address, settings, redistribute=True, cap=0, tx_format=TxFormat.JSONRPC): @@ -59,6 +60,8 @@ class DemurrageToken(ERC20): enc.uint256(settings.demurrage_level) enc.uint256(settings.period_minutes) enc.address(settings.sink_address) + if cap > 0: + enc.uint256(cap) code += enc.get() tx = self.template(sender_address, None, use_nonce=True) tx = self.set_code(tx, code) @@ -255,6 +258,10 @@ class DemurrageToken(ERC20): return self.call_noarg('demurrageAmount', contract_address, sender_address=sender_address) + def supply_cap(self, contract_address, sender_address=ZERO_ADDRESS): + return self.call_noarg('supplyCap', contract_address, sender_address=sender_address) + + @classmethod def parse_actual_period(self, v): return abi_decode_single(ABIContractType.UINT256, v) @@ -298,3 +305,8 @@ class DemurrageToken(ERC20): @classmethod def parse_to_redistribution_period(self, v): return abi_decode_single(ABIContractType.UINT256, v) + + + @classmethod + def parse_supply_cap(self, v): + return abi_decode_single(ABIContractType.UINT256, v) diff --git a/python/test.sh b/python/test.sh @@ -0,0 +1,29 @@ +#!/bin/bash + +set -e + +export PYTHONPATH=. + +modes=(MultiNocap MultiCap SingleCap SingleNocap) +for m in ${modes[@]}; do + ERC20_DEMURRAGE_TOKEN_TEST_MODE=$m python tests/test_pure.py + ERC20_DEMURRAGE_TOKEN_TEST_MODE=$m python tests/test_period.py + ERC20_DEMURRAGE_TOKEN_TEST_MODE=$m python tests/test_basic.py +done + +modes=(MultiCap SingleCap) +for m in ${modes[@]}; do + ERC20_DEMURRAGE_TOKEN_TEST_MODE=$m python tests/test_cap.py +done + +modes=(SingleCap SingleNocap) +for m in ${modes[@]}; do + ERC20_DEMURRAGE_TOKEN_TEST_MODE=$m python tests/test_single.py +done + +modes=(MultiCap MultiNocap) +for m in ${modes[@]}; do + ERC20_DEMURRAGE_TOKEN_TEST_MODE=$m python tests/test_redistribution.py +done + +set +e diff --git a/python/tests/base.py b/python/tests/base.py @@ -62,7 +62,7 @@ class TestDemurrage(EthTesterCase): self.start_time = int(r['timestamp']) self.default_supply = 1000000000000 - self.default_supply_cap = self.default_supply * 10 + self.default_supply_cap = int(self.default_supply * 10) def deploy(self, interface, mode): @@ -73,9 +73,11 @@ class TestDemurrage(EthTesterCase): elif mode == 'SingleNocap': (tx_hash, o) = interface.constructor(self.accounts[0], self.settings, redistribute=False, cap=0) elif mode == 'MultiCap': + (tx_hash, o) = interface.constructor(self.accounts[0], self.settings, redistribute=True, cap=self.default_supply_cap) + elif mode == 'SingleCap': (tx_hash, o) = interface.constructor(self.accounts[0], self.settings, redistribute=False, cap=self.default_supply_cap) else: - raise ValueError('Invalid mode "{}", valid are {}'.format(mode, DeurrageToken.valid_modes)) + raise ValueError('Invalid mode "{}", valid are {}'.format(self.mode, DemurrageToken.valid_modes)) r = self.rpc.do(o) o = receipt(tx_hash) @@ -88,11 +90,13 @@ class TestDemurrage(EthTesterCase): r = self.rpc.do(o) self.start_time = r['timestamp'] + logg.debug('contract address {} start block {} start time {}'.format(self.address, self.start_block, self.start_time)) + + def tearDown(self): pass - class TestDemurrageDefault(TestDemurrage): def setUp(self): @@ -104,24 +108,58 @@ class TestDemurrageDefault(TestDemurrage): self.mode = os.environ.get('ERC20_DEMURRAGE_TOKEN_TEST_MODE') if self.mode == None: self.mode = 'MultiNocap' + logg.debug('executing test setup default mode {}'.format(self.mode)) self.deploy(c, self.mode) logg.info('deployed with mode {}'.format(self.mode)) -class TestDemurrageSingleNocap(TestDemurrage): +class TestDemurrageSingle(TestDemurrage): def setUp(self): - super(TestDemurrageSingleNocap, self).setUp() + super(TestDemurrageSingle, self).setUp() nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc) c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle) - self.mode = 'SingleNocap' + self.mode = os.environ.get('ERC20_DEMURRAGE_TOKEN_TEST_MODE') + single_valid_modes = [ + 'SingleNocap', + 'SingleCap', + ] + if self.mode != None: + if self.mode not in single_valid_modes: + raise ValueError('Invalid mode "{}" for "single" contract tests, valid are {}'.format(self.mode, single_valid_modes)) + else: + self.mode = 'SingleNocap' + logg.debug('executing test setup demurragesingle mode {}'.format(self.mode)) self.deploy(c, self.mode) logg.info('deployed with mode {}'.format(self.mode)) +class TestDemurrageCap(TestDemurrage): + + def setUp(self): + super(TestDemurrageCap, self).setUp() + + nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc) + c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle) + + self.mode = os.environ.get('ERC20_DEMURRAGE_TOKEN_TEST_MODE') + cap_valid_modes = [ + 'MultiCap', + 'SingleCap', + ] + if self.mode != None: + if self.mode not in cap_valid_modes: + raise ValueError('Invalid mode "{}" for "cap" contract tests, valid are {}'.format(self.mode, cap_valid_modes)) + else: + self.mode = 'MultiCap' + logg.debug('executing test setup demurragecap mode {}'.format(self.mode)) + + self.deploy(c, self.mode) + + logg.info('deployed with mode {}'.format(self.mode)) diff --git a/python/tests/test_basic.py b/python/tests/test_basic.py @@ -16,7 +16,7 @@ from erc20_demurrage_token import DemurrageToken # test imports from tests.base import TestDemurrageDefault -logging.basicConfig(level=logging.INFO) +logging.basicConfig(level=logging.DEBUG) logg = logging.getLogger() testdir = os.path.dirname(__file__) diff --git a/python/tests/test_cap.py b/python/tests/test_cap.py @@ -0,0 +1,67 @@ +import os +import unittest +import json +import logging + +# 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 +from chainlib.eth.address import to_checksum_address +from hexathon import ( + strip_0x, + add_0x, + ) + +# local imports +from erc20_demurrage_token import DemurrageToken + +# test imports +from tests.base import TestDemurrageCap + +logging.basicConfig(level=logging.DEBUG) +logg = logging.getLogger() + +testdir = os.path.dirname(__file__) + + +class TestCap(TestDemurrageCap): + + def test_cap_set(self): + nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc) + c = DemurrageToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle) + o = c.supply_cap(self.address, sender_address=self.accounts[0]) + r = self.rpc.do(o) + cap = c.parse_supply_cap(r) + self.assertEqual(cap, self.default_supply_cap) + + + def test_cap(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.mint_to(self.address, self.accounts[0], self.accounts[1], self.default_supply_cap) + r = self.rpc.do(o) + o = receipt(tx_hash) + r = self.rpc.do(o) + self.assertEqual(r['status'], 1) + + (tx_hash, o) = c.mint_to(self.address, self.accounts[0], self.accounts[2], 1) + r = self.rpc.do(o) + o = receipt(tx_hash) + r = self.rpc.do(o) + self.assertEqual(r['status'], 0) + + + def test_cap_first(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.mint_to(self.address, self.accounts[0], self.accounts[1], self.default_supply_cap + 1) + r = self.rpc.do(o) + o = receipt(tx_hash) + r = self.rpc.do(o) + self.assertEqual(r['status'], 0) + + +if __name__ == '__main__': + unittest.main() diff --git a/python/tests/test_single.py b/python/tests/test_single.py @@ -18,7 +18,7 @@ from hexathon import ( from erc20_demurrage_token import DemurrageToken # test imports -from tests.base import TestDemurrageSingleNocap +from tests.base import TestDemurrageSingle logging.basicConfig(level=logging.DEBUG) logg = logging.getLogger() @@ -26,7 +26,7 @@ logg = logging.getLogger() testdir = os.path.dirname(__file__) -class TestRedistributionSingle(TestDemurrageSingleNocap): +class TestRedistributionSingle(TestDemurrageSingle): def test_single_even_if_multiple(self): diff --git a/solidity/DemurrageTokenMultiCap.sol b/solidity/DemurrageTokenMultiCap.sol @@ -101,7 +101,7 @@ contract DemurrageTokenMultiCap { // EIP173 event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); // EIP173 - constructor(string memory _name, string memory _symbol, uint8 _decimals, uint256 _taxLevelMinute, uint256 _periodMinutes, address _defaultSinkAddress uint256 _supplyCap) public { + constructor(string memory _name, string memory _symbol, uint8 _decimals, uint256 _taxLevelMinute, uint256 _periodMinutes, address _defaultSinkAddress, uint256 _supplyCap) public { // ACL setup owner = msg.sender; minter[owner] = true; @@ -121,7 +121,7 @@ contract DemurrageTokenMultiCap { redistributions.push(initialRedistribution); // Misc settings - supplyCap = supplyCap; + supplyCap = _supplyCap; sinkAddress = _defaultSinkAddress; minimumParticipantSpend = 10 ** uint256(_decimals); } diff --git a/solidity/DemurrageTokenSingleCap.sol b/solidity/DemurrageTokenSingleCap.sol @@ -0,0 +1,614 @@ +pragma solidity > 0.6.11; + +// SPDX-License-Identifier: GPL-3.0-or-later + +contract DemurrageTokenSingleNocap { + + // Redistribution bit field, with associated shifts and masks + // (Uses sub-byte boundaries) + bytes32[] public redistributions; // uint1(isFractional) | uint95(unused) | uint20(demurrageModifier) | uint36(participants) | uint72(value) | uint32(period) + uint8 constant shiftRedistributionPeriod = 0; + uint256 constant maskRedistributionPeriod = 0x00000000000000000000000000000000000000000000000000000000ffffffff; // (1 << 32) - 1 + uint8 constant shiftRedistributionValue = 32; + uint256 constant maskRedistributionValue = 0x00000000000000000000000000000000000000ffffffffffffffffff00000000; // ((1 << 72) - 1) << 32 + uint8 constant shiftRedistributionParticipants = 104; + uint256 constant maskRedistributionParticipants = 0x00000000000000000000000000000fffffffff00000000000000000000000000; // ((1 << 36) - 1) << 104 + uint8 constant shiftRedistributionDemurrage = 140; + uint256 constant maskRedistributionDemurrage = 0x000000000000000000000000fffff00000000000000000000000000000000000; // ((1 << 20) - 1) << 140 + uint8 constant shiftRedistributionIsFractional = 255; + uint256 constant maskRedistributionIsFractional = 0x8000000000000000000000000000000000000000000000000000000000000000; // 1 << 255 + + // Account bit field, with associated shifts and masks + // Mirrors structure of redistributions for consistency + mapping (address => bytes32) account; // uint152(unused) | uint32(period) | uint72(value) + uint8 constant shiftAccountValue = 0; + uint256 constant maskAccountValue = 0x0000000000000000000000000000000000000000000000ffffffffffffffffff; // (1 << 72) - 1 + uint8 constant shiftAccountPeriod = 72; + uint256 constant maskAccountPeriod = 0x00000000000000000000000000000000000000ffffffff000000000000000000; // ((1 << 32) - 1) << 72 + + // Cached demurrage amount, ppm with 38 digit resolution + uint128 public demurrageAmount; + + // Cached demurrage period; the period for which demurrageAmount was calculated + uint128 public demurragePeriod; + + // Implements EIP172 + address public owner; + + address newOwner; + + // Implements ERC20 + string public name; + + // Implements ERC20 + string public symbol; + + // Implements ERC20 + uint256 public decimals; + + // Implements ERC20 + uint256 public totalSupply; + + // Maximum amount of tokens that can be minted + uint256 public supplyCap; + + // Minimum amount of (demurraged) tokens an account must spend to participate in redistribution for a particular period + uint256 public minimumParticipantSpend; + + // 128 bit resolution of the demurrage divisor + // (this constant x 1000000 is contained within 128 bits) + uint256 constant ppmDivider = 100000000000000000000000000000000; + + // Timestamp of start of periods (time which contract constructor was called) + uint256 public immutable periodStart; + + // Duration of a single redistribution period in seconds + uint256 public immutable periodDuration; + + // Demurrage in ppm per minute + uint256 public immutable taxLevel; + + // Addresses allowed to mint new tokens + mapping (address => bool) minter; + + // Storage for ERC20 approve/transferFrom methods + mapping (address => mapping (address => uint256 ) ) allowance; // holder -> spender -> amount (amount is subject to demurrage) + + // Address to send unallocated redistribution tokens + address sinkAddress; + + // Implements ERC20 + event Transfer(address indexed _from, address indexed _to, uint256 _value); + + // Implements ERC20 + event Approval(address indexed _owner, address indexed _spender, uint256 _value); + + // New tokens minted + event Mint(address indexed _minter, address indexed _beneficiary, uint256 _value); + + // New demurrage cache milestone calculated + event Decayed(uint256 indexed _period, uint256 indexed _periodCount, uint256 indexed _oldAmount, uint256 _newAmount); + + // When a new period threshold has been crossed + event Period(uint256 _period); + + // Redistribution applied on a single eligible account + event Redistribution(address indexed _account, uint256 indexed _period, uint256 _value); + + // Temporary event used in development, will be removed on prod + event Debug(bytes32 _foo); + + // EIP173 + event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); // EIP173 + + constructor(string memory _name, string memory _symbol, uint8 _decimals, uint256 _taxLevelMinute, uint256 _periodMinutes, address _defaultSinkAddress, uint256 _supplyCap) public { + // ACL setup + owner = msg.sender; + minter[owner] = true; + + // ERC20 setup + name = _name; + symbol = _symbol; + decimals = _decimals; + + // Demurrage setup + periodStart = block.timestamp; + periodDuration = _periodMinutes * 60; + demurrageAmount = uint128(ppmDivider * 1000000); // Represents 38 decimal places + demurragePeriod = 1; + taxLevel = _taxLevelMinute; // Represents 38 decimal places + bytes32 initialRedistribution = toRedistribution(0, 1000000, 0, 1); + redistributions.push(initialRedistribution); + + // Misc settings + supplyCap = _supplyCap; + sinkAddress = _defaultSinkAddress; + minimumParticipantSpend = 10 ** uint256(_decimals); + } + + // Given address will be allowed to call the mintTo() function + function addMinter(address _minter) public returns (bool) { + require(msg.sender == owner); + minter[_minter] = true; + return true; + } + + // Given address will no longer be allowed to call the mintTo() function + function removeMinter(address _minter) public returns (bool) { + require(msg.sender == owner || _minter == msg.sender); + minter[_minter] = false; + return true; + } + + /// Implements ERC20 + function balanceOf(address _account) public view returns (uint256) { + uint256 baseBalance; + uint256 currentDemurragedAmount; + uint256 periodCount; + + baseBalance = baseBalanceOf(_account); + + periodCount = actualPeriod() - demurragePeriod; + + currentDemurragedAmount = uint128(decayBy(demurrageAmount, periodCount)); + + return (baseBalance * currentDemurragedAmount) / (ppmDivider * 1000000); + } + + /// Balance unmodified by demurrage + function baseBalanceOf(address _account) public view returns (uint256) { + return uint256(account[_account]) & maskAccountValue; + } + + /// Increases base balance for a single account + function increaseBaseBalance(address _account, uint256 _delta) private returns (bool) { + uint256 oldBalance; + uint256 newBalance; + uint256 workAccount; + + workAccount = uint256(account[_account]); + + if (_delta == 0) { + return false; + } + + oldBalance = baseBalanceOf(_account); + newBalance = oldBalance + _delta; + require(uint160(newBalance) > uint160(oldBalance), 'ERR_WOULDWRAP'); // revert if increase would result in a wrapped value + workAccount &= (~maskAccountValue); + workAccount |= (newBalance & maskAccountValue); + account[_account] = bytes32(workAccount); + return true; + } + + /// Decreases base balance for a single account + function decreaseBaseBalance(address _account, uint256 _delta) private returns (bool) { + uint256 oldBalance; + uint256 newBalance; + uint256 workAccount; + + workAccount = uint256(account[_account]); + + if (_delta == 0) { + return false; + } + + oldBalance = baseBalanceOf(_account); + require(oldBalance >= _delta, 'ERR_OVERSPEND'); // overspend guard + newBalance = oldBalance - _delta; + workAccount &= (~maskAccountValue); + workAccount |= (newBalance & maskAccountValue); + account[_account] = bytes32(workAccount); + return true; + } + + // Creates new tokens out of thin air, and allocates them to the given address + // Triggers tax + function mintTo(address _beneficiary, uint256 _amount) external returns (bool) { + uint256 baseAmount; + + require(minter[msg.sender]); + require(_amount + totalSupply <= supplyCap); + + changePeriod(); + baseAmount = _amount; + totalSupply += _amount; + increaseBaseBalance(_beneficiary, baseAmount); + emit Mint(msg.sender, _beneficiary, _amount); + saveRedistributionSupply(); + return true; + } + + // Deserializes the redistribution word + // uint1(isFractional) | uint95(unused) | uint20(demurrageModifier) | uint36(participants) | uint72(value) | uint32(period) + function toRedistribution(uint256 _participants, uint256 _demurrageModifierPpm, uint256 _value, uint256 _period) private pure returns(bytes32) { + bytes32 redistribution; + + redistribution |= bytes32((_demurrageModifierPpm << shiftRedistributionDemurrage) & maskRedistributionDemurrage); + redistribution |= bytes32((_participants << shiftRedistributionParticipants) & maskRedistributionParticipants); + redistribution |= bytes32((_value << shiftRedistributionValue) & maskRedistributionValue); + redistribution |= bytes32(_period & maskRedistributionPeriod); + return redistribution; + } + + // Serializes the demurrage period part of the redistribution word + function toRedistributionPeriod(bytes32 redistribution) public pure returns (uint256) { + return uint256(redistribution) & maskRedistributionPeriod; + } + + // Serializes the supply part of the redistribution word + function toRedistributionSupply(bytes32 redistribution) public pure returns (uint256) { + return (uint256(redistribution) & maskRedistributionValue) >> shiftRedistributionValue; + } + + // Serializes the number of participants part of the redistribution word + function toRedistributionParticipants(bytes32 redistribution) public pure returns (uint256) { + return (uint256(redistribution) & maskRedistributionParticipants) >> shiftRedistributionParticipants; + } + + // Serializes the number of participants part of the redistribution word + function toRedistributionDemurrageModifier(bytes32 redistribution) public pure returns (uint256) { + return (uint256(redistribution) & maskRedistributionDemurrage) >> shiftRedistributionDemurrage; + } + + // Client accessor to the redistributions array length + function redistributionCount() public view returns (uint256) { + return redistributions.length; + } + + // Add number of participants for the current redistribution period by one + function incrementRedistributionParticipants() private returns (bool) { + bytes32 currentRedistribution; + uint256 tmpRedistribution; + uint256 participants; + + currentRedistribution = redistributions[redistributions.length-1]; + participants = toRedistributionParticipants(currentRedistribution) + 1; + tmpRedistribution = uint256(currentRedistribution); + tmpRedistribution &= (~maskRedistributionParticipants); + tmpRedistribution |= ((participants << shiftRedistributionParticipants) & maskRedistributionParticipants); + + redistributions[redistributions.length-1] = bytes32(tmpRedistribution); + + return true; + } + + // Save the current total supply amount to the current redistribution period + function saveRedistributionSupply() private returns (bool) { + uint256 currentRedistribution; + + currentRedistribution = uint256(redistributions[redistributions.length-1]); + currentRedistribution &= (~maskRedistributionValue); + currentRedistribution |= (totalSupply << shiftRedistributionValue); + + redistributions[redistributions.length-1] = bytes32(currentRedistribution); + return true; + } + + // Get the demurrage period of the current block number + function actualPeriod() public view returns (uint128) { + return uint128((block.timestamp - periodStart) / periodDuration + 1); + } + + // Add an entered demurrage period to the redistribution array + function checkPeriod() private view returns (bytes32) { + bytes32 lastRedistribution; + uint256 currentPeriod; + + lastRedistribution = redistributions[redistributions.length-1]; + currentPeriod = this.actualPeriod(); + if (currentPeriod <= toRedistributionPeriod(lastRedistribution)) { + return bytes32(0x00); + } + return lastRedistribution; + } + + // Deserialize the pemurrage period for the given account is participating in + function accountPeriod(address _account) public view returns (uint256) { + return (uint256(account[_account]) & maskAccountPeriod) >> shiftAccountPeriod; + } + + // Save the given demurrage period as the currently participation period for the given address + function registerAccountPeriod(address _account, uint256 _period) private returns (bool) { + account[_account] &= bytes32(~maskAccountPeriod); + account[_account] |= bytes32((_period << shiftAccountPeriod) & maskAccountPeriod); + incrementRedistributionParticipants(); + return true; + } + + // Determine whether the unit number is rounded down, rounded up or evenly divides. + // Returns 0 if evenly distributed, or the remainder as a positive number + // A _numParts value 0 will be interpreted as the value 1 + function remainder(uint256 _numParts, uint256 _sumWhole) public pure returns (uint256) { + uint256 unit; + uint256 truncatedResult; + + if (_numParts == 0) { // no division by zero please + revert('ERR_NUMPARTS_ZERO'); + } + require(_numParts < _sumWhole); // At least you are never LESS than the sum of your parts. Think about that. + + unit = _sumWhole / _numParts; + truncatedResult = unit * _numParts; + return _sumWhole - truncatedResult; + } + + // Returns the amount sent to the sink address + function applyDefaultRedistribution(bytes32 _redistribution) private returns (uint256) { + uint256 redistributionSupply; + uint256 redistributionPeriod; + uint256 unit; + uint256 truncatedResult; + + redistributionSupply = toRedistributionSupply(_redistribution); + + unit = (redistributionSupply * taxLevel) / 1000000; + truncatedResult = (unit * 1000000) / taxLevel; + + if (truncatedResult < redistributionSupply) { + redistributionPeriod = toRedistributionPeriod(_redistribution); // since we reuse period here, can possibly be optimized by passing period instead + redistributions[redistributionPeriod-1] &= bytes32(~maskRedistributionParticipants); // just to be safe, zero out all participant count data, in this case there will be only one + redistributions[redistributionPeriod-1] |= bytes32(maskRedistributionIsFractional | (1 << shiftRedistributionParticipants)); + } + + increaseBaseBalance(sinkAddress, unit / ppmDivider); + return unit; + } + + // sets the remainder bit for the given period and books the remainder to the sink address balance + // returns false if no change was made + function applyRemainderOnPeriod(uint256 _remainder, uint256 _period) private returns (bool) { + uint256 periodSupply; + + if (_remainder == 0) { + return false; + } + + // TODO: is this needed? + redistributions[_period-1] |= bytes32(maskRedistributionIsFractional); + + periodSupply = toRedistributionSupply(redistributions[_period-1]); + increaseBaseBalance(sinkAddress, periodSupply - _remainder); + return true; + } + + + // Calculate and cache the demurrage value corresponding to the (period of the) time of the method call + function applyDemurrage() public returns (bool) { + uint128 epochPeriodCount; + uint128 periodCount; + uint256 lastDemurrageAmount; + uint256 newDemurrageAmount; + + epochPeriodCount = actualPeriod(); + periodCount = epochPeriodCount - demurragePeriod; + if (periodCount == 0) { + return false; + } + lastDemurrageAmount = demurrageAmount; + demurrageAmount = uint128(decayBy(lastDemurrageAmount, periodCount)); + demurragePeriod = epochPeriodCount; + emit Decayed(epochPeriodCount, periodCount, lastDemurrageAmount, demurrageAmount); + return true; + } + + // Return timestamp of start of period threshold + function getPeriodTimeDelta(uint256 _periodCount) public view returns (uint256) { + return periodStart + (_periodCount * periodDuration); + } + + // Amount of demurrage cycles inbetween the current timestamp and the given target time + function demurrageCycles(uint256 _target) public view returns (uint256) { + return (block.timestamp - _target) / 60; + } + + // Recalculate the demurrage modifier for the new period + function changePeriod() public returns (bool) { + bytes32 currentRedistribution; + bytes32 nextRedistribution; + uint256 currentPeriod; + uint256 currentParticipants; + uint256 currentRemainder; + uint256 currentDemurrageAmount; + uint256 nextRedistributionDemurrage; + uint256 demurrageCounts; + uint256 periodTimestamp; + uint256 nextPeriod; + + currentRedistribution = checkPeriod(); + if (currentRedistribution == bytes32(0x00)) { + return false; + } + + currentPeriod = toRedistributionPeriod(currentRedistribution); + nextPeriod = currentPeriod + 1; + periodTimestamp = getPeriodTimeDelta(currentPeriod); + + applyDemurrage(); + currentDemurrageAmount = demurrageAmount; + + demurrageCounts = demurrageCycles(periodTimestamp); + if (demurrageCounts > 0) { + nextRedistributionDemurrage = growBy(currentDemurrageAmount, demurrageCounts) / ppmDivider; + } else { + nextRedistributionDemurrage = currentDemurrageAmount / ppmDivider; + } + + nextRedistribution = toRedistribution(0, nextRedistributionDemurrage, totalSupply, nextPeriod); + redistributions.push(nextRedistribution); + + //currentParticipants = toRedistributionParticipants(currentRedistribution); + //if (currentParticipants == 0) { + currentRemainder = applyDefaultRedistribution(currentRedistribution); + //} else { + // currentRemainder = remainder(currentParticipants, totalSupply); // we can use totalSupply directly because it will always be the same as the recorded supply on the current redistribution + // applyRemainderOnPeriod(currentRemainder, currentPeriod); + //} + emit Period(nextPeriod); + return true; + } + + // Reverse a value reduced by demurrage by the given period to its original value + function growBy(uint256 _value, uint256 _period) public view returns (uint256) { + uint256 valueFactor; + uint256 truncatedTaxLevel; + + valueFactor = 1000000; + truncatedTaxLevel = taxLevel / ppmDivider; + + for (uint256 i = 0; i < _period; i++) { + valueFactor = valueFactor + ((valueFactor * truncatedTaxLevel) / 1000000); + } + return (valueFactor * _value) / 1000000; + } + + // Calculate a value reduced by demurrage by the given period + // TODO: higher precision if possible + function decayBy(uint256 _value, uint256 _period) public view returns (uint256) { + uint256 valueFactor; + uint256 truncatedTaxLevel; + + valueFactor = 1000000; + truncatedTaxLevel = taxLevel / ppmDivider; + + for (uint256 i = 0; i < _period; i++) { + valueFactor = valueFactor - ((valueFactor * truncatedTaxLevel) / 1000000); + } + return (valueFactor * _value) / 1000000; + } + + // If the given account is participating in a period and that period has been crossed + // THEN increase the base value of the account with its share of the value reduction of the period + function applyRedistributionOnAccount(address _account) public returns (bool) { +// bytes32 periodRedistribution; +// uint256 supply; +// uint256 participants; +// uint256 baseValue; +// uint256 value; + uint256 period; +// uint256 demurrage; +// + period = accountPeriod(_account); + if (period == 0 || period >= actualPeriod()) { + return false; + } +// periodRedistribution = redistributions[period-1]; +// participants = toRedistributionParticipants(periodRedistribution); +// if (participants == 0) { +// return false; +// } +// +// supply = toRedistributionSupply(periodRedistribution); +// demurrage = toRedistributionDemurrageModifier(periodRedistribution); +// baseValue = ((supply / participants) * (taxLevel / 1000000)) / ppmDivider; +// value = (baseValue * demurrage) / 1000000; +// +// // zero out period for the account + account[_account] &= bytes32(~maskAccountPeriod); +// increaseBaseBalance(_account, value); +// +// emit Redistribution(_account, period, value); + return true; + } + + // Inflates the given amount according to the current demurrage modifier + function toBaseAmount(uint256 _value) public view returns (uint256) { + //return (_value * ppmDivider * 1000000) / toDemurrageAmount(demurrageModifier); + return (_value * ppmDivider * 1000000) / demurrageAmount; + } + + // Implements ERC20, triggers tax and/or redistribution + function approve(address _spender, uint256 _value) public returns (bool) { + uint256 baseValue; + + changePeriod(); + //applyRedistributionOnAccount(msg.sender); + + baseValue = toBaseAmount(_value); + allowance[msg.sender][_spender] += baseValue; + emit Approval(msg.sender, _spender, _value); + return true; + } + + // Implements ERC20, triggers tax and/or redistribution + function transfer(address _to, uint256 _value) public returns (bool) { + uint256 baseValue; + bool result; + + changePeriod(); + //applyRedistributionOnAccount(msg.sender); + + baseValue = toBaseAmount(_value); + result = transferBase(msg.sender, _to, baseValue); + emit Transfer(msg.sender, _to, _value); + return result; + } + + + // Implements ERC20, triggers tax and/or redistribution + function transferFrom(address _from, address _to, uint256 _value) public returns (bool) { + uint256 baseValue; + bool result; + + changePeriod(); + //applyRedistributionOnAccount(msg.sender); + + baseValue = toBaseAmount(_value); + require(allowance[_from][msg.sender] >= baseValue); + + result = transferBase(_from, _to, baseValue); + emit Transfer(_from, _to, _value); + return result; + } + + // ERC20 transfer backend for transfer, transferFrom + function transferBase(address _from, address _to, uint256 _value) private returns (bool) { + uint256 period; + + decreaseBaseBalance(_from, _value); + increaseBaseBalance(_to, _value); + + period = actualPeriod(); + if (_value >= minimumParticipantSpend && accountPeriod(_from) != period && _from != _to) { + registerAccountPeriod(_from, period); + } + return true; + } + + // 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 == 0xc6bb4b70) { // ERC20 + return true; + } + if (_sum == 0x449a52f8) { // Minter + return true; + } + if (_sum == 0x01ffc9a7) { // EIP165 + return true; + } + if (_sum == 0x9493f8b2) { // EIP173 + return true; + } + if (_sum == 0x37a47be4) { // OwnedAccepter + return true; + } + return false; + } +} diff --git a/solidity/Makefile b/solidity/Makefile @@ -1,17 +1,16 @@ SOLC = /usr/bin/solc -all: multi_nocap multi_cap single_nocap - +all: multi single multi_nocap: $(SOLC) DemurrageTokenMultiNocap.sol --abi --evm-version byzantium | awk 'NR>3' > DemurrageTokenMultiNocap.json $(SOLC) DemurrageTokenMultiNocap.sol --bin --evm-version byzantium | awk 'NR>3' > DemurrageTokenMultiNocap.bin - truncate -s -1 DemurrageTokenMultiCap.bin + truncate -s -1 DemurrageTokenMultiNocap.bin multi_cap: $(SOLC) DemurrageTokenMultiCap.sol --abi --evm-version byzantium | awk 'NR>3' > DemurrageTokenMultiCap.json $(SOLC) DemurrageTokenMultiCap.sol --bin --evm-version byzantium | awk 'NR>3' > DemurrageTokenMultiCap.bin - truncate -s -1 DemurrageTokenMultiNocap.bin + truncate -s -1 DemurrageTokenMultiCap.bin multi: multi_nocap multi_cap @@ -20,6 +19,13 @@ single_nocap: $(SOLC) DemurrageTokenSingleNocap.sol --bin --evm-version byzantium | awk 'NR>3' > DemurrageTokenSingleNocap.bin truncate -s -1 DemurrageTokenSingleNocap.bin +single_cap: + $(SOLC) DemurrageTokenSingleCap.sol --abi --evm-version byzantium | awk 'NR>3' > DemurrageTokenSingleCap.json + $(SOLC) DemurrageTokenSingleCap.sol --bin --evm-version byzantium | awk 'NR>3' > DemurrageTokenSingleCap.bin + truncate -s -1 DemurrageTokenSingleCap.bin + +single: single_nocap single_cap + test: all python ../python/tests/test_basic.py python ../python/tests/test_period.py