convex-sdk 0.3.2__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- convex_sdk/__init__.py +12 -0
- convex_sdk/account.py +192 -0
- convex_sdk/contract.py +211 -0
- convex_sdk/convex.py +813 -0
- convex_sdk/exceptions.py +23 -0
- convex_sdk/key_pair.py +570 -0
- convex_sdk/models.py +86 -0
- convex_sdk/py.typed +0 -0
- convex_sdk/registry.py +85 -0
- convex_sdk/tool/__init__.py +0 -0
- convex_sdk/tool/command/__init__.py +0 -0
- convex_sdk/tool/command/account_balance_command.py +60 -0
- convex_sdk/tool/command/account_command.py +68 -0
- convex_sdk/tool/command/account_create_command.py +92 -0
- convex_sdk/tool/command/account_fund_command.py +68 -0
- convex_sdk/tool/command/account_info_command.py +59 -0
- convex_sdk/tool/command/account_name_register_command.py +81 -0
- convex_sdk/tool/command/account_name_resolve_command.py +56 -0
- convex_sdk/tool/command/account_topup_command.py +60 -0
- convex_sdk/tool/command/argparse_typing.py +35 -0
- convex_sdk/tool/command/command_base.py +136 -0
- convex_sdk/tool/command/help_command.py +29 -0
- convex_sdk/tool/command/peer_command.py +55 -0
- convex_sdk/tool/command/peer_create_command.py +105 -0
- convex_sdk/tool/command/query_command.py +66 -0
- convex_sdk/tool/command/submit_command.py +65 -0
- convex_sdk/tool/convex_tool.py +110 -0
- convex_sdk/tool/output.py +68 -0
- convex_sdk-0.3.2.data/scripts/convex_tools.py +13 -0
- convex_sdk-0.3.2.dist-info/METADATA +272 -0
- convex_sdk-0.3.2.dist-info/RECORD +34 -0
- convex_sdk-0.3.2.dist-info/WHEEL +6 -0
- convex_sdk-0.3.2.dist-info/licenses/LICENSE +201 -0
- convex_sdk-0.3.2.dist-info/top_level.txt +1 -0
convex_sdk/__init__.py
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"""
|
|
2
|
+
|
|
3
|
+
Convex API Python Library
|
|
4
|
+
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from convex_sdk.account import Account # type: ignore # noqa: F401
|
|
8
|
+
from convex_sdk.convex import Convex # type: ignore # noqa: F401
|
|
9
|
+
from convex_sdk.contract import Contract # type: ignore # noqa: F401
|
|
10
|
+
from convex_sdk.key_pair import KeyPair # type: ignore # noqa: F401
|
|
11
|
+
|
|
12
|
+
__version__ = '0.3.2'
|
convex_sdk/account.py
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
"""
|
|
2
|
+
|
|
3
|
+
Account class for convex api
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
"""
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import re
|
|
10
|
+
from convex_sdk.key_pair import KeyPair
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class Account:
|
|
14
|
+
|
|
15
|
+
@staticmethod
|
|
16
|
+
def is_address(text: int | str) -> bool:
|
|
17
|
+
"""
|
|
18
|
+
Returns True if the text value is a valid address.
|
|
19
|
+
|
|
20
|
+
:param str, int text: Possible address field.
|
|
21
|
+
|
|
22
|
+
:returns: True if the text field is a valid address.
|
|
23
|
+
|
|
24
|
+
"""
|
|
25
|
+
return Account.to_address(text) >= 0
|
|
26
|
+
|
|
27
|
+
@staticmethod
|
|
28
|
+
def to_address(value: Account | int | str) -> int:
|
|
29
|
+
"""
|
|
30
|
+
Convert address text with possible leading '#' to an integer address value.
|
|
31
|
+
|
|
32
|
+
:param str text: Address text to convert
|
|
33
|
+
|
|
34
|
+
:returns: Integer address
|
|
35
|
+
|
|
36
|
+
:raises ValueError: If the address is not valid
|
|
37
|
+
|
|
38
|
+
"""
|
|
39
|
+
if isinstance(value, Account):
|
|
40
|
+
return value.address
|
|
41
|
+
elif isinstance(value, int):
|
|
42
|
+
return int(value)
|
|
43
|
+
else:
|
|
44
|
+
try:
|
|
45
|
+
address = int(re.sub(r'^#', '', value.strip()))
|
|
46
|
+
except ValueError:
|
|
47
|
+
raise ValueError(f'Invalid address {value}')
|
|
48
|
+
return address
|
|
49
|
+
|
|
50
|
+
def __init__(self, key_pair: KeyPair, address: Account | int | str, name: str | None = None):
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
Create a new account with a private key KeyPair.
|
|
54
|
+
|
|
55
|
+
:param KeyPair key_pair: The public/private key of the account
|
|
56
|
+
|
|
57
|
+
:param int address: address of the account
|
|
58
|
+
|
|
59
|
+
:param str name: Optional name of the account
|
|
60
|
+
|
|
61
|
+
.. code-block:: python
|
|
62
|
+
|
|
63
|
+
>>> # import convex-api
|
|
64
|
+
>>> from convex_sdk import Convex, KeyPair, Account
|
|
65
|
+
|
|
66
|
+
>>> # setup the network connection
|
|
67
|
+
>>> convex = Convex('https://convex.world')
|
|
68
|
+
|
|
69
|
+
>>> # create a random keypair
|
|
70
|
+
>>> key_pair = KeyPair()
|
|
71
|
+
|
|
72
|
+
>>> # create a new account and address
|
|
73
|
+
>>> account = convex.create_account(key_pair)
|
|
74
|
+
|
|
75
|
+
>>> # export the private key to a file
|
|
76
|
+
>>> key_pair.export_to_file('/tmp/my_account.pem', 'my secret password')
|
|
77
|
+
|
|
78
|
+
>>> # save the address for later
|
|
79
|
+
>>> my_address = account.address
|
|
80
|
+
|
|
81
|
+
>>> # ----
|
|
82
|
+
|
|
83
|
+
>>> # now import the account and address for later use
|
|
84
|
+
>>> key_pair = KeyPair.import_from_file('/tmp/my_account.pem', 'my secret password')
|
|
85
|
+
>>> account = Account(key_pair, my_address)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
"""
|
|
89
|
+
self._key_pair = key_pair
|
|
90
|
+
self._address = Account.to_address(address)
|
|
91
|
+
self._name = name
|
|
92
|
+
|
|
93
|
+
def sign(self, hash_text: str) -> str:
|
|
94
|
+
"""
|
|
95
|
+
|
|
96
|
+
Sign a hash text using the internal key_pair.
|
|
97
|
+
|
|
98
|
+
:param str hash_text: Hex string of the hash to sign
|
|
99
|
+
|
|
100
|
+
:returns: Hex string of the signed text
|
|
101
|
+
|
|
102
|
+
.. code-block:: python
|
|
103
|
+
|
|
104
|
+
>>> # create an account
|
|
105
|
+
>>> account = convex.create_account(key_pair)
|
|
106
|
+
>>> # sign a given hash
|
|
107
|
+
>>> sig = account.sign('7e2f1062f5fc51ed65a28b5945b49425aa42df6b7e67107efec357794096e05e')
|
|
108
|
+
>>> print(sig)
|
|
109
|
+
'5d41b964c63d1087ad66e58f4f9d3fe2b7bd0560b..'
|
|
110
|
+
|
|
111
|
+
"""
|
|
112
|
+
return self._key_pair.sign(hash_text)
|
|
113
|
+
|
|
114
|
+
def __str__(self):
|
|
115
|
+
return f'Account {self.address}:{self.key_pair.public_key}'
|
|
116
|
+
|
|
117
|
+
@property
|
|
118
|
+
def address(self) -> int:
|
|
119
|
+
"""
|
|
120
|
+
|
|
121
|
+
:returns: the network account address
|
|
122
|
+
:rtype: int
|
|
123
|
+
|
|
124
|
+
.. code-block:: python
|
|
125
|
+
|
|
126
|
+
>>> # create an account with the network
|
|
127
|
+
>>> key_pair = KeyPair()
|
|
128
|
+
>>> account = convex.create_account(key_pair)
|
|
129
|
+
>>> print(account.address)
|
|
130
|
+
42
|
|
131
|
+
|
|
132
|
+
"""
|
|
133
|
+
return self._address
|
|
134
|
+
|
|
135
|
+
@address.setter
|
|
136
|
+
def address(self, value: Account | int | str) -> None:
|
|
137
|
+
"""
|
|
138
|
+
|
|
139
|
+
Sets the network address of this account
|
|
140
|
+
|
|
141
|
+
:param value: Address to use for this account
|
|
142
|
+
:type value: str, int
|
|
143
|
+
|
|
144
|
+
.. code-block:: python
|
|
145
|
+
|
|
146
|
+
>>> # import the account keys
|
|
147
|
+
>>> key_pair = KeyPair.import_from_mnemonic('my private key words ..')
|
|
148
|
+
|
|
149
|
+
>>> account = convex.create_account(key_pair)
|
|
150
|
+
>>> # set the address that was given to us when we created the account on the network
|
|
151
|
+
>>> account.address = 42
|
|
152
|
+
|
|
153
|
+
"""
|
|
154
|
+
self._address = Account.to_address(value)
|
|
155
|
+
|
|
156
|
+
@property
|
|
157
|
+
def name(self) -> str | None:
|
|
158
|
+
return self._name
|
|
159
|
+
|
|
160
|
+
@name.setter
|
|
161
|
+
def name(self, value: str) -> None:
|
|
162
|
+
self._name = value
|
|
163
|
+
|
|
164
|
+
@property
|
|
165
|
+
def public_key(self) -> bytes:
|
|
166
|
+
"""
|
|
167
|
+
|
|
168
|
+
Return the public key of the account in the format '0x....'
|
|
169
|
+
|
|
170
|
+
:returns: public_key with leading '0x'
|
|
171
|
+
:rtype: str
|
|
172
|
+
|
|
173
|
+
.. code-block:: python
|
|
174
|
+
|
|
175
|
+
>>> # create an account with the network
|
|
176
|
+
>>> account = convex.create_account(key_pair)
|
|
177
|
+
|
|
178
|
+
>>> # show the public key as a hex string
|
|
179
|
+
>>> print(account.public_key)
|
|
180
|
+
0x36d8c5c40dbe2d1b0131acf41c38b9d37ebe04d85...
|
|
181
|
+
|
|
182
|
+
"""
|
|
183
|
+
return self._key_pair.public_key_bytes
|
|
184
|
+
|
|
185
|
+
@property
|
|
186
|
+
def key_pair(self) -> KeyPair:
|
|
187
|
+
"""
|
|
188
|
+
|
|
189
|
+
Return the internal KeyPair object for this account
|
|
190
|
+
|
|
191
|
+
"""
|
|
192
|
+
return self._key_pair
|
convex_sdk/contract.py
ADDED
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
"""
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
Convex Contract
|
|
5
|
+
|
|
6
|
+
"""
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from typing import TYPE_CHECKING
|
|
10
|
+
|
|
11
|
+
if TYPE_CHECKING:
|
|
12
|
+
from convex_sdk.convex import Convex
|
|
13
|
+
|
|
14
|
+
import re
|
|
15
|
+
|
|
16
|
+
from convex_sdk.account import Account
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class Contract:
|
|
20
|
+
def __init__(self, convex: Convex):
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
Contract class to provide access and name resolution to deployed convex contracts.
|
|
24
|
+
|
|
25
|
+
"""
|
|
26
|
+
self._convex = convex
|
|
27
|
+
self._name = None
|
|
28
|
+
self._address = None
|
|
29
|
+
self._owner_address = None
|
|
30
|
+
|
|
31
|
+
def load(
|
|
32
|
+
self,
|
|
33
|
+
name: str | None = None,
|
|
34
|
+
address: Account | int | str | None = None,
|
|
35
|
+
owner_address: Account | int | str | None = None
|
|
36
|
+
):
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
Load a contract details using it's registered name or directly using it's known address.
|
|
40
|
+
|
|
41
|
+
:param str name: Name of the contract that has been registered.
|
|
42
|
+
If provided the address and owner_address of the registration is stored within this object
|
|
43
|
+
|
|
44
|
+
:param str, int, Account address: Address of the contract, if the name is not known,
|
|
45
|
+
then you can provide the actual address of the contract.
|
|
46
|
+
|
|
47
|
+
:param str, int, Account owner_address: If the contract is registered the owner address of the registration.
|
|
48
|
+
|
|
49
|
+
:returns int The address of the resolved contract
|
|
50
|
+
|
|
51
|
+
"""
|
|
52
|
+
if name:
|
|
53
|
+
address = self.resolve_address(name)
|
|
54
|
+
owner_address = self.resolve_owner_address(name)
|
|
55
|
+
self._name = name
|
|
56
|
+
|
|
57
|
+
if address is None:
|
|
58
|
+
raise ValueError('no contract found')
|
|
59
|
+
|
|
60
|
+
if owner_address is None:
|
|
61
|
+
owner_address = address
|
|
62
|
+
|
|
63
|
+
self._address = Account.to_address(address)
|
|
64
|
+
self._owner_address = Account.to_address(owner_address)
|
|
65
|
+
return self._address
|
|
66
|
+
|
|
67
|
+
def deploy(
|
|
68
|
+
self,
|
|
69
|
+
account: Account,
|
|
70
|
+
text: str | None = None,
|
|
71
|
+
filename: str | None = None,
|
|
72
|
+
name: str | None = None,
|
|
73
|
+
owner_account: Account | None = None
|
|
74
|
+
):
|
|
75
|
+
"""
|
|
76
|
+
|
|
77
|
+
Deploy a new/updated contract on the Convex network.
|
|
78
|
+
|
|
79
|
+
:param Account account: Account to use to deploy the contract
|
|
80
|
+
|
|
81
|
+
:param str text: Contract text to deploy
|
|
82
|
+
|
|
83
|
+
:param str filename: Filename of the contract to deploy
|
|
84
|
+
|
|
85
|
+
:param str name: Name of the contract to register
|
|
86
|
+
|
|
87
|
+
:param Account owner_account: Optional owner account of the registration.
|
|
88
|
+
If not provided then the Account will be used.
|
|
89
|
+
|
|
90
|
+
:returns Address of the new contract
|
|
91
|
+
|
|
92
|
+
"""
|
|
93
|
+
if filename:
|
|
94
|
+
with open(filename, 'r') as fp:
|
|
95
|
+
text = fp.read()
|
|
96
|
+
if text is None:
|
|
97
|
+
raise ValueError('You need to provide a contract filename or text to deploy')
|
|
98
|
+
deploy_line = f"""
|
|
99
|
+
(deploy
|
|
100
|
+
(quote
|
|
101
|
+
(do
|
|
102
|
+
{text}
|
|
103
|
+
)
|
|
104
|
+
)
|
|
105
|
+
)
|
|
106
|
+
"""
|
|
107
|
+
result = self._convex.transact(deploy_line, account)
|
|
108
|
+
if result is not None and result.value:
|
|
109
|
+
address = Account.to_address(result.value)
|
|
110
|
+
if name:
|
|
111
|
+
if owner_account is None:
|
|
112
|
+
owner_account = account
|
|
113
|
+
self._convex.registry.register(name, address, owner_account)
|
|
114
|
+
return address
|
|
115
|
+
|
|
116
|
+
def register_contract_name(self, name: str, address: int, account: Account):
|
|
117
|
+
"""
|
|
118
|
+
|
|
119
|
+
Register a contract address with a resolvable name. This name can be used on the Convex network to resolve
|
|
120
|
+
to the contract address.
|
|
121
|
+
|
|
122
|
+
:param str name: Name to register.
|
|
123
|
+
|
|
124
|
+
:param str, int, Account address: Address to use to assign with the name.
|
|
125
|
+
|
|
126
|
+
:param Account account: Account who owns the registration.
|
|
127
|
+
|
|
128
|
+
:returns Result from the register transaction
|
|
129
|
+
|
|
130
|
+
"""
|
|
131
|
+
return self._convex.registry.register(name, address, account)
|
|
132
|
+
|
|
133
|
+
def transact(self, transaction: str, account: Account):
|
|
134
|
+
"""
|
|
135
|
+
|
|
136
|
+
Submit a transaction to the contract. You need to run `load` before calling this method.
|
|
137
|
+
|
|
138
|
+
:param str transaction: Transaction to submit to the contract.
|
|
139
|
+
|
|
140
|
+
:param Account account: Account to pay for the transaction.
|
|
141
|
+
|
|
142
|
+
:returns The transaction result.
|
|
143
|
+
|
|
144
|
+
"""
|
|
145
|
+
if not self._address:
|
|
146
|
+
raise ValueError(f'No contract address found for {self._name}')
|
|
147
|
+
return self._convex.transact(f'(call #{self._address} {transaction})', account)
|
|
148
|
+
|
|
149
|
+
def query(self, transaction: str, account_address: Account | int | str | None = None):
|
|
150
|
+
"""
|
|
151
|
+
|
|
152
|
+
Sends a query to the contract.
|
|
153
|
+
|
|
154
|
+
:param str transaction: The transaction query to send to the contract
|
|
155
|
+
|
|
156
|
+
:param str, int, Account account_address: The address to provide as the sender for this query.
|
|
157
|
+
|
|
158
|
+
:returns The query result
|
|
159
|
+
|
|
160
|
+
"""
|
|
161
|
+
if not self._address:
|
|
162
|
+
raise ValueError(f'No contract address found for {self._name}')
|
|
163
|
+
if account_address is not None:
|
|
164
|
+
account_address = Account.to_address(account_address)
|
|
165
|
+
if account_address is None:
|
|
166
|
+
account_address = self._address
|
|
167
|
+
return self._convex.query(f'(call #{self._address} {transaction})', account_address)
|
|
168
|
+
|
|
169
|
+
def resolve_address(self, name: str):
|
|
170
|
+
"""
|
|
171
|
+
|
|
172
|
+
Return an address from a registered name.
|
|
173
|
+
|
|
174
|
+
"""
|
|
175
|
+
return self._convex.registry.resolve_address(name)
|
|
176
|
+
|
|
177
|
+
def resolve_owner_address(self, name: str):
|
|
178
|
+
"""
|
|
179
|
+
|
|
180
|
+
Returns the register owner of a registered name.
|
|
181
|
+
|
|
182
|
+
"""
|
|
183
|
+
return self._convex.registry.resolve_owner(name)
|
|
184
|
+
|
|
185
|
+
@property
|
|
186
|
+
def is_registered(self) -> bool:
|
|
187
|
+
return self._address is not None
|
|
188
|
+
|
|
189
|
+
@property
|
|
190
|
+
def address(self):
|
|
191
|
+
return self._address
|
|
192
|
+
|
|
193
|
+
@property
|
|
194
|
+
def owner_address(self):
|
|
195
|
+
return self._owner_address
|
|
196
|
+
|
|
197
|
+
@property
|
|
198
|
+
def name(self):
|
|
199
|
+
return self._name
|
|
200
|
+
|
|
201
|
+
@staticmethod
|
|
202
|
+
def escape_string(text: str) -> str:
|
|
203
|
+
"""
|
|
204
|
+
Escape any string and replace quote chars with leading escape chars
|
|
205
|
+
|
|
206
|
+
"""
|
|
207
|
+
escape_text = re.sub('\\\\', '\\\\\\\\', text)
|
|
208
|
+
escape_text = re.sub('"', '\\"', escape_text)
|
|
209
|
+
escape_text = re.sub('\n', '\\\\n', escape_text)
|
|
210
|
+
escape_text = re.sub('\t', '\\\\t', escape_text)
|
|
211
|
+
return escape_text
|