Skip to content

Commit f992bc8

Browse files
tkumor3ddoktorski
andauthored
Add estimate_fee to Account (#1279)
* Add estimate_fee to Account * fix * add support list od transaction and allows use skip_validate * update * remove print * update * Update starknet_py/net/account/base_account.py Co-authored-by: ddoktorski <45050160+ddoktorski@users.noreply.github.com> * Update starknet_py/net/account/account.py Co-authored-by: ddoktorski <45050160+ddoktorski@users.noreply.github.com> * fmt * add test * fix test * update test * use two distinct transaction types in test * feedback --------- Co-authored-by: ddoktorski <45050160+ddoktorski@users.noreply.github.com>
1 parent 0dcf387 commit f992bc8

File tree

3 files changed

+89
-17
lines changed

3 files changed

+89
-17
lines changed

starknet_py/net/account/account.py

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,9 @@ async def _get_max_fee(
136136
)
137137

138138
if auto_estimate:
139-
estimated_fee = await self._estimate_fee(transaction)
139+
estimated_fee = await self.estimate_fee(transaction)
140+
assert isinstance(estimated_fee, EstimatedFee)
141+
140142
max_fee = int(estimated_fee.overall_fee * Account.ESTIMATED_FEE_MULTIPLIER)
141143

142144
if max_fee is None:
@@ -158,7 +160,9 @@ async def _get_resource_bounds(
158160
)
159161

160162
if auto_estimate:
161-
estimated_fee = await self._estimate_fee(transaction)
163+
estimated_fee = await self.estimate_fee(transaction)
164+
assert isinstance(estimated_fee, EstimatedFee)
165+
162166
l1_resource_bounds = ResourceBounds(
163167
max_amount=int(
164168
estimated_fee.gas_consumed * Account.ESTIMATED_AMOUNT_MULTIPLIER
@@ -246,28 +250,25 @@ async def _prepare_invoke_v3(
246250
)
247251
return _add_resource_bounds_to_transaction(transaction, resource_bounds)
248252

249-
async def _estimate_fee(
253+
async def estimate_fee(
250254
self,
251-
tx: AccountTransaction,
255+
tx: Union[AccountTransaction, List[AccountTransaction]],
256+
skip_validate: bool = False,
252257
block_hash: Optional[Union[Hash, Tag]] = None,
253258
block_number: Optional[Union[int, Tag]] = None,
254-
) -> EstimatedFee:
255-
"""
256-
:param tx: Transaction which fee we want to calculate.
257-
:param block_hash: a block hash.
258-
:param block_number: a block number.
259-
:return: Estimated fee.
260-
"""
261-
tx = await self.sign_for_fee_estimate(tx)
259+
) -> Union[EstimatedFee, List[EstimatedFee]]:
260+
transactions = (
261+
await self.sign_for_fee_estimate(tx)
262+
if isinstance(tx, AccountTransaction)
263+
else [await self.sign_for_fee_estimate(t) for t in tx]
264+
)
262265

263-
estimated_fee = await self._client.estimate_fee(
264-
tx=tx,
266+
return await self._client.estimate_fee(
267+
tx=transactions,
268+
skip_validate=skip_validate,
265269
block_hash=block_hash,
266270
block_number=block_number,
267271
)
268-
assert isinstance(estimated_fee, EstimatedFee)
269-
270-
return estimated_fee
271272

272273
async def get_nonce(
273274
self,

starknet_py/net/account/base_account.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,15 @@
44
from starknet_py.net.client import Client
55
from starknet_py.net.client_models import (
66
Calls,
7+
EstimatedFee,
78
Hash,
89
ResourceBounds,
910
SentTransactionResponse,
1011
Tag,
1112
)
1213
from starknet_py.net.models import AddressRepresentation, StarknetChainId
1314
from starknet_py.net.models.transaction import (
15+
AccountTransaction,
1416
DeclareV1,
1517
DeclareV2,
1618
DeclareV3,
@@ -51,6 +53,27 @@ def client(self) -> Client:
5153
Get the Client used by the Account.
5254
"""
5355

56+
@abstractmethod
57+
async def estimate_fee(
58+
self,
59+
tx: Union[AccountTransaction, List[AccountTransaction]],
60+
skip_validate: bool = False,
61+
block_hash: Optional[Union[Hash, Tag]] = None,
62+
block_number: Optional[Union[int, Tag]] = None,
63+
) -> Union[EstimatedFee, List[EstimatedFee]]:
64+
"""
65+
Estimates the resources required by a given sequence of transactions when applied on a given state.
66+
If one of the transactions reverts or fails due to any reason (e.g. validation failure or an internal error),
67+
a TRANSACTION_EXECUTION_ERROR is returned.
68+
For v0-2 transactions the estimate is given in Wei, and for v3 transactions it is given in Fri.
69+
70+
:param tx: Transaction or list of transactions to estimate
71+
:param skip_validate: Flag checking whether the validation part of the transaction should be executed
72+
:param block_hash: Block hash or literals `"pending"` or `"latest"`
73+
:param block_number: Block number or literals `"pending"` or `"latest"`
74+
:return: Estimated fee or list of estimated fees for each transaction
75+
"""
76+
5477
@abstractmethod
5578
async def get_nonce(
5679
self,

starknet_py/tests/e2e/account/account_test.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,54 @@ async def test_estimate_fee_for_declare_transaction(account, map_compiled_contra
9999
)
100100

101101

102+
@pytest.mark.asyncio
103+
async def test_account_estimate_fee_for_declare_transaction(
104+
account, map_compiled_contract
105+
):
106+
declare_tx = await account.sign_declare_v1(
107+
compiled_contract=map_compiled_contract, max_fee=MAX_FEE
108+
)
109+
110+
estimated_fee = await account.estimate_fee(tx=declare_tx)
111+
112+
assert estimated_fee.unit == PriceUnit.WEI
113+
assert isinstance(estimated_fee.overall_fee, int)
114+
assert estimated_fee.overall_fee > 0
115+
assert (
116+
estimated_fee.gas_consumed * estimated_fee.gas_price
117+
== estimated_fee.overall_fee
118+
)
119+
120+
121+
@pytest.mark.asyncio
122+
async def test_account_estimate_fee_for_transactions(
123+
account, map_compiled_contract, map_contract
124+
):
125+
declare_tx = await account.sign_declare_v1(
126+
compiled_contract=map_compiled_contract, max_fee=MAX_FEE
127+
)
128+
129+
invoke_tx = await account.sign_invoke_v3(
130+
calls=Call(map_contract.address, get_selector_from_name("put"), [3, 4]),
131+
l1_resource_bounds=MAX_RESOURCE_BOUNDS_L1,
132+
nonce=(declare_tx.nonce + 1),
133+
)
134+
135+
estimated_fee = await account.estimate_fee(tx=[declare_tx, invoke_tx])
136+
137+
assert len(estimated_fee) == 2
138+
assert isinstance(estimated_fee[0], EstimatedFee)
139+
assert isinstance(estimated_fee[1], EstimatedFee)
140+
assert estimated_fee[0].unit == PriceUnit.WEI
141+
assert estimated_fee[1].unit == PriceUnit.FRI
142+
assert isinstance(estimated_fee[0].overall_fee, int)
143+
assert estimated_fee[0].overall_fee > 0
144+
assert (
145+
estimated_fee[0].gas_consumed * estimated_fee[0].gas_price
146+
== estimated_fee[0].overall_fee
147+
)
148+
149+
102150
@pytest.mark.asyncio
103151
@pytest.mark.parametrize("key, val", [(20, 20), (30, 30)])
104152
async def test_sending_multicall(account, map_contract, key, val):

0 commit comments

Comments
 (0)