Skip to content

NestedMultiSign#675

Open
RichardAH wants to merge 1 commit intodevfrom
multi-sig-nested-squash
Open

NestedMultiSign#675
RichardAH wants to merge 1 commit intodevfrom
multi-sig-nested-squash

Conversation

@RichardAH
Copy link
Contributor

NestedMultiSign Amendment

Overview

This amendment introduces nested multi-signature validation, allowing signer lists to delegate signing authority to other accounts that themselves have signer lists. This enables hierarchical organizational structures where, for example, a company account can require signatures from department accounts, which in turn require signatures from authorized individuals.

Key Features

Hierarchical Signing (up to 4 levels deep)

  • Signers can now delegate to their own signer lists rather than providing a direct signature
  • Enables corporate governance structures: Company → Departments → Teams → Individuals
  • Each level validates against its own signer list and quorum requirements
  • Weight is only contributed to the parent level when a signer's own quorum is satisfied

Cycle Detection & Quorum Relaxation

  • Detects circular dependencies in signer list configurations (e.g., A→B→A)
  • Prevents permanent fund lockout when accounts accidentally create cyclical signer relationships
  • When a cycle makes certain signers unavailable, the effective quorum is relaxed to the maximum achievable weight
  • Accounts with effectiveQuorum == 0 (all signers cyclic) correctly fail with tefBAD_QUORUM

Transaction Structure

Nested signers are represented by including an sfSigners array instead of sfSigningPubKey/sfTxnSignature:

{
  "Signers": [{
    "Signer": {
      "Account": "DepartmentA",
      "Signers": [{
        "Signer": {
          "Account": "Employee1",
          "SigningPubKey": "...",
          "TxnSignature": "..."
        }
      }]
    }
  }]
}

Validation Rules

  • Maximum nesting depth: 4 levels
  • Signers at each level must be in strict ascending order (consensus requirement)
  • A signer entry cannot have both nested signers AND signature fields
  • Leaf signers must provide valid SigningPubKey and TxnSignature
  • Each level's accumulated weight must meet its quorum (or relaxed quorum if cycles exist)

Error Codes

Code Condition
tefBAD_SIGNATURE Depth limit exceeded, invalid signer, or malformed signer entry
tefBAD_QUORUM Insufficient weight to meet quorum, or all signers are cyclic
tefNOT_MULTI_SIGNING Nested signer account has no signer list configured
tefMASTER_DISABLED Leaf signer's master key is disabled
tefINTERNAL Invariant violation (should never occur)

Backward Compatibility

When featureNestedMultiSign is disabled, nested signer arrays are rejected with temMALFORMED, preserving existing behavior.

Comment on lines -1186 to +1187
return (
// A Signer object always contains these fields and no
// others.
obj.isFieldPresent(sfAccount) &&
obj.isFieldPresent(sfSigningPubKey) &&
obj.isFieldPresent(sfTxnSignature) && obj.getCount() == 3);
if (obj.getCount() != 4 || !obj.isFieldPresent(sfAccount))
return false;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove 4 here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

        if (!obj.isFieldPresent(sfAccount))
            return false;

        // leaf signer
        if (obj.isFieldPresent(sfSigningPubKey) &&
            obj.isFieldPresent(sfTxnSignature) &&
            !obj.isFieldPresent(sfSigners))
            return obj.getCount() == 3;

        // nested signer
        if (!obj.isFieldPresent(sfSigningPubKey) &&
            !obj.isFieldPresent(sfTxnSignature) &&
            obj.isFieldPresent(sfSigners))
            return obj.getCount == 2;

if (lastAccountID == accountID)
return Unexpected("Duplicate Signers not allowed.");
checkSignersArray = [&](STArray const& signersArray,
AccountID const& parentAccountID,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unused parentAccuontID

@zgrguric
Copy link

zgrguric commented Feb 6, 2026

First, thank you for doing this.
What is overhead to xahaud for more than 4 levels? Is there benchmark tests for this?

@sublimator
Copy link
Collaborator

What is overhead to xahaud for more than 4 levels?

Good question, wonder if there should be some kind of leaf specified limit ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants