symbol-sdk-python 3.3.1__tar.gz → 3.3.2__tar.gz
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.
- {symbol_sdk_python-3.3.1 → symbol_sdk_python-3.3.2}/PKG-INFO +2 -2
- {symbol_sdk_python-3.3.1 → symbol_sdk_python-3.3.2}/README.md +102 -102
- {symbol_sdk_python-3.3.1 → symbol_sdk_python-3.3.2}/pyproject.toml +2 -2
- {symbol_sdk_python-3.3.1 → symbol_sdk_python-3.3.2}/symbolchain/ArrayHelpers.py +116 -116
- {symbol_sdk_python-3.3.1 → symbol_sdk_python-3.3.2}/symbolchain/RuleBasedTransactionFactory.py +12 -1
- symbol_sdk_python-3.3.2/symbolchain/nem/FeeCalculator.py +94 -0
- {symbol_sdk_python-3.3.1 → symbol_sdk_python-3.3.2}/symbolchain/nem/TransactionFactory.py +0 -4
- symbol_sdk_python-3.3.2/symbolchain/symbol/FeeCalculator.py +7 -0
- {symbol_sdk_python-3.3.1 → symbol_sdk_python-3.3.2}/symbolchain/AccountDescriptorRepository.py +0 -0
- {symbol_sdk_python-3.3.1 → symbol_sdk_python-3.3.2}/symbolchain/BaseValue.py +0 -0
- {symbol_sdk_python-3.3.1 → symbol_sdk_python-3.3.2}/symbolchain/Bip32.py +0 -0
- {symbol_sdk_python-3.3.1 → symbol_sdk_python-3.3.2}/symbolchain/BlockchainSettings.py +0 -0
- {symbol_sdk_python-3.3.1 → symbol_sdk_python-3.3.2}/symbolchain/BufferReader.py +0 -0
- {symbol_sdk_python-3.3.1 → symbol_sdk_python-3.3.2}/symbolchain/BufferWriter.py +0 -0
- {symbol_sdk_python-3.3.1 → symbol_sdk_python-3.3.2}/symbolchain/ByteArray.py +0 -0
- {symbol_sdk_python-3.3.1 → symbol_sdk_python-3.3.2}/symbolchain/Cipher.py +0 -0
- {symbol_sdk_python-3.3.1 → symbol_sdk_python-3.3.2}/symbolchain/CodeWordsEncoder.py +0 -0
- {symbol_sdk_python-3.3.1 → symbol_sdk_python-3.3.2}/symbolchain/CryptoTypes.py +0 -0
- {symbol_sdk_python-3.3.1 → symbol_sdk_python-3.3.2}/symbolchain/DiceMnemonicGenerator.py +0 -0
- {symbol_sdk_python-3.3.1 → symbol_sdk_python-3.3.2}/symbolchain/Network.py +0 -0
- {symbol_sdk_python-3.3.1 → symbol_sdk_python-3.3.2}/symbolchain/NetworkTimestamp.py +0 -0
- {symbol_sdk_python-3.3.1 → symbol_sdk_python-3.3.2}/symbolchain/NodeDescriptorRepository.py +0 -0
- {symbol_sdk_python-3.3.1 → symbol_sdk_python-3.3.2}/symbolchain/Ordered.py +0 -0
- {symbol_sdk_python-3.3.1 → symbol_sdk_python-3.3.2}/symbolchain/PrivateKeyStorage.py +0 -0
- {symbol_sdk_python-3.3.1 → symbol_sdk_python-3.3.2}/symbolchain/QrSignatureStorage.py +0 -0
- {symbol_sdk_python-3.3.1 → symbol_sdk_python-3.3.2}/symbolchain/QrStorage.py +0 -0
- {symbol_sdk_python-3.3.1 → symbol_sdk_python-3.3.2}/symbolchain/SharedKey.py +0 -0
- {symbol_sdk_python-3.3.1 → symbol_sdk_python-3.3.2}/symbolchain/TransactionDescriptorProcessor.py +0 -0
- {symbol_sdk_python-3.3.1 → symbol_sdk_python-3.3.2}/symbolchain/Transforms.py +0 -0
- {symbol_sdk_python-3.3.1 → symbol_sdk_python-3.3.2}/symbolchain/__init__.py +0 -0
- {symbol_sdk_python-3.3.1 → symbol_sdk_python-3.3.2}/symbolchain/external/__init__.py +0 -0
- {symbol_sdk_python-3.3.1 → symbol_sdk_python-3.3.2}/symbolchain/external/ed25519.py +0 -0
- {symbol_sdk_python-3.3.1 → symbol_sdk_python-3.3.2}/symbolchain/facade/BatchOperations.py +0 -0
- {symbol_sdk_python-3.3.1 → symbol_sdk_python-3.3.2}/symbolchain/facade/NemFacade.py +0 -0
- {symbol_sdk_python-3.3.1 → symbol_sdk_python-3.3.2}/symbolchain/facade/SymbolFacade.py +0 -0
- {symbol_sdk_python-3.3.1 → symbol_sdk_python-3.3.2}/symbolchain/facade/__init__.py +0 -0
- {symbol_sdk_python-3.3.1 → symbol_sdk_python-3.3.2}/symbolchain/impl/CipherHelpers.py +0 -0
- {symbol_sdk_python-3.3.1 → symbol_sdk_python-3.3.2}/symbolchain/impl/__init__.py +0 -0
- {symbol_sdk_python-3.3.1 → symbol_sdk_python-3.3.2}/symbolchain/nc/__init__.py +0 -0
- {symbol_sdk_python-3.3.1 → symbol_sdk_python-3.3.2}/symbolchain/nem/KeyPair.py +0 -0
- {symbol_sdk_python-3.3.1 → symbol_sdk_python-3.3.2}/symbolchain/nem/MessageEncoder.py +0 -0
- {symbol_sdk_python-3.3.1 → symbol_sdk_python-3.3.2}/symbolchain/nem/Network.py +0 -0
- {symbol_sdk_python-3.3.1 → symbol_sdk_python-3.3.2}/symbolchain/nem/SharedKey.py +0 -0
- {symbol_sdk_python-3.3.1 → symbol_sdk_python-3.3.2}/symbolchain/nem/__init__.py +0 -0
- {symbol_sdk_python-3.3.1 → symbol_sdk_python-3.3.2}/symbolchain/ripemd160.py +0 -0
- {symbol_sdk_python-3.3.1 → symbol_sdk_python-3.3.2}/symbolchain/sc/__init__.py +0 -0
- {symbol_sdk_python-3.3.1 → symbol_sdk_python-3.3.2}/symbolchain/symbol/IdGenerator.py +0 -0
- {symbol_sdk_python-3.3.1 → symbol_sdk_python-3.3.2}/symbolchain/symbol/KeyPair.py +0 -0
- {symbol_sdk_python-3.3.1 → symbol_sdk_python-3.3.2}/symbolchain/symbol/Merkle.py +0 -0
- {symbol_sdk_python-3.3.1 → symbol_sdk_python-3.3.2}/symbolchain/symbol/MessageEncoder.py +0 -0
- {symbol_sdk_python-3.3.1 → symbol_sdk_python-3.3.2}/symbolchain/symbol/Metadata.py +0 -0
- {symbol_sdk_python-3.3.1 → symbol_sdk_python-3.3.2}/symbolchain/symbol/Network.py +0 -0
- {symbol_sdk_python-3.3.1 → symbol_sdk_python-3.3.2}/symbolchain/symbol/Restriction.py +0 -0
- {symbol_sdk_python-3.3.1 → symbol_sdk_python-3.3.2}/symbolchain/symbol/SharedKey.py +0 -0
- {symbol_sdk_python-3.3.1 → symbol_sdk_python-3.3.2}/symbolchain/symbol/TransactionFactory.py +0 -0
- {symbol_sdk_python-3.3.1 → symbol_sdk_python-3.3.2}/symbolchain/symbol/VotingKeysGenerator.py +0 -0
- {symbol_sdk_python-3.3.1 → symbol_sdk_python-3.3.2}/symbolchain/symbol/__init__.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: symbol-sdk-python
|
|
3
|
-
Version: 3.3.
|
|
3
|
+
Version: 3.3.2
|
|
4
4
|
Summary: Symbol SDK
|
|
5
5
|
Home-page: https://github.com/symbol/symbol/tree/main/sdk/python
|
|
6
6
|
License: MIT
|
|
@@ -17,7 +17,7 @@ Classifier: Programming Language :: Python :: 3.11
|
|
|
17
17
|
Classifier: Programming Language :: Python :: 3.12
|
|
18
18
|
Classifier: Programming Language :: Python :: 3.13
|
|
19
19
|
Classifier: Programming Language :: Python :: 3.14
|
|
20
|
-
Requires-Dist: cryptography (>=
|
|
20
|
+
Requires-Dist: cryptography (>=49.0.0,<49.1.0)
|
|
21
21
|
Requires-Dist: mnemonic (>=0.20,<1.0)
|
|
22
22
|
Requires-Dist: pillow (>=12.2.0,<12.3.0)
|
|
23
23
|
Requires-Dist: pynacl (>=1.6.0,<1.7.0)
|
|
@@ -1,102 +1,102 @@
|
|
|
1
|
-
# Symbol-SDK
|
|
2
|
-
|
|
3
|
-
[![lint][sdk-python-lint]][sdk-python-job] [![test][sdk-python-test]][sdk-python-job] [![vectors][sdk-python-vectors]][sdk-python-job] [![][sdk-python-cov]][sdk-python-cov-link] [![][sdk-python-package]][sdk-python-package-link]
|
|
4
|
-
|
|
5
|
-
[sdk-python-job]: https://jenkins.symbolsyndicate.us/blue/organizations/jenkins/Symbol%2Fgenerated%2Fsymbol%2Fpython/activity?branch=dev
|
|
6
|
-
[sdk-python-lint]: https://jenkins.symbolsyndicate.us/buildStatus/icon?job=Symbol%2Fgenerated%2Fsymbol%2Fpython%2Fdev%2F&config=sdk-python-lint
|
|
7
|
-
[sdk-python-build]: https://jenkins.symbolsyndicate.us/buildStatus/icon?job=Symbol%2Fgenerated%2Fsymbol%2Fpython%2Fdev%2F&config=sdk-python-build
|
|
8
|
-
[sdk-python-test]: https://jenkins.symbolsyndicate.us/buildStatus/icon?job=Symbol%2Fgenerated%2Fsymbol%2Fpython%2Fdev%2F&config=sdk-python-test
|
|
9
|
-
[sdk-python-examples]: https://jenkins.symbolsyndicate.us/buildStatus/icon?job=Symbol%2Fgenerated%2Fsymbol%2Fpython%2Fdev%2F&config=sdk-python-examples
|
|
10
|
-
[sdk-python-vectors]: https://jenkins.symbolsyndicate.us/buildStatus/icon?job=Symbol%2Fgenerated%2Fsymbol%2Fpython%2Fdev%2F&config=sdk-python-vectors
|
|
11
|
-
[sdk-python-cov]: https://codecov.io/gh/symbol/symbol/branch/dev/graph/badge.svg?token=SSYYBMK0M7&flag=sdk-python
|
|
12
|
-
[sdk-python-cov-link]: https://codecov.io/gh/symbol/symbol/tree/dev/sdk/python
|
|
13
|
-
[sdk-python-package]: https://img.shields.io/pypi/v/symbol-sdk-python
|
|
14
|
-
[sdk-python-package-link]: https://pypi.org/project/symbol-sdk-python
|
|
15
|
-
|
|
16
|
-
Python SDK for interacting with the Symbol and NEM blockchains.
|
|
17
|
-
|
|
18
|
-
Most common functionality is grouped under facades so that the same programming paradigm can be used for interacting with both Symbol and NEM.
|
|
19
|
-
|
|
20
|
-
## Sending a Transaction
|
|
21
|
-
|
|
22
|
-
To send a transaction, first create a facade for the desired network:
|
|
23
|
-
|
|
24
|
-
_Symbol_
|
|
25
|
-
```python
|
|
26
|
-
from symbolchain.CryptoTypes import PrivateKey
|
|
27
|
-
from symbolchain.facade.SymbolFacade import SymbolFacade
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
facade = SymbolFacade('testnet')
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
_NEM_
|
|
34
|
-
```python
|
|
35
|
-
from symbolchain.CryptoTypes import PrivateKey
|
|
36
|
-
from symbolchain.facade.NemFacade import NemFacade
|
|
37
|
-
|
|
38
|
-
facade = NemFacade('testnet')
|
|
39
|
-
````
|
|
40
|
-
|
|
41
|
-
Second, describe the transaction using a Python dictionary. For example, a transfer transaction can be described as follows:
|
|
42
|
-
|
|
43
|
-
_Symbol_
|
|
44
|
-
```python
|
|
45
|
-
transaction = facade.transaction_factory.create({
|
|
46
|
-
'type': 'transfer_transaction_v1',
|
|
47
|
-
'signer_public_key': '87DA603E7BE5656C45692D5FC7F6D0EF8F24BB7A5C10ED5FDA8C5CFBC49FCBC8',
|
|
48
|
-
'fee': 1000000,
|
|
49
|
-
'deadline': 41998024783,
|
|
50
|
-
'recipient_address': 'TCHBDENCLKEBILBPWP3JPB2XNY64OE7PYHHE32I',
|
|
51
|
-
'mosaics': [
|
|
52
|
-
{'mosaic_id': 0x7CDF3B117A3C40CC, 'amount': 1000000}
|
|
53
|
-
]
|
|
54
|
-
})
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
_NEM_
|
|
58
|
-
```python
|
|
59
|
-
transaction = facade.transaction_factory.create({
|
|
60
|
-
'type': 'transfer_transaction_v1',
|
|
61
|
-
'signer_public_key': 'A59277D56E9F4FA46854F5EFAAA253B09F8AE69A473565E01FD9E6A738E4AB74',
|
|
62
|
-
'fee': 0x186A0,
|
|
63
|
-
'timestamp': 191205516,
|
|
64
|
-
'deadline': 191291916,
|
|
65
|
-
'recipient_address': 'TALICE5VF6J5FYMTCB7A3QG6OIRDRUXDWJGFVXNW',
|
|
66
|
-
'amount': 5100000
|
|
67
|
-
})
|
|
68
|
-
````
|
|
69
|
-
|
|
70
|
-
Third, sign the transaction and attach the signature:
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
```python
|
|
74
|
-
private_key = PrivateKey('EDB671EB741BD676969D8A035271D1EE5E75DF33278083D877F23615EB839FEC')
|
|
75
|
-
signature = facade.sign_transaction(facade.KeyPair(private_key), transaction)
|
|
76
|
-
|
|
77
|
-
json_payload = facade.transaction_factory.attach_signature(transaction, signature)
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
Finally, send the payload to the desired network using the specified node endpoint:
|
|
81
|
-
|
|
82
|
-
_Symbol_: PUT `/transactions`
|
|
83
|
-
<br>
|
|
84
|
-
_NEM_: POST `/transaction/announce`
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
## NEM Cheat Sheet
|
|
88
|
-
|
|
89
|
-
In order to simplify the learning curve for NEM and Symbol usage, the SDK uses Symbol terminology for shared Symbol and NEM concepts.
|
|
90
|
-
Where appropriate, NEM terminology is replaced with Symbol terminology, including the names of many of the NEM transactions.
|
|
91
|
-
The mapping of NEM transactions to SDK descriptors can be found in the following table:
|
|
92
|
-
|
|
93
|
-
| NEM name (used in docs) | SDK descriptor name|
|
|
94
|
-
|--- |--- |
|
|
95
|
-
| ImportanceTransfer transaction | `account_key_link_transaction_v1` |
|
|
96
|
-
| MosaicDefinitionCreation transaction | `mosaic_definition_transaction_v1` |
|
|
97
|
-
| MosaicSupplyChange transaction | `mosaic_supply_change_transaction_v1` |
|
|
98
|
-
| MultisigAggregateModification transaction | `multisig_account_modification_transaction_v1`<br>`multisig_account_modification_transaction_v2` |
|
|
99
|
-
| MultisigSignature transaction or Cosignature transaction | `cosignature_v1` |
|
|
100
|
-
| Multisig transaction | `multisig_transaction_v1` |
|
|
101
|
-
| ProvisionNamespace transaction | `namespace_registration_transaction_v1` |
|
|
102
|
-
| Transfer transaction | `transfer_transaction_v1`<br>`transfer_transaction_v2` |
|
|
1
|
+
# Symbol-SDK
|
|
2
|
+
|
|
3
|
+
[![lint][sdk-python-lint]][sdk-python-job] [![test][sdk-python-test]][sdk-python-job] [![vectors][sdk-python-vectors]][sdk-python-job] [![][sdk-python-cov]][sdk-python-cov-link] [![][sdk-python-package]][sdk-python-package-link]
|
|
4
|
+
|
|
5
|
+
[sdk-python-job]: https://jenkins.symbolsyndicate.us/blue/organizations/jenkins/Symbol%2Fgenerated%2Fsymbol%2Fpython/activity?branch=dev
|
|
6
|
+
[sdk-python-lint]: https://jenkins.symbolsyndicate.us/buildStatus/icon?job=Symbol%2Fgenerated%2Fsymbol%2Fpython%2Fdev%2F&config=sdk-python-lint
|
|
7
|
+
[sdk-python-build]: https://jenkins.symbolsyndicate.us/buildStatus/icon?job=Symbol%2Fgenerated%2Fsymbol%2Fpython%2Fdev%2F&config=sdk-python-build
|
|
8
|
+
[sdk-python-test]: https://jenkins.symbolsyndicate.us/buildStatus/icon?job=Symbol%2Fgenerated%2Fsymbol%2Fpython%2Fdev%2F&config=sdk-python-test
|
|
9
|
+
[sdk-python-examples]: https://jenkins.symbolsyndicate.us/buildStatus/icon?job=Symbol%2Fgenerated%2Fsymbol%2Fpython%2Fdev%2F&config=sdk-python-examples
|
|
10
|
+
[sdk-python-vectors]: https://jenkins.symbolsyndicate.us/buildStatus/icon?job=Symbol%2Fgenerated%2Fsymbol%2Fpython%2Fdev%2F&config=sdk-python-vectors
|
|
11
|
+
[sdk-python-cov]: https://codecov.io/gh/symbol/symbol/branch/dev/graph/badge.svg?token=SSYYBMK0M7&flag=sdk-python
|
|
12
|
+
[sdk-python-cov-link]: https://codecov.io/gh/symbol/symbol/tree/dev/sdk/python
|
|
13
|
+
[sdk-python-package]: https://img.shields.io/pypi/v/symbol-sdk-python
|
|
14
|
+
[sdk-python-package-link]: https://pypi.org/project/symbol-sdk-python
|
|
15
|
+
|
|
16
|
+
Python SDK for interacting with the Symbol and NEM blockchains.
|
|
17
|
+
|
|
18
|
+
Most common functionality is grouped under facades so that the same programming paradigm can be used for interacting with both Symbol and NEM.
|
|
19
|
+
|
|
20
|
+
## Sending a Transaction
|
|
21
|
+
|
|
22
|
+
To send a transaction, first create a facade for the desired network:
|
|
23
|
+
|
|
24
|
+
_Symbol_
|
|
25
|
+
```python
|
|
26
|
+
from symbolchain.CryptoTypes import PrivateKey
|
|
27
|
+
from symbolchain.facade.SymbolFacade import SymbolFacade
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
facade = SymbolFacade('testnet')
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
_NEM_
|
|
34
|
+
```python
|
|
35
|
+
from symbolchain.CryptoTypes import PrivateKey
|
|
36
|
+
from symbolchain.facade.NemFacade import NemFacade
|
|
37
|
+
|
|
38
|
+
facade = NemFacade('testnet')
|
|
39
|
+
````
|
|
40
|
+
|
|
41
|
+
Second, describe the transaction using a Python dictionary. For example, a transfer transaction can be described as follows:
|
|
42
|
+
|
|
43
|
+
_Symbol_
|
|
44
|
+
```python
|
|
45
|
+
transaction = facade.transaction_factory.create({
|
|
46
|
+
'type': 'transfer_transaction_v1',
|
|
47
|
+
'signer_public_key': '87DA603E7BE5656C45692D5FC7F6D0EF8F24BB7A5C10ED5FDA8C5CFBC49FCBC8',
|
|
48
|
+
'fee': 1000000,
|
|
49
|
+
'deadline': 41998024783,
|
|
50
|
+
'recipient_address': 'TCHBDENCLKEBILBPWP3JPB2XNY64OE7PYHHE32I',
|
|
51
|
+
'mosaics': [
|
|
52
|
+
{'mosaic_id': 0x7CDF3B117A3C40CC, 'amount': 1000000}
|
|
53
|
+
]
|
|
54
|
+
})
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
_NEM_
|
|
58
|
+
```python
|
|
59
|
+
transaction = facade.transaction_factory.create({
|
|
60
|
+
'type': 'transfer_transaction_v1',
|
|
61
|
+
'signer_public_key': 'A59277D56E9F4FA46854F5EFAAA253B09F8AE69A473565E01FD9E6A738E4AB74',
|
|
62
|
+
'fee': 0x186A0,
|
|
63
|
+
'timestamp': 191205516,
|
|
64
|
+
'deadline': 191291916,
|
|
65
|
+
'recipient_address': 'TALICE5VF6J5FYMTCB7A3QG6OIRDRUXDWJGFVXNW',
|
|
66
|
+
'amount': 5100000
|
|
67
|
+
})
|
|
68
|
+
````
|
|
69
|
+
|
|
70
|
+
Third, sign the transaction and attach the signature:
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
private_key = PrivateKey('EDB671EB741BD676969D8A035271D1EE5E75DF33278083D877F23615EB839FEC')
|
|
75
|
+
signature = facade.sign_transaction(facade.KeyPair(private_key), transaction)
|
|
76
|
+
|
|
77
|
+
json_payload = facade.transaction_factory.attach_signature(transaction, signature)
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Finally, send the payload to the desired network using the specified node endpoint:
|
|
81
|
+
|
|
82
|
+
_Symbol_: PUT `/transactions`
|
|
83
|
+
<br>
|
|
84
|
+
_NEM_: POST `/transaction/announce`
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
## NEM Cheat Sheet
|
|
88
|
+
|
|
89
|
+
In order to simplify the learning curve for NEM and Symbol usage, the SDK uses Symbol terminology for shared Symbol and NEM concepts.
|
|
90
|
+
Where appropriate, NEM terminology is replaced with Symbol terminology, including the names of many of the NEM transactions.
|
|
91
|
+
The mapping of NEM transactions to SDK descriptors can be found in the following table:
|
|
92
|
+
|
|
93
|
+
| NEM name (used in docs) | SDK descriptor name|
|
|
94
|
+
|--- |--- |
|
|
95
|
+
| ImportanceTransfer transaction | `account_key_link_transaction_v1` |
|
|
96
|
+
| MosaicDefinitionCreation transaction | `mosaic_definition_transaction_v1` |
|
|
97
|
+
| MosaicSupplyChange transaction | `mosaic_supply_change_transaction_v1` |
|
|
98
|
+
| MultisigAggregateModification transaction | `multisig_account_modification_transaction_v1`<br>`multisig_account_modification_transaction_v2` |
|
|
99
|
+
| MultisigSignature transaction or Cosignature transaction | `cosignature_v1` |
|
|
100
|
+
| Multisig transaction | `multisig_transaction_v1` |
|
|
101
|
+
| ProvisionNamespace transaction | `namespace_registration_transaction_v1` |
|
|
102
|
+
| Transfer transaction | `transfer_transaction_v1`<br>`transfer_transaction_v2` |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = 'symbol-sdk-python'
|
|
3
|
-
version = '3.3.
|
|
3
|
+
version = '3.3.2'
|
|
4
4
|
description = 'Symbol SDK'
|
|
5
5
|
authors = ['Symbol Contributors <contributors@symbol.dev>']
|
|
6
6
|
maintainers = ['Symbol Contributors <contributors@symbol.dev>']
|
|
@@ -18,7 +18,7 @@ classifiers = ['Programming Language :: Python :: 3.10', 'Programming Language :
|
|
|
18
18
|
|
|
19
19
|
[tool.poetry.dependencies]
|
|
20
20
|
python = "^3.10"
|
|
21
|
-
cryptography = ">=
|
|
21
|
+
cryptography = ">=49.0.0,<49.1.0"
|
|
22
22
|
mnemonic = ">=0.20,<1.0"
|
|
23
23
|
pillow = ">=12.2.0,<12.3.0"
|
|
24
24
|
pynacl = ">=1.6.0,<1.7.0"
|
|
@@ -1,116 +1,116 @@
|
|
|
1
|
-
def read_array_impl(view, factory_class, accessor, should_continue):
|
|
2
|
-
elements = []
|
|
3
|
-
previous_element = None
|
|
4
|
-
|
|
5
|
-
i = 0
|
|
6
|
-
while should_continue(i, view):
|
|
7
|
-
element = factory_class.deserialize(view)
|
|
8
|
-
|
|
9
|
-
if element.size <= 0:
|
|
10
|
-
raise ValueError('element size has invalid size')
|
|
11
|
-
|
|
12
|
-
if accessor and previous_element and accessor(previous_element) >= accessor(element):
|
|
13
|
-
raise ValueError('elements in array are not sorted')
|
|
14
|
-
|
|
15
|
-
elements.append(element)
|
|
16
|
-
view = view[element.size:]
|
|
17
|
-
|
|
18
|
-
previous_element = element
|
|
19
|
-
i += 1
|
|
20
|
-
|
|
21
|
-
return elements
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
def write_array_impl(elements, count, accessor):
|
|
25
|
-
output_buffer = bytes()
|
|
26
|
-
for i in range(0, count):
|
|
27
|
-
element = elements[i]
|
|
28
|
-
if accessor and i > 0 and accessor(elements[i - 1]) >= accessor(element):
|
|
29
|
-
raise ValueError('array passed to write array is not sorted')
|
|
30
|
-
|
|
31
|
-
output_buffer += element.serialize()
|
|
32
|
-
|
|
33
|
-
return output_buffer
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
class ArrayHelpers:
|
|
37
|
-
@staticmethod
|
|
38
|
-
def get_bytes(view, size):
|
|
39
|
-
"""Returns first size bytes of view."""
|
|
40
|
-
if size > len(view):
|
|
41
|
-
raise ValueError(f'size should not exceed {len(view)}. The value of size was: {size}.')
|
|
42
|
-
|
|
43
|
-
return view[:size].tobytes()
|
|
44
|
-
|
|
45
|
-
@staticmethod
|
|
46
|
-
def align_up(size, alignment):
|
|
47
|
-
"""Calculates aligned size."""
|
|
48
|
-
return (size + alignment - 1) // alignment * alignment
|
|
49
|
-
|
|
50
|
-
@staticmethod
|
|
51
|
-
def size(elements, alignment=0, skip_last_element_padding=False):
|
|
52
|
-
"""Calculates size of variable size objects."""
|
|
53
|
-
if not alignment:
|
|
54
|
-
return sum(map(lambda e: e.size, elements))
|
|
55
|
-
|
|
56
|
-
if not skip_last_element_padding:
|
|
57
|
-
return sum(map(lambda e: ArrayHelpers.align_up(e.size, alignment), elements))
|
|
58
|
-
|
|
59
|
-
return sum(map(lambda e: ArrayHelpers.align_up(e.size, alignment), elements[:-1])) + sum(map(lambda e: e.size, elements[-1:]))
|
|
60
|
-
|
|
61
|
-
@staticmethod
|
|
62
|
-
def read_array(view, factory_class, accessor=None):
|
|
63
|
-
"""Reads array of objects."""
|
|
64
|
-
return read_array_impl(view, factory_class, accessor, lambda _, view: len(view) > 0)
|
|
65
|
-
|
|
66
|
-
@staticmethod
|
|
67
|
-
def read_array_count(view, factory_class, count, accessor=None):
|
|
68
|
-
"""Reads array of deterministic number of objects."""
|
|
69
|
-
return read_array_impl(view, factory_class, accessor, lambda index, _: count > index)
|
|
70
|
-
|
|
71
|
-
@staticmethod
|
|
72
|
-
def read_variable_size_elements(view, factory_class, alignment, skip_last_element_padding=False):
|
|
73
|
-
"""Reads array of variable size objects."""
|
|
74
|
-
elements = []
|
|
75
|
-
while len(view) > 0:
|
|
76
|
-
element = factory_class.deserialize(view)
|
|
77
|
-
|
|
78
|
-
if element.size <= 0:
|
|
79
|
-
raise ValueError('element size has invalid size')
|
|
80
|
-
|
|
81
|
-
elements.append(element)
|
|
82
|
-
|
|
83
|
-
aligned_size = ArrayHelpers.align_up(element.size, alignment)
|
|
84
|
-
if skip_last_element_padding and element.size >= len(view):
|
|
85
|
-
aligned_size = element.size
|
|
86
|
-
|
|
87
|
-
if aligned_size > len(view):
|
|
88
|
-
raise ValueError('unexpected buffer length')
|
|
89
|
-
|
|
90
|
-
view = view[aligned_size:]
|
|
91
|
-
|
|
92
|
-
return elements
|
|
93
|
-
|
|
94
|
-
@staticmethod
|
|
95
|
-
def write_array(elements, accessor=None):
|
|
96
|
-
"""Writes array of objects."""
|
|
97
|
-
return write_array_impl(elements, len(elements), accessor)
|
|
98
|
-
|
|
99
|
-
@staticmethod
|
|
100
|
-
def write_array_count(elements, count, accessor=None):
|
|
101
|
-
"""Writes array of deterministic number of objects."""
|
|
102
|
-
return write_array_impl(elements, count, accessor)
|
|
103
|
-
|
|
104
|
-
@staticmethod
|
|
105
|
-
def write_variable_size_elements(elements, alignment, skip_last_element_padding=False):
|
|
106
|
-
"""Writes array of variable size objects."""
|
|
107
|
-
output_buffer = bytes()
|
|
108
|
-
for index, element in enumerate(elements):
|
|
109
|
-
output_buffer += element.serialize()
|
|
110
|
-
|
|
111
|
-
if not skip_last_element_padding or len(elements) - 1 != index:
|
|
112
|
-
aligned_size = ArrayHelpers.align_up(element.size, alignment)
|
|
113
|
-
if aligned_size != element.size:
|
|
114
|
-
output_buffer += bytes(aligned_size - element.size)
|
|
115
|
-
|
|
116
|
-
return output_buffer
|
|
1
|
+
def read_array_impl(view, factory_class, accessor, should_continue):
|
|
2
|
+
elements = []
|
|
3
|
+
previous_element = None
|
|
4
|
+
|
|
5
|
+
i = 0
|
|
6
|
+
while should_continue(i, view):
|
|
7
|
+
element = factory_class.deserialize(view)
|
|
8
|
+
|
|
9
|
+
if element.size <= 0:
|
|
10
|
+
raise ValueError('element size has invalid size')
|
|
11
|
+
|
|
12
|
+
if accessor and previous_element and accessor(previous_element) >= accessor(element):
|
|
13
|
+
raise ValueError('elements in array are not sorted')
|
|
14
|
+
|
|
15
|
+
elements.append(element)
|
|
16
|
+
view = view[element.size:]
|
|
17
|
+
|
|
18
|
+
previous_element = element
|
|
19
|
+
i += 1
|
|
20
|
+
|
|
21
|
+
return elements
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def write_array_impl(elements, count, accessor):
|
|
25
|
+
output_buffer = bytes()
|
|
26
|
+
for i in range(0, count):
|
|
27
|
+
element = elements[i]
|
|
28
|
+
if accessor and i > 0 and accessor(elements[i - 1]) >= accessor(element):
|
|
29
|
+
raise ValueError('array passed to write array is not sorted')
|
|
30
|
+
|
|
31
|
+
output_buffer += element.serialize()
|
|
32
|
+
|
|
33
|
+
return output_buffer
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class ArrayHelpers:
|
|
37
|
+
@staticmethod
|
|
38
|
+
def get_bytes(view, size):
|
|
39
|
+
"""Returns first size bytes of view."""
|
|
40
|
+
if size > len(view):
|
|
41
|
+
raise ValueError(f'size should not exceed {len(view)}. The value of size was: {size}.')
|
|
42
|
+
|
|
43
|
+
return view[:size].tobytes()
|
|
44
|
+
|
|
45
|
+
@staticmethod
|
|
46
|
+
def align_up(size, alignment):
|
|
47
|
+
"""Calculates aligned size."""
|
|
48
|
+
return (size + alignment - 1) // alignment * alignment
|
|
49
|
+
|
|
50
|
+
@staticmethod
|
|
51
|
+
def size(elements, alignment=0, skip_last_element_padding=False):
|
|
52
|
+
"""Calculates size of variable size objects."""
|
|
53
|
+
if not alignment:
|
|
54
|
+
return sum(map(lambda e: e.size, elements))
|
|
55
|
+
|
|
56
|
+
if not skip_last_element_padding:
|
|
57
|
+
return sum(map(lambda e: ArrayHelpers.align_up(e.size, alignment), elements))
|
|
58
|
+
|
|
59
|
+
return sum(map(lambda e: ArrayHelpers.align_up(e.size, alignment), elements[:-1])) + sum(map(lambda e: e.size, elements[-1:]))
|
|
60
|
+
|
|
61
|
+
@staticmethod
|
|
62
|
+
def read_array(view, factory_class, accessor=None):
|
|
63
|
+
"""Reads array of objects."""
|
|
64
|
+
return read_array_impl(view, factory_class, accessor, lambda _, view: len(view) > 0)
|
|
65
|
+
|
|
66
|
+
@staticmethod
|
|
67
|
+
def read_array_count(view, factory_class, count, accessor=None):
|
|
68
|
+
"""Reads array of deterministic number of objects."""
|
|
69
|
+
return read_array_impl(view, factory_class, accessor, lambda index, _: count > index)
|
|
70
|
+
|
|
71
|
+
@staticmethod
|
|
72
|
+
def read_variable_size_elements(view, factory_class, alignment, skip_last_element_padding=False):
|
|
73
|
+
"""Reads array of variable size objects."""
|
|
74
|
+
elements = []
|
|
75
|
+
while len(view) > 0:
|
|
76
|
+
element = factory_class.deserialize(view)
|
|
77
|
+
|
|
78
|
+
if element.size <= 0:
|
|
79
|
+
raise ValueError('element size has invalid size')
|
|
80
|
+
|
|
81
|
+
elements.append(element)
|
|
82
|
+
|
|
83
|
+
aligned_size = ArrayHelpers.align_up(element.size, alignment)
|
|
84
|
+
if skip_last_element_padding and element.size >= len(view):
|
|
85
|
+
aligned_size = element.size
|
|
86
|
+
|
|
87
|
+
if aligned_size > len(view):
|
|
88
|
+
raise ValueError('unexpected buffer length')
|
|
89
|
+
|
|
90
|
+
view = view[aligned_size:]
|
|
91
|
+
|
|
92
|
+
return elements
|
|
93
|
+
|
|
94
|
+
@staticmethod
|
|
95
|
+
def write_array(elements, accessor=None):
|
|
96
|
+
"""Writes array of objects."""
|
|
97
|
+
return write_array_impl(elements, len(elements), accessor)
|
|
98
|
+
|
|
99
|
+
@staticmethod
|
|
100
|
+
def write_array_count(elements, count, accessor=None):
|
|
101
|
+
"""Writes array of deterministic number of objects."""
|
|
102
|
+
return write_array_impl(elements, count, accessor)
|
|
103
|
+
|
|
104
|
+
@staticmethod
|
|
105
|
+
def write_variable_size_elements(elements, alignment, skip_last_element_padding=False):
|
|
106
|
+
"""Writes array of variable size objects."""
|
|
107
|
+
output_buffer = bytes()
|
|
108
|
+
for index, element in enumerate(elements):
|
|
109
|
+
output_buffer += element.serialize()
|
|
110
|
+
|
|
111
|
+
if not skip_last_element_padding or len(elements) - 1 != index:
|
|
112
|
+
aligned_size = ArrayHelpers.align_up(element.size, alignment)
|
|
113
|
+
if aligned_size != element.size:
|
|
114
|
+
output_buffer += bytes(aligned_size - element.size)
|
|
115
|
+
|
|
116
|
+
return output_buffer
|
{symbol_sdk_python-3.3.1 → symbol_sdk_python-3.3.2}/symbolchain/RuleBasedTransactionFactory.py
RENAMED
|
@@ -161,6 +161,17 @@ class RuleBasedTransactionFactory:
|
|
|
161
161
|
|
|
162
162
|
@staticmethod
|
|
163
163
|
def _auto_encode_strings(entity):
|
|
164
|
+
if not hasattr(entity, '__dict__'): # skip non-objects
|
|
165
|
+
return
|
|
166
|
+
|
|
164
167
|
for key, value in vars(entity).items():
|
|
168
|
+
if '_' == key[0] and '_' == key[-1]: # skip system properties
|
|
169
|
+
continue
|
|
170
|
+
|
|
165
171
|
if isinstance(value, str):
|
|
166
|
-
setattr(entity, key, value.encode('utf8'))
|
|
172
|
+
setattr(entity, key, value.encode('utf8')) # convert string literals to byte array
|
|
173
|
+
elif hasattr(value, '__len__'): # process list items
|
|
174
|
+
for item in value:
|
|
175
|
+
RuleBasedTransactionFactory._auto_encode_strings(item)
|
|
176
|
+
else:
|
|
177
|
+
RuleBasedTransactionFactory._auto_encode_strings(value) # process nested objects
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import math
|
|
2
|
+
|
|
3
|
+
from symbolchain.nc import TransactionType
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def calculate_mosaic_rental_fee():
|
|
7
|
+
"""Calculates the minimum required mosaic rental fee."""
|
|
8
|
+
|
|
9
|
+
return 10 * 1_000_000
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def calculate_namespace_rental_fee(is_root):
|
|
13
|
+
"""
|
|
14
|
+
Calculates the minimum required namespace rental fee.
|
|
15
|
+
When is_root is True, calculates the root namespace fee.
|
|
16
|
+
Otherwise, calculates the child namespace fee.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
return (100 if is_root else 10) * 1_000_000
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _decode_mosaic_id(mosaic_id):
|
|
23
|
+
return {'namespace_id': {'name': mosaic_id.namespace_id.name.decode('utf8')}, 'name': mosaic_id.name.decode('utf8')}
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _calculate_unweighted_transfer_fee(transaction, mosaic_information_lookup):
|
|
27
|
+
xem_supply = 8_999_999_999
|
|
28
|
+
max_mosaic_units = 9_000_000_000_000_000
|
|
29
|
+
|
|
30
|
+
def _calculate_xem_transfer_fee(amount):
|
|
31
|
+
return int(min(25, max(1, amount // 10000)))
|
|
32
|
+
|
|
33
|
+
def _calculate_mosaic_total_quantity(mosaic_information):
|
|
34
|
+
return mosaic_information['supply'] * (10 ** mosaic_information['divisibility'])
|
|
35
|
+
|
|
36
|
+
def _calculate_xem_equivalent(amount, mosaic_amount, mosaic_information):
|
|
37
|
+
if 0 == mosaic_information['supply']:
|
|
38
|
+
return 0
|
|
39
|
+
|
|
40
|
+
# amount XEM whole units
|
|
41
|
+
# mosaic_amount mosaic atomic units
|
|
42
|
+
# xem_supply / _calculate_mosaic_total_quantity(mosaic_information) convert mosaic_amount from mosaic units to XEM equivalent units
|
|
43
|
+
return amount * mosaic_amount * xem_supply / _calculate_mosaic_total_quantity(mosaic_information)
|
|
44
|
+
|
|
45
|
+
def _calculate_mosaic_transfer_fee(amount, mosaic, mosaic_information):
|
|
46
|
+
if 0 == mosaic_information['divisibility'] and 10_000 >= mosaic_information['supply']:
|
|
47
|
+
return 1
|
|
48
|
+
|
|
49
|
+
xem_equivalent = _calculate_xem_equivalent(amount, mosaic.mosaic.amount.value, mosaic_information)
|
|
50
|
+
xem_fee = _calculate_xem_transfer_fee(xem_equivalent)
|
|
51
|
+
mosaic_total_quantity = _calculate_mosaic_total_quantity(mosaic_information)
|
|
52
|
+
supply_related_adjustment = 0 if 0 == mosaic_total_quantity else int(0.8 * math.log(max_mosaic_units / mosaic_total_quantity))
|
|
53
|
+
return max(1, xem_fee - supply_related_adjustment)
|
|
54
|
+
|
|
55
|
+
message_fee = 0 if not transaction.message else len(transaction.message.message) // 32 + 1
|
|
56
|
+
amount = transaction.amount.value // 1_000_000 # convert to XEM whole units
|
|
57
|
+
if not transaction.mosaics:
|
|
58
|
+
transfer_fee = _calculate_xem_transfer_fee(amount)
|
|
59
|
+
return message_fee + transfer_fee
|
|
60
|
+
|
|
61
|
+
def _lookup_and_calculate_mosaic_transfer_fee(mosaic):
|
|
62
|
+
mosaic_id = _decode_mosaic_id(mosaic.mosaic.mosaic_id)
|
|
63
|
+
mosaic_information = mosaic_information_lookup(mosaic_id)
|
|
64
|
+
if not mosaic_information:
|
|
65
|
+
raise ValueError(f'unable to find fee information for {mosaic_id["namespace_id"]["name"]}:{mosaic_id["name"]}')
|
|
66
|
+
|
|
67
|
+
return _calculate_mosaic_transfer_fee(amount, mosaic, mosaic_information)
|
|
68
|
+
|
|
69
|
+
transfer_fee = sum(_lookup_and_calculate_mosaic_transfer_fee(mosaic) for mosaic in transaction.mosaics)
|
|
70
|
+
return message_fee + transfer_fee
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def calculate_transaction_fee(transaction, mosaic_information_lookup=None):
|
|
74
|
+
"""
|
|
75
|
+
Calculates the minimum required transaction fee for a transaction.
|
|
76
|
+
mosaic_information_lookup looks up mosaic information ({supply, divisibility}) given mosaic identifier.
|
|
77
|
+
When a function, mosaic identifier will be passed as parameter.
|
|
78
|
+
When an object map, fully qualified mosaic identifier will be used as an index.
|
|
79
|
+
When None, this function will be unable to calculate fees for custom mosaic transfers.
|
|
80
|
+
"""
|
|
81
|
+
|
|
82
|
+
def _weight_with_fee_unit(amount):
|
|
83
|
+
return amount * 50_000
|
|
84
|
+
|
|
85
|
+
if TransactionType.TRANSFER != transaction.type_:
|
|
86
|
+
return _weight_with_fee_unit(10 if TransactionType.MULTISIG_ACCOUNT_MODIFICATION == transaction.type_ else 3)
|
|
87
|
+
|
|
88
|
+
def _make_lookup_function(lookup):
|
|
89
|
+
if callable(lookup):
|
|
90
|
+
return lookup
|
|
91
|
+
|
|
92
|
+
return lambda mosaic_id: lookup[f'{mosaic_id["namespace_id"]["name"]}:{mosaic_id["name"]}']
|
|
93
|
+
|
|
94
|
+
return _weight_with_fee_unit(_calculate_unweighted_transfer_fee(transaction, _make_lookup_function(mosaic_information_lookup)))
|
|
@@ -33,10 +33,6 @@ class TransactionFactory:
|
|
|
33
33
|
if autosort:
|
|
34
34
|
transaction.sort()
|
|
35
35
|
|
|
36
|
-
# hack: explicitly translate transfer message
|
|
37
|
-
if nc.TransactionType.TRANSFER == transaction.type_ and transaction.message and isinstance(transaction.message.message, str):
|
|
38
|
-
transaction.message.message = transaction.message.message.encode('utf8')
|
|
39
|
-
|
|
40
36
|
return transaction
|
|
41
37
|
|
|
42
38
|
@staticmethod
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
from symbolchain.sc import Cosignature
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def calculate_transaction_fee(transaction, fee_multiplier, cosignature_count=0):
|
|
5
|
+
"""Calculates the minimum required transaction fee for a transaction."""
|
|
6
|
+
|
|
7
|
+
return transaction.size * fee_multiplier + Cosignature().size * cosignature_count
|
{symbol_sdk_python-3.3.1 → symbol_sdk_python-3.3.2}/symbolchain/AccountDescriptorRepository.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{symbol_sdk_python-3.3.1 → symbol_sdk_python-3.3.2}/symbolchain/TransactionDescriptorProcessor.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{symbol_sdk_python-3.3.1 → symbol_sdk_python-3.3.2}/symbolchain/symbol/TransactionFactory.py
RENAMED
|
File without changes
|
{symbol_sdk_python-3.3.1 → symbol_sdk_python-3.3.2}/symbolchain/symbol/VotingKeysGenerator.py
RENAMED
|
File without changes
|
|
File without changes
|