Skip to content

Commit 4eabf05

Browse files
authored
Merge pull request #48 from ltonetwork/cobalt-alloy
Cobalt alloy
2 parents 1c4050d + 0ba91a3 commit 4eabf05

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+933
-386
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,3 +59,5 @@ target/
5959

6060
# dev
6161
test.py
62+
project
63+
/src/lto/test2.py

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,30 +8,30 @@ Python client library for interacting with LTO Network
88
The chain_id is 'L' for the MainNet and 'T' TestNet
99

1010
```python
11-
from src.lto.account_factory import AccountFactory
11+
from lto.accounts.account_factory import AccountFactory
1212

1313
account = AccountFactory(chain_id).create()
1414
```
1515
### Create an account from seed
1616

1717
```python
18-
from src.lto.account_factory import AccountFactory
18+
from lto.accounts.account_factory import AccountFactory
1919

2020
account = AccountFactory(chain_id).create_from_seed(seed)
2121
```
2222

2323
### Create an account from public key
2424

2525
```python
26-
from src.lto.account_factory import AccountFactory
26+
from lto.accounts.account_factory import AccountFactory
2727

2828
account = AccountFactory(chain_id).create_from_public_key(public_key)
2929
```
3030

3131
### Create an account from private key
3232

3333
```python
34-
from src.lto.account_factory import AccountFactory
34+
from lto.accounts.account_factory import AccountFactory
3535

3636
account = AccountFactory(chain_id).create_from_private_key(private_key)
3737
```

setup.cfg

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ install_requires =
2929
ecdsa~=0.17.0
3030
inflection~=0.5.1
3131
freezegun~=1.1.0
32+
mnemonic~=0.20
33+
eth-utils~=2.0.0
34+
pycryptodome~=3.12.0
35+
pysha3~=1.0.2
3236

3337
[options.packages.find]
3438
where = src

src/lto/__init__.py

Lines changed: 17 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,15 @@
11
from __future__ import absolute_import, division, print_function, unicode_literals
22

3-
from lto.account_factory import AccountFactory
4-
from lto.public_node import PublicNode
3+
import base58
54

6-
from lto.transactions.anchor import Anchor
7-
from lto.transactions.lease import Lease
8-
from lto.transactions.association import Association
9-
from lto.transactions.cancel_lease import CancelLease
10-
from lto.transactions.cancel_sponsorship import CancelSponsorship
11-
from lto.transactions.mass_transfer import MassTransfer
12-
from lto.transactions.revoke_association import RevokeAssociation
13-
from lto.transactions.set_script import SetScript
14-
from lto.transactions.sponsorship import Sponsorship
15-
from lto.transactions.transfer import Transfer
16-
from lto.accounts.account_factory_ecdsa import AccountFactoryECDSA
17-
from lto.accounts.account_factory_ed25519 import AccountFactoryED25519
5+
from lto.accounts import AccountFactory
6+
from lto.public_node import PublicNode
7+
from lto.accounts import AccountFactoryECDSA, AccountFactoryED25519
188

199

2010
class LTO:
2111

2212
def __init__(self, chain_id='T'):
23-
2413
if chain_id == 'T':
2514
self.NODE = PublicNode('https://testnet.lto.network')
2615
elif chain_id == 'L':
@@ -29,15 +18,15 @@ def __init__(self, chain_id='T'):
2918
self.NODE = ''
3019

3120
self.chain_id = chain_id
32-
3321
self.account_factories = {
3422
'ed25519': AccountFactoryED25519(chain_id),
3523
'secp256r1': AccountFactoryECDSA(chain_id, curve='secp256r1'),
3624
'secp256k1': AccountFactoryECDSA(chain_id, curve='secp256k1')
3725
}
3826

39-
def Account(self, public_key=None, private_key=None, key_type='ed25519', seed=None, nonce=0):
40-
factory = self.account_factories[key_type]
27+
def Account(self, public_key=None, private_key=None, key_type='ed25519', seed=None, seed_method=None, nonce=0):
28+
factory = self.account_factories[key_type].with_seed_method(seed_method)
29+
4130
if seed:
4231
account = factory.create_from_seed(seed, nonce)
4332
elif private_key:
@@ -46,32 +35,17 @@ def Account(self, public_key=None, private_key=None, key_type='ed25519', seed=No
4635
account = factory.create_from_public_key(public_key)
4736
else:
4837
account = factory.create()
49-
return account
5038

51-
def getchain_id(self):
52-
return self.chain_id
39+
# assert public_key is None or account.get_public_key() == self.__key_base58(public_key), "Public key mismatch"
40+
# assert private_key is None or account.get_private_key() == self.__key_base58(private_key), "Private key mismatch"
5341

54-
def from_data(self, data):
42+
return account
5543

56-
if data['type'] == 4:
57-
return Transfer(recipient=data['recipient'], amount=data['amount']).from_data(data)
58-
elif data['type'] == 8:
59-
return Lease(amount=1, recipient='').from_data(data)
60-
elif data['type'] == 11:
61-
return MassTransfer(transfers='').from_data(data)
62-
elif data['type'] == 15:
63-
return Anchor(anchor='').from_data(data)
64-
elif data['type'] == 16:
65-
return Association(recipient='', association_type='', anchor='').from_data(data)
66-
elif data['type'] == 17:
67-
return RevokeAssociation(recipient='', association_type='').from_data(data)
68-
elif data['type'] == 18:
69-
return Sponsorship(data['recipient']).from_data(data)
70-
elif data['type'] == 19:
71-
return CancelSponsorship(data['recipient']).from_data(data)
72-
elif data['type'] == 13:
73-
return SetScript(data['script']).from_data(data)
74-
elif data['type'] == 9:
75-
return CancelLease(lease_id='').from_data(data)
44+
@staticmethod
45+
def __key_base58(key):
46+
if type(key) == object:
47+
return base58.b58encode(bytes(key))
48+
elif type(key) == bytes:
49+
return base58.b58encode(key)
7650
else:
77-
raise Exception('Incorrect transaction Type')
51+
return key

src/lto/account_factory.py

Lines changed: 0 additions & 54 deletions
This file was deleted.

src/lto/accounts/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
from lto.accounts.account import Account
2+
from lto.accounts.account_factory import AccountFactory
3+
from lto.accounts.ecdsa.account_factory_ecdsa import AccountFactoryECDSA
4+
from lto.accounts.ed25519.account_factory_ed25519 import AccountFactoryED25519
File renamed without changes.

src/lto/accounts/account_factory.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import copy
2+
from abc import ABC, abstractmethod
3+
from lto.accounts.brainwallet import random_seed as brainwallet_random_seed
4+
from lto.accounts.bip39 import random_seed as bip39_random_seed
5+
6+
7+
class AccountFactory(ABC):
8+
def __init__(self, chain_id, seed_method):
9+
self.chain_id = chain_id
10+
self.seed_method = seed_method
11+
12+
def with_seed_method(self, seed_method):
13+
if seed_method is None or self.seed_method == seed_method:
14+
return self
15+
16+
clone = copy.copy(self)
17+
clone.seed_method = seed_method
18+
return clone
19+
20+
@abstractmethod
21+
def create_sign_keys(self, seed, nonce):
22+
pass
23+
24+
@abstractmethod
25+
def create_address(self, public_key):
26+
pass
27+
28+
def create(self):
29+
if self.seed_method == 'brainwallet':
30+
seed = brainwallet_random_seed()
31+
elif self.seed_method == 'bip39':
32+
seed = bip39_random_seed()
33+
elif self.seed_method.startswith('bip39:'):
34+
# raise Exception("Method under construction")
35+
seed = bip39_random_seed(self.seed_method[6:])
36+
else:
37+
raise Exception('Unknown seed method')
38+
39+
return self.create_from_seed(seed)
40+
41+
@abstractmethod
42+
def create_from_seed(self, seed, nonce=0):
43+
pass
44+
45+
@abstractmethod
46+
def create_from_private_key(self, private_key):
47+
pass
48+
49+
@abstractmethod
50+
def create_from_public_key(self, public_key):
51+
pass
52+
53+
@abstractmethod
54+
def create_with_values(self, address, public_key, private_key, key_type, seed=''):
55+
pass
56+

src/lto/accounts/bip39.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from mnemonic import Mnemonic
2+
3+
4+
def random_seed(language="english"):
5+
return Mnemonic(language).generate(strength=256)

src/lto/accounts/brainwallet.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import os
2+
from lto import crypto
3+
from lto.word_list import wordList
4+
5+
def random_seed():
6+
word_count = len(wordList)
7+
words = []
8+
for i in range(5):
9+
r = crypto.bytes2str(os.urandom(4))
10+
x = (ord(r[3])) + (ord(r[2]) << 8) + (ord(r[1]) << 16) + (ord(r[0]) << 24)
11+
w1 = x % word_count
12+
w2 = ((int(x / word_count) >> 0) + w1) % word_count
13+
w3 = ((int((int(x / word_count) >> 0) / word_count) >> 0) + w2) % word_count
14+
words.append(wordList[w1])
15+
words.append(wordList[w2])
16+
words.append(wordList[w3])
17+
return ' '.join(words)

src/lto/accounts/ecdsa/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
from lto.accounts.ecdsa.account_ecdsa import AccountECDSA as Account
2+
from lto.accounts.ecdsa.account_factory_ecdsa import AccountFactoryECDSA as AccountFactory

src/lto/accounts/ecdsa/account_ecdsa.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
from lto.account import Account
1+
from lto.accounts.account import Account
22
import base58
33
from lto import crypto
4-
import ecdsa
4+
55

66
class AccountECDSA(Account):
77

@@ -11,6 +11,9 @@ def init(self, address, public_key, private_key=None, key_type ='secp256k1',seed
1111
def get_public_key(self):
1212
return base58.b58encode(self.public_key.to_string(encoding="compressed"))
1313

14+
def get_private_key(self):
15+
return base58.b58encode(self.private_key.to_string())
16+
1417
def sign(self, message):
1518
if not self.private_key:
1619
raise Exception("Private key not set")

src/lto/accounts/account_factory_ecdsa.py renamed to src/lto/accounts/ecdsa/account_factory_ecdsa.py

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
1-
from lto.account_factory import AccountFactory
1+
from lto.accounts.account_factory import AccountFactory
22
from ecdsa import VerifyingKey, SECP256k1, NIST256p, SigningKey
33
import hashlib
4-
from ecdsa.util import randrange_from_seed__trytryagain
4+
from ecdsa.util import randrange_from_seed__trytryagain as randrange_from_seed
55
import base58
66
from lto import crypto
77
from lto.accounts.ecdsa.account_ecdsa import AccountECDSA as Account
8+
from mnemonic import Mnemonic
9+
from lto import ethereum_mnemonic_utils as eth
810

911

1012
class AccountFactoryECDSA(AccountFactory):
1113

1214
def __init__(self, chain_id, curve='secp256k1'):
13-
super().__init__(chain_id)
15+
super().__init__(chain_id, 'bip39')
1416

1517
self.key_type = curve
1618
if curve == 'secp256k1':
@@ -21,14 +23,15 @@ def __init__(self, chain_id, curve='secp256k1'):
2123
raise Exception("Curve not supported")
2224

2325
def _MakeKey(self, seed):
24-
secexp = randrange_from_seed__trytryagain(seed, self.curve.order)
26+
secexp = randrange_from_seed(seed, self.curve.order)
2527
return SigningKey.from_secret_exponent(secexp, curve=self.curve, hashfunc=hashlib.sha256)
2628

2729
def create_sign_keys(self, seed, nonce=0):
2830
private_key = self._MakeKey(seed)
2931
public_key = private_key.verifying_key
3032
return private_key, public_key, self.key_type
3133

34+
3235
def create_address(self, public_key):
3336
unhashed_address = chr(1) + str(self.chain_id) + crypto.hash_chain(public_key.to_string(encoding="compressed"))[0:20]
3437
address_hash = crypto.hash_chain(crypto.str2bytes(unhashed_address))[0:4]
@@ -60,9 +63,13 @@ def create_from_private_key(self, private_key):
6063
return Account(address=address, public_key=public_key, private_key=private_key, key_type=self.key_type)
6164

6265
def create_from_seed(self, seed, nonce=0):
63-
private_key, public_key, key_type = self.create_sign_keys(seed, nonce)
64-
address = self.create_address(public_key)
65-
return Account(address, public_key, private_key, key_type, seed, nonce)
66+
private_key = eth.mnemonic_to_private_key(seed, nonce=nonce)
67+
public_key = eth.derive_public_key(private_key)
68+
address = eth.address_from_private_key(private_key)
69+
key_type = "secp256k1"
70+
# private_key, public_key, key_type = self.create_sign_keys(seed, nonce)
71+
# address = self.create_address(public_key)
72+
return Account(address[2:], public_key, private_key, key_type, seed, nonce)
6673

6774
def create_with_values(self, address, public_key, private_key, key_type, seed=None):
6875
return Account(address, public_key, private_key, key_type, seed)

src/lto/accounts/ed25519/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from lto.accounts.ed25519.account_ed25519 import AccountED25519 as Account
2+
from lto.accounts.ed25519.account_factory_ed25519 import AccountFactoryED25519 as AccountFactory
3+
from nacl.signing import SigningKey, VerifyKey

src/lto/accounts/ed25519/account_ed25519.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
from lto.account import Account
1+
from lto.accounts.account import Account
22
import base58
33
from lto import crypto
4-
from nacl.signing import SigningKey, VerifyKey
54

65

76
class AccountED25519(Account):
@@ -12,6 +11,9 @@ def init(self, address, public_key, private_key=None, seed=None, nonce=0):
1211
def get_public_key(self):
1312
return base58.b58encode(bytes(self.public_key))
1413

14+
def get_private_key(self):
15+
return base58.b58encode(bytes(self.private_key))
16+
1517
def sign(self, message):
1618
if not self.private_key:
1719
raise Exception("Private key not set")

0 commit comments

Comments
 (0)