-
Notifications
You must be signed in to change notification settings - Fork 3
/
utils.py
118 lines (96 loc) · 3.61 KB
/
utils.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
"""Utilities for testing Cairo contracts."""
import math
from starkware.crypto.signature.signature import private_to_stark_key, sign
from starkware.starknet.public.abi import get_selector_from_name
from starkware.starknet.compiler.compile import compile_starknet_files
from starkware.starkware_utils.error_handling import StarkException
from starkware.starknet.testing.starknet import StarknetContract
from starkware.starknet.core.os.transaction_hash.transaction_hash import (
calculate_transaction_hash_common,
TransactionHashPrefix,
)
from starkware.starknet.definitions.general_config import StarknetChainId
TRANSACTION_VERSION = 0
SHORT_STR_SIZE = 31
def to_uint(a):
"""Takes in value, returns uint256-ish tuple."""
return (a & ((1 << 128) - 1), a >> 128)
def uint(a):
return (a, 0)
def str_to_felt(text):
b_text = bytes(text, "ascii")
return int.from_bytes(b_text, "big")
def str_to_short_str_array(text):
res = []
for i in range(len(text)):
temp = text[i:i+SHORT_STR_SIZE]
res.append(str_to_felt(temp))
i += SHORT_STR_SIZE
return res
class Signer:
"""
Utility for sending signed transactions to an Account on Starknet.
Parameters
----------
private_key : int
Examples
---------
Constructing a Signer object
>>> signer = Signer(1234)
Sending a transaction
>>> await signer.send_transaction(account,
account.contract_address,
'set_public_key',
[other.public_key]
)
"""
def __init__(self, private_key):
self.private_key = private_key
self.public_key = private_to_stark_key(private_key)
def sign(self, message_hash):
return sign(msg_hash=message_hash, priv_key=self.private_key)
async def send_transaction(
self, account, to, selector_name, calldata, nonce=None, max_fee=0
):
return await self.send_transactions(
account, [(to, selector_name, calldata)], nonce, max_fee
)
async def send_transactions(self, account, calls, nonce=None, max_fee=0):
if nonce is None:
execution_info = await account.get_nonce().call()
(nonce,) = execution_info.result
(call_array, calldata) = from_call_to_call_array(calls)
message_hash = get_transaction_hash(
account.contract_address, call_array, calldata, nonce, max_fee
)
sig_r, sig_s = self.sign(message_hash)
return await account.__execute__(call_array, calldata, nonce).invoke(
signature=[sig_r, sig_s]
)
def from_call_to_call_array(calls):
call_array = []
calldata = []
for i, call in enumerate(calls):
assert len(call) == 3, "Invalid call parameters"
entry = (call[0], get_selector_from_name(call[1]), len(calldata), len(call[2]))
call_array.append(entry)
calldata.extend(call[2])
return (call_array, calldata)
def get_transaction_hash(account, call_array, calldata, nonce, max_fee):
execute_calldata = [
len(call_array),
*[x for t in call_array for x in t],
len(calldata),
*calldata,
nonce,
]
return calculate_transaction_hash_common(
TransactionHashPrefix.INVOKE,
TRANSACTION_VERSION,
account,
get_selector_from_name("__execute__"),
execute_calldata,
max_fee,
StarknetChainId.TESTNET.value,
[],
)