xls: 91d title: Beneficiary description: An inheritance mechanism: a designated account gains the regular key after a chosen period of account inactivity. author: Chris Dangerfield (@xrpl365), Denis Angell (@dangell7) category: Amendment status: Draft proposal-from: Standards discussion 269 created: 2025-02-25 updated: 2026-09-11
When an XRP Ledger account holder dies, the assets in the account are unreachable: without the private key nobody can move them, and there is no protocol mechanism to pass them on. The alternatives available today are to share the key with an executor, which grants full control while the holder is still alive, or to lose the assets.
This amendment lets an account designate a beneficiary and an inactivity period. Once the account has sent no transaction for that period, the beneficiary's signature is accepted on the account's transactions, exactly as a regular key's is. Nothing on the account is replaced: the master key and any regular key keep working, so an owner who reappears simply signs, which resets the inactivity period and closes the beneficiary's access again.
There is no claim transaction. The designation is a second key that starts working after a period of silence and stops the moment the owner is heard from.
Revision 1 of this proposal is the body of Standards discussion 269, posted 2025-02-25. Review in that thread produced six changes, each agreed by an author in the thread, and this revision is revision 1 plus those changes:
- The data moves off
AccountRootinto its own ledger entry. Ed Hennis (@ximinez) asked whether a ledger object had been considered, on the ground that the extra data is worth an incremental reserve. Denis Angell: "LedgerEntry is a winner here imo."sfLastInteractionis the exception and is explained in section 3.2. - The transactions are renamed to noun-verb order. Mayukha Vadari
(@mvadari): "Transactions are usually named in the form of NounVerb. So they
should be
BeneficiarySetandBeneficiaryInvoke." Chris Dangerfield: "noted, we can update". Beneficiarybecomes optional onBeneficiarySet, and its absence clears the designation. Proposed by @ximinez, agreed by @dangell7. This is also the answer to @xVet asking for a separate delete transaction.- Clearing removes every field the amendment added, so nothing is left behind. Proposed by @ximinez ("Great Suggestion").
sfLastInteractionis maintained only while a designation exists. Proposed by @ximinez, agreed by @dangell7 ("Agree"). An account that has never set a beneficiary is unaffected by this amendment and pays nothing for it.- The claim transaction is gone and the beneficiary became an additional
signer. This is the largest change and it resolves the thread's one
unsettled objection. Mayukha Vadari described an owner whose master key is
blackholed, who signs with a regular key, who designates a beneficiary and
then happens to go quiet: under revision 1 the beneficiary overwrites that
regular key and locks the live owner out of their own account.
@xrpl365 confirmed the reading. @mvadari then asked "why does the regular key
have to change at all? Why can't the beneficiary just be an additional key
that can sign for the account?", and @ximinez took it further: "You could get
rid of the
InvokeBeneficiarytransaction entirely... modify the signature checking logic such that if the amount of time has passed, and the transaction is signed by the beneficiary, it works." @xrpl365 called it a design choice and said he was happy with either. This revision takes that route: no key is ever replaced, so the lockout cannot happen. - Brandon Wilson's objection is answered by the same change. He asked whether claiming should require the beneficiary's signature, so that an unreachable beneficiary cannot be designated. It now does, necessarily: the only way the designation has any effect is a transaction the beneficiary signs. An unreachable beneficiary account is simply never used, and the owner's assets stay where they are.
Three review points were answered without a change. @tequdev asked what happens
to a blackholed account: nothing, now, because no key is overwritten — the
beneficiary gains a signing path while the account's own key settings stay as
they are (section 7). @mvadari observed that funds are never moved by this
amendment, which is why the risk profile is narrower than it first appears.
@Tapanito asked what happens when two accounts name each other and both become
claimable in the same ledger; @dangell7's answer was that it is no different
from two SetRegularKey transactions, and under this revision it is narrower
still, since neither account's keys change at all.
One question in the thread is still open and is not settled here. @xrpl365 observed that a designation plus a blackhole amounts to a form of escrow for an issued asset, and asked "Should we work to prevent this?" Nobody answered. This revision does not prevent it.
One entry per account that has a designation, owned by that account, charging one owner reserve.
The ID is the tagged hash of the Beneficiary key space prefix and the owning
AccountID. One account, one designation, no sequence in the key: setting a
beneficiary twice updates the entry rather than creating a second one.
| Field Name | Required | Internal Type | Description |
|---|---|---|---|
| LedgerEntryType | Yes | UINT16 | Identifies this as a Beneficiary entry |
| Account | Yes | ACCOUNT | The account that will be inherited. Owns the entry |
| Beneficiary | Yes | ACCOUNT | The account that receives the regular key |
| TimeLock | Yes | UINT32 | Seconds of silence required before the beneficiary's signature is accepted |
| OwnerNode | Yes | UINT64 | Owner directory hint |
| PreviousTxnID | Yes | HASH256 | Standard |
| PreviousTxnLgrSeq | Yes | UINT32 | Standard |
Beneficiary is not required to differ from Account's regular key, nor to be
an account that can sign. See section 7.
None.
Deleted by BeneficiarySet submitted without a Beneficiary field, and by
nothing else. Deleting the entry also removes
sfLastInteraction from the AccountRoot, so an account that clears its
designation is left exactly as it was before setting one.
An account with a Beneficiary entry cannot be deleted, in the ordinary way
that an owned object blocks AccountDelete.
beneficiary, in account_objects as a type filter and in ledger_entry
either as an object index or as the owning account's address.
A single new optional field on AccountRoot, sfLastInteraction (UINT32),
holding the parent close time of the last ledger in which this account was the
sending account of a successfully applied transaction.
This one field stays on AccountRoot rather than moving to the ledger entry
with the other two, because the sending account's AccountRoot is already
being modified by every transaction it sends — the sequence number is
incremented there. Writing the timestamp beside it costs nothing. Maintaining
it on a separate ledger entry would add a lookup and a second modified entry to
every transaction on the ledger, which is a far larger cost than the field
saves.
It is written only when it is already present, which is exactly while a
designation exists, so an account that has never used this amendment is never
touched. BeneficiarySet creates it and BeneficiarySet-to-clear removes it.
The value is the parent close time of the applying ledger, the same clock
Expiration and FinishAfter use elsewhere, so it is comparable with
TimeLock without conversion.
Designates, updates or clears the beneficiary. Only the account itself may
submit it, and it is not delegable: it decides who may eventually sign for the
account, which puts it in the same class as SetRegularKey, SignerListSet
and AccountDelete, none of which may be delegated.
| Field Name | Required | Internal Type | Description |
|---|---|---|---|
| Account | Yes | ACCOUNT | The account being designated for |
| Beneficiary | No | ACCOUNT | The beneficiary. Absent clears the designation |
| TimeLock | Conditional | UINT32 | Required when Beneficiary is present, forbidden when it is absent |
Beneficiaryequal toAccount:temMALFORMED. An account cannot inherit from itself, and allowing it would let an account set a regular key on itself by a route that bypassesSetRegularKey.TimeLockpresent withoutBeneficiary, or absent with it:temMALFORMED.TimeLockof zero, or abovekMaxBeneficiaryTimeLock:temMALFORMED. A zero time lock makes the designation invocable in the same ledger it is set, which isSetRegularKeywith extra steps. The ceiling answers the "Maximum TimeLock" open question of revision 1 and is set at ten years, long enough for the intended use and short enough that the value is meaningful.Beneficiarynaming an account that does not exist:tecNO_TARGET.- Clearing when no designation exists:
tecNO_ENTRY. - Insufficient reserve for the new entry:
tecINSUFFICIENT_RESERVE.
Creating: the Beneficiary entry is created in the account's owner directory,
one owner reserve is charged, and sfLastInteraction is set on the
AccountRoot to the current parent close time.
Updating: the entry's Beneficiary and TimeLock are overwritten.
sfLastInteraction is updated by the ordinary rule in section 3.2, since this
is an outgoing transaction, so an update also resets the timer.
Clearing: the entry is deleted, the reserve released, and sfLastInteraction
removed.
There is no second transaction. The designation takes effect in the signature authorization the ledger already performs for every transaction.
Transactor::checkSingleSign accepts a signature when the signing key's account
is the account itself and the master key is enabled, or when it equals the
account's sfRegularKey. This amendment adds a third case, tried after those
two: the signing key's account equals the Beneficiary of the account's
designation, and
parentCloseTime - LastInteraction >= TimeLock
If the designation exists and the signer is the beneficiary but the period has
not elapsed, the result is tefBAD_AUTH, the same as any other unauthorized
key.
This is single-signature only. A multi-signed transaction carries no
SigningPubKey and is authorized against the account's signer list, which this
amendment does not touch.
Three consequences follow, and they are the point of the design:
- The owner is never locked out. No key is replaced. The master key, the regular key and the signer list all keep working exactly as they did.
- The owner reclaims by doing nothing special. Any transaction they sign
updates
sfLastInteraction(section 3.2), which puts the beneficiary back outside the window until the period elapses again. - A beneficiary-signed transaction does not update
sfLastInteraction. The field records the owner's activity, not the account's. Were it otherwise, the beneficiary's first transaction would reset the timer and shut the door behind it.
The designation is not consumed. It stays on the ledger, and the beneficiary's
access opens and closes with the owner's silence, indefinitely, until a
BeneficiarySet changes or clears it.
Once the period has elapsed the beneficiary may sign anything the owner could,
including a BeneficiarySet that changes or clears the designation. Clearing it
removes the beneficiary's own access, which is the same foot-gun as clearing
one's own regular key.
- A
Beneficiaryentry exists if and only if its owner'sAccountRoothassfLastInteraction. Accounton the entry is never equal toBeneficiary.TimeLockis neither zero nor abovekMaxBeneficiaryTimeLock.Accounton the entry never changes after creation.- A
Beneficiaryentry is deleted only byBeneficiarySet. sfLastInteractionnever moves backwards.- This amendment never changes
sfRegularKey,sfSignerListorlsfDisableMasteron any account.
Why a signing path rather than moving the assets. Moving assets would require the protocol to decide what "the assets" are — trust lines, MPTs, NFTs, objects with their own owners — and to move each of them, which is unbounded work and duplicates every existing transfer rule. Admitting a second signer transfers control of the account itself in constant time, and every existing rule about what an account may do continues to apply unchanged.
Why a signing path rather than replacing the regular key. Replacing a key takes something away from whoever held it. An owner alive and well, signing with a regular key, who simply did not transact for the period they chose, would lose their account to a mechanism they set up to help their family. Adding a key takes nothing from anyone: the owner's keys keep working, and using one closes the beneficiary's window again.
Why inactivity rather than a proof of death. The ledger cannot observe death. Inactivity is the only signal the protocol has, and it is under the holder's control: any transaction they send resets it.
Why no claim transaction. There is nothing to claim. The condition is checkable at signature time, so the beneficiary simply signs; a transaction whose only effect was to announce that a deadline had passed would add a step, a fee and a piece of ledger state for nothing.
A new amendment, featureBeneficiary, purely additive. sfLastInteraction is
optional on AccountRoot and absent from every existing account.
Two existing behaviours are extended, both only for accounts that have a
designation. A transaction sent from such an account writes a timestamp to an
AccountRoot it was already modifying. And checkSingleSign gains a third
accepting case, reached only after the master-key and regular-key cases have
both been tried, so an account without a designation behaves identically.
No signature that was valid before this amendment becomes invalid under it.
Allocated clear of XRPLF develop 9403736199 and of the firewall,
subscriptions, confidential-voting, AMM-curves and repo-market branches, since
alphanet merges all of them and develop can see none.
| Code | |
|---|---|
featureBeneficiary |
Supported::No, VoteBehavior::DefaultNo |
ltBENEFICIARY |
0x0096 |
| Ledger name space | 'Y' |
ttBENEFICIARY_SET |
119 |
sfBeneficiary |
ACCOUNT 33 |
sfTimeLock |
UINT32 96 |
sfLastInteraction |
UINT32 97 |
kMaxBeneficiaryTimeLock |
315,360,000 seconds |
BeneficiarySet is not delegable, and it is the only transaction: the
designation is exercised by signing, not by a second transaction type.
No new result code is needed: every failure uses one develop already defines
(temMALFORMED, tecNO_TARGET, tecNO_ENTRY, tecINSUFFICIENT_RESERVE,
tecHAS_OBLIGATIONS, and tefBAD_AUTH for a signature offered too early).
sfAccount, sfOwnerNode, sfPreviousTxnID and sfPreviousTxnLgrSeq are
develop's own.
src/test/app/Beneficiary_test.cpp (xrpl.app.Beneficiary) covers the
amendment gate, every malformed combination, set/update/clear with the reserve
charged and released, the beneficiary's signature refused before the period and
accepted after, an unrelated account's signature refused throughout, a
beneficiary-signed transaction leaving sfLastInteraction alone so the
beneficiary can keep signing, the owner reclaiming by signing once, an owner
who signs with a regular key and has disabled the master key keeping their
account after the beneficiary has begun signing, an outgoing payment resetting
the timer, an incoming payment not resetting it, an account without a
designation never being stamped, account deletion blocked and then permitted,
and the account_objects and ledger_entry lookups.
src/test/app/invariants/InvariantsBeneficiary_test.cpp
(xrpl.app.InvariantsBeneficiary) drives ValidBeneficiary with deliberate
violations of each of its rules.
Still to write: the beneficiary signing a BeneficiarySet that clears the
designation out from under itself, and the behaviour when the beneficiary
account is deleted while a designation naming it exists.
Transia-RnD/rippled branch dangell7/beneficiary, on develop 9403736199.
Registered Supported::No, VoteBehavior::DefaultNo while it is unaudited.
- The beneficiary is not verified to be usable. Nothing checks that the beneficiary account can sign, and this is deliberate, per the discussion. If the beneficiary's keys are lost, the outcome is that the owner's assets stay in the owner's account, which is where they already were. The designation may be replaced at any time while the owner is active.
- A designation makes a blackholed account signable again, and the account's
key fields no longer show it. An account that disabled its master key and
set its regular key to a zero or one address is conventionally called
blackholed. If such an account has a designation, its beneficiary can sign
once the period elapses. Under revision 1 this was visible after the fact,
because the regular key changed; under this revision nothing on the
AccountRootchanges, so the master key stays disabled and the regular key stays the zero address while the account is nonetheless usable. Software that reports an account as blackholed MUST check for aBeneficiaryentry, and this is a stronger requirement than it was, because no other field will ever reveal the difference. @tequdev raised the question and the authors' position was that designating before blackholing is the owner's choice. - A designation plus a blackhole is a form of issued-asset escrow. @xrpl365 observed in the thread that an issuer could designate a beneficiary with a long period and then blackhole, achieving something that behaves like an escrow of the issuance, and asked "Should we work to prevent this?" The question was never answered and this revision does not prevent it.
- The timer is only as good as the owner's activity. An owner who sets a designation and then stops transacting for the time lock will have the beneficiary able to sign while they are alive. That is no longer a loss of the account — the owner's own keys still work, and using one closes the window — but it is a loss of exclusivity. The time lock is the owner's estimate of their own longest plausible silence.
- No notification. The ledger does not tell a beneficiary that a designation exists or that it has become invocable. This is off-ledger work, and remains an open question from revision 1.
- Nothing is moved and nothing is replaced. The amendment adds a signing
path and a timestamp. It pays nobody, transfers no asset, and never writes
sfRegularKey, a signer list orlsfDisableMaster.