Skip to main content

When operation source accounts differ from that of the parent transaction

Let's review the unique case where an operation may have a source account different from that of the parent transaction envelope.

There are two main situations where this may happen:

  1. Operations that affect more than one account
  2. Operations with a high threshold weight

Operations that affect multiple accounts

If a transaction has operations with multiple source accounts, it will require the source account signature for each operation.

One case where this happens is with specialized transactions such as Sponsored Reserves where a sponsoring account agrees to pay the base reserves for a sponsored account.

In this example, there are two sponsoring accounts, S1 and S2, that sponsor trustlines for Account A.

//
// 2. Both S1 and S2 sponsor trustlines for Account A for different assets.
//
let aAccount = await server.loadAccount(A.publicKey());
let tx = new TransactionBuilder(aAccount, { fee: BASE_FEE })
.addOperation(
Operation.beginSponsoringFutureReserves({
source: S1.publicKey(),
sponsoredId: A.publicKey(),
}),
)
.addOperation(
Operation.changeTrust({
asset: usdcAsset,
limit: "5000",
}),
)
.addOperation(Operation.endSponsoringFutureReserves({}))

.addOperation(
Operation.beginSponsoringFutureReserves({
source: S2.publicKey(),
sponsoredId: A.publicKey(),
}),
)
.addOperation(
Operation.changeTrust({
asset: usdtAsset,
limit: "2500",
}),
)
.addOperation(Operation.endSponsoringFutureReserves({}))
.setNetworkPassphrase(Networks.TESTNET)
.setTimeout(180)
.build();

// All 3 accounts must approve/sign this transaction.
tx.sign(S1, S2, A);
let txResponse = await server.submitTransaction(tx);

Learn more about Sponsored Reserves here.

Operations with a high threshold weight

Operations fall into one of three threshold categories:

  1. Low
  2. Medium
  3. High

Each threshold category has a weight between 0 and 255. This determines the signature weight required for an operation. The combined weight of all signatures for the source account of the operation meets the threshold for the operation. Combined weight of the signatures for the source account of the transaction meets the low threshold for the source account.

Here is an example.

const account = await server.loadAccount(sourceAccountKeypair.publicKey());

const transaction = new StellarSdk.TransactionBuilder(account, {
fee: StellarSdk.BASE_FEE,
networkPassphrase: StellarSdk.Networks.TESTNET, // or StellarSdk.Networks.PUBLIC
})
.addOperation(
StellarSdk.Operation.setOptions({
signer: {
pubKey: signer1Keypair.publicKey(),
weight: 1,
},
}),
)
.addOperation(
StellarSdk.Operation.setOptions({
signer: {
pubKey: signer2PublicKey,
weight: 1,
},
lowThreshold: 2,
medThreshold: 2,
highThreshold: 2,
}),
)
.setTimeout(30)
.build();

transaction.sign(sourceAccountKeypair);
transaction.sign(signer1Keypair);