def send(self, to, value, price=4): ''' :param to: Hex string of payment receiver. :param value: Value in Ether :param price: Price of gas :return: Receipt of the transaction. ''' # Gas estimation also depends on the specified ethereum network nonce = self.web3.eth.getTransactionCount(self.key.address) gas = self.web3.eth.estimateGas({ 'to': to, 'from': self.key.address, 'value': Web3.toWei(value, 'ether') }) trans = { 'to': to, 'value': Web3.toWei(value, 'ether'), 'gas': gas, 'gasPrice': Web3.toWei(price, 'gwei'), 'nonce': nonce, 'chainId': netIds[self.network] } #self.web3.eth.enable_unaudited_features() signObj = self.web3.eth.account.signTransaction( trans, self.key.getPrivate()) try: txnHash = self.web3.eth.sendRawTransaction(signObj.rawTransaction) except Exception as e: print(e + ' ' + str(type(e))) else: return self.wait_for_receipt(byte32(txnHash), 10)
def call(self, contractAddress, methodName, *arg, price=4, value=0): ''' Broadcasts a method call transaction to the network. :param contractAddress: HexString address of a contract deployed through Nim. #TODO: Let people load their own abi ? :param methodName: (string) :param arg: Respective arguments for the method :param price: (unsigned int) price in gwei for gas :param value: (ether)value for the transaction in ether. :return: tuple with locally calculated return value at [0] and transaction receipt at [1]. ''' self.c.execute('SELECT contractObj FROM Deployed WHERE address = ?', (contractAddress, )) data = self.c.fetchone() if data == None: raise exc.ContractNotDeployed('Infura.call()') interface = pickle.loads(data[0]) contract = self.web3.eth.contract(abi=interface['abi'], bytecode=interface['bin'], address=contractAddress) #print(contract.functions.__dict__.keys()) if methodName not in contract.functions.__dict__.keys(): raise exc.MethodNotDefined('Infura.call()') if methodName == 'fallback': func = contract.functions.fallback else: func = contract.functions.__dict__[methodName] counter = 0 b = True while True: try: counter += 1 nonce = self.web3.eth.getTransactionCount(self.key.address) trans = { 'gasPrice': Web3.toWei(price, 'gwei'), 'value': Web3.toWei(value, 'ether'), 'nonce': nonce, 'chainId': netIds[self.network], 'from': self.address, 'gas': 90000 } txn = func(*arg).buildTransaction(trans) except ValueError as e: print(type(e.args[0])) else: print('Cost of method calling : ' + str( self.web3.fromWei( txn['gasPrice'] * txn['gas'] + txn['value'], 'ether')) + ' ETH') signObj = self.web3.eth.account.signTransaction( txn, self.key.getPrivate()) txnHash = byte32( self.web3.eth.sendRawTransaction(signObj.rawTransaction)) return (func(*arg).call(), self.wait_for_receipt(txnHash, 5))
def deploy(self, path, *arg, price=2, value=0): ''' Deploys a solidity source file and returns the address of the contract. Also stores the serialized compile object on a sql database. ''' # self.c.execute('SELECT address FROM Deployed WHERE address = ?', (contractAddress,)) solname = path path = solpath + path f = open(path, 'r') compiled_sol = compile_source(f.read()) f.close() contractName, contract_interface = compiled_sol.popitem() blob = pickle.dumps(contract_interface) bin, abi = contract_interface['bin'], contract_interface['abi'] contract = self.web3.eth.contract(abi=abi, bytecode=bin) nonce = self.web3.eth.getTransactionCount(self.key.address) trans = { 'gasPrice': Web3.toWei(price, 'gwei'), 'value': Web3.toWei(value, 'ether'), 'nonce': nonce, 'chainId': netIds[self.network], 'from': self.address } if arg == None: txn = contract.constructor().buildTransaction(trans) else: txn = contract.constructor(*arg).buildTransaction(trans) print('Cost of deployment: ' + str( self.web3.fromWei(txn['gasPrice'] * txn['gas'] + txn['value'], 'ether')) + ' ETH') signObj = self.web3.eth.account.signTransaction( txn, self.key.getPrivate()) try: txnHash = self.web3.eth.sendRawTransaction(signObj.rawTransaction) except ValueError as e: print(type(e.args[0])) txnHash = byte32(txnHash) address = self.wait_for_receipt(txnHash, 10)['contractAddress'] entry = (address, solname, blob, datetime.datetime.now()) self.c.execute( 'INSERT INTO Deployed(address,filename,contractObj,dat) VALUES (?,?,?,?)', entry) self.conn.commit() return address
def test_hash(self): print('...test_hash()') stri = 'this is a test' sign = self.A.signStr(stri) self.assertEqual(self.A.address, self.A.whoSign(sign.messageHash, sign.signature)) print("...Local string hashing test passed.") print("...Recover signer from signature obj test passed.") address = self.A.deploy('test3.sol') print("...test3.sol contract deployed") a = self.B.call(address,'hash',4)[0] b = soliditySha3(['uint256'], [4]) self.assertEqual(a, b) hash1 = self.B.call(address, 'hashSenderAddress')[1]['logs'][0]['data'] hash2 = byte32(soliditySha3(['address'], [self.B.address])) rAddress = self.B.call(address, 'returnAddress')[1] rAddress =rAddress['logs'][0]['data'] print("msg.sender(Event): "+ str(rAddress)) print("msg.sender(self.B.address): " +self.B.address) print("Calculated Hash of address(EVM event): "+str(hash1)) print("Web3Py calculated byte32(keccak256(address)): "+ hash2) self.assertEqual(hash1,hash2) hash3 = self.B.call(address,'hashSpecial',10,3)[1]['logs'][0]['data'] hash4 = byte32(soliditySha3(['address','uint256','uint256','address'], [self.B.address,10,3,address])) print("EVM keccak256(msg.sender,amount,nonce,this): " + str(hash3)) print('Web3Py calculated byte32(print("EVM keccak256(msg.sender,amount,nonce,this))'+ hash4) self.assertEqual(hash3, hash4) print()
def write(self,recipient,amount): ''' :param recipient: Address of check recipient(HexString). :param amount: Amount in ether to be sent.(int) :return: json with ''' self.address = self.connection.deploy('check.sol',price=4, value=amount) nonce = random.randrange(1,10000) while nonce in self.nonces: nonce = random.randrange(1,10000) print('Check deployed at: ' + self.address) amount = Web3.toWei(amount, 'ether') hash = byte32(soliditySha3(["address", "uint256","uint256","address"], [recipient, amount,nonce,self.address])) sign = format(self.connection.signHash(hash)) check = {'address':self.address,'amount':amount,'nonce':nonce,'msgHash':sign[0], 'v':sign[1],'r':sign[2],'s':sign[3]} return json.dumps(check)