Skip to content

Commit ca0d193

Browse files
committed
Add create functions
1 parent 9cfcb10 commit ca0d193

2 files changed

Lines changed: 162 additions & 1 deletion

File tree

src/soroban/__init__.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,13 @@
1+
from soroban.create import *
12
from soroban.invoke import *
23
from soroban.models import *
34

4-
__all__ = ["invoke"]
5+
__all__ = [
6+
"Identity",
7+
"NetworkConfig",
8+
"Parameters",
9+
"Parameter",
10+
"invoke",
11+
"create_account",
12+
"create_asset",
13+
]

src/soroban/create.py

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
import logging
2+
from decimal import Decimal
3+
4+
import stellar_sdk
5+
from stellar_sdk.exceptions import SdkError
6+
import tomli_w
7+
8+
import soroban.models as soroban_models
9+
10+
11+
__all__ = ["create_account", "create_asset"]
12+
13+
14+
logger = logging.getLogger(__name__)
15+
16+
17+
def create_account(
18+
*,
19+
name: str,
20+
balance: Decimal = Decimal(10),
21+
source_account: soroban_models.Identity | stellar_sdk.Keypair | str | None = None,
22+
network: soroban_models.NetworkConfig | soroban_models.NetworkConfig | None = None,
23+
) -> stellar_sdk.Keypair:
24+
"""Create an account.
25+
26+
It automatically stores the secret key to a file.
27+
28+
Parameters
29+
----------
30+
name : name of the account. Used to name the toml file.
31+
balance : initial balance to transfer to the account from the source.
32+
source_account : account creating the new account.
33+
network : network to use.
34+
35+
Returns
36+
-------
37+
account : the new account.
38+
39+
"""
40+
identity = (
41+
source_account
42+
if isinstance(source_account, soroban_models.Identity)
43+
else soroban_models.Identity.from_source_account(account=source_account)
44+
)
45+
network = (
46+
network
47+
if isinstance(network, soroban_models.NetworkConfig)
48+
else soroban_models.NetworkConfig.from_network(network=network)
49+
)
50+
51+
horizon_server = stellar_sdk.Server(network.rpc_url)
52+
source_account_ = horizon_server.load_account(identity.public_key)
53+
54+
# the new account itself
55+
new_account = stellar_sdk.Keypair.random()
56+
with open(f"{name}.toml", "wb") as fd:
57+
tomli_w.dump({"secret_key": new_account.secret}, fd)
58+
59+
tx = (
60+
stellar_sdk.TransactionBuilder(
61+
source_account=source_account_,
62+
network_passphrase=network.network_passphrase,
63+
base_fee=network.base_fee,
64+
)
65+
.append_create_account_op(
66+
destination=new_account.public_key, starting_balance=str(balance)
67+
)
68+
.set_timeout(30)
69+
.build()
70+
)
71+
tx.sign(identity.keypair)
72+
response = horizon_server.submit_transaction(tx)
73+
if not response["successful"]:
74+
raise SdkError(response)
75+
logger.debug(f"Create account Op Resp:\n{response}")
76+
return new_account
77+
78+
79+
def create_asset(
80+
*,
81+
name: str,
82+
mint: Decimal = Decimal(1e9),
83+
source_account: soroban_models.Identity | stellar_sdk.Keypair | str | None = None,
84+
network: soroban_models.NetworkConfig | soroban_models.NetworkConfig | None = None,
85+
) -> None:
86+
"""Create a Stellar Asset.
87+
88+
It creates two accounts:
89+
90+
1. Issuer account: create the asset
91+
2. Distribution account: set a trustline to the asset and use to manage the
92+
asset.
93+
94+
Parameters
95+
----------
96+
name : The asset code, in the formats specified in Stellar's guide on assets.
97+
mint : Initial
98+
source_account : Account used to create the issuer and distribution accounts.
99+
network : network to use.
100+
101+
"""
102+
network = (
103+
network
104+
if isinstance(network, soroban_models.NetworkConfig)
105+
else soroban_models.NetworkConfig.from_network(network=network)
106+
)
107+
108+
issuer = create_account(name="issuer", source_account=source_account)
109+
distributor = create_account(name="distributor", source_account=source_account)
110+
111+
# Transactions require a valid sequence number that is specific to this account.
112+
# We can fetch the current sequence number for the source account from Horizon.
113+
horizon_server = stellar_sdk.Server(network.rpc_url)
114+
distributor_account = horizon_server.load_account(distributor.public_key)
115+
116+
asset = stellar_sdk.Asset(code=name, issuer=issuer.public_key)
117+
118+
# Establish a trust line between distribution account and the asset
119+
trust_transaction = (
120+
stellar_sdk.TransactionBuilder(
121+
source_account=distributor_account,
122+
network_passphrase=network.network_passphrase,
123+
base_fee=network.base_fee,
124+
)
125+
.append_change_trust_op(asset=asset)
126+
.set_timeout(30)
127+
.build()
128+
)
129+
130+
trust_transaction.sign(distributor)
131+
response = horizon_server.submit_transaction(trust_transaction)
132+
if not response["successful"]:
133+
raise SdkError(response)
134+
logger.debug(f"Change Trust Op Resp:\n{response}")
135+
136+
issuer_account = horizon_server.load_account(issuer.public_key)
137+
# Second, the issuing account actually sends a payment using the asset.
138+
payment_transaction = (
139+
stellar_sdk.TransactionBuilder(
140+
source_account=issuer_account,
141+
network_passphrase=network.network_passphrase,
142+
base_fee=network.base_fee,
143+
)
144+
.append_payment_op(destination=distributor.public_key, amount=mint, asset=asset)
145+
.set_timeout(30)
146+
.build()
147+
)
148+
payment_transaction.sign(issuer)
149+
response = horizon_server.submit_transaction(payment_transaction)
150+
if not response["successful"]:
151+
raise SdkError(response)
152+
logger.debug(f"Payment Op Resp:\n{response}")

0 commit comments

Comments
 (0)