hive-nectar 0.0.11__py3-none-any.whl → 0.1.1__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.

Potentially problematic release.


This version of hive-nectar might be problematic. Click here for more details.

Files changed (56) hide show
  1. {hive_nectar-0.0.11.dist-info → hive_nectar-0.1.1.dist-info}/METADATA +12 -11
  2. hive_nectar-0.1.1.dist-info/RECORD +88 -0
  3. nectar/__init__.py +1 -4
  4. nectar/account.py +791 -685
  5. nectar/amount.py +82 -21
  6. nectar/asset.py +1 -2
  7. nectar/block.py +49 -23
  8. nectar/blockchain.py +111 -143
  9. nectar/blockchaininstance.py +396 -247
  10. nectar/blockchainobject.py +33 -5
  11. nectar/cli.py +1058 -1349
  12. nectar/comment.py +313 -181
  13. nectar/community.py +39 -43
  14. nectar/constants.py +1 -14
  15. nectar/discussions.py +793 -139
  16. nectar/hive.py +137 -77
  17. nectar/hivesigner.py +106 -68
  18. nectar/imageuploader.py +33 -23
  19. nectar/instance.py +31 -79
  20. nectar/market.py +128 -264
  21. nectar/memo.py +40 -13
  22. nectar/message.py +23 -10
  23. nectar/nodelist.py +115 -81
  24. nectar/price.py +80 -61
  25. nectar/profile.py +6 -3
  26. nectar/rc.py +45 -25
  27. nectar/snapshot.py +285 -163
  28. nectar/storage.py +16 -5
  29. nectar/transactionbuilder.py +132 -41
  30. nectar/utils.py +37 -17
  31. nectar/version.py +1 -1
  32. nectar/vote.py +171 -30
  33. nectar/wallet.py +26 -19
  34. nectar/witness.py +153 -54
  35. nectarapi/graphenerpc.py +147 -133
  36. nectarapi/noderpc.py +12 -6
  37. nectarapi/rpcutils.py +12 -6
  38. nectarapi/version.py +1 -1
  39. nectarbase/ledgertransactions.py +24 -1
  40. nectarbase/objects.py +17 -6
  41. nectarbase/operations.py +160 -90
  42. nectarbase/signedtransactions.py +38 -2
  43. nectarbase/version.py +1 -1
  44. nectargraphenebase/account.py +295 -17
  45. nectargraphenebase/chains.py +0 -135
  46. nectargraphenebase/ecdsasig.py +152 -176
  47. nectargraphenebase/types.py +18 -4
  48. nectargraphenebase/unsignedtransactions.py +1 -1
  49. nectargraphenebase/version.py +1 -1
  50. hive_nectar-0.0.11.dist-info/RECORD +0 -91
  51. nectar/blurt.py +0 -562
  52. nectar/conveyor.py +0 -308
  53. nectar/steem.py +0 -581
  54. {hive_nectar-0.0.11.dist-info → hive_nectar-0.1.1.dist-info}/WHEEL +0 -0
  55. {hive_nectar-0.0.11.dist-info → hive_nectar-0.1.1.dist-info}/entry_points.txt +0 -0
  56. {hive_nectar-0.0.11.dist-info → hive_nectar-0.1.1.dist-info}/licenses/LICENSE.txt +0 -0
@@ -8,10 +8,27 @@ import re
8
8
  import unicodedata
9
9
  from binascii import hexlify, unhexlify
10
10
 
11
- import ecdsa
11
+ # Optional ecdsa import for backward compatibility
12
+ try:
13
+ import ecdsa
14
+
15
+ ECDSA_AVAILABLE = True
16
+ except ImportError:
17
+ ecdsa = None
18
+ ECDSA_AVAILABLE = False
12
19
 
13
20
  from .base58 import Base58, doublesha256, ripemd160
14
- from .bip32 import BIP32Key, parse_path
21
+
22
+ # Optional bip32 import for BIP32 key derivation
23
+ try:
24
+ from .bip32 import BIP32Key, parse_path
25
+
26
+ BIP32_AVAILABLE = True
27
+ except ImportError:
28
+ BIP32Key = None
29
+ parse_path = None
30
+ BIP32_AVAILABLE = False
31
+
15
32
  from .dictionary import words as BrainKeyDictionary
16
33
  from .dictionary import words_bip39 as MnemonicDictionary
17
34
  from .prefix import Prefix
@@ -19,8 +36,199 @@ from .prefix import Prefix
19
36
  PBKDF2_ROUNDS = 2048
20
37
 
21
38
 
39
+ # secp256k1 curve parameters for pure Python implementation
40
+ SECP256K1_P = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F
41
+ SECP256K1_A = 0
42
+ SECP256K1_B = 7
43
+ SECP256K1_GX = 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798
44
+ SECP256K1_GY = 0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8
45
+ SECP256K1_N = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141
46
+
47
+
48
+ def _mod_inverse(a, m):
49
+ """
50
+ Return the modular inverse of a modulo m using the extended Euclidean algorithm.
51
+
52
+ Given integers a and m, compute x such that (a * x) % m == 1. The result is normalized
53
+ to the range [0, m-1]. If m == 1 the function returns 0.
54
+
55
+ Parameters:
56
+ a (int): The value to invert modulo m.
57
+ m (int): The modulus.
58
+
59
+ Returns:
60
+ int: The modular inverse of a modulo m, or 0 when m == 1.
61
+ """
62
+ m0, y, x = m, 0, 1
63
+ if m == 1:
64
+ return 0
65
+ while a > 1:
66
+ q = a // m
67
+ m, a = a % m, m
68
+ y, x = x - q * y, y
69
+ if x < 0:
70
+ x += m0
71
+ return x
72
+
73
+
74
+ def _is_on_curve(x, y, p=SECP256K1_P, a=SECP256K1_A, b=SECP256K1_B):
75
+ """Check if point (x, y) is on the secp256k1 curve: y² = x³ + a*x + b"""
76
+ left_side = (y * y) % p
77
+ right_side = (x * x * x + a * x + b) % p
78
+ return left_side == right_side
79
+
80
+
81
+ def _point_add(p1, p2, p=SECP256K1_P):
82
+ """
83
+ Add two points on an elliptic curve over a prime field.
84
+
85
+ Both p1 and p2 are either None (the point at infinity) or 2-tuples (x, y) of integers
86
+ interpreted modulo p. Returns a 2-tuple (x, y) representing the sum (mod p), or None
87
+ for the point at infinity. Uses the short Weierstrass group law (handles point
88
+ doubling and addition, including the inverse/vertical-tangent cases).
89
+
90
+ Parameters:
91
+ p1 (tuple|None): First point as (x, y) or None for infinity.
92
+ p2 (tuple|None): Second point as (x, y) or None for infinity.
93
+ p (int): Prime modulus of the field (defaults to SECP256K1_P).
94
+
95
+ Returns:
96
+ tuple|None: Resulting point (x, y) modulo p, or None if the result is the
97
+ point at infinity.
98
+ """
99
+ if p1 is None:
100
+ return p2
101
+ if p2 is None:
102
+ return p1
103
+
104
+ x1, y1 = p1
105
+ x2, y2 = p2
106
+
107
+ # P + (-P) = O
108
+ if x1 == x2 and (y1 + y2) % p == 0:
109
+ return None # Point at infinity
110
+
111
+ if x1 == x2:
112
+ # Point doubling - for secp256k1: s = (3*x1^2) / (2*y1)
113
+ if y1 % p == 0:
114
+ return None # vertical tangent => infinity
115
+ numerator = (3 * x1 * x1) % p
116
+ denominator = (2 * y1) % p
117
+ s = (numerator * _mod_inverse(denominator, p)) % p
118
+ else:
119
+ # Point addition
120
+ denom = (x2 - x1) % p
121
+ s = ((y2 - y1) % p) * _mod_inverse(denom, p) % p
122
+
123
+ x3 = (s * s - x1 - x2) % p
124
+ y3 = (s * (x1 - x3) - y1) % p
125
+
126
+ return (x3, y3)
127
+
128
+
129
+ def _scalar_mult(k, point, p=SECP256K1_P):
130
+ """
131
+ Compute k * point on the secp256k1 curve using the binary (double-and-add) method.
132
+
133
+ Parameters:
134
+ k (int): Non-negative integer scalar.
135
+ point (tuple|None): Elliptic-curve point as (x, y) or None to represent the point at infinity.
136
+ p (int, optional): Prime modulus of the field (defaults to SECP256K1_P).
137
+
138
+ Returns:
139
+ tuple|None: The resulting point (x, y) after scalar multiplication, or None for the point at infinity.
140
+ """
141
+ if k == 0:
142
+ return None # Point at infinity
143
+ if k == 1:
144
+ return point
145
+
146
+ result = None
147
+ current = point
148
+
149
+ while k > 0:
150
+ if k & 1:
151
+ result = _point_add(result, current, p)
152
+ current = _point_add(current, current, p)
153
+ k >>= 1
154
+
155
+ return result
156
+
157
+
158
+ def _point_to_compressed(point):
159
+ """
160
+ Return the 33-byte SEC compressed encoding of an EC point on secp256k1.
161
+
162
+ The input `point` must be a tuple (x, y) of integers representing coordinates on the curve.
163
+ The result is a 33-byte bytes object: a 1-byte prefix 0x02 (even y) or 0x03 (odd y)
164
+ followed by the 32-byte big-endian x coordinate.
165
+
166
+ Raises:
167
+ ValueError: If `point` is None (the point at infinity cannot be compressed).
168
+ """
169
+ if point is None:
170
+ raise ValueError("Cannot compress point at infinity")
171
+
172
+ x, y = point
173
+ prefix = 0x02 if y % 2 == 0 else 0x03
174
+ return prefix.to_bytes(1, "big") + x.to_bytes(32, "big")
175
+
176
+
177
+ def _compressed_to_point(compressed):
178
+ """
179
+ Convert a 33-byte SEC compressed public key to an (x, y) point on the secp256k1 curve.
180
+
181
+ Parameters:
182
+ compressed (bytes): 33-byte compressed point (prefix 0x02 or 0x03 followed by 32-byte big-endian x).
183
+
184
+ Returns:
185
+ tuple[int, int]: The affine coordinates (x, y) of the corresponding point.
186
+
187
+ Raises:
188
+ ValueError: If the input length is not 33 bytes, the prefix is not 0x02/0x03, or the recovered point is not on the secp256k1 curve.
189
+ """
190
+ if len(compressed) != 33:
191
+ raise ValueError("Invalid compressed point length")
192
+
193
+ prefix = compressed[0]
194
+ x = int.from_bytes(compressed[1:], "big")
195
+
196
+ if prefix not in (0x02, 0x03):
197
+ raise ValueError("Invalid compressed point prefix")
198
+
199
+ # Calculate y from x using curve equation: y^2 = x^3 + a*x + b
200
+ y_squared = (x * x * x + SECP256K1_A * x + SECP256K1_B) % SECP256K1_P
201
+
202
+ # Find square root mod p
203
+ y = pow(y_squared, (SECP256K1_P + 1) // 4, SECP256K1_P)
204
+
205
+ # Choose the correct y based on parity
206
+ if (prefix == 0x02 and y % 2 != 0) or (prefix == 0x03 and y % 2 == 0):
207
+ y = SECP256K1_P - y
208
+
209
+ if not _is_on_curve(x, y):
210
+ raise ValueError("Point not on curve")
211
+
212
+ return (x, y)
213
+
214
+
22
215
  # From <https://stackoverflow.com/questions/212358/binary-search-bisection-in-python/2233940#2233940>
23
216
  def binary_search(a, x, lo=0, hi=None): # can't use a to specify default for hi
217
+ """
218
+ Locate the index of x in sorted sequence a using binary search.
219
+
220
+ Performs a binary search on the sorted sequence `a` and returns the lowest index i in [lo, hi)
221
+ such that a[i] == x. If x is not present in that slice, returns -1.
222
+
223
+ Parameters:
224
+ a (Sequence): Sorted sequence (ascending) to search.
225
+ x: Value to locate.
226
+ lo (int, optional): Lower bound (inclusive) index to search from. Defaults to 0.
227
+ hi (int, optional): Upper bound (exclusive) index to search to. Defaults to len(a).
228
+
229
+ Returns:
230
+ int: Index of the first matching element in [lo, hi), or -1 if not found.
231
+ """
24
232
  hi = hi if hi is not None else len(a) # hi defaults to len(a)
25
233
  pos = bisect.bisect_left(a, x, lo, hi) # find insertion position
26
234
  return pos if pos != hi and a[pos] == x else -1 # don't walk off the end
@@ -627,23 +835,88 @@ class PublicKey(Prefix):
627
835
  return self.add(s)
628
836
 
629
837
  def add(self, digest256):
630
- """Derive new public key from this key and a sha256 "digest" """
631
- from .ecdsa import tweakaddPubkey
838
+ """
839
+ Return a new PublicKey obtained by adding a 32-byte tweak (interpreted as a big-endian scalar) times the curve generator to this public key.
840
+
841
+ Parameters:
842
+ digest256 (bytes): A 32-byte SHA-256 digest used as the tweak scalar (big-endian). Must be length 32, non-zero, and less than the curve order.
632
843
 
633
- return tweakaddPubkey(self, digest256)
844
+ Returns:
845
+ PublicKey: A new PublicKey instance representing (tweak * G) + current_public_key, preserving this key's prefix.
846
+
847
+ Raises:
848
+ ValueError: If `digest256` is not bytes, not 32 bytes long, is zero, is >= curve order, or if intermediate point multiplication/addition results in the point at infinity.
849
+ """
850
+ # Validate tweak
851
+ if not isinstance(digest256, (bytes, bytearray)):
852
+ raise ValueError("Tweak must be bytes")
853
+ if len(digest256) != 32:
854
+ raise ValueError("Tweak must be exactly 32 bytes")
855
+
856
+ tweak = int.from_bytes(digest256, "big")
857
+ if tweak == 0:
858
+ raise ValueError("Tweak cannot be zero")
859
+ if tweak >= SECP256K1_N:
860
+ raise ValueError("Tweak must be less than curve order")
861
+
862
+ # Convert current public key to point
863
+ current_compressed = bytes(self)
864
+ current_point = _compressed_to_point(current_compressed)
865
+
866
+ # Compute G*tweak (scalar multiplication of generator)
867
+ generator_point = (SECP256K1_GX, SECP256K1_GY)
868
+ tweak_point = _scalar_mult(tweak, generator_point)
869
+
870
+ if tweak_point is None:
871
+ raise ValueError("Tweak multiplication resulted in point at infinity")
872
+
873
+ # Add points: result = tweak_point + current_point
874
+ result_point = _point_add(tweak_point, current_point)
875
+
876
+ if result_point is None:
877
+ raise ValueError("Point addition resulted in point at infinity")
878
+
879
+ # Convert back to compressed format
880
+ result_compressed = _point_to_compressed(result_point)
881
+
882
+ # Create new PublicKey with same prefix
883
+ return PublicKey(hexlify(result_compressed).decode("ascii"), prefix=self.prefix)
634
884
 
635
885
  @classmethod
636
886
  def from_privkey(cls, privkey, prefix=None):
637
- """Derive uncompressed public key"""
887
+ """
888
+ Derive a compressed public key from a private key and return a PublicKey instance.
889
+
890
+ Parameters:
891
+ privkey: The private key material to derive from — accepts a WIF/hex string or a PrivateKey instance.
892
+ prefix (optional): Network/key prefix to use for the resulting PublicKey; if omitted the module default prefix is used.
893
+
894
+ Returns:
895
+ PublicKey: A PublicKey (compressed form) constructed from the derived public key bytes.
896
+
897
+ Raises:
898
+ ImportError: If the `ecdsa` library is not available.
899
+ """
638
900
  privkey = PrivateKey(privkey, prefix=prefix or Prefix.prefix)
639
901
  secret = unhexlify(repr(privkey))
640
- order = ecdsa.SigningKey.from_string(secret, curve=ecdsa.SECP256k1).curve.generator.order()
641
- p = ecdsa.SigningKey.from_string(secret, curve=ecdsa.SECP256k1).verifying_key.pubkey.point
642
- x_str = ecdsa.util.number_to_string(p.x(), order)
643
- # y_str = ecdsa.util.number_to_string(p.y(), order)
644
- compressed = hexlify(chr(2 + (p.y() & 1)).encode("ascii") + x_str).decode("ascii")
645
- # uncompressed = hexlify(
646
- # chr(4).encode('ascii') + x_str + y_str).decode('ascii')
902
+
903
+ if ECDSA_AVAILABLE:
904
+ order = ecdsa.SigningKey.from_string(
905
+ secret, curve=ecdsa.SECP256k1
906
+ ).curve.generator.order()
907
+ p = ecdsa.SigningKey.from_string(
908
+ secret, curve=ecdsa.SECP256k1
909
+ ).verifying_key.pubkey.point
910
+ x_str = ecdsa.util.number_to_string(p.x(), order)
911
+ compressed = hexlify(chr(2 + (p.y() & 1)).encode("ascii") + x_str).decode("ascii")
912
+ return cls(compressed, prefix=prefix or Prefix.prefix)
913
+ # Fallback: derive with pure-Python EC math
914
+ secexp = int.from_bytes(secret, "big")
915
+ if secexp <= 0 or secexp >= SECP256K1_N:
916
+ raise ValueError("Invalid private key scalar")
917
+ G = (SECP256K1_GX, SECP256K1_GY)
918
+ P = _scalar_mult(secexp, G)
919
+ compressed = hexlify(_point_to_compressed(P)).decode("ascii")
647
920
  return cls(compressed, prefix=prefix or Prefix.prefix)
648
921
 
649
922
  def __repr__(self):
@@ -764,13 +1037,18 @@ class PrivateKey(Prefix):
764
1037
  return self.derive_from_seed(s)
765
1038
 
766
1039
  def derive_from_seed(self, offset):
767
- """Derive private key using "generate_from_seed" method.
768
- Here, the key itself serves as a `seed`, and `offset`
769
- is expected to be a sha256 digest.
1040
+ """
1041
+ Derive a new PrivateKey by adding a 32-byte integer offset to this key's seed modulo the secp256k1 order.
1042
+
1043
+ Parameters:
1044
+ offset (bytes): A 32-byte SHA-256 digest interpreted as a big-endian integer offset to add to this key's secret.
1045
+
1046
+ Returns:
1047
+ PrivateKey: A new PrivateKey created from (seed + offset) mod SECP256K1_N, preserving this key's prefix.
770
1048
  """
771
1049
  seed = int(hexlify(bytes(self)).decode("ascii"), 16)
772
1050
  z = int(hexlify(offset).decode("ascii"), 16)
773
- order = ecdsa.SECP256k1.order
1051
+ order = SECP256K1_N
774
1052
  secexp = (seed + z) % order
775
1053
  secret = "%0x" % secexp
776
1054
  if len(secret) < 64: # left-pad with zeroes
@@ -2,16 +2,6 @@
2
2
  default_prefix = "STM"
3
3
  known_chains = {
4
4
  "HIVE": {
5
- "chain_id": "0" * int(256 / 4),
6
- "min_version": "0.23.0",
7
- "prefix": "STM",
8
- "chain_assets": [
9
- {"asset": "@@000000013", "symbol": "HBD", "precision": 3, "id": 0},
10
- {"asset": "@@000000021", "symbol": "HIVE", "precision": 3, "id": 1},
11
- {"asset": "@@000000037", "symbol": "VESTS", "precision": 6, "id": 2},
12
- ],
13
- },
14
- "HIVE2": {
15
5
  "chain_id": "beeab0de00000000000000000000000000000000000000000000000000000000",
16
6
  "min_version": "0.24.0",
17
7
  "prefix": "STM",
@@ -21,129 +11,4 @@ known_chains = {
21
11
  {"asset": "@@000000037", "symbol": "VESTS", "precision": 6, "id": 2},
22
12
  ],
23
13
  },
24
- "BLURT": {
25
- "chain_id": "cd8d90f29ae273abec3eaa7731e25934c63eb654d55080caff2ebb7f5df6381f",
26
- "min_version": "0.0.0",
27
- "prefix": "BLT",
28
- "chain_assets": [
29
- {"asset": "@@000000021", "symbol": "BLURT", "precision": 3, "id": 1},
30
- {"asset": "@@000000037", "symbol": "VESTS", "precision": 6, "id": 2},
31
- ],
32
- },
33
- "STEEM": {
34
- "chain_id": "0" * int(256 / 4),
35
- "min_version": "0.19.10",
36
- "prefix": "STM",
37
- "chain_assets": [
38
- {"asset": "@@000000013", "symbol": "SBD", "precision": 3, "id": 0},
39
- {"asset": "@@000000021", "symbol": "STEEM", "precision": 3, "id": 1},
40
- {"asset": "@@000000037", "symbol": "VESTS", "precision": 6, "id": 2},
41
- ],
42
- },
43
- "TESTNET": {
44
- "chain_id": "79276aea5d4877d9a25892eaa01b0adf019d3e5cb12a97478df3298ccdd01673",
45
- "min_version": "0.20.0",
46
- "prefix": "STX",
47
- "chain_assets": [
48
- {"asset": "@@000000013", "symbol": "SBD", "precision": 3, "id": 0},
49
- {"asset": "@@000000021", "symbol": "STEEM", "precision": 3, "id": 1},
50
- {"asset": "@@000000037", "symbol": "VESTS", "precision": 6, "id": 2},
51
- ],
52
- },
53
- "TESTDEV": {
54
- "chain_id": "18dcf0a285365fc58b71f18b3d3fec954aa0c141c44e4e5cb4cf777b9eab274e",
55
- "min_version": "0.20.0",
56
- "prefix": "TST",
57
- "chain_assets": [
58
- {"asset": "@@000000013", "symbol": "TBD", "precision": 3, "id": 0},
59
- {"asset": "@@000000021", "symbol": "TESTS", "precision": 3, "id": 1},
60
- {"asset": "@@000000037", "symbol": "VESTS", "precision": 6, "id": 2},
61
- ],
62
- },
63
- "GOLOS": {
64
- "chain_id": "782a3039b478c839e4cb0c941ff4eaeb7df40bdd68bd441afd444b9da763de12",
65
- "min_version": "0.0.0",
66
- "prefix": "GLS",
67
- "chain_assets": [
68
- {"asset": "SBD", "symbol": "GBG", "precision": 3, "id": 0},
69
- {"asset": "STEEM", "symbol": "GOLOS", "precision": 3, "id": 1},
70
- {"asset": "VESTS", "symbol": "GESTS", "precision": 6, "id": 2},
71
- ],
72
- },
73
- "VIT": {
74
- "chain_id": "73f14dd4b7b07a8663be9d84300de0f65ef2ee7e27aae32bbe911c548c08f000",
75
- "min_version": "0.0.0",
76
- "prefix": "VIT",
77
- "chain_assets": [
78
- {"asset": "STEEM", "symbol": "VIT", "precision": 3, "id": 1},
79
- {"asset": "VESTS", "symbol": "VESTS", "precision": 6, "id": 2},
80
- ],
81
- },
82
- "VIZ": {
83
- "chain_id": "2040effda178d4fffff5eab7a915d4019879f5205cc5392e4bcced2b6edda0cd",
84
- "min_version": "2.5.0",
85
- "prefix": "VIZ",
86
- "chain_assets": [
87
- {"asset": "STEEM", "symbol": "VIZ", "precision": 3, "id": 1},
88
- {"asset": "VESTS", "symbol": "VESTS", "precision": 6, "id": 2},
89
- ],
90
- },
91
- "WEKU": {
92
- "chain_id": "b24e09256ee14bab6d58bfa3a4e47b0474a73ef4d6c47eeea007848195fa085e",
93
- "min_version": "0.19.3",
94
- "prefix": "WKA",
95
- "chain_assets": [
96
- {"asset": "SBD", "symbol": "WKD", "precision": 3, "id": 0},
97
- {"asset": "STEEM", "symbol": "WEKU", "precision": 3, "id": 1},
98
- {"asset": "VESTS", "symbol": "VESTS", "precision": 6, "id": 2},
99
- ],
100
- },
101
- "SMOKE": {
102
- "chain_id": "1ce08345e61cd3bf91673a47fc507e7ed01550dab841fd9cdb0ab66ef576aaf0",
103
- "min_version": "0.1.0",
104
- "prefix": "SMK",
105
- "chain_assets": [
106
- {"asset": "STEEM", "symbol": "SMOKE", "precision": 3, "id": 1},
107
- {"asset": "VESTS", "symbol": "VESTS", "precision": 6, "id": 2},
108
- ],
109
- },
110
- "EFTGAPPBASE": {
111
- "chain_id": "1c15984beb16945c01cb9bc3d654b0417c650461dfe535018fe03a4fc5a36864",
112
- "min_version": "0.19.12",
113
- "prefix": "EUR",
114
- "chain_assets": [
115
- {"asset": "@@000000013", "symbol": "EUR", "precision": 3, "id": 0},
116
- {"asset": "@@000000021", "symbol": "EFTG", "precision": 3, "id": 1},
117
- {"asset": "@@000000037", "symbol": "VESTS", "precision": 6, "id": 2},
118
- ],
119
- },
120
- "EFTG": {
121
- "chain_id": "1c15984beb16945c01cb9bc3d654b0417c650461dfe535018fe03a4fc5a36864",
122
- "min_version": "0.19.6",
123
- "prefix": "EUR",
124
- "chain_assets": [
125
- {"asset": "SBD", "symbol": "EUR", "precision": 3, "id": 0},
126
- {"asset": "STEEM", "symbol": "EFTG", "precision": 3, "id": 1},
127
- {"asset": "VESTS", "symbol": "VESTS", "precision": 6, "id": 2},
128
- ],
129
- },
130
- "PULSAR": {
131
- "chain_id": "07c687c01f134adaf217a9b9367d1cef679c3c020167fdd25ee8c403f687528e",
132
- "min_version": "0.101.0",
133
- "prefix": "EUR",
134
- "chain_assets": [
135
- {"asset": "@@000000013", "symbol": "EUR", "precision": 3, "id": 0},
136
- {"asset": "@@000000021", "symbol": "PULSE", "precision": 3, "id": 1},
137
- {"asset": "@@000000037", "symbol": "VESTS", "precision": 6, "id": 2},
138
- ],
139
- },
140
- "WLS": {
141
- "chain_id": "de999ada2ff7ed3d3d580381f229b40b5a0261aec48eb830e540080817b72866",
142
- "min_version": "0.0.0",
143
- "prefix": "WLS",
144
- "chain_assets": [
145
- {"asset": "STEEM", "symbol": "WLS", "precision": 3, "id": 1},
146
- {"asset": "VESTS", "symbol": "VESTS", "precision": 6, "id": 2},
147
- ],
148
- },
149
14
  }