Skip to main content

Create SubWallet On Enterprise Profile

POST /v1/trovo-api/users/subwallet

Json Body

{
WalletType int `json:"walletType"` //0=normal, 1= assetIssuing (if issuing wallet, then linkedWalletPublicKey is required). Required for initial Call
SubwalletPublicKey string `json:"subwalletPublicKey"` //required for Initial Call. public key of the subwallet being created
WalletTag string `json:"walletTag"` //required for initial Call. tag for the subwallet. If an issuing wallet that is to be used to issue a token like BRT then let the tag be brtissuer.
Alias string `json:"alias"` // this is the friendly wallet alias generated by the api, that can be used to reference this wallet directly when interacting with it for payment.
Transaction string `json:"transaction"` //base64Txn string
PrimarySignature string `json:"primarySignature"` //signature obtained by signing the transaction with the primary wallet ( the enterprise profile wallet). This allows for fees and activation tokens to be deducted from the enterprise wallet and used to activate the subwallet and any possible linked wallets.
SubWalletMustSign int `json:"subWalletMustSign"`// when set to 1, then the subwallet secret key must be used to sign the transaction object.
SubWalletSignature string `json:"subWalletSignature"` //signature obtained by signing the transaction with the secret key of the subwallet.
TransactionID string `json:"transactionId"`
NetworkPassPhrase string `json:"networkPassPhrase"`
Messages []string `json:"messages"` //messages returned containing useful information the enterprise needs to be aware of.
FeeAmount string `json:"feeAmount"`
FeeCode string `json:"feeCode"` //asset code for the fee that will be charged for this creation of subwallet
LinkedWalletMustSign int `json:"linkedWalletMustSign"` //0 = no linked wallet, 1= linked wallet must provide signature too for authentication.
LinkedWalletPublicKey string `json:"linkedWalletPublicKey"` //required for initial call only if wallet type is 1 (issuing wallet)
LinkedWalletSignature string `json:"linkedWalletSignature"` // only if linkedWalletMustSign = 1. This is the signature obtained from signing the transaction object with the linked wallet secret key.
}

INITIAL CALL REQUIRED PARAMETERS:

  • walletType
  • subwalletPublicKey
  • walletTag
  • linkedWalletPublicKey (only if the wallet type is 1)

SECOND CALL: ALL needed signatures must be returned with the response object.

Options

ISSUING WALLET: This is the wallet type option that will be used when you intend to create a wallet for minting/issuing a token. The wallet type value to be given is 1. When this wallet type is specified, there must be a wallet public key of a linked distribution wallet that is specified as the linked wallet public key. The Issuing wallet requires generation of two separate wallets. First is for the issuer and then the second is for the linked distribution wallet. Any change made to the permissions of the issuing wallet is also mirrored in the distribution wallet also. When an issuing wallet is created, then there must also be a signature for the distribution wallet that is submitted on the second call.

STANDARD WALLET: This is a standard wallet that is generally used for performing transactions. Wallet type value should be specified as 0 and there is no linked wallet needed for this.

Sample Code - Signing Function

//signSubwalletBase64Txn.js
import { Keypair, Transaction, Utils } from "stellar-sdk";

/**
* Sign a Stellar Transaction XDR (base64) with 3 separate secret keys
* and return ONLY the base64-encoded signatures (not the signed envelope)
*
* @param {string} primarySecretKey
* @param {string} subWalletSecretKey
* @param {string} linkedWalletSecret
* @param {string} base64Txn
* @param {string} networkPassPhrase
* @returns {Promise<{primarySignature: string, subWalletSignature: string, linkedWalletSignature: string}>}
*/
export async function SignSubwalletBase64Txn(
primarySecretKey,
subWalletSecretKey,
linkedWalletSecret,
base64Txn,
networkPassPhrase
) {
try {
// ---- equivalent of keypair.ParseFull ----
const primaryKP = Keypair.fromSecret(primarySecretKey);
const subWalletKP = Keypair.fromSecret(subWalletSecretKey);
const linkedWalletKP = Keypair.fromSecret(linkedWalletSecret);

// ---- parse transaction from base64 XDR ----
const tx = new Transaction(base64Txn, networkPassPhrase);

// ---- calculate tx hash ----
const txHash = tx.hash(); // returns Buffer of the transaction hash

// ---- sign using raw hash (Go version signs the hash, not the envelope) ----
const primarySignature = primaryKP.sign(txHash).toString("base64");
const subWalletSignature = subWalletKP.sign(txHash).toString("base64");
const linkedWalletSignature = linkedWalletKP
.sign(txHash)
.toString("base64");

return {
primarySignature,
subWalletSignature,
linkedWalletSignature,
};
} catch (err) {
throw err;
}
}

Sample Code - Full Implementation

// subwallet.js

import axios from "axios";
import { Keypair, Networks, Transaction } from "stellar-sdk";

async function createSubwallet() {
try {
// === 1️⃣ CONFIGURATION ===
const API_URL = BASE_URL + "/v1/trovo-api/users/subwallet"; // replace with real API endpoint

const WALLET_TYPE = 1; //create an issuing wallet
// subwallet (the wallet that is being created under the enterprise)
const subwalletKeypair = Keypair.random();
const subwalletPublicKey = subwalletKeypair.publicKey();
const linkedWalletKeypair = Keypair.random();
const linkedWalletPublicKey = linkedWalletKeypair.publicKey();

// Primary Secret key (the account that is creating the subwallet)
const PRIMARY_SECRET = getFromEnvVariable(); // inject the secret from ENV variable. This is the signer of your enterprise primary wallet.
const primaryKeypair = Keypair.fromSecret(PRIMARY_SECRET);

// === 2️⃣ INITIAL REQUEST (Create unsigned transaction) ===
const subwalletRequestBody = {
walletType: walletType,
subwalletPublicKey: subwalletPublicKey,
walletTag: walletTag,
linkedWalletPublicKey: linkedWalletPublicKey,
};

console.log("🔹 Sending initial subwallet creation request...");
const { data: unsignedTxResponse } = await axios.post(
API_URL,
subwalletRequestBody
);

// The response should contain: Transaction (XDR) and NetworkPassPhrase
const { Transaction: base64Txn, NetworkPassPhrase: networkPassphrase } =
unsignedTxResponse;

if (!base64Txn || !networkPassphrase) {
throw new Error(
"Invalid response from endpoint — missing transaction or networkPassPhrase"
);
}

console.log("✅ Received unsigned transaction from server.");

// === 3️⃣ SIGN THE TRANSACTION ===
const result = await SignSubwalletBase64Txn(
primaryKeypair.secretKey(),
subWalletKeypair.secretKey(),
linkedWalletKeypair.secretKey(),
base64Txn,
networkPassPhrase
);

// === 4️⃣ SECOND CALL — Send back signed transaction ===
const signedBody = {
...unsignedTxResponse,
primarySignature: result.primarySignature,
subwalletSignature: result.subWalletSignature,
linkedWalletSignature: result.linkedWalletSignature,
};

console.log("🔹 Sending signed transaction back for mint commit...");
const { data: finalResponse } = await axios.post(API_URL, signedBody);

// === 5️⃣ SUCCESS RESPONSE ===
console.log("✅ SubwalletCreation completed successfully!");
console.log("Transaction ID:", finalResponse.TransactionID);
console.log("Full response:", finalResponse);
} catch (error) {
console.error(
"❌ Error creating subwallet:",
error.response?.data || error.message
);
}
}

// Run the function
createSubwallet();