0

I run a validator node on the public network for which I need to create an account. Hence, I started by creating a Stellar account in the test network as described here. So far so good.

As per my understanding, I can now create additional accounts using this account by using the TransactionBuilder and CreateAccount functions. So based on the documentation of the TransationBuilder and this example I ended up with the following code.

from stellar_sdk.keypair import Keypair
from stellar_sdk.network import Network
from stellar_sdk.server import Server
from stellar_sdk.transaction_builder import TransactionBuilder
from stellar_sdk.exceptions import NotFoundError, BadResponseError, BadRequestError

server = Server("https://horizon-testnet.stellar.org")
source_key = Keypair.from_secret("SXXXX") # Account in test network

# Thew new account's public key = my validator's public key
destination_id = "GXXXXX"

source_account = server.load_account(source_key.public_key)

base_fee = server.fetch_base_fee()

# Start building the transaction.
transaction = (
    TransactionBuilder(
        source_account=source_account,
        network_passphrase=Network.PUBLIC_NETWORK_PASSPHRASE,
        base_fee=base_fee,
    )
        .append_create_account_op(destination=destination_id, starting_balance="10")  
        # Wait a maximum of three minutes for the transaction
        .set_timeout(180)
        .build()
)

Network.public_network()
transaction.sign(source_key)

try:
    # And finally, send it off to Stellar!
    response = server.submit_transaction(transaction)
    print(f"Response: {response}")
except (BadRequestError, BadResponseError) as err:
    print(f"Something went wrong!\n{err}")

The program exits with the error below. A similar question on this site was solved by adding the public network line before signing the transaction.


Something went wrong!
{
  "type": "https://stellar.org/horizon-errors/transaction_failed",
  "title": "Transaction Failed",
  "status": 400,
  "detail": "The transaction failed when submitted to the stellar network. The `extras.result_codes` field on this response contains further details.  Descriptions of each code can be found at: https://www.stellar.org/developers/guides/concepts/list-of-operations.html",
  "extras": {
    "envelope_xdr": "AAAAADx4IYtDyD1GcNQMLowZLkxHGWFCa2pDpVl/t2wEDNPtAAAAZAAQCjsAAAABAAAAAQAAAAAAAAAAAAAAAF6Jq9EAAAABAAAAF0NyZWF0aW5nIGFjYyB0cmFuc2F0aW9uAAAAAAEAAAAAAAAAAAAAAAAiqAyTZW5SpZuTDf/IS+zflveRXANlVd7uVU2AyJh7UQAAAAAF9eEAAAAAAAAAAAEEDNPtAAAAQHZ0sr4K6oxvJq+HowKpQjz4z8pCxTZiZn/JtBaouqxJB9HOS1JHI5zMwOuhge+Tf2j75ntb5KcDBAkVxUb7MQg=",
    "result_codes": {
      "transaction": "tx_bad_auth"
    },
    "result_xdr": "AAAAAAAAAGT////6AAAAAA=="
  }
}


What am I doing wrong? Is my approach/understanding maybe just fundamentally wrong?

1 Answer 1

0

The code pasted below does exactly what you describe. The only issue is that my example uses the Java SDK instead of the Javascript one. The seed in the method signature is from the source account that you have created. You need the seed so that you can create a KeyPair to sign the transaction. The AccountResponseBag returned is just a wrapper for AccountResponse that includes the secret seed for the newly created account. Hope this helps:

public AccountResponseBag createAndFundStellarAccount(String seed, String startingBalance) throws Exception {
        LOGGER.info("\uD83D\uDC99 ... ... ... ... createAndFundStellarAccount starting ....... startingBalance: " + startingBalance);
        setServerAndNetwork();
        AccountResponse accountResponse;
        try {
            KeyPair newAccountKeyPair = KeyPair.random();
            KeyPair sourceKeyPair = KeyPair.fromSecretSeed(seed);
            String secret = new String(newAccountKeyPair.getSecretSeed());
            AccountResponse sourceAccount = server.accounts().account(sourceKeyPair.getAccountId());

            Transaction transaction = new Transaction.Builder(sourceAccount, network)
                    .addOperation(new CreateAccountOperation.Builder(
                            newAccountKeyPair.getAccountId(), startingBalance)
                            .build())
                    .addMemo(Memo.text("CreateAccount Tx"))
                    .setTimeout(180)
                    .setOperationFee(100)
                    .build();

            transaction.sign(sourceKeyPair);

            SubmitTransactionResponse submitTransactionResponse = server.submitTransaction(transaction);
            if (submitTransactionResponse.isSuccess()) {
                accountResponse = server.accounts().account(newAccountKeyPair.getAccountId());
                LOGGER.info("\uD83D\uDC99  " +
                        "Stellar account has been created and funded!: \uD83C\uDF4E \uD83C\uDF4E YEBO!!!");
                AccountResponseBag bag = new AccountResponseBag(accountResponse, secret);
                LOGGER.info(("\uD83C\uDF4E \uD83C\uDF4E RESPONSE from Stellar; " +
                        "\uD83D\uDC99 new accountId: ").concat(bag.getAccountResponse().getAccountId()));
                LOGGER.info("\uD83D\uDC99 \uD83D\uDC99 Account created, check the funded balance, " +
                        "\uD83D\uDC99 should be: " + startingBalance + " " + G.toJson(bag));
                return bag;
            } else {
                LOGGER.warning("CreateAccountOperation ERROR: \uD83C\uDF45 resultXdr: "
                        + submitTransactionResponse.getResultXdr().get());

                throw new Exception("CreateAccountOperation transactionResponse is NOT success");
            }


        } catch (IOException e) {
            LOGGER.severe("Failed to create account - see below ...");
            throw new Exception("\uD83D\uDD34 Unable to create Account", e);
        }
    }
4
  • Thaks for your answer. I am not sure if this does what I intend to happen . newAccountKeyPair = KeyPair.random(); generates a new seed and public key, right? Then the new account is assigned to this pair, correct? What I need however, is my validator, that ALREADY has a keypair, to get a new account. In that case, why do I need to generate a new keypair?
    – cndolo
    Commented Apr 5, 2020 at 17:53
  • Also, what is the network variable in Transaction transaction = new Transaction.Builder(sourceAccount, network)?
    – cndolo
    Commented Apr 5, 2020 at 18:05
  • network = Network.TESTNET or PUBLIC Commented Apr 8, 2020 at 12:26
  • also, you are not generating a new KeyPair; you just are recreating the KeyPair that you already own Commented Apr 8, 2020 at 12:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.