partiallySignTransaction function
Given a list of KeyPair objects which are key pairs pertaining to addresses that are required to sign a transaction, this method will return a new signed transaction.
Though the resulting transaction might have every signature it needs to land on the network, this function will not assert that it does.
Implementation
Future<Transaction> partiallySignTransaction(
List<KeyPair> keyPairs,
Transaction transaction,
) async {
Map<Address, SignatureBytes>? newSignatures;
Set<Address>? unexpectedSigners;
for (final keyPair in keyPairs) {
final addr = getAddressFromPublicKey(keyPair.publicKey);
final existingSignature = transaction.signatures[addr];
// Check if the address is expected to sign the transaction.
if (!transaction.signatures.containsKey(addr)) {
unexpectedSigners ??= <Address>{};
unexpectedSigners.add(addr);
continue;
}
// Skip if there are already unexpected signers since we won't be using
// the signatures.
if (unexpectedSigners != null) {
continue;
}
final newSignature = signBytes(
keyPair.privateKey,
transaction.messageBytes,
);
if (existingSignature != null &&
_bytesEqual(newSignature.value, existingSignature.value)) {
// Already have the same signature.
continue;
}
newSignatures ??= <Address, SignatureBytes>{};
newSignatures[addr] = newSignature;
}
if (unexpectedSigners != null && unexpectedSigners.isNotEmpty) {
final expectedSigners = transaction.signatures.keys.toList();
throw SolanaError(
SolanaErrorCode.transactionAddressesCannotSignTransaction,
{
'expectedAddresses': expectedSigners.map((a) => a.value).toList(),
'unexpectedAddresses': unexpectedSigners.map((a) => a.value).toList(),
},
);
}
if (newSignatures == null) {
return transaction;
}
final mergedSignatures = <Address, SignatureBytes?>{
...transaction.signatures,
...newSignatures,
};
if (transaction is TransactionWithLifetime) {
return TransactionWithLifetime(
messageBytes: transaction.messageBytes,
signatures: mergedSignatures,
lifetimeConstraint: transaction.lifetimeConstraint,
);
}
return Transaction(
messageBytes: transaction.messageBytes,
signatures: mergedSignatures,
);
}