commit d316071755dfa8ef8b12176ffd1b19f30a7ba8a9
parent d1e667118b1cc33fa97afe41222f8c872227db4f
Author: lash <dev@holbrook.no>
Date: Sun, 7 May 2023 09:40:36 +0100
Add missing events test file, add immediate final on complete, cancellation
Diffstat:
12 files changed, 447 insertions(+), 85 deletions(-)
diff --git a/python/evm_tokenvote/data/Voter.bin b/python/evm_tokenvote/data/Voter.bin
@@ -1 +1 @@
-60806040523480156200001157600080fd5b506040516200353a3803806200353a8339818101604052810190620000379190620003da565b6200004162000217565b826000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555081600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506001819080600181540180825580915050600190039060005260206000209060070201600090919091909150600082015181600001556020820151816001019080519060200190620001169291906200028e565b50604082015181600201908051906020019062000135929190620002e0565b50606082015181600301556080820151816004015560a0820151816005015560c08201518160060160006101000a81548162ffffff021916908362ffffff16021790555060e08201518160060160036101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506101008201518160060160176101000a81548160ff021916908360ff1602179055506101208201518160060160186101000a81548160ff021916908360ff1602179055505050600160038190555050505062000421565b604051806101400160405280600080191681526020016060815260200160608152602001600081526020016000815260200160008152602001600062ffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600060ff168152602001600060ff1681525090565b828054828255906000526020600020908101928215620002cd579160200282015b82811115620002cc578251825591602001919060010190620002af565b5b509050620002dc919062000332565b5090565b8280548282559060005260206000209081019282156200031f579160200282015b828111156200031e57825182559160200191906001019062000301565b5b5090506200032e919062000351565b5090565b5b808211156200034d57600081600090555060010162000333565b5090565b5b808211156200036c57600081600090555060010162000352565b5090565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000620003a28262000375565b9050919050565b620003b48162000395565b8114620003c057600080fd5b50565b600081519050620003d481620003a9565b92915050565b60008060408385031215620003f457620003f362000370565b5b60006200040485828601620003c3565b92505060206200041785828601620003c3565b9150509250929050565b61310980620004316000396000f3fe608060405234801561001057600080fd5b5060043610610107576000357c01000000000000000000000000000000000000000000000000000000009004806384385191116100a9578063ba32941411610083578063ba329414146102b6578063c7f758a8146102e6578063e99a943e14610316578063fc0c546a1461034657610107565b806384385191146102265780638bb5221314610256578063b05c65ba1461028657610107565b806341ec6870116100e557806341ec68701461018a5780634bb278f3146101a8578063509bd337146101c657806370a08231146101f657610107565b80630121b93f1461010c5780631ce309271461013c5780633ccfd60b1461016c575b600080fd5b61012660048036038101906101219190611f20565b610364565b6040516101339190611f68565b60405180910390f35b61015660048036038101906101519190611f83565b610378565b6040516101639190611fdc565b60405180910390f35b6101746103d4565b6040516101819190612006565b60405180910390f35b61019261075d565b60405161019f91906122f9565b60405180910390f35b6101b0610985565b6040516101bd9190611f68565b60405180910390f35b6101e060048036038101906101db9190611f83565b610b52565b6040516101ed9190611f68565b60405180910390f35b610210600480360381019061020b9190612347565b61102e565b60405161021d9190612006565b60405180910390f35b610240600480360381019061023b9190611f20565b611046565b60405161024d9190612006565b60405180910390f35b610270600480360381019061026b91906123a0565b611088565b60405161027d9190611f68565b60405180910390f35b6102a0600480360381019061029b9190612591565b61133d565b6040516102ad9190612006565b60405180910390f35b6102d060048036038101906102cb9190611f83565b611637565b6040516102dd9190612006565b60405180910390f35b61030060048036038101906102fb9190611f20565b6116f3565b60405161030d91906122f9565b60405180910390f35b610330600480360381019061032b9190612614565b6118c6565b60405161033d9190612006565b60405180910390f35b61034e6118e0565b60405161035b9190612676565b60405180910390f35b6000610371600083610b52565b9050919050565b6000806001808561038991906126c0565b8154811061039a576103996126f4565b5b906000526020600020906007020190508060010183815481106103c0576103bf6126f4565b5b906000526020600020015491505092915050565b600080600060606000600460003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050600354600560003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054036105145760016003548154811061047d5761047c6126f4565b5b90600052602060002090600702019350438460050154116104f757600060028560060160179054906101000a900460ff161660ff16116104f2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104e990612780565b60405180910390fd5b610513565b8084600401600082825461050b91906127a0565b925050819055505b5b6000600460003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506000600560003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555060008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1633826040516024016105e89291906127d4565b6040516020818303038152906040527fa9059cbb000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050604051610672919061286e565b6000604051808303816000865af19150503d80600081146106af576040519150601f19603f3d011682016040523d82523d6000602084013e6106b4565b606091505b508093508194505050826106fd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106f4906128d1565b60405180910390fd5b81806020019051810190610711919061291d565b925082610753576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161074a90612996565b60405180910390fd5b8094505050505090565b610765611d8b565b600060016003548154811061077d5761077c6126f4565b5b90600052602060002090600702019050600060018260060160179054906101000a900460ff161660ff16116107e7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107de90612a02565b60405180910390fd5b8060405180610140016040529081600082015481526020016001820180548060200260200160405190810160405280929190818152602001828054801561084d57602002820191906000526020600020905b815481526020019060010190808311610839575b50505050508152602001600282018054806020026020016040519081016040528092919081815260200182805480156108a557602002820191906000526020600020905b815481526020019060010190808311610891575b505050505081526020016003820154815260200160048201548152602001600582015481526020016006820160009054906101000a900462ffffff1662ffffff1662ffffff1681526020016006820160039054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016006820160179054906101000a900460ff1660ff1660ff1681526020016006820160189054906101000a900460ff1660ff1660ff168152505091505090565b60008060006001600354815481106109a05761099f6126f4565b5b90600052602060002090600702019150600060028360060160179054906101000a900460ff161660ff1614610a0a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a0190612a6e565b60405180910390fd5b600060048360060160179054906101000a900460ff161660ff1611610a64576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a5b90612ada565b60405180910390fd5b6000610a6f83611904565b03610a7f57600092505050610b4f565b60028260060160178282829054906101000a900460ff161792506101000a81548160ff021916908360ff160217905550600160036000828254610ac291906126c0565b92505081905550620f42408260040154610adc9190612afa565b90508160060160009054906101000a900462ffffff1662ffffff16826003015482610b079190612b6b565b1015610b485760088260060160178282829054906101000a900460ff161792506101000a81548160ff021916908360ff160217905550600092505050610b4f565b6001925050505b90565b60008060006060610b6233611b6f565b600160035481548110610b7857610b776126f4565b5b90600052602060002090600702019250600060018460060160179054906101000a900460ff161660ff1611610be2576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bd990612be8565b60405180910390fd5b6000610bed84611904565b03610bfe5760009350505050611028565b43836005015411610c44576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c3b90612c54565b60405180910390fd5b6000600560003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541115610d1057600354600560003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205414610d0f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d0690612cc0565b60405180910390fd5b5b600083600101805490501115610d6a5782600101805490508610610d69576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d6090612d2c565b60405180910390fd5b5b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16333087604051602401610db693929190612dab565b6040516020818303038152906040527f23b872dd000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050604051610e40919061286e565b6000604051808303816000865af19150503d8060008114610e7d576040519150601f19603f3d011682016040523d82523d6000602084013e610e82565b606091505b50809250819350505081610ecb576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ec2906128d1565b60405180910390fd5b80806020019051810190610edf919061291d565b915081610f21576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f1890612996565b60405180910390fd5b600354600560003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555084600460003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254610fb691906126c0565b9250508190555084836004016000828254610fd191906126c0565b925050819055506000836001018054905011156110205784836002018781548110610fff57610ffe6126f4565b5b90600052602060002001600082825461101891906126c0565b925050819055505b600193505050505b92915050565b60046020528060005260406000206000915090505481565b6000806001808461105791906126c0565b81548110611068576110676126f4565b5b906000526020600020906007020190508060010180549050915050919050565b6000806000806000806000806001808b6110a291906126c0565b815481106110b3576110b26126f4565b5b90600052602060002090600702019650438760050154111561110a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161110190612780565b60405180910390fd5b600060048860060160179054906101000a900460ff161660ff16111561113a576000975050505050505050611337565b60008760010180549050036111895760048760060160178282829054906101000a900460ff161792506101000a81548160ff021916908360ff1602179055506001975050505050505050611337565b8660060160189054906101000a900460ff169150866001018054905089836111b19190612de2565b60ff1611156111d0578187600101805490506111cd9190612e17565b98505b81896111dc9190612de2565b98508660060160179054906101000a900460ff1690508195505b8860ff168660ff16101561128557866002018660ff168154811061121d5761121c6126f4565b5b9060005260206000200154925060008311801561123957508383145b1561124957601081179050611263565b83831115611262578293508560ff169450601019811690505b5b6001826112709190612de2565b9150858061127d90612e4c565b9650506111f6565b818760060160186101000a81548160ff021916908360ff160217905550808760060160176101000a81548160ff021916908360ff16021790555086600101805490508760060160189054906101000a900460ff1660ff16106113125760048760060160178282829054906101000a900460ff161792506101000a81548160ff021916908360ff1602179055505b600060048860060160179054906101000a900460ff161660ff16119750505050505050505b92915050565b6000611347611d8b565b60008061010087511061138f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161138690612ec1565b60405180910390fd5b338360e0019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505087836000018181525050868360200181905250865167ffffffffffffffff8111156113f5576113f4612422565b5b6040519080825280602002602001820160405280156114235781602001602082028036833780820191505090505b508360400181905250848360c0019062ffffff16908162ffffff1681525050854361144e91906126c0565b9050808360a00181815250506001805490509150600183610100019060ff16908160ff168152505060018390806001815401808255809150506001900390600052602060002090600702016000909190919091506000820151816000015560208201518160010190805190602001906114c8929190611e02565b5060408201518160020190805190602001906114e5929190611e4f565b50606082015181600301556080820151816004015560a0820151816005015560c08201518160060160006101000a81548162ffffff021916908362ffffff16021790555060e08201518160060160036101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506101008201518160060160176101000a81548160ff021916908360ff1602179055506101208201518160060160186101000a81548160ff021916908360ff16021790555050506115e0600183815481106115cd576115cc6126f4565b5b9060005260206000209060070201611904565b8360600181815250506001826115f691906127a0565b8562ffffff16827f5a41400aa51d78e9e5ca645b0d045817eaa7d90e4344d773fdbe24ffb183d3ce60405160405180910390a4819350505050949350505050565b6000806001808561164891906126c0565b81548110611659576116586126f4565b5b9060005260206000209060070201905060008160010180549050036116c857600083146116bb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016116b290612f2d565b60405180910390fd5b80600401549150506116ed565b8060020183815481106116de576116dd6126f4565b5b90600052602060002001549150505b92915050565b6116fb611d8b565b6001808361170991906126c0565b8154811061171a576117196126f4565b5b906000526020600020906007020160405180610140016040529081600082015481526020016001820180548060200260200160405190810160405280929190818152602001828054801561178d57602002820191906000526020600020905b815481526020019060010190808311611779575b50505050508152602001600282018054806020026020016040519081016040528092919081815260200182805480156117e557602002820191906000526020600020905b8154815260200190600101908083116117d1575b505050505081526020016003820154815260200160048201548152602001600582015481526020016006820160009054906101000a900462ffffff1662ffffff1662ffffff1681526020016006820160039054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016006820160179054906101000a900460ff1660ff1660ff1681526020016006820160189054906101000a900460ff1660ff1660ff16815250509050919050565b600060606118d68582868661133d565b9150509392505050565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600080606060008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166040516024016040516020818303038152906040527f18160ddd000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506040516119d3919061286e565b6000604051808303816000865af19150503d8060008114611a10576040519150601f19603f3d011682016040523d82523d6000602084013e611a15565b606091505b50809350819450505082611a5e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611a55906128d1565b60405180910390fd5b81806020019051810190611a729190612f62565b905060008111611ab7576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611aae90612fdb565b60405180910390fd5b6000856003015403611ad157808560030181905550611b63565b84600301548114611b625760208560060160178282829054906101000a900460ff161792506101000a81548160ff021916908360ff16021790555060028560060160178282829054906101000a900460ff161792506101000a81548160ff021916908360ff160217905550600160036000828254611b4f91906126c0565b9250508190555060009350505050611b6a565b5b8093505050505b919050565b60006060600073ffffffffffffffffffffffffffffffffffffffff16600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1603611bd0575050611d88565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1683604051602401611c1a9190612676565b6040516020818303038152906040527f3ef25013000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050604051611ca4919061286e565b6000604051808303816000865af19150503d8060008114611ce1576040519150601f19603f3d011682016040523d82523d6000602084013e611ce6565b606091505b50809250819350505081611d2f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611d2690613047565b60405180910390fd5b80806020019051810190611d43919061291d565b915081611d85576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611d7c906130b3565b60405180910390fd5b50505b50565b604051806101400160405280600080191681526020016060815260200160608152602001600081526020016000815260200160008152602001600062ffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600060ff168152602001600060ff1681525090565b828054828255906000526020600020908101928215611e3e579160200282015b82811115611e3d578251825591602001919060010190611e22565b5b509050611e4b9190611e9c565b5090565b828054828255906000526020600020908101928215611e8b579160200282015b82811115611e8a578251825591602001919060010190611e6f565b5b509050611e989190611eb9565b5090565b5b80821115611eb5576000816000905550600101611e9d565b5090565b5b80821115611ed2576000816000905550600101611eba565b5090565b6000604051905090565b600080fd5b600080fd5b6000819050919050565b611efd81611eea565b8114611f0857600080fd5b50565b600081359050611f1a81611ef4565b92915050565b600060208284031215611f3657611f35611ee0565b5b6000611f4484828501611f0b565b91505092915050565b60008115159050919050565b611f6281611f4d565b82525050565b6000602082019050611f7d6000830184611f59565b92915050565b60008060408385031215611f9a57611f99611ee0565b5b6000611fa885828601611f0b565b9250506020611fb985828601611f0b565b9150509250929050565b6000819050919050565b611fd681611fc3565b82525050565b6000602082019050611ff16000830184611fcd565b92915050565b61200081611eea565b82525050565b600060208201905061201b6000830184611ff7565b92915050565b61202a81611fc3565b82525050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b60006120688383612021565b60208301905092915050565b6000602082019050919050565b600061208c82612030565b612096818561203b565b93506120a18361204c565b8060005b838110156120d25781516120b9888261205c565b97506120c483612074565b9250506001810190506120a5565b5085935050505092915050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b61211481611eea565b82525050565b6000612126838361210b565b60208301905092915050565b6000602082019050919050565b600061214a826120df565b61215481856120ea565b935061215f836120fb565b8060005b83811015612190578151612177888261211a565b975061218283612132565b925050600181019050612163565b5085935050505092915050565b600062ffffff82169050919050565b6121b58161219d565b82525050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006121e6826121bb565b9050919050565b6121f6816121db565b82525050565b600060ff82169050919050565b612212816121fc565b82525050565b6000610140830160008301516122316000860182612021565b50602083015184820360208601526122498282612081565b91505060408301518482036040860152612263828261213f565b9150506060830151612278606086018261210b565b50608083015161228b608086018261210b565b5060a083015161229e60a086018261210b565b5060c08301516122b160c08601826121ac565b5060e08301516122c460e08601826121ed565b506101008301516122d9610100860182612209565b506101208301516122ee610120860182612209565b508091505092915050565b600060208201905081810360008301526123138184612218565b905092915050565b612324816121db565b811461232f57600080fd5b50565b6000813590506123418161231b565b92915050565b60006020828403121561235d5761235c611ee0565b5b600061236b84828501612332565b91505092915050565b61237d816121fc565b811461238857600080fd5b50565b60008135905061239a81612374565b92915050565b600080604083850312156123b7576123b6611ee0565b5b60006123c585828601611f0b565b92505060206123d68582860161238b565b9150509250929050565b6123e981611fc3565b81146123f457600080fd5b50565b600081359050612406816123e0565b92915050565b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b61245a82612411565b810181811067ffffffffffffffff8211171561247957612478612422565b5b80604052505050565b600061248c611ed6565b90506124988282612451565b919050565b600067ffffffffffffffff8211156124b8576124b7612422565b5b602082029050602081019050919050565b600080fd5b60006124e16124dc8461249d565b612482565b90508083825260208201905060208402830185811115612504576125036124c9565b5b835b8181101561252d578061251988826123f7565b845260208401935050602081019050612506565b5050509392505050565b600082601f83011261254c5761254b61240c565b5b813561255c8482602086016124ce565b91505092915050565b61256e8161219d565b811461257957600080fd5b50565b60008135905061258b81612565565b92915050565b600080600080608085870312156125ab576125aa611ee0565b5b60006125b9878288016123f7565b945050602085013567ffffffffffffffff8111156125da576125d9611ee5565b5b6125e687828801612537565b93505060406125f787828801611f0b565b92505060606126088782880161257c565b91505092959194509250565b60008060006060848603121561262d5761262c611ee0565b5b600061263b868287016123f7565b935050602061264c86828701611f0b565b925050604061265d8682870161257c565b9150509250925092565b612670816121db565b82525050565b600060208201905061268b6000830184612667565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006126cb82611eea565b91506126d683611eea565b92508282019050808211156126ee576126ed612691565b5b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600082825260208201905092915050565b7f4552525f5052454d415455524500000000000000000000000000000000000000600082015250565b600061276a600d83612723565b915061277582612734565b602082019050919050565b600060208201905081810360008301526127998161275d565b9050919050565b60006127ab82611eea565b91506127b683611eea565b92508282039050818111156127ce576127cd612691565b5b92915050565b60006040820190506127e96000830185612667565b6127f66020830184611ff7565b9392505050565b600081519050919050565b600081905092915050565b60005b83811015612831578082015181840152602081019050612816565b60008484015250505050565b6000612848826127fd565b6128528185612808565b9350612862818560208601612813565b80840191505092915050565b600061287a828461283d565b915081905092915050565b7f4552525f544f4b454e0000000000000000000000000000000000000000000000600082015250565b60006128bb600983612723565b91506128c682612885565b602082019050919050565b600060208201905081810360008301526128ea816128ae565b9050919050565b6128fa81611f4d565b811461290557600080fd5b50565b600081519050612917816128f1565b92915050565b60006020828403121561293357612932611ee0565b5b600061294184828501612908565b91505092915050565b7f4552525f5452414e534645520000000000000000000000000000000000000000600082015250565b6000612980600c83612723565b915061298b8261294a565b602082019050919050565b600060208201905081810360008301526129af81612973565b9050919050565b7f4552525f4e4f5f43555252454e545f50524f504f53414c000000000000000000600082015250565b60006129ec601783612723565b91506129f7826129b6565b602082019050919050565b60006020820190508181036000830152612a1b816129df565b9050919050565b7f4552525f414c52454144595f53544154455f46494e414c000000000000000000600082015250565b6000612a58601783612723565b9150612a6382612a22565b602082019050919050565b60006020820190508181036000830152612a8781612a4b565b9050919050565b7f4552525f5343414e5f4649525354000000000000000000000000000000000000600082015250565b6000612ac4600e83612723565b9150612acf82612a8e565b602082019050919050565b60006020820190508181036000830152612af381612ab7565b9050919050565b6000612b0582611eea565b9150612b1083611eea565b9250828202612b1e81611eea565b91508282048414831517612b3557612b34612691565b5b5092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000612b7682611eea565b9150612b8183611eea565b925082612b9157612b90612b3c565b5b828204905092915050565b7f4552525f50524f504f53414c5f494e4143544956450000000000000000000000600082015250565b6000612bd2601583612723565b9150612bdd82612b9c565b602082019050919050565b60006020820190508181036000830152612c0181612bc5565b9050919050565b7f4552525f444541444c494e450000000000000000000000000000000000000000600082015250565b6000612c3e600c83612723565b9150612c4982612c08565b602082019050919050565b60006020820190508181036000830152612c6d81612c31565b9050919050565b7f4552525f57495448445241575f46495253540000000000000000000000000000600082015250565b6000612caa601283612723565b9150612cb582612c74565b602082019050919050565b60006020820190508181036000830152612cd981612c9d565b9050919050565b7f4552525f4f5054494f4e5f494e56414c49440000000000000000000000000000600082015250565b6000612d16601283612723565b9150612d2182612ce0565b602082019050919050565b60006020820190508181036000830152612d4581612d09565b9050919050565b6000819050919050565b6000612d71612d6c612d67846121bb565b612d4c565b6121bb565b9050919050565b6000612d8382612d56565b9050919050565b6000612d9582612d78565b9050919050565b612da581612d8a565b82525050565b6000606082019050612dc06000830186612667565b612dcd6020830185612d9c565b612dda6040830184611ff7565b949350505050565b6000612ded826121fc565b9150612df8836121fc565b9250828201905060ff811115612e1157612e10612691565b5b92915050565b6000612e22826121fc565b9150612e2d836121fc565b9250828203905060ff811115612e4657612e45612691565b5b92915050565b6000612e57826121fc565b915060ff8203612e6a57612e69612691565b5b600182019050919050565b7f4552525f544f4f5f4d414e595f4f5054494f4e53000000000000000000000000600082015250565b6000612eab601483612723565b9150612eb682612e75565b602082019050919050565b60006020820190508181036000830152612eda81612e9e565b9050919050565b7f4552525f4e4f5f4f5054494f4e53000000000000000000000000000000000000600082015250565b6000612f17600e83612723565b9150612f2282612ee1565b602082019050919050565b60006020820190508181036000830152612f4681612f0a565b9050919050565b600081519050612f5c81611ef4565b92915050565b600060208284031215612f7857612f77611ee0565b5b6000612f8684828501612f4d565b91505092915050565b7f4552525f5a45524f5f535550504c590000000000000000000000000000000000600082015250565b6000612fc5600f83612723565b9150612fd082612f8f565b602082019050919050565b60006020820190508181036000830152612ff481612fb8565b9050919050565b7f4552525f52454749535452590000000000000000000000000000000000000000600082015250565b6000613031600c83612723565b915061303c82612ffb565b602082019050919050565b6000602082019050818103600083015261306081613024565b9050919050565b7f4552525f554e415554485f4143434f554e540000000000000000000000000000600082015250565b600061309d601283612723565b91506130a882613067565b602082019050919050565b600060208201905081810360008301526130cc81613090565b905091905056fea264697066735822122030203a12e5b129eb8d5e78a8864cc83722b605569b104295cf05367a05d6bf8764736f6c63430008130033
-\ No newline at end of file
+60806040523480156200001157600080fd5b50604051620038f5380380620038f583398181016040528101906200003791906200042e565b6200004162000264565b836000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555082600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555081600360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600181908060018154018082558091505060019003906000526020600020906008020160009091909190915060008201518160000155602082015181600101908051906020019062000157929190620002e2565b5060408201518160020190805190602001906200017692919062000334565b50606082015181600301556080820151816004015560a0820151816005015560c0820151816006015560e08201518160070160006101000a81548162ffffff021916908362ffffff1602179055506101008201518160070160036101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506101208201518160070160176101000a81548160ff021916908360ff1602179055506101408201518160070160186101000a81548160ff021916908360ff16021790555050506001600481905550505050506200048a565b60405180610160016040528060008019168152602001606081526020016060815260200160008152602001600081526020016000815260200160008152602001600062ffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600060ff168152602001600060ff1681525090565b82805482825590600052602060002090810192821562000321579160200282015b828111156200032057825182559160200191906001019062000303565b5b50905062000330919062000386565b5090565b82805482825590600052602060002090810192821562000373579160200282015b828111156200037257825182559160200191906001019062000355565b5b509050620003829190620003a5565b5090565b5b80821115620003a157600081600090555060010162000387565b5090565b5b80821115620003c0576000816000905550600101620003a6565b5090565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000620003f682620003c9565b9050919050565b6200040881620003e9565b81146200041457600080fd5b50565b6000815190506200042881620003fd565b92915050565b6000806000606084860312156200044a5762000449620003c4565b5b60006200045a8682870162000417565b93505060206200046d8682870162000417565b9250506040620004808682870162000417565b9150509250925092565b61345b806200049a6000396000f3fe608060405234801561001057600080fd5b506004361061011d576000357c010000000000000000000000000000000000000000000000000000000090048063826d9873116100b4578063ba32941411610083578063ba3294141461032c578063c7f758a81461035c578063e99a943e1461038c578063fc0c546a146103bc5761011d565b8063826d98731461026c578063843851911461029c5780638bb52213146102cc578063b05c65ba146102fc5761011d565b806341ec6870116100f057806341ec6870146101d05780634bb278f3146101ee578063509bd3371461020c57806370a082311461023c5761011d565b80630121b93f146101225780631ce30927146101525780632e1a7d4d146101825780633ccfd60b146101b2575b600080fd5b61013c6004803603810190610137919061225d565b6103da565b60405161014991906122a5565b60405180910390f35b61016c600480360381019061016791906122c0565b610456565b6040516101799190612319565b60405180910390f35b61019c6004803603810190610197919061225d565b6104b2565b6040516101a99190612343565b60405180910390f35b6101ba610544565b6040516101c79190612343565b60405180910390f35b6101d86108a1565b6040516101e5919061264b565b60405180910390f35b6101f6610ad3565b60405161020391906122a5565b60405180910390f35b610226600480360381019061022191906122c0565b610c78565b60405161023391906122a5565b60405180910390f35b61025660048036038101906102519190612699565b610d9c565b6040516102639190612343565b60405180910390f35b6102866004803603810190610281919061225d565b610db4565b60405161029391906122a5565b60405180910390f35b6102b660048036038101906102b1919061225d565b610ecb565b6040516102c39190612343565b60405180910390f35b6102e660048036038101906102e191906126f2565b610f0d565b6040516102f391906122a5565b60405180910390f35b610316600480360381019061031191906128e3565b6111e2565b6040516103239190612343565b60405180910390f35b610346600480360381019061034191906122c0565b611514565b6040516103539190612343565b60405180910390f35b6103766004803603810190610371919061225d565b6115d0565b604051610383919061264b565b60405180910390f35b6103a660048036038101906103a19190612966565b6117ad565b6040516103b39190612343565b60405180910390f35b6103c46117c7565b6040516103d191906129c8565b60405180910390f35b60008061040933600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff166117eb565b60016004548154811061041f5761041e6129e3565b5b90600052602060002090600802019050600281600101805490501061044357600080fd5b61044e600084610c78565b915050919050565b600080600180856104679190612a41565b81548110610478576104776129e3565b5b9060005260206000209060080201905080600101838154811061049e5761049d6129e3565b5b906000526020600020015491505092915050565b6000600560003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020548214610535576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161052c90612ad2565b60405180910390fd5b61053d610544565b9050919050565b600080600060606000600560003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050600454600660003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205403610658576001600454815481106105ed576105ec6129e3565b5b90600052602060002090600802019350600060028560070160179054906101000a900460ff161660ff1611610657576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161064e90612b3e565b60405180910390fd5b5b6000600560003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506000600660003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555060008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16338260405160240161072c929190612b5e565b6040516020818303038152906040527fa9059cbb000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506040516107b69190612bf8565b6000604051808303816000865af19150503d80600081146107f3576040519150601f19603f3d011682016040523d82523d6000602084013e6107f8565b606091505b50809350819450505082610841576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161083890612c5b565b60405180910390fd5b818060200190518101906108559190612ca7565b925082610897576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161088e90612d20565b60405180910390fd5b8094505050505090565b6108a96120c1565b60006001600454815481106108c1576108c06129e3565b5b90600052602060002090600802019050600060018260070160179054906101000a900460ff161660ff161161092b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161092290612d8c565b60405180910390fd5b8060405180610160016040529081600082015481526020016001820180548060200260200160405190810160405280929190818152602001828054801561099157602002820191906000526020600020905b81548152602001906001019080831161097d575b50505050508152602001600282018054806020026020016040519081016040528092919081815260200182805480156109e957602002820191906000526020600020905b8154815260200190600101908083116109d5575b50505050508152602001600382015481526020016004820154815260200160058201548152602001600682015481526020016007820160009054906101000a900462ffffff1662ffffff1662ffffff1681526020016007820160039054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016007820160179054906101000a900460ff1660ff1660ff1681526020016007820160189054906101000a900460ff1660ff1660ff168152505091505090565b6000806000600160045481548110610aee57610aed6129e3565b5b90600052602060002090600802019150600060028360070160179054906101000a900460ff161660ff1614610b58576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b4f90612df8565b60405180910390fd5b6000610b63836119c4565b03610b7357600092505050610c75565b60028260070160178282829054906101000a900460ff161792506101000a81548160ff021916908360ff160217905550610bac82611c2f565b610be95760088260070160178282829054906101000a900460ff161792506101000a81548160ff021916908360ff16021790555060019050610bea565b5b801515600060808460070160179054906101000a900460ff161660ff161115156001600454610c199190612e18565b7f2d899e808be4b1d81a259d3f56d6d5c829a7cc913a35373a29f6363ebbb2c6c38560050154604051610c4c9190612343565b60405180910390a4600160046000828254610c679190612a41565b925050819055508015925050505b90565b600080610ca733600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff166117eb565b600160045481548110610cbd57610cbc6129e3565b5b90600052602060002090600802019050610cd681611c7a565b610ce4576000915050610d96565b600081600101805490501115610d3e5780600101805490508410610d3d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d3490612e98565b60405180910390fd5b5b610d488184611e0a565b600081600101805490501115610d905782816002018581548110610d6f57610d6e6129e3565b5b906000526020600020016000828254610d889190612a41565b925050819055505b60019150505b92915050565b60056020528060005260406000206000915090505481565b6000806000610de533600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff166117eb565b600160045481548110610dfb57610dfa6129e3565b5b90600052602060002090600802019150610e1482611c7a565b610e2357600092505050610ec6565b610e2d8285611e0a565b83826003016000828254610e419190612a41565b92505081905550620f42408260030154610e5b9190612eb8565b90508160070160009054906101000a900462ffffff1662ffffff16826004015482610e869190612f29565b10610ebf5760406080178260070160178282829054906101000a900460ff161792506101000a81548160ff021916908360ff1602179055505b6001925050505b919050565b60008060018084610edc9190612a41565b81548110610eed57610eec6129e3565b5b906000526020600020906008020190508060010180549050915050919050565b6000806000806000806000806001808b610f279190612a41565b81548110610f3857610f376129e3565b5b90600052602060002090600802019650600060408860070160179054906101000a900460ff161660ff1603610faf574387600601541115610fae576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610fa590612b3e565b60405180910390fd5b5b600060048860070160179054906101000a900460ff161660ff161115610fdf5760009750505050505050506111dc565b600087600101805490500361102e5760048760070160178282829054906101000a900460ff161792506101000a81548160ff021916908360ff16021790555060019750505050505050506111dc565b8660070160189054906101000a900460ff169150866001018054905089836110569190612f5a565b60ff161115611075578187600101805490506110729190612f8f565b98505b81896110819190612f5a565b98508660070160179054906101000a900460ff1690508195505b8860ff168660ff16101561112a57866002018660ff16815481106110c2576110c16129e3565b5b906000526020600020015492506000831180156110de57508383145b156110ee57601081179050611108565b83831115611107578293508560ff169450601019811690505b5b6001826111159190612f5a565b9150858061112290612fc4565b96505061109b565b818760070160186101000a81548160ff021916908360ff160217905550808760070160176101000a81548160ff021916908360ff16021790555086600101805490508760070160189054906101000a900460ff1660ff16106111b75760048760070160178282829054906101000a900460ff161792506101000a81548160ff021916908360ff1602179055505b600060048860070160179054906101000a900460ff161660ff16119750505050505050505b92915050565b60006111ec6120c1565b60008061121b33600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff166117eb565b610100875110611260576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161125790613039565b60405180910390fd5b3383610100019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505087836000018181525050868360200181905250865167ffffffffffffffff8111156112c7576112c6612774565b5b6040519080825280602002602001820160405280156112f55781602001602082028036833780820191505090505b508360400181905250848360e0019062ffffff16908162ffffff168152505085436113209190612a41565b9050808360c00181815250506001805490509150600183610120019060ff16908160ff1681525050600183908060018154018082558091505060019003906000526020600020906008020160009091909190915060008201518160000155602082015181600101908051906020019061139a92919061213f565b5060408201518160020190805190602001906113b792919061218c565b50606082015181600301556080820151816004015560a0820151816005015560c0820151816006015560e08201518160070160006101000a81548162ffffff021916908362ffffff1602179055506101008201518160070160036101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506101208201518160070160176101000a81548160ff021916908360ff1602179055506101408201518160070160186101000a81548160ff021916908360ff16021790555050506114bd600183815481106114aa576114a96129e3565b5b90600052602060002090600802016119c4565b8360800181815250506001826114d39190612e18565b8562ffffff16827f5a41400aa51d78e9e5ca645b0d045817eaa7d90e4344d773fdbe24ffb183d3ce60405160405180910390a4819350505050949350505050565b600080600180856115259190612a41565b81548110611536576115356129e3565b5b9060005260206000209060080201905060008160010180549050036115a55760008314611598576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161158f906130a5565b60405180910390fd5b80600501549150506115ca565b8060020183815481106115bb576115ba6129e3565b5b90600052602060002001549150505b92915050565b6115d86120c1565b600180836115e69190612a41565b815481106115f7576115f66129e3565b5b906000526020600020906008020160405180610160016040529081600082015481526020016001820180548060200260200160405190810160405280929190818152602001828054801561166a57602002820191906000526020600020905b815481526020019060010190808311611656575b50505050508152602001600282018054806020026020016040519081016040528092919081815260200182805480156116c257602002820191906000526020600020905b8154815260200190600101908083116116ae575b50505050508152602001600382015481526020016004820154815260200160058201548152602001600682015481526020016007820160009054906101000a900462ffffff1662ffffff1662ffffff1681526020016007820160039054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016007820160179054906101000a900460ff1660ff1660ff1681526020016007820160189054906101000a900460ff1660ff1660ff16815250509050919050565b600060606117bd858286866111e2565b9150509392505050565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60006060600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff160361182a5750506119c0565b8273ffffffffffffffffffffffffffffffffffffffff168460405160240161185291906129c8565b6040516020818303038152906040527f3ef25013000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506040516118dc9190612bf8565b6000604051808303816000865af19150503d8060008114611919576040519150601f19603f3d011682016040523d82523d6000602084013e61191e565b606091505b50809250819350505081611967576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161195e90613111565b60405180910390fd5b8080602001905181019061197b9190612ca7565b9150816119bd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016119b49061317d565b60405180910390fd5b50505b5050565b600080606060008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166040516024016040516020818303038152906040527f18160ddd000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050604051611a939190612bf8565b6000604051808303816000865af19150503d8060008114611ad0576040519150601f19603f3d011682016040523d82523d6000602084013e611ad5565b606091505b50809350819450505082611b1e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611b1590612c5b565b60405180910390fd5b81806020019051810190611b3291906131b2565b905060008111611b77576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611b6e9061322b565b60405180910390fd5b6000856004015403611b9157808560040181905550611c23565b84600401548114611c225760208560070160178282829054906101000a900460ff161792506101000a81548160ff021916908360ff16021790555060028560070160178282829054906101000a900460ff161792506101000a81548160ff021916908360ff160217905550600160046000828254611c0f9190612a41565b9250508190555060009350505050611c2a565b5b8093505050505b919050565b600080620f42408360050154611c459190612eb8565b90508260070160009054906101000a900462ffffff1662ffffff16836004015482611c709190612f29565b1015915050919050565b60008060018360070160179054906101000a900460ff161660ff1611611cd5576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611ccc90613297565b60405180910390fd5b6000611ce0836119c4565b03611cee5760009050611e05565b43826006015411611d34576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611d2b90613303565b60405180910390fd5b6000600660003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541115611e0057600454600660003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205414611dff576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611df69061336f565b60405180910390fd5b5b600190505b919050565b6000606060008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16333085604051602401611e5a939291906133ee565b6040516020818303038152906040527f23b872dd000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050604051611ee49190612bf8565b6000604051808303816000865af19150503d8060008114611f21576040519150601f19603f3d011682016040523d82523d6000602084013e611f26565b606091505b50809250819350505081611f6f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611f6690612c5b565b60405180910390fd5b80806020019051810190611f839190612ca7565b915081611fc5576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611fbc90612d20565b60405180910390fd5b600454600660003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555082600560003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825461205a9190612a41565b92505081905550828460050160008282546120759190612a41565b9250508190555061208584611c2f565b156120bb5760408460070160178282829054906101000a900460ff161792506101000a81548160ff021916908360ff1602179055505b50505050565b60405180610160016040528060008019168152602001606081526020016060815260200160008152602001600081526020016000815260200160008152602001600062ffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600060ff168152602001600060ff1681525090565b82805482825590600052602060002090810192821561217b579160200282015b8281111561217a57825182559160200191906001019061215f565b5b50905061218891906121d9565b5090565b8280548282559060005260206000209081019282156121c8579160200282015b828111156121c75782518255916020019190600101906121ac565b5b5090506121d591906121f6565b5090565b5b808211156121f25760008160009055506001016121da565b5090565b5b8082111561220f5760008160009055506001016121f7565b5090565b6000604051905090565b600080fd5b600080fd5b6000819050919050565b61223a81612227565b811461224557600080fd5b50565b60008135905061225781612231565b92915050565b6000602082840312156122735761227261221d565b5b600061228184828501612248565b91505092915050565b60008115159050919050565b61229f8161228a565b82525050565b60006020820190506122ba6000830184612296565b92915050565b600080604083850312156122d7576122d661221d565b5b60006122e585828601612248565b92505060206122f685828601612248565b9150509250929050565b6000819050919050565b61231381612300565b82525050565b600060208201905061232e600083018461230a565b92915050565b61233d81612227565b82525050565b60006020820190506123586000830184612334565b92915050565b61236781612300565b82525050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b60006123a5838361235e565b60208301905092915050565b6000602082019050919050565b60006123c98261236d565b6123d38185612378565b93506123de83612389565b8060005b8381101561240f5781516123f68882612399565b9750612401836123b1565b9250506001810190506123e2565b5085935050505092915050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b61245181612227565b82525050565b60006124638383612448565b60208301905092915050565b6000602082019050919050565b60006124878261241c565b6124918185612427565b935061249c83612438565b8060005b838110156124cd5781516124b48882612457565b97506124bf8361246f565b9250506001810190506124a0565b5085935050505092915050565b600062ffffff82169050919050565b6124f2816124da565b82525050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000612523826124f8565b9050919050565b61253381612518565b82525050565b600060ff82169050919050565b61254f81612539565b82525050565b60006101608301600083015161256e600086018261235e565b506020830151848203602086015261258682826123be565b915050604083015184820360408601526125a0828261247c565b91505060608301516125b56060860182612448565b5060808301516125c86080860182612448565b5060a08301516125db60a0860182612448565b5060c08301516125ee60c0860182612448565b5060e083015161260160e08601826124e9565b5061010083015161261661010086018261252a565b5061012083015161262b610120860182612546565b50610140830151612640610140860182612546565b508091505092915050565b600060208201905081810360008301526126658184612555565b905092915050565b61267681612518565b811461268157600080fd5b50565b6000813590506126938161266d565b92915050565b6000602082840312156126af576126ae61221d565b5b60006126bd84828501612684565b91505092915050565b6126cf81612539565b81146126da57600080fd5b50565b6000813590506126ec816126c6565b92915050565b600080604083850312156127095761270861221d565b5b600061271785828601612248565b9250506020612728858286016126dd565b9150509250929050565b61273b81612300565b811461274657600080fd5b50565b60008135905061275881612732565b92915050565b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6127ac82612763565b810181811067ffffffffffffffff821117156127cb576127ca612774565b5b80604052505050565b60006127de612213565b90506127ea82826127a3565b919050565b600067ffffffffffffffff82111561280a57612809612774565b5b602082029050602081019050919050565b600080fd5b600061283361282e846127ef565b6127d4565b905080838252602082019050602084028301858111156128565761285561281b565b5b835b8181101561287f578061286b8882612749565b845260208401935050602081019050612858565b5050509392505050565b600082601f83011261289e5761289d61275e565b5b81356128ae848260208601612820565b91505092915050565b6128c0816124da565b81146128cb57600080fd5b50565b6000813590506128dd816128b7565b92915050565b600080600080608085870312156128fd576128fc61221d565b5b600061290b87828801612749565b945050602085013567ffffffffffffffff81111561292c5761292b612222565b5b61293887828801612889565b935050604061294987828801612248565b925050606061295a878288016128ce565b91505092959194509250565b60008060006060848603121561297f5761297e61221d565b5b600061298d86828701612749565b935050602061299e86828701612248565b92505060406129af868287016128ce565b9150509250925092565b6129c281612518565b82525050565b60006020820190506129dd60008301846129b9565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000612a4c82612227565b9150612a5783612227565b9250828201905080821115612a6f57612a6e612a12565b5b92915050565b600082825260208201905092915050565b7f4552525f4d5553545f57495448445241575f414c4c0000000000000000000000600082015250565b6000612abc601583612a75565b9150612ac782612a86565b602082019050919050565b60006020820190508181036000830152612aeb81612aaf565b9050919050565b7f4552525f5052454d415455524500000000000000000000000000000000000000600082015250565b6000612b28600d83612a75565b9150612b3382612af2565b602082019050919050565b60006020820190508181036000830152612b5781612b1b565b9050919050565b6000604082019050612b7360008301856129b9565b612b806020830184612334565b9392505050565b600081519050919050565b600081905092915050565b60005b83811015612bbb578082015181840152602081019050612ba0565b60008484015250505050565b6000612bd282612b87565b612bdc8185612b92565b9350612bec818560208601612b9d565b80840191505092915050565b6000612c048284612bc7565b915081905092915050565b7f4552525f544f4b454e0000000000000000000000000000000000000000000000600082015250565b6000612c45600983612a75565b9150612c5082612c0f565b602082019050919050565b60006020820190508181036000830152612c7481612c38565b9050919050565b612c848161228a565b8114612c8f57600080fd5b50565b600081519050612ca181612c7b565b92915050565b600060208284031215612cbd57612cbc61221d565b5b6000612ccb84828501612c92565b91505092915050565b7f4552525f5452414e534645520000000000000000000000000000000000000000600082015250565b6000612d0a600c83612a75565b9150612d1582612cd4565b602082019050919050565b60006020820190508181036000830152612d3981612cfd565b9050919050565b7f4552525f4e4f5f43555252454e545f50524f504f53414c000000000000000000600082015250565b6000612d76601783612a75565b9150612d8182612d40565b602082019050919050565b60006020820190508181036000830152612da581612d69565b9050919050565b7f4552525f414c52454144595f53544154455f46494e414c000000000000000000600082015250565b6000612de2601783612a75565b9150612ded82612dac565b602082019050919050565b60006020820190508181036000830152612e1181612dd5565b9050919050565b6000612e2382612227565b9150612e2e83612227565b9250828203905081811115612e4657612e45612a12565b5b92915050565b7f4552525f4f5054494f4e5f494e56414c49440000000000000000000000000000600082015250565b6000612e82601283612a75565b9150612e8d82612e4c565b602082019050919050565b60006020820190508181036000830152612eb181612e75565b9050919050565b6000612ec382612227565b9150612ece83612227565b9250828202612edc81612227565b91508282048414831517612ef357612ef2612a12565b5b5092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000612f3482612227565b9150612f3f83612227565b925082612f4f57612f4e612efa565b5b828204905092915050565b6000612f6582612539565b9150612f7083612539565b9250828201905060ff811115612f8957612f88612a12565b5b92915050565b6000612f9a82612539565b9150612fa583612539565b9250828203905060ff811115612fbe57612fbd612a12565b5b92915050565b6000612fcf82612539565b915060ff8203612fe257612fe1612a12565b5b600182019050919050565b7f4552525f544f4f5f4d414e595f4f5054494f4e53000000000000000000000000600082015250565b6000613023601483612a75565b915061302e82612fed565b602082019050919050565b6000602082019050818103600083015261305281613016565b9050919050565b7f4552525f4e4f5f4f5054494f4e53000000000000000000000000000000000000600082015250565b600061308f600e83612a75565b915061309a82613059565b602082019050919050565b600060208201905081810360008301526130be81613082565b9050919050565b7f4552525f52454749535452590000000000000000000000000000000000000000600082015250565b60006130fb600c83612a75565b9150613106826130c5565b602082019050919050565b6000602082019050818103600083015261312a816130ee565b9050919050565b7f4552525f554e415554485f4143434f554e540000000000000000000000000000600082015250565b6000613167601283612a75565b915061317282613131565b602082019050919050565b600060208201905081810360008301526131968161315a565b9050919050565b6000815190506131ac81612231565b92915050565b6000602082840312156131c8576131c761221d565b5b60006131d68482850161319d565b91505092915050565b7f4552525f5a45524f5f535550504c590000000000000000000000000000000000600082015250565b6000613215600f83612a75565b9150613220826131df565b602082019050919050565b6000602082019050818103600083015261324481613208565b9050919050565b7f4552525f50524f504f53414c5f494e4143544956450000000000000000000000600082015250565b6000613281601583612a75565b915061328c8261324b565b602082019050919050565b600060208201905081810360008301526132b081613274565b9050919050565b7f4552525f444541444c494e450000000000000000000000000000000000000000600082015250565b60006132ed600c83612a75565b91506132f8826132b7565b602082019050919050565b6000602082019050818103600083015261331c816132e0565b9050919050565b7f4552525f57495448445241575f46495253540000000000000000000000000000600082015250565b6000613359601283612a75565b915061336482613323565b602082019050919050565b600060208201905081810360008301526133888161334c565b9050919050565b6000819050919050565b60006133b46133af6133aa846124f8565b61338f565b6124f8565b9050919050565b60006133c682613399565b9050919050565b60006133d8826133bb565b9050919050565b6133e8816133cd565b82525050565b600060608201905061340360008301866129b9565b61341060208301856133df565b61341d6040830184612334565b94935050505056fea2646970667358221220404b6dba1e7886412f41bdc047a6bf6c4754d19eb0b17541fb904266d1eff25264736f6c63430008130033
+\ No newline at end of file
diff --git a/python/evm_tokenvote/data/Voter.json b/python/evm_tokenvote/data/Voter.json
@@ -1 +1 @@
-[{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_accountsRegistry","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_blockDeadline","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"voteTargetPpm","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"_proposalIdx","type":"uint256"}],"name":"ProposalAdded","type":"event"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"finalize","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getCurrentProposal","outputs":[{"components":[{"internalType":"bytes32","name":"description","type":"bytes32"},{"internalType":"bytes32[]","name":"options","type":"bytes32[]"},{"internalType":"uint256[]","name":"optionVotes","type":"uint256[]"},{"internalType":"uint256","name":"supply","type":"uint256"},{"internalType":"uint256","name":"total","type":"uint256"},{"internalType":"uint256","name":"blockDeadline","type":"uint256"},{"internalType":"uint24","name":"targetVotePpm","type":"uint24"},{"internalType":"address","name":"proposer","type":"address"},{"internalType":"uint8","name":"state","type":"uint8"},{"internalType":"uint8","name":"scanCursor","type":"uint8"}],"internalType":"struct ERC20Vote.Proposal","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_proposalIdx","type":"uint256"},{"internalType":"uint256","name":"_optionIdx","type":"uint256"}],"name":"getOption","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_proposalIdx","type":"uint256"}],"name":"getProposal","outputs":[{"components":[{"internalType":"bytes32","name":"description","type":"bytes32"},{"internalType":"bytes32[]","name":"options","type":"bytes32[]"},{"internalType":"uint256[]","name":"optionVotes","type":"uint256[]"},{"internalType":"uint256","name":"supply","type":"uint256"},{"internalType":"uint256","name":"total","type":"uint256"},{"internalType":"uint256","name":"blockDeadline","type":"uint256"},{"internalType":"uint24","name":"targetVotePpm","type":"uint24"},{"internalType":"address","name":"proposer","type":"address"},{"internalType":"uint8","name":"state","type":"uint8"},{"internalType":"uint8","name":"scanCursor","type":"uint8"}],"internalType":"struct ERC20Vote.Proposal","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_proposalIdx","type":"uint256"}],"name":"optionCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_description","type":"bytes32"},{"internalType":"uint256","name":"_blockWait","type":"uint256"},{"internalType":"uint24","name":"_targetVotePpm","type":"uint24"}],"name":"propose","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_description","type":"bytes32"},{"internalType":"bytes32[]","name":"_options","type":"bytes32[]"},{"internalType":"uint256","name":"_blockWait","type":"uint256"},{"internalType":"uint24","name":"_targetVotePpm","type":"uint24"}],"name":"proposeMulti","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_proposalIndex","type":"uint256"},{"internalType":"uint8","name":"_count","type":"uint8"}],"name":"scan","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"token","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"vote","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_proposalIdx","type":"uint256"},{"internalType":"uint256","name":"_optionIdx","type":"uint256"}],"name":"voteCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_optionIndex","type":"uint256"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"voteOption","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"}]
+[{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_voterRegistry","type":"address"},{"internalType":"address","name":"_proposerRegistry","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_blockDeadline","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"voteTargetPpm","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"_proposalIdx","type":"uint256"}],"name":"ProposalAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_proposalIdx","type":"uint256"},{"indexed":true,"internalType":"bool","name":"_cancelled","type":"bool"},{"indexed":true,"internalType":"bool","name":"_insufficient","type":"bool"},{"indexed":false,"internalType":"uint256","name":"_totalVote","type":"uint256"}],"name":"ProposalCompleted","type":"event"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"finalize","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getCurrentProposal","outputs":[{"components":[{"internalType":"bytes32","name":"description","type":"bytes32"},{"internalType":"bytes32[]","name":"options","type":"bytes32[]"},{"internalType":"uint256[]","name":"optionVotes","type":"uint256[]"},{"internalType":"uint256","name":"cancelVotes","type":"uint256"},{"internalType":"uint256","name":"supply","type":"uint256"},{"internalType":"uint256","name":"total","type":"uint256"},{"internalType":"uint256","name":"blockDeadline","type":"uint256"},{"internalType":"uint24","name":"targetVotePpm","type":"uint24"},{"internalType":"address","name":"proposer","type":"address"},{"internalType":"uint8","name":"state","type":"uint8"},{"internalType":"uint8","name":"scanCursor","type":"uint8"}],"internalType":"struct ERC20Vote.Proposal","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_proposalIdx","type":"uint256"},{"internalType":"uint256","name":"_optionIdx","type":"uint256"}],"name":"getOption","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_proposalIdx","type":"uint256"}],"name":"getProposal","outputs":[{"components":[{"internalType":"bytes32","name":"description","type":"bytes32"},{"internalType":"bytes32[]","name":"options","type":"bytes32[]"},{"internalType":"uint256[]","name":"optionVotes","type":"uint256[]"},{"internalType":"uint256","name":"cancelVotes","type":"uint256"},{"internalType":"uint256","name":"supply","type":"uint256"},{"internalType":"uint256","name":"total","type":"uint256"},{"internalType":"uint256","name":"blockDeadline","type":"uint256"},{"internalType":"uint24","name":"targetVotePpm","type":"uint24"},{"internalType":"address","name":"proposer","type":"address"},{"internalType":"uint8","name":"state","type":"uint8"},{"internalType":"uint8","name":"scanCursor","type":"uint8"}],"internalType":"struct ERC20Vote.Proposal","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_proposalIdx","type":"uint256"}],"name":"optionCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_description","type":"bytes32"},{"internalType":"uint256","name":"_blockWait","type":"uint256"},{"internalType":"uint24","name":"_targetVotePpm","type":"uint24"}],"name":"propose","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_description","type":"bytes32"},{"internalType":"bytes32[]","name":"_options","type":"bytes32[]"},{"internalType":"uint256","name":"_blockWait","type":"uint256"},{"internalType":"uint24","name":"_targetVotePpm","type":"uint24"}],"name":"proposeMulti","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_proposalIndex","type":"uint256"},{"internalType":"uint8","name":"_count","type":"uint8"}],"name":"scan","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"token","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"vote","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"voteCancel","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_proposalIdx","type":"uint256"},{"internalType":"uint256","name":"_optionIdx","type":"uint256"}],"name":"voteCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_optionIndex","type":"uint256"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"voteOption","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"withdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"}]
diff --git a/python/evm_tokenvote/data/Voter.metadata.json b/python/evm_tokenvote/data/Voter.metadata.json
@@ -1 +1 @@
-{"compiler":{"version":"0.8.19+commit.7dd6d404"},"language":"Solidity","output":{"abi":[{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_accountsRegistry","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_blockDeadline","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"voteTargetPpm","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"_proposalIdx","type":"uint256"}],"name":"ProposalAdded","type":"event"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"finalize","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getCurrentProposal","outputs":[{"components":[{"internalType":"bytes32","name":"description","type":"bytes32"},{"internalType":"bytes32[]","name":"options","type":"bytes32[]"},{"internalType":"uint256[]","name":"optionVotes","type":"uint256[]"},{"internalType":"uint256","name":"supply","type":"uint256"},{"internalType":"uint256","name":"total","type":"uint256"},{"internalType":"uint256","name":"blockDeadline","type":"uint256"},{"internalType":"uint24","name":"targetVotePpm","type":"uint24"},{"internalType":"address","name":"proposer","type":"address"},{"internalType":"uint8","name":"state","type":"uint8"},{"internalType":"uint8","name":"scanCursor","type":"uint8"}],"internalType":"struct ERC20Vote.Proposal","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_proposalIdx","type":"uint256"},{"internalType":"uint256","name":"_optionIdx","type":"uint256"}],"name":"getOption","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_proposalIdx","type":"uint256"}],"name":"getProposal","outputs":[{"components":[{"internalType":"bytes32","name":"description","type":"bytes32"},{"internalType":"bytes32[]","name":"options","type":"bytes32[]"},{"internalType":"uint256[]","name":"optionVotes","type":"uint256[]"},{"internalType":"uint256","name":"supply","type":"uint256"},{"internalType":"uint256","name":"total","type":"uint256"},{"internalType":"uint256","name":"blockDeadline","type":"uint256"},{"internalType":"uint24","name":"targetVotePpm","type":"uint24"},{"internalType":"address","name":"proposer","type":"address"},{"internalType":"uint8","name":"state","type":"uint8"},{"internalType":"uint8","name":"scanCursor","type":"uint8"}],"internalType":"struct ERC20Vote.Proposal","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_proposalIdx","type":"uint256"}],"name":"optionCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_description","type":"bytes32"},{"internalType":"uint256","name":"_blockWait","type":"uint256"},{"internalType":"uint24","name":"_targetVotePpm","type":"uint24"}],"name":"propose","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_description","type":"bytes32"},{"internalType":"bytes32[]","name":"_options","type":"bytes32[]"},{"internalType":"uint256","name":"_blockWait","type":"uint256"},{"internalType":"uint24","name":"_targetVotePpm","type":"uint24"}],"name":"proposeMulti","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_proposalIndex","type":"uint256"},{"internalType":"uint8","name":"_count","type":"uint8"}],"name":"scan","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"token","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"vote","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_proposalIdx","type":"uint256"},{"internalType":"uint256","name":"_optionIdx","type":"uint256"}],"name":"voteCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_optionIndex","type":"uint256"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"voteOption","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"}],"devdoc":{"kind":"dev","methods":{},"version":1},"userdoc":{"kind":"user","methods":{},"version":1}},"settings":{"compilationTarget":{"Voter.sol":"ERC20Vote"},"evmVersion":"byzantium","libraries":{},"metadata":{"bytecodeHash":"ipfs"},"optimizer":{"enabled":false,"runs":200},"remappings":[]},"sources":{"Voter.sol":{"keccak256":"0xb9caa4e34413aafaab82a8d14bc9a8960765a71d5fc7cdc10ea39fb52ed2a2c2","license":"AGPL-3.0-or-later","urls":["bzz-raw://83f759873e36a24f455c883d13bd3626d111a164e727220debace5b9da9b4cb8","dweb:/ipfs/QmNxDUpyYgHtJb6vs6Ntv15WKFbXQ5JRomyzWZKNvseeTY"]}},"version":1}
+{"compiler":{"version":"0.8.19+commit.7dd6d404"},"language":"Solidity","output":{"abi":[{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_voterRegistry","type":"address"},{"internalType":"address","name":"_proposerRegistry","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_blockDeadline","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"voteTargetPpm","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"_proposalIdx","type":"uint256"}],"name":"ProposalAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_proposalIdx","type":"uint256"},{"indexed":true,"internalType":"bool","name":"_cancelled","type":"bool"},{"indexed":true,"internalType":"bool","name":"_insufficient","type":"bool"},{"indexed":false,"internalType":"uint256","name":"_totalVote","type":"uint256"}],"name":"ProposalCompleted","type":"event"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"finalize","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getCurrentProposal","outputs":[{"components":[{"internalType":"bytes32","name":"description","type":"bytes32"},{"internalType":"bytes32[]","name":"options","type":"bytes32[]"},{"internalType":"uint256[]","name":"optionVotes","type":"uint256[]"},{"internalType":"uint256","name":"cancelVotes","type":"uint256"},{"internalType":"uint256","name":"supply","type":"uint256"},{"internalType":"uint256","name":"total","type":"uint256"},{"internalType":"uint256","name":"blockDeadline","type":"uint256"},{"internalType":"uint24","name":"targetVotePpm","type":"uint24"},{"internalType":"address","name":"proposer","type":"address"},{"internalType":"uint8","name":"state","type":"uint8"},{"internalType":"uint8","name":"scanCursor","type":"uint8"}],"internalType":"struct ERC20Vote.Proposal","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_proposalIdx","type":"uint256"},{"internalType":"uint256","name":"_optionIdx","type":"uint256"}],"name":"getOption","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_proposalIdx","type":"uint256"}],"name":"getProposal","outputs":[{"components":[{"internalType":"bytes32","name":"description","type":"bytes32"},{"internalType":"bytes32[]","name":"options","type":"bytes32[]"},{"internalType":"uint256[]","name":"optionVotes","type":"uint256[]"},{"internalType":"uint256","name":"cancelVotes","type":"uint256"},{"internalType":"uint256","name":"supply","type":"uint256"},{"internalType":"uint256","name":"total","type":"uint256"},{"internalType":"uint256","name":"blockDeadline","type":"uint256"},{"internalType":"uint24","name":"targetVotePpm","type":"uint24"},{"internalType":"address","name":"proposer","type":"address"},{"internalType":"uint8","name":"state","type":"uint8"},{"internalType":"uint8","name":"scanCursor","type":"uint8"}],"internalType":"struct ERC20Vote.Proposal","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_proposalIdx","type":"uint256"}],"name":"optionCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_description","type":"bytes32"},{"internalType":"uint256","name":"_blockWait","type":"uint256"},{"internalType":"uint24","name":"_targetVotePpm","type":"uint24"}],"name":"propose","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_description","type":"bytes32"},{"internalType":"bytes32[]","name":"_options","type":"bytes32[]"},{"internalType":"uint256","name":"_blockWait","type":"uint256"},{"internalType":"uint24","name":"_targetVotePpm","type":"uint24"}],"name":"proposeMulti","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_proposalIndex","type":"uint256"},{"internalType":"uint8","name":"_count","type":"uint8"}],"name":"scan","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"token","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"vote","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"voteCancel","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_proposalIdx","type":"uint256"},{"internalType":"uint256","name":"_optionIdx","type":"uint256"}],"name":"voteCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_optionIndex","type":"uint256"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"voteOption","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"withdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"}],"devdoc":{"kind":"dev","methods":{},"version":1},"userdoc":{"kind":"user","methods":{},"version":1}},"settings":{"compilationTarget":{"Voter.sol":"ERC20Vote"},"evmVersion":"byzantium","libraries":{},"metadata":{"bytecodeHash":"ipfs"},"optimizer":{"enabled":false,"runs":200},"remappings":[]},"sources":{"Voter.sol":{"keccak256":"0xf65cf2af03b63a8e215dbc5ebc77f5750ba634c7c99f015cb1a1e46b7ec02047","license":"AGPL-3.0-or-later","urls":["bzz-raw://d113abcfa639a671e9870dc517900e8faa26e3075f72597a6488b49bf7271c59","dweb:/ipfs/QmRzp6MDLeem3WFdzVZjAwojqabGWPoJPdBWuM8oo5CGxj"]}},"version":1}
diff --git a/python/evm_tokenvote/unittest/base.py b/python/evm_tokenvote/unittest/base.py
@@ -97,7 +97,7 @@ class TestEvmVoteRegistry(TestEvmVoteAccounts):
o = receipt(tx_hash)
r = self.rpc.do(o)
self.registry_address = r['contract_address']
- logg.debug('published with accounts registry contract address {}'.format(r['contract_address']))
+ logg.debug('published with accounts registry (voter) contract address {}'.format(r['contract_address']))
(tx_hash, o) = c.add_writer(self.registry_address, self.accounts[0], self.accounts[0])
self.conn.do(o)
@@ -105,8 +105,21 @@ class TestEvmVoteRegistry(TestEvmVoteAccounts):
r = self.rpc.do(o)
self.assertEqual(r['status'], 1)
+ (tx_hash, o) = c.constructor(self.accounts[0])
+ self.conn.do(o)
+ o = receipt(tx_hash)
+ r = self.rpc.do(o)
+ self.proposer_registry_address = r['contract_address']
+ logg.debug('published with accounts registry (proposer) contract address {}'.format(r['contract_address']))
+
+ (tx_hash, o) = c.add_writer(self.proposer_registry_address, self.accounts[0], self.accounts[0])
+ self.conn.do(o)
+ o = receipt(tx_hash)
+ r = self.rpc.do(o)
+ self.assertEqual(r['status'], 1)
+
c = Voter(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
- (tx_hash, o) = c.constructor(self.accounts[0], self.token_address, accounts_registry_address=self.registry_address)
+ (tx_hash, o) = c.constructor(self.accounts[0], self.token_address, voter_registry_address=self.registry_address, proposer_registry_address=self.proposer_registry_address)
self.rpc.do(o)
o = receipt(tx_hash)
r = self.rpc.do(o)
diff --git a/python/evm_tokenvote/voter.py b/python/evm_tokenvote/voter.py
@@ -37,6 +37,8 @@ class ProposalState(enum.IntEnum):
INSUFFICIENT = 8
TIED = 16
SUPPLYCHANGE = 32
+ IMMEDIATE = 64
+ CANCELLED = 128
class Proposal:
@@ -47,6 +49,7 @@ class Proposal:
self.total = kwargs.get('total')
self.block_deadline = kwargs.get('block_deadline')
self.target_vote_ppm = kwargs.get('target_vote_ppm')
+ self.cancel_votes = kwargs.get('cancel_votes')
self.proposer = kwargs.get('proposer')
self.state = kwargs.get('state')
self.serial = kwargs.get('serial')
@@ -61,23 +64,26 @@ class Voter(TxFactory):
__abi = None
__bytecode = None
- def constructor(self, sender_address, token_address, accounts_registry_address=None, tx_format=TxFormat.JSONRPC, version=None):
- code = self.cargs(token_address, accounts_registry_address=accounts_registry_address)
+ def constructor(self, sender_address, token_address, voter_registry_address=None, proposer_registry_address=None, tx_format=TxFormat.JSONRPC, version=None):
+ code = self.cargs(token_address, voter_registry_address=voter_registry_address, proposer_registry_address=proposer_registry_address)
tx = self.template(sender_address, None, use_nonce=True)
tx = self.set_code(tx, code)
return self.finalize(tx, tx_format)
@staticmethod
- def cargs(token_address, accounts_registry_address=None, version=None):
- if accounts_registry_address == None:
- accounts_registry_address = ZERO_ADDRESS
+ def cargs(token_address, voter_registry_address=None, proposer_registry_address=None, version=None):
+ if voter_registry_address == None:
+ voter_registry_address = ZERO_ADDRESS
+ if proposer_registry_address == None:
+ proposer_registry_address = ZERO_ADDRESS
if token_address == None:
raise ValueError("token address cannot be zero address")
code = Voter.bytecode(version=version)
enc = ABIContractEncoder()
enc.address(token_address)
- enc.address(accounts_registry_address)
+ enc.address(voter_registry_address)
+ enc.address(proposer_registry_address)
args = enc.get()
code += args
logg.debug('constructor code: ' + args)
@@ -155,6 +161,18 @@ class Voter(TxFactory):
return tx
+ def vote_cancel(self, contract_address, sender_address, value, tx_format=TxFormat.JSONRPC, id_generator=None):
+ enc = ABIContractEncoder()
+ enc.method('voteCancel')
+ enc.typ(ABIContractType.UINT256)
+ enc.uint256(value)
+ data = add_0x(enc.get())
+ tx = self.template(sender_address, contract_address, use_nonce=True)
+ tx = self.set_code(tx, data)
+ tx = self.finalize(tx, tx_format, id_generator=id_generator)
+ return tx
+
+
def scan(self, contract_address, sender_address, proposal_index, count, tx_format=TxFormat.JSONRPC, id_generator=None):
enc = ABIContractEncoder()
enc.method('scan')
@@ -289,6 +307,7 @@ class Voter(TxFactory):
dec.typ(ABIContractType.UINT256)
dec.typ(ABIContractType.UINT256)
dec.typ(ABIContractType.UINT256)
+ dec.typ(ABIContractType.UINT256)
dec.typ(ABIContractType.UINT256) # actually uint24
dec.typ(ABIContractType.ADDRESS)
dec.typ(ABIContractType.UINT8)
@@ -309,15 +328,18 @@ class Voter(TxFactory):
cursor += 64
dec.val(v[cursor:cursor+64])
cursor += 64
+ dec.val(v[cursor:cursor+64])
+ cursor += 64
r = dec.get()
o = Proposal(r[0],
- supply=r[1],
- total=r[2],
- block_deadline=r[3],
- target_vote_ppm=r[4],
- proposer=r[5],
- state=r[6],
+ cancelVotes=r[1],
+ supply=r[2],
+ total=r[3],
+ block_deadline=r[4],
+ target_vote_ppm=r[5],
+ proposer=r[6],
+ state=r[7],
serial=serial,
)
return o
diff --git a/python/test_requirements.txt b/python/test_requirements.txt
@@ -1,4 +1,4 @@
eth_tester==0.5.0b3
py-evm==0.3.0a20
eth-interface==0.1.1
-eth-accounts-index~=0.5.2
+eth-accounts-index~=0.5.3
diff --git a/python/tests/test_base.py b/python/tests/test_base.py
@@ -126,9 +126,10 @@ class TestVoteBase(TestEvmVoteProposal):
self.rpc.do(o)
c = Voter(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
- (tx_hash, o) = c.vote(self.voter_address, self.alice, half_supply)
+ (tx_hash, o) = c.vote(self.voter_address, self.alice, half_supply - 1)
self.rpc.do(o)
+ # no majority and deadline not reached
nonce_oracle = RPCNonceOracle(self.trent, conn=self.conn)
c = Voter(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
(tx_hash, o) = c.scan(self.voter_address, self.trent, 0, 0)
@@ -137,15 +138,24 @@ class TestVoteBase(TestEvmVoteProposal):
r = self.rpc.do(o)
self.assertEqual(r['status'], 0)
- o = block_latest()
- now_block_height = self.rpc.do(o)
- need_blocks = self.proposal_block_height + 100 - now_block_height + 1
- self.backend.mine_blocks(need_blocks)
+ nonce_oracle = RPCNonceOracle(self.alice, conn=self.conn)
+ c = Voter(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
+ (tx_hash, o) = c.vote(self.voter_address, self.alice, 1)
+ self.rpc.do(o)
+
+ # majority, don't care about deadline
+ nonce_oracle = RPCNonceOracle(self.trent, conn=self.conn)
+ c = Voter(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
+ (tx_hash, o) = c.scan(self.voter_address, self.trent, 0, 0)
+ self.rpc.do(o)
+ o = receipt(tx_hash)
+ r = self.rpc.do(o)
+ self.assertEqual(r['status'], 1)
o = c.get_proposal(self.voter_address, 0, sender_address=self.accounts[0])
r = self.rpc.do(o)
proposal = c.parse_proposal(r)
- self.assertEqual(proposal.state, ProposalState.INIT)
+ self.assertEqual(proposal.state & ProposalState.INIT, ProposalState.INIT)
c = Voter(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
(tx_hash, o) = c.scan(self.voter_address, self.trent, 0, 0)
@@ -158,6 +168,7 @@ class TestVoteBase(TestEvmVoteProposal):
r = self.rpc.do(o)
proposal = c.parse_proposal(r)
self.assertEqual(proposal.state & ProposalState.SCANNED, ProposalState.SCANNED)
+ self.assertEqual(proposal.state & ProposalState.IMMEDIATE, ProposalState.IMMEDIATE)
(tx_hash, o) = c.finalize_vote(self.voter_address, self.trent)
self.rpc.do(o)
diff --git a/python/tests/test_cancel.py b/python/tests/test_cancel.py
@@ -0,0 +1,76 @@
+# standard imports
+import unittest
+import logging
+import os
+from chainlib.eth.nonce import RPCNonceOracle
+from chainlib.eth.tx import receipt
+from chainlib.eth.block import block_latest
+from hexathon import same as same_hex
+from eth_erc20 import ERC20
+from giftable_erc20_token import GiftableToken
+
+# local imports
+from evm_tokenvote.unittest import TestEvmVoteProposal
+from evm_tokenvote.unittest.base import hash_of_foo
+from evm_tokenvote import Voter
+from evm_tokenvote import ProposalState
+
+
+logging.basicConfig(level=logging.DEBUG)
+logg = logging.getLogger()
+
+class TestVoteBase(TestEvmVoteProposal):
+
+ def test_cancel(self):
+ half_supply = int(self.initial_supply / 2)
+ nonce_oracle = RPCNonceOracle(self.accounts[0], conn=self.conn)
+ c = ERC20(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
+ (tx_hash, o) = c.transfer(self.address, self.accounts[0], self.alice, half_supply)
+ self.rpc.do(o)
+
+ nonce_oracle = RPCNonceOracle(self.alice, conn=self.conn)
+ c = ERC20(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
+ (tx_hash, o) = c.approve(self.address, self.alice, self.voter_address, half_supply)
+ self.rpc.do(o)
+
+ c = Voter(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
+ (tx_hash, o) = c.vote_cancel(self.voter_address, self.alice, half_supply - 1)
+ self.rpc.do(o)
+ o = receipt(tx_hash)
+ r = self.rpc.do(o)
+ self.assertEqual(r['status'], 1)
+
+ nonce_oracle = RPCNonceOracle(self.trent, conn=self.conn)
+ c = Voter(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
+ (tx_hash, o) = c.scan(self.voter_address, self.trent, 0, 0)
+ self.rpc.do(o)
+ o = receipt(tx_hash)
+ r = self.rpc.do(o)
+ self.assertEqual(r['status'], 0)
+
+ nonce_oracle = RPCNonceOracle(self.alice, conn=self.conn)
+ c = Voter(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
+ (tx_hash, o) = c.vote_cancel(self.voter_address, self.alice, 1)
+ self.rpc.do(o)
+ o = receipt(tx_hash)
+ r = self.rpc.do(o)
+ self.assertEqual(r['status'], 1)
+
+ nonce_oracle = RPCNonceOracle(self.trent, conn=self.conn)
+ c = Voter(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
+ (tx_hash, o) = c.scan(self.voter_address, self.trent, 0, 0)
+ self.rpc.do(o)
+ o = receipt(tx_hash)
+ r = self.rpc.do(o)
+ self.assertEqual(r['status'], 1)
+
+ o = c.get_proposal(self.voter_address, 0, sender_address=self.accounts[0])
+ r = self.rpc.do(o)
+ proposal = c.parse_proposal(r)
+ self.assertEqual(proposal.state & ProposalState.SCANNED, ProposalState.SCANNED)
+ self.assertEqual(proposal.state & ProposalState.IMMEDIATE, ProposalState.IMMEDIATE)
+ self.assertEqual(proposal.state & ProposalState.CANCELLED, ProposalState.CANCELLED)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/python/tests/test_events.py b/python/tests/test_events.py
@@ -0,0 +1,170 @@
+# standard imports
+import unittest
+import logging
+import os
+from chainlib.eth.nonce import RPCNonceOracle
+from chainlib.eth.contract import ABIContractLogDecoder
+from chainlib.eth.contract import ABIContractType
+from chainlib.eth.tx import receipt
+from chainlib.eth.block import block_latest
+from hexathon import same as same_hex
+from eth_erc20 import ERC20
+from giftable_erc20_token import GiftableToken
+
+# local imports
+from evm_tokenvote.unittest import TestEvmVote
+from evm_tokenvote.unittest.base import hash_of_foo
+from evm_tokenvote import Voter
+from evm_tokenvote import ProposalState
+
+
+logging.basicConfig(level=logging.DEBUG)
+logg = logging.getLogger()
+
+class TestVoteEvents(TestEvmVote):
+
+ def test_event_propose(self):
+ description = hash_of_foo
+ nonce_oracle = RPCNonceOracle(self.ivan, conn=self.conn)
+ c = Voter(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
+ (tx_hash, o) = c.propose(self.voter_address, self.ivan, description, 100)
+ self.rpc.do(o)
+ o = receipt(tx_hash)
+ r = self.rpc.do(o)
+
+ rlog = r['logs'][0]
+
+ o = block_latest()
+ now_block_height = self.rpc.do(o)
+
+ topic = ABIContractLogDecoder()
+ topic.topic('ProposalAdded')
+ topic.typ(ABIContractType.UINT256)
+ topic.typ(ABIContractType.UINT256)
+ topic.typ(ABIContractType.UINT256)
+ topic.apply(rlog['topics'], rlog['data'])
+ self.assertEqual(int(topic.contents[0], 16), now_block_height + 100)
+ self.assertEqual(int(topic.contents[1], 16), 500000)
+ self.assertEqual(int(topic.contents[2], 16), 0)
+
+
+ def test_event_complete(self):
+ half_supply = int(self.initial_supply / 2)
+ description = hash_of_foo
+ nonce_oracle = RPCNonceOracle(self.ivan, conn=self.conn)
+ c = Voter(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
+ (tx_hash, o) = c.propose(self.voter_address, self.ivan, description, 100)
+ self.rpc.do(o)
+
+ nonce_oracle = RPCNonceOracle(self.accounts[0], conn=self.conn)
+ c = ERC20(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
+ (tx_hash, o) = c.transfer(self.address, self.accounts[0], self.alice, half_supply)
+ self.rpc.do(o)
+
+ nonce_oracle = RPCNonceOracle(self.alice, conn=self.conn)
+ c = ERC20(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
+ (tx_hash, o) = c.approve(self.address, self.alice, self.voter_address, half_supply)
+ self.rpc.do(o)
+
+ c = Voter(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
+ (tx_hash, o) = c.vote(self.voter_address, self.alice, half_supply)
+ self.rpc.do(o)
+
+ (tx_hash, o) = c.finalize_vote(self.voter_address, self.alice)
+ self.rpc.do(o)
+ o = receipt(tx_hash)
+ r = self.rpc.do(o)
+ self.assertEqual(r['status'], 1)
+
+ rlog = r['logs'][0]
+
+ topic = ABIContractLogDecoder()
+ topic.topic('ProposalCompleted')
+ topic.typ(ABIContractType.UINT256)
+ topic.typ(ABIContractType.BOOLEAN)
+ topic.typ(ABIContractType.BOOLEAN)
+ topic.typ(ABIContractType.UINT256)
+ topic.apply(rlog['topics'], [rlog['data']])
+ self.assertEqual(int(topic.contents[0], 16), 0)
+ self.assertEqual(int(topic.contents[1], 16), 0)
+ self.assertEqual(int(topic.contents[2], 16), 0)
+ self.assertEqual(int(topic.contents[3], 16), half_supply)
+
+
+ def test_event_insufficient(self):
+ half_supply = int(self.initial_supply / 2)
+ description = hash_of_foo
+ nonce_oracle = RPCNonceOracle(self.ivan, conn=self.conn)
+ c = Voter(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
+ (tx_hash, o) = c.propose(self.voter_address, self.ivan, description, 100)
+ self.rpc.do(o)
+
+ self.backend.mine_blocks(100)
+
+ (tx_hash, o) = c.finalize_vote(self.voter_address, self.ivan)
+ self.rpc.do(o)
+ o = receipt(tx_hash)
+ r = self.rpc.do(o)
+ self.assertEqual(r['status'], 1)
+
+ rlog = r['logs'][0]
+
+ topic = ABIContractLogDecoder()
+ topic.topic('ProposalCompleted')
+ topic.typ(ABIContractType.UINT256)
+ topic.typ(ABIContractType.BOOLEAN)
+ topic.typ(ABIContractType.BOOLEAN)
+ topic.typ(ABIContractType.UINT256)
+ topic.apply(rlog['topics'], [rlog['data']])
+ self.assertEqual(int(topic.contents[0], 16), 0)
+ self.assertEqual(int(topic.contents[1], 16), 0)
+ self.assertEqual(int(topic.contents[2], 16), 1)
+ self.assertEqual(int(topic.contents[3], 16), 0)
+
+
+
+ def test_event_cancelled(self):
+ half_supply = int(self.initial_supply / 2)
+ description = hash_of_foo
+ nonce_oracle = RPCNonceOracle(self.ivan, conn=self.conn)
+ c = Voter(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
+ (tx_hash, o) = c.propose(self.voter_address, self.ivan, description, 100)
+ self.rpc.do(o)
+
+ nonce_oracle = RPCNonceOracle(self.accounts[0], conn=self.conn)
+ c = ERC20(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
+ (tx_hash, o) = c.transfer(self.address, self.accounts[0], self.alice, half_supply)
+ self.rpc.do(o)
+
+ nonce_oracle = RPCNonceOracle(self.alice, conn=self.conn)
+ c = ERC20(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
+ (tx_hash, o) = c.approve(self.address, self.alice, self.voter_address, half_supply)
+ self.rpc.do(o)
+
+ c = Voter(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
+ (tx_hash, o) = c.vote_cancel(self.voter_address, self.alice, half_supply)
+ self.rpc.do(o)
+
+ (tx_hash, o) = c.finalize_vote(self.voter_address, self.alice)
+ self.rpc.do(o)
+ o = receipt(tx_hash)
+ r = self.rpc.do(o)
+ self.assertEqual(r['status'], 1)
+
+ rlog = r['logs'][0]
+
+ topic = ABIContractLogDecoder()
+ topic.topic('ProposalCompleted')
+ topic.typ(ABIContractType.UINT256)
+ topic.typ(ABIContractType.BOOLEAN)
+ topic.typ(ABIContractType.BOOLEAN)
+ topic.typ(ABIContractType.UINT256)
+ topic.apply(rlog['topics'], [rlog['data']])
+ self.assertEqual(int(topic.contents[0], 16), 0)
+ self.assertEqual(int(topic.contents[1], 16), 1)
+ self.assertEqual(int(topic.contents[2], 16), 0)
+ self.assertEqual(int(topic.contents[3], 16), half_supply)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/python/tests/test_registry.py b/python/tests/test_registry.py
@@ -32,6 +32,19 @@ class TestVoteRegistry(TestEvmVoteRegistry):
self.rpc.do(o)
o = receipt(tx_hash)
r = self.rpc.do(o)
+ self.assertEqual(r['status'], 0)
+
+ nonce_oracle = RPCNonceOracle(self.accounts[0], conn=self.conn)
+ c = AccountsIndex(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
+ (tx_hash, o) = c.add(self.proposer_registry_address, self.accounts[0], self.ivan)
+ self.rpc.do(o)
+
+ nonce_oracle = RPCNonceOracle(self.ivan, conn=self.conn)
+ c = Voter(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
+ (tx_hash, o) = c.propose(self.voter_address, self.ivan, description, 100)
+ self.rpc.do(o)
+ o = receipt(tx_hash)
+ r = self.rpc.do(o)
self.assertEqual(r['status'], 1)
nonce_oracle = RPCNonceOracle(self.accounts[0], conn=self.conn)
@@ -58,9 +71,6 @@ class TestVoteRegistry(TestEvmVoteRegistry):
c = AccountsIndex(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
(tx_hash, o) = c.add(self.registry_address, self.accounts[0], self.alice)
self.rpc.do(o)
- o = receipt(tx_hash)
- r = self.rpc.do(o)
- self.assertEqual(r['status'], 1)
nonce_oracle = RPCNonceOracle(self.alice, conn=self.conn)
c = Voter(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
diff --git a/python/tests/test_token.py b/python/tests/test_token.py
@@ -60,35 +60,24 @@ class TestVoteToken(TestEvmVoteProposal):
self.rpc.do(o)
o = receipt(tx_hash)
r = self.rpc.do(o)
- self.assertEqual(r['status'], 1)
+ self.assertEqual(r['status'], 0)
c = ERC20(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
o = c.balance_of(self.voter_address, self.alice, sender_address=self.accounts[0])
r = self.rpc.do(o)
balance = int(r, 16)
- self.assertEqual(balance, 0)
+ self.assertEqual(balance, half_supply)
o = c.balance_of(self.address, self.alice, sender_address=self.accounts[0])
r = self.rpc.do(o)
balance = int(r, 16)
- self.assertEqual(balance, half_supply)
+ self.assertEqual(balance, 0)
c = Voter(self.chain_spec)
o = c.get_proposal(self.voter_address, 0, sender_address=self.alice)
r = self.rpc.do(o)
proposal = c.parse_proposal(r)
- self.assertEqual(proposal.total, 0)
-
- c = ERC20(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
- (tx_hash, o) = c.approve(self.address, self.alice, self.voter_address, half_supply)
- self.rpc.do(o)
-
- c = Voter(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
- (tx_hash, o) = c.vote(self.voter_address, self.alice, half_supply)
- self.rpc.do(o)
- o = receipt(tx_hash)
- r = self.rpc.do(o)
- self.assertEqual(r['status'], 1)
+ self.assertEqual(proposal.total, half_supply)
o = block_latest()
now_block_height = self.rpc.do(o)
diff --git a/solidity/Voter.sol b/solidity/Voter.sol
@@ -5,9 +5,6 @@ pragma solidity ^0.8.0;
// File-Version: 1
// Description: Voting contract using ERC20 tokens as shares
-// TODO: how to cancel vote prematurely
-// TODO: voter registration vote, to enforce 50% per-entity cap rule
-
contract ERC20Vote {
uint8 constant STATE_INIT = 1;
uint8 constant STATE_FINAL = 2;
@@ -15,6 +12,8 @@ contract ERC20Vote {
uint8 constant STATE_INSUFFICIENT = 8;
uint8 constant STATE_TIED = 16;
uint8 constant STATE_SUPPLYCHANGE = 32;
+ uint8 constant STATE_IMMEDIATE = 64;
+ uint8 constant STATE_CANCELLED = 128;
address public token;
@@ -22,6 +21,7 @@ contract ERC20Vote {
bytes32 description;
bytes32 []options;
uint256 []optionVotes;
+ uint256 cancelVotes;
uint256 supply;
uint256 total;
uint256 blockDeadline;
@@ -32,7 +32,8 @@ contract ERC20Vote {
}
Proposal[] proposals;
- address accountsRegistry;
+ address voterRegistry;
+ address proposerRegistry;
uint256 currentProposal;
@@ -40,11 +41,13 @@ contract ERC20Vote {
mapping ( address => uint256 ) proposalIdxLock;
event ProposalAdded(uint256 indexed _blockDeadline, uint256 indexed voteTargetPpm, uint256 indexed _proposalIdx);
+ event ProposalCompleted(uint256 indexed _proposalIdx, bool indexed _cancelled, bool indexed _insufficient, uint256 _totalVote);
- constructor(address _token, address _accountsRegistry) {
+ constructor(address _token, address _voterRegistry, address _proposerRegistry) {
Proposal memory l_proposal;
token = _token;
- accountsRegistry = _accountsRegistry;
+ voterRegistry = _voterRegistry;
+ proposerRegistry = _proposerRegistry;
proposals.push(l_proposal);
currentProposal = 1;
}
@@ -55,7 +58,9 @@ contract ERC20Vote {
uint256 l_proposalIndex;
uint256 l_blockDeadline;
+ mustAccount(msg.sender, proposerRegistry);
require(_options.length < 256, "ERR_TOO_MANY_OPTIONS");
+
l_proposal.proposer = msg.sender;
l_proposal.description = _description;
l_proposal.options = _options;
@@ -72,6 +77,13 @@ contract ERC20Vote {
return l_proposalIndex;
}
+ // create new proposal without options
+ function propose(bytes32 _description, uint256 _blockWait, uint24 _targetVotePpm) public returns (uint256) {
+ bytes32[] memory options;
+
+ return proposeMulti(_description, options, _blockWait, _targetVotePpm);
+ }
+
// get proposal by index
function getProposal(uint256 _proposalIdx) public view returns(Proposal memory) {
return proposals[_proposalIdx + 1];
@@ -86,12 +98,7 @@ contract ERC20Vote {
return proposal;
}
- function propose(bytes32 _description, uint256 _blockWait, uint24 _targetVotePpm) public returns (uint256) {
- bytes32[] memory options;
-
- return proposeMulti(_description, options, _blockWait, _targetVotePpm);
- }
-
+ // get description for option
function getOption(uint256 _proposalIdx, uint256 _optionIdx) public view returns (bytes32) {
Proposal storage proposal;
@@ -99,6 +106,7 @@ contract ERC20Vote {
return proposal.options[_optionIdx];
}
+ // number of options in proposal
function optionCount(uint256 _proposalIdx) public view returns(uint256) {
Proposal storage proposal;
@@ -106,6 +114,7 @@ contract ERC20Vote {
return proposal.options.length;
}
+ // total number of votes (across all options)
function voteCount(uint256 _proposalIdx, uint256 _optionIdx) public view returns(uint256) {
Proposal storage proposal;
@@ -118,15 +127,15 @@ contract ERC20Vote {
}
// reverts on unregistered account if an accounts registry has been added.
- function mustAccount(address _account) private {
+ function mustAccount(address _account, address _registry) private {
bool r;
bytes memory v;
- if (accountsRegistry == address(0)) {
+ if (_registry == address(0)) {
return;
}
- (r, v) = accountsRegistry.call(abi.encodeWithSignature('have(address)', _account));
+ (r, v) = _registry.call(abi.encodeWithSignature('have(address)', _account));
require(r, "ERR_REGISTRY");
r = abi.decode(v, (bool));
require(r, "ERR_UNAUTH_ACCOUNT");
@@ -137,22 +146,27 @@ contract ERC20Vote {
// If false is returned, proposal has been invalidated.
function voteOption(uint256 _optionIndex, uint256 _value) public returns (bool) {
Proposal storage proposal;
- bool r;
- bytes memory v;
- mustAccount(msg.sender);
+ mustAccount(msg.sender, voterRegistry);
proposal = proposals[currentProposal];
- require(proposal.state & STATE_INIT > 0, "ERR_PROPOSAL_INACTIVE");
- if (checkSupply(proposal) == 0) {
+ if (!voteable(proposal)) {
return false;
}
- require(proposal.blockDeadline > block.number, "ERR_DEADLINE");
- if (proposalIdxLock[msg.sender] > 0) {
- require(proposalIdxLock[msg.sender] == currentProposal, "ERR_WITHDRAW_FIRST");
- }
if (proposal.options.length > 0) {
require(_optionIndex < proposal.options.length, "ERR_OPTION_INVALID");
}
+ voteCore(proposal, _value);
+ if (proposal.options.length > 0) {
+ proposal.optionVotes[_optionIndex] += _value;
+ }
+ return true;
+ }
+
+ // common code for all vote methods
+ // executes the token transfer, updates total and sets immediate flag if target vote has been met
+ function voteCore(Proposal storage proposal, uint256 _value) private {
+ bool r;
+ bytes memory v;
(r, v) = token.call(abi.encodeWithSignature('transferFrom(address,address,uint256)', msg.sender, this, _value));
require(r, "ERR_TOKEN");
@@ -162,19 +176,61 @@ contract ERC20Vote {
proposalIdxLock[msg.sender] = currentProposal;
balanceOf[msg.sender] += _value;
proposal.total += _value;
- if (proposal.options.length > 0) {
- proposal.optionVotes[_optionIndex] += _value;
+ if (haveQuota(proposal)) {
+ proposal.state |= STATE_IMMEDIATE;
}
- return true;
}
// Cast vote for a proposal without options
// Can be called multiple times as long as balance is sufficient.
// If false is returned, proposal has been invalidated.
function vote(uint256 _value) public returns (bool) {
+ Proposal storage proposal;
+
+ mustAccount(msg.sender, voterRegistry);
+ proposal = proposals[currentProposal];
+ require(proposal.options.length < 2); // allow both no options and single option.
return voteOption(0, _value);
}
+ // cast vote to cancel proposal
+ // will set immediate termination and cancelled flag if has target vote majority
+ function voteCancel(uint256 _value) public returns (bool) {
+ Proposal storage proposal;
+ uint256 l_total_m;
+
+ mustAccount(msg.sender, voterRegistry);
+ proposal = proposals[currentProposal];
+ if (!voteable(proposal)) {
+ return false;
+ }
+ voteCore(proposal, _value);
+ proposal.cancelVotes += _value;
+
+ l_total_m = proposal.cancelVotes * 1000000;
+ if (l_total_m / proposal.supply >= proposal.targetVotePpm) {
+ proposal.state |= STATE_CANCELLED | STATE_IMMEDIATE;
+ }
+ return true;
+ }
+
+ // proposal is voteable if:
+ // * has been initialized
+ // * within deadline
+ // * voter released tokens from previous vote
+ function voteable(Proposal storage proposal) private returns(bool) {
+ require(proposal.state & STATE_INIT > 0, "ERR_PROPOSAL_INACTIVE");
+ if (checkSupply(proposal) == 0) {
+ return false;
+ }
+ require(proposal.blockDeadline > block.number, "ERR_DEADLINE");
+ if (proposalIdxLock[msg.sender] > 0) {
+ require(proposalIdxLock[msg.sender] == currentProposal, "ERR_WITHDRAW_FIRST");
+ }
+ return true;
+ }
+
+
// Optionally scan the results for a proposal to make result visible.
// Returns false as long as there are more options to scan.
function scan(uint256 _proposalIndex, uint8 _count) public returns (bool) {
@@ -187,7 +243,9 @@ contract ERC20Vote {
uint8 state;
proposal = proposals[_proposalIndex + 1];
- require(proposal.blockDeadline <= block.number, "ERR_PREMATURE");
+ if (proposal.state & STATE_IMMEDIATE == 0) {
+ require(proposal.blockDeadline <= block.number, "ERR_PREMATURE");
+ }
if (proposal.state & STATE_SCANNED > 0) {
return false;
}
@@ -227,27 +285,35 @@ contract ERC20Vote {
// will record and return whether voting participation was insufficient.
function finalize() public returns (bool) {
Proposal storage proposal;
- uint256 l_total_m;
+ bool r;
proposal = proposals[currentProposal];
require(proposal.state & STATE_FINAL == 0, "ERR_ALREADY_STATE_FINAL");
- require(proposal.state & STATE_SCANNED > 0, "ERR_SCAN_FIRST");
+ //require(proposal.state & STATE_SCANNED > 0, "ERR_SCAN_FIRST");
if (checkSupply(proposal) == 0) {
return false;
}
proposal.state |= STATE_FINAL;
- currentProposal += 1;
-
- l_total_m = proposal.total * 1000000;
- if (l_total_m / proposal.supply < proposal.targetVotePpm) {
+ if (!haveQuota(proposal)) {
proposal.state |= STATE_INSUFFICIENT;
- return false;
-
+ r = true;
+ } else {
}
- return true;
+ emit ProposalCompleted(currentProposal - 1, proposal.state & STATE_CANCELLED > 0, r, proposal.total);
+
+ currentProposal += 1;
+ return !r;
}
+ // check if target vote count has been met
+ function haveQuota(Proposal storage proposal) private view returns (bool) {
+ uint256 l_total_m;
+ l_total_m = proposal.total * 1000000;
+ return l_total_m / proposal.supply >= proposal.targetVotePpm;
+ }
+
+
// should be checked for proposal creation, each recorded vote and finalization.
function checkSupply(Proposal storage proposal) private returns (uint256) {
bool r;
@@ -271,6 +337,14 @@ contract ERC20Vote {
return l_supply;
}
+ // Implements Escrow
+ // Can only be called with the full balance held by the contract. Use withdraw() instead.
+ function withdraw(uint256 _value) public returns (uint256) {
+ require(_value == balanceOf[msg.sender], "ERR_MUST_WITHDRAW_ALL");
+ return withdraw();
+ }
+
+ // Implements Escrow
// Recover tokens from a finished vote or from an active vote before deadline.
function withdraw() public returns (uint256) {
Proposal storage proposal;
@@ -281,13 +355,10 @@ contract ERC20Vote {
l_value = balanceOf[msg.sender];
if (proposalIdxLock[msg.sender] == currentProposal) {
proposal = proposals[currentProposal];
- if (proposal.blockDeadline <= block.number) {
- require(proposal.state & STATE_FINAL > 0, "ERR_PREMATURE");
- } else {
- proposal.total -= l_value;
- }
+ require(proposal.state & STATE_FINAL > 0, "ERR_PREMATURE");
}
+
balanceOf[msg.sender] = 0;
proposalIdxLock[msg.sender] = 0;
(r, v) = token.call(abi.encodeWithSignature('transfer(address,uint256)', msg.sender, l_value));