MultisigAccount constructor
Creates a new MultisigAccount instance with automatic address derivation.
This factory constructor performs the following operations:
- Validates the threshold (must be ≥2 and ≤ number of signatories)
- Deduplicates the provided addresses
- Validates the signatory count (2-100 signatories)
- Converts addresses to public keys
- Sorts public keys deterministically
- Derives the multisig account address using Substrate's algorithm
Parameters:
addresses: List of signatory addresses (SS58 encoded). Duplicates are automatically removed.threshold: Number of approvals required for execution (must be between 2 and number of signatories)
Returns: A MultisigAccount instance with the derived multisig address.
Throws:
- ArgumentError if threshold is less than 2
- ArgumentError if fewer than 2 unique addresses are provided
- ArgumentError if more than 100 addresses are provided
- ArgumentError if threshold exceeds the number of signatories
- ArgumentError if any address is invalid or cannot be decoded
Example:
final multisigAccount = MultisigAccount(
addresses: [alice.address, bob.address, charlie.address],
threshold: 2,
);
// Any 2 of the 3 signatories can approve transactions
Implementation
factory MultisigAccount({required final List<String> addresses, required final int threshold}) {
// Validate threshold
if (threshold < 2) {
throw ArgumentError('Threshold must be at least 2, got $threshold');
}
// Remove duplicates
final uniqueAddresses = addresses.toSet().toList(growable: false);
// Validate count
if (uniqueAddresses.length < 2) {
throw ArgumentError('At least 2 signatories required, got ${uniqueAddresses.length}');
}
if (uniqueAddresses.length > 100) {
throw ArgumentError('Maximum 100 signatories allowed, got ${uniqueAddresses.length}');
}
if (threshold > uniqueAddresses.length) {
throw ArgumentError(
'Threshold ($threshold) cannot exceed signatories (${uniqueAddresses.length})',
);
}
// Convert to public keys and sort
final pubkeysWithAddresses = <Uint8List>[];
for (final address in uniqueAddresses) {
try {
final pubkey = Address.decode(address).pubkey;
pubkeysWithAddresses.add(pubkey);
} catch (e) {
throw ArgumentError('Invalid address: $address');
}
}
// Sort by public key bytes
pubkeysWithAddresses.sort((final a, final b) => a.compareBytes(b));
// Generate multisig address
final multisigPubkey = _deriveMultisigAddress(pubkeysWithAddresses, threshold);
return MultisigAccount._(
threshold: threshold,
publicKeys: pubkeysWithAddresses,
multisigPubkey: multisigPubkey,
);
}