Skip to content

Commit

Permalink
Defaults units to WEI & adds transaction() method
Browse files Browse the repository at this point in the history
  • Loading branch information
AndreMiras committed Oct 12, 2019
1 parent a3028dc commit 15e8d15
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 15 deletions.
3 changes: 2 additions & 1 deletion README.md
Expand Up @@ -16,12 +16,13 @@ from pyetheroll.etheroll import Etheroll

etheroll = Etheroll()
bet_size_ether = 0.1
bet_size_wei = int(bet_size_ether * 1e18)
chances = 50
wallet_path = 'wallet.json'
wallet_password = 'password'

transaction = etheroll.player_roll_dice(
bet_size_ether, chances, wallet_path, wallet_password)
bet_size_wei, chances, wallet_path, wallet_password)
```

It's also possible to set different contract address and chain ID:
Expand Down
1 change: 1 addition & 0 deletions pyetheroll/constants.py
Expand Up @@ -2,6 +2,7 @@

ROUND_DIGITS = 2
DEFAULT_GAS_PRICE_GWEI = 4
DEFAULT_GAS_PRICE_WEI = int(DEFAULT_GAS_PRICE_GWEI * 1e9)


class ChainID(Enum):
Expand Down
37 changes: 26 additions & 11 deletions pyetheroll/etheroll.py
Expand Up @@ -11,10 +11,9 @@
from etherscan.client import EmptyResponse
from hexbytes.main import HexBytes
from web3 import Web3
from web3.auto import w3
from web3.contract import Contract

from pyetheroll.constants import DEFAULT_GAS_PRICE_GWEI, ROUND_DIGITS, ChainID
from pyetheroll.constants import DEFAULT_GAS_PRICE_WEI, ROUND_DIGITS, ChainID
from pyetheroll.etherscan_utils import (ChainEtherscanAccountFactory,
ChainEtherscanContractFactory,
get_etherscan_api_key)
Expand Down Expand Up @@ -144,29 +143,24 @@ def events_logs(self, event_list):
return events_logs

def player_roll_dice(
self, bet_size_ether, chances, wallet_path, wallet_password,
gas_price_gwei=DEFAULT_GAS_PRICE_GWEI):
self, bet_size_wei, chances, wallet_path, wallet_password,
gas_price_wei=DEFAULT_GAS_PRICE_WEI):
"""
Signs and broadcasts `playerRollDice` transaction.
Returns transaction hash.
"""
roll_under = chances
# `w3.toWei` one has some issues on Android, see:
# https://github.com/AndreMiras/EtherollApp/issues/77
# value_wei = w3.toWei(bet_size_ether, 'ether')
value_wei = int(bet_size_ether * 1e18)
gas = 310000
gas_price = w3.toWei(gas_price_gwei, 'gwei')
wallet_encrypted = load_keyfile(wallet_path)
address = wallet_encrypted['address']
from_address_normalized = to_checksum_address(address)
nonce = self.web3.eth.getTransactionCount(from_address_normalized)
transaction = {
'chainId': self.chain_id.value,
'gas': gas,
'gasPrice': gas_price,
'gasPrice': gas_price_wei,
'nonce': nonce,
'value': value_wei,
'value': bet_size_wei,
}
transaction = self.contract.functions.playerRollDice(
roll_under).buildTransaction(transaction)
Expand All @@ -176,6 +170,27 @@ def player_roll_dice(
tx_hash = self.web3.eth.sendRawTransaction(signed_tx.rawTransaction)
return tx_hash

def transaction(self, to, value, wallet_path, wallet_password,
gas_price_wei=DEFAULT_GAS_PRICE_WEI):
gas = 25000
wallet_encrypted = load_keyfile(wallet_path)
address = wallet_encrypted['address']
from_address_normalized = to_checksum_address(address)
nonce = self.web3.eth.getTransactionCount(from_address_normalized)
transaction = {
'chainId': self.chain_id.value,
'gas': gas,
'gasPrice': gas_price_wei,
'nonce': nonce,
'value': value,
'to': to,
}
private_key = Account.decrypt(wallet_encrypted, wallet_password)
signed_tx = self.web3.eth.account.signTransaction(
transaction, private_key)
tx_hash = self.web3.eth.sendRawTransaction(signed_tx.rawTransaction)
return tx_hash

def get_transaction_page(
self, address=None, page=1, offset=100, internal=False):
"""
Expand Down
57 changes: 54 additions & 3 deletions tests/test_etheroll.py
Expand Up @@ -237,6 +237,7 @@ def test_player_roll_dice(self):
m_get_abi.return_value = json.dumps(contract_abi)
etheroll = Etheroll()
bet_size_ether = 0.1
bet_size_wei = int(bet_size_ether * 1e18)
chances = 50
wallet_password = 'password'
account = self.create_account_helper(wallet_password)
Expand All @@ -250,7 +251,7 @@ def test_player_roll_dice(self):
) as m_signTransaction:
m_getTransactionCount.return_value = 0
transaction = etheroll.player_roll_dice(
bet_size_ether, chances, wallet_path, wallet_password)
bet_size_wei, chances, wallet_path, wallet_password)
# the method should return a transaction hash
assert transaction is not None
# and getTransactionCount been called with the normalized address
Expand All @@ -261,9 +262,10 @@ def test_player_roll_dice(self):
# getTransactionCount
# a second one with custom gas (in gwei), refs #23
gas_price_gwei = 12
gas_price_wei = int(gas_price_gwei * 1e9)
transaction = etheroll.player_roll_dice(
bet_size_ether, chances, wallet_path, wallet_password,
gas_price_gwei)
bet_size_wei, chances, wallet_path, wallet_password,
gas_price_wei)
assert transaction is not None
# the nonce was retrieved
assert m_getTransactionCount.called is True
Expand Down Expand Up @@ -299,6 +301,55 @@ def test_player_roll_dice(self):
# because float are not accepted
assert type(transaction_dict['value']) is float

def test_transaction(self):
"""
Verifies the transaction is properly built and sent.
"""
# simplified contract ABI
contract_abi = [self.player_roll_dice_abi]
with mock.patch('etherscan.contracts.Contract.get_abi') \
as m_get_abi:
m_get_abi.return_value = json.dumps(contract_abi)
etheroll = Etheroll()
to = '0x46044beAa1E985C67767E04dE58181de5DAAA00F'
value = 1
gas_price_gwei = 12
gas_price_wei = int(gas_price_gwei * 1e9)
wallet_password = 'password'
account = self.create_account_helper(wallet_password)
wallet_path = account.path
with \
mock.patch('web3.eth.Eth.sendRawTransaction') \
as m_sendRawTransaction, mock.patch(
'web3.eth.Eth.getTransactionCount'
) as m_getTransactionCount, mock.patch(
'eth_account.account.Account.signTransaction'
) as m_signTransaction:
m_getTransactionCount.return_value = 0
transaction = etheroll.transaction(
to, value, wallet_path, wallet_password, gas_price_wei)
# the method should return a transaction hash
assert transaction is not None
# and getTransactionCount been called with the normalized address
normalized_address = account.address
assert m_getTransactionCount.call_args_list == [
mock.call(normalized_address)
]
# the nonce was retrieved
assert m_getTransactionCount.called is True
# the transaction was sent
assert m_sendRawTransaction.called is True
# the transaction should be built that way
expected_transaction1 = {
'nonce': 0, 'chainId': 1,
'to': to,
'gas': 25000,
'value': value, 'gasPrice': 12000000000,
}
expected_call1 = mock.call(expected_transaction1, account.privateKey)
expected_calls = [expected_call1]
assert m_signTransaction.call_args_list == expected_calls

def test_get_last_bets_transactions(self):
"""
Verifies `get_last_bets_transactions()` performs the correct calls to
Expand Down

0 comments on commit 15e8d15

Please sign in to comment.