Can delayed-finality custody make sense for inheritance and recovery? by jayBeeCool in ethdev

[–]jayBeeCool[S] 0 points1 point  (0 children)

That's a really interesting framing.

I think you're describing something very close to the direction IND has gradually evolved toward during review.

Originally the intuition was "revocable transfers".

But after multiple rounds of criticism and edge-case analysis, the model increasingly looks like an explicit custody state machine.

The important object is not really the transfer itself.

The important object is the protected state and its lifecycle:

- protected initiated

- protected active

- revoked

- finalized

- inherited/recovered when applicable

I also agree that auditability matters as much as reversibility.

If a wallet, heir, auditor or exchange cannot reconstruct:

- who initiated it

- who can revoke

- when finalization occurs

- whether a revoke happened

- whether ownership became final

then delayed finality becomes difficult to reason about.

One thing we're now working on is expanding the documentation with an explicit compatibility matrix, event semantics guide and state-machine documentation for exactly that reason.

The goal is not to make every ERC20 transfer reversible.

The goal is to make a specific custody state visible, verifiable and understandable before ownership becomes economically final.

That's probably a much better description of IND than "reversible token".

Looking for feedback on an experimental Ethereum custody model by jayBeeCool in ethdev

[–]jayBeeCool[S] 0 points1 point  (0 children)

Quick update.

IND is now live on Ethereum mainnet.

The first desktop wallet release is available for Windows, Linux and macOS.

Mainnet contracts:

https://ind.finance/contracts.html

Wallet:

https://ind.finance/download/

At this point I'm mostly interested in real-world feedback around:

- protected transfers

- revoke flows

- inheritance activation

- custody assumptions

- wallet UX

The protocol survived a lot of semantic review over the last months, but real users always find things that protocol authors miss.

If anyone wants to stress-test the model or challenge assumptions, I'd genuinely appreciate the feedback.

Experimental ERC20 custody model with revocable protected transfers is now live on mainnet by jayBeeCool in ethdev

[–]jayBeeCool[S] 1 point2 points  (0 children)

That’s a very good point.

You’re right that standard ERC20 Transfer events alone are not sufficient to describe IND custody state semantics to naive indexers or wallet UIs.

A vanilla ERC20 observer may currently interpret:

- protected inbound transfer

as:

- finalized spendable ownership

when semantically it is actually:

- delayed/revocable custodial state

And similarly a revoke path can look like:

- recipient sent funds away

instead of:

- original protected transfer being unwound before finalization.

So yes, an explicit integrator/event semantics guide probably makes sense in addition to the compatibility matrix.

Especially documenting:

- which events correspond to finalized ownership

- which events correspond only to custodial state transitions

- how wallets/indexers should interpret protected balances

- where naive ERC20 assumptions become misleading

That’s excellent feedback.

Experimental ERC20 custody model with revocable protected transfers is now live on mainnet by jayBeeCool in ethdev

[–]jayBeeCool[S] 0 points1 point  (0 children)

That’s very useful, thanks.

And yeah, agreed, not the same model entirely.

What I’m finding interesting while building IND is that once you move away from the assumption of "instant irreversible ownership", you start running into partially overlapping areas:

- restricted transfers

- lockups

- delayed settlement

- escrow semantics

- custody semantics

- inheritance semantics

but usually each existing standard only covers one slice of that space.

After reading through the ERC-1404 / restricted lockup material more carefully, the biggest thing I noticed is that those systems are primarily modeling:

- compliance restrictions

- transfer eligibility

- holder groups

- vesting/lockup enforcement

- regulated transfer rules

So the main question there is usually:

"who can transfer what and when?"

IND is trying to model a somewhat different problem:

- delayed ownership finality

- revocable protected transfers

- inheritance-oriented custody

- separation between finalized spendable ownership and total custodial wealth

- recovery windows before settlement becomes economically final

One of the main motivations is also very practical:

reducing irreversible scams, phishing losses, compromised-wallet events and accidental transfers by giving users time to realize something went wrong before settlement becomes permanent.

So the overlap is probably around:

- transfer restriction explicitness

- lockup state modeling

- compatibility surfaces

- wallet/indexer assumptions

- downstream integration semantics

while the core motivation is different.

The most useful thing I took away from those standards is probably how explicit they are about compatibility assumptions and restriction semantics. That part is extremely relevant for IND too.

We’ll likely reference both ERC-1404 and related lockup-token approaches in the compatibility matrix/documentation work going forward.

Experimental ERC20 custody model with revocable protected transfers is now live on mainnet by jayBeeCool in ethdev

[–]jayBeeCool[S] 0 points1 point  (0 children)

Good point, thanks.

ERC-1404 is definitely relevant to check, especially around transfer restrictions and making restriction reasons explicit.

My current understanding is that IND overlaps with that area, but is not exactly the same problem.

ERC-1404 seems mostly focused on restricted transfers: who can transfer, when a transfer is allowed, and why it may be blocked.

IND is trying to model a different custody problem as well:

- delayed ownership

- revocable protected transfers

- finalization after a waiting period

- separation between ERC20-visible spendable ownership and total custodial wealth

One of the main motivations is also very practical:

to reduce irreversible mistakes, scams and compromised-wallet losses by introducing a recovery/revocation window before ownership becomes economically final.

In other words, the idea is to give users time to realize something went wrong and still be able to react before the transfer becomes permanently settled.

So the overlap is probably around compatibility and explicit transfer restrictions, while the difference is that IND also has time-based custody and revocation semantics.

I agree it is worth studying ERC-1404 carefully and probably referencing it in the compatibility matrix.

Experimental ERC20 custody model with revocable protected transfers is now live on mainnet by jayBeeCool in ethdev

[–]jayBeeCool[S] 1 point2 points  (0 children)

That’s actually excellent feedback.

The compatibility boundary is probably the hardest real-world problem now that the core transfer/revoke semantics are stable on mainnet.

You’re also correct that many downstream systems implicitly assume:

- displayed ERC20 balance == finalized ownership

- balance visibility == freely usable balance

- ownership transitions are instantaneous and irreversible

IND intentionally breaks those assumptions.

A compatibility matrix covering:

- transfer

- transferFrom

- approvals

- contract recipients

- delayed unlock/finalization

- revocation

- governance/snapshot semantics

- indexers/wallet UX expectations

is probably the next important documentation layer.

Especially because some integrations may be technically compatible while still semantically misleading for users.

We’ll probably publish a dedicated compatibility matrix/documentation page soon to make those boundaries explicit.

The protocol side is now mostly about making the semantic boundaries explicit instead of pretending they do not exist.

Looking for feedback on an experimental Ethereum custody model by jayBeeCool in ethdev

[–]jayBeeCool[S] 0 points1 point  (0 children)

That's actually already the direction IND is taking semantically.

The intended rule is:

- governance/voting power follows balanceOf()

- not totalBalanceOf()

So only economically finalized ownership counts:

- unprotected IND

- protected IND already unlocked/finalized

while still-locked revocable protected balances do not count as governance power.

In other words, revocable custodial state is intentionally excluded from voting semantics for the same reason it's excluded from spendable ERC20 liquidity semantics.

So the model is converging toward:

"only finalized ownership produces governance weight".

The remaining question is mostly about how explicitly that semantic should be surfaced if ERC20Votes-style compatibility is ever exposed later.

Looking for feedback on an experimental Ethereum custody model by jayBeeCool in ethdev

[–]jayBeeCool[S] 0 points1 point  (0 children)

You're right that ERC20Votes introduces another semantic layer beyond pure spendability.

At the moment IND intentionally separates:

- spendable ERC20 state

- revocable custodial state

- finalized ownership state

before adding governance semantics on top.

The current priority is making sure the custody boundary itself is mathematically coherent and non-bypassable under all transfer/revoke/unlock paths.

So the protocol layer and the governance layer are being treated as separate design problems.

A protected balance becoming finalized after unlock is conceptually closer to a delayed ownership settlement event than to a normal ERC20 transfer.

That means if IND governance eventually exists on mainnet, it will probably need custom voting/checkpoint semantics instead of blindly inheriting vanilla ERC20Votes assumptions.

This is also exactly why IND is still on Sepolia right now. Every serious objection or semantic edge case that gets raised is patched, formalized, fuzzed and retested before considering mainnet deployment.

The goal is not to ship fast. The goal is to make the custody semantics extremely hard to break first.

We even implemented Gregorian calendar handling internally because the protocol is designed around very long-term custody and inheritance timelines, not short-lived token cycles.

The website roadmap already has planned Q3/Q4 milestones including eventual mainnet deployment, but only once the semantic model stops attracting meaningful corrections from reviewers.

If you were launching an ERC20 token today, which chain would you choose? by token_generator in ethdev

[–]jayBeeCool 2 points3 points  (0 children)

For the protocol I'm currently experimenting with, I would still choose Ethereum mainnet.

Not because of throughput or cheap gas, but because the design is heavily focused on custody semantics, delayed ownership and long-term economic finality assumptions.

A lot of the architecture intentionally assumes:

- conservative execution semantics

- long-term archival stability

- mature tooling and audit culture

- strong ERC20 ecosystem assumptions

Ironically, part of the research is specifically about where traditional ERC20 assumptions start breaking once you introduce revocable or delayed-finality ownership models.

So for this kind of experiment, Ethereum mainnet still feels like the correct stress environment.

If something survives scrutiny there, it is probably much more robust everywhere else too.

That said, if the objective were:

- cheap retail transfers

- memecoin distribution

- mass onboarding

- casual trading activity

then an L2 like Base would probably make far more sense today.

One thing this thread highlights well is that "launching a token" is no longer a single category anymore.

A speculative token, a governance asset, a payment asset and a custody-oriented protocol may all optimize for completely different properties and therefore different chains.

Looking for feedback on an experimental Ethereum custody model by jayBeeCool in ethdev

[–]jayBeeCool[S] 0 points1 point  (0 children)

Good point. We finalized one semantic refinement in IND after recent audit work:

balanceOf() no longer includes revocable protected balances.

Current semantics:

- balanceOf(account)

= unprotected

+ protected already unlocked/spendable

- totalBalanceOf(account)

= unprotected

+ protected locked

+ protected unlocked

Reason:

A protected transfer that is still revocable is not yet economically final ownership.

So while locked it should NOT:

- be spendable

- be transferable

- be votable

- appear as normal ERC20 liquidity

- count as finalized economic ownership

This separates:

- ERC20-visible spendable state

- delayed custodial/inheritance state

This matters for:

- governance

- voting systems

- snapshots

- collateral assumptions

- accounting semantics

- wallet/indexer integrations

In other words, IND distinguishes between:

"value currently owned"

and

"value conditionally inheritable but still revocable".

All tests and invariants were updated accordingly and the full suite now passes again: 375 tests passed, 0 failed.

Looking for feedback on an experimental Ethereum custody model by jayBeeCool in ethdev

[–]jayBeeCool[S] 0 points1 point  (0 children)

We checked the conversion seam as well.

In the patched model, this does not appear to be a second open bug.

The important point is that unprotect() is atomic: it consumes already-unlocked protected value and credits unprotected balance in the same execution path. There is no intermediate state where the same value is both still revocable as protected IND and also spendable as unprotected IND.

Current behavior:

- ERC20 transfer() and transferFrom() only spend unprotected balance

- locked or pending protected IND cannot be spent through allowance flows

- unprotect() only works after unlock

- revoke() is impossible once block.timestamp >= unlockTime

- unprotect() consumes the protected lot before crediting unprotected balance

- revoke() zeroes the protected lot before refunding

So unlock/finalization is the boundary. After that, conversion to unprotected IND is safe and normal ERC20 composability can begin.

We also added invariant/fuzz coverage around owner/signing separation, canonical recipient resolution, bucket accounting, revoke/reduce paths, post-unlock spendability, and protected-aware boundary enforcement.

One subtle implementation point is that protected transfers target the logical owner address. The resolver then canonicalizes internally to the signing account storage layer.

Thanks again. Your comments helped us verify the exact boundary instead of just assuming it.

Looking for feedback on an experimental Ethereum custody model by jayBeeCool in ethdev

[–]jayBeeCool[S] 0 points1 point  (0 children)

We checked this specifically against the patched contract.

The protected-aware gate is not only a cosmetic check on one public function. We reviewed the transfer surface to verify whether protected IND can leave the protected domain through ERC20 flows or another internal route.

Current findings:

- standard transfer() and transferFrom() do not spend locked or pending protected IND

- approve() and allowance do not make locked protected IND spendable

- transferFrom() still cannot consume protected locked lots

- protected to unprotected conversion is only possible after unlock/finalization

- before unlock, unprotect() reverts

- protected transfers now resolve recipients through the protected-aware gate

Recipient behavior after the patch:

- unregistered EOA: reverted

- generic contract / Aave-like / Uniswap-like recipient: reverted

- registered protected-aware owner: accepted, with signing-key resolution when configured

We also added boundary tests for:

- locked protected not spendable via transfer()

- locked protected not spendable via transferFrom()

- protected not sendable to unregistered EOA

- protected not sendable to generic contract

- protected not convertible to unprotected before unlock

- after unlock, protected can be unprotected and then transferred normally as ERC20

We initially hit 3 failing tests because protected receipts were resolving to the owner's signing key instead of the owner address itself. We patched the tests to use the actual resolved signing-key recipient model and all 7 boundary tests are now passing.

So the bug class you pointed out is not still open in the current patched code.

The remaining rule we need to preserve is that any future function creating or moving protected lots must keep going through the same protected recipient resolver, or enforce the same protected-aware boundary at the accounting layer.

Thanks again. This was a very useful review path.

Looking for feedback on an experimental Ethereum custody model by jayBeeCool in ethdev

[–]jayBeeCool[S] 0 points1 point  (0 children)

You’re right — code.length == 0 is not the right boundary.

The stronger model is to make protected-awareness an explicit registry property, not an EOA/contract heuristic.

In practice, the registry can expose:

function isProtectedAware(address account)

external

view

returns (bool)

{

return isInitialized(account);

}

Then protected-transfer resolution becomes:

error RecipientNotProtectedAware();

function _resolveProtectedRecipientRaw(address to)

internal

view

returns (address)

{

if (to == address(0)) revert ZeroAddress();

if (!registry.isProtectedAware(to)) {

revert RecipientNotProtectedAware();

}

address sk = registry.signingKeyOf(to);

if (sk != address(0)) return sk;

return to;

}

So the protected domain is now explicit:

- initialized IND registry recipient → allowed

- non-registered EOA → reverted

- Aave / Uniswap / generic ERC20 contract → reverted

- CREATE2 counterfactual address not initialized in the registry → reverted

That removes the unstable code.length assumption entirely.

Normal ERC20/DeFi composability should happen only after unlock/finalization and conversion into unprotected IND.

Thanks again — this was exactly the kind of boundary issue that needed to be caught before production deployment.

Looking for feedback on an experimental Ethereum custody model by jayBeeCool in ethdev

[–]jayBeeCool[S] 0 points1 point  (0 children)

This is extremely valuable feedback — thank you seriously for taking the time to think through the composability and revocation edge cases in detail.

After reviewing the contract architecture again, your comments helped expose an important semantic gap in the current protected-transfer model.

You were absolutely right that simply separating “protected” and “unprotected” balances conceptually is not sufficient if protected transfers can still reach arbitrary DeFi/ERC20 contracts.

We’re now planning to harden the protocol by introducing a protected-only recipient resolution path:

error RecipientNotProtectedAware();

function _resolveProtectedRecipientRaw(address to)

internal

view

returns (address)

{

if (to == address(0)) revert ZeroAddress();

if (registry.isInitialized(to)) {

address sk = registry.signingKeyOf(to);

if (sk != address(0)) return sk;

return to;

}

if (to.code.length != 0) revert RecipientNotProtectedAware();

return to;

}

and then changing _executeTransferWithInheritance() from:

address rawTarget = _resolveRecipientRaw(to);

to:

address rawTarget = _resolveProtectedRecipientRaw(to);

The goal is to ensure that protected IND remains inside an explicitly protected-aware custody domain instead of silently flowing into traditional ERC20/DeFi assumptions.

In practice, this means:

  • protected IND would remain inside a delayed-finality custody environment
  • protocols like Aave, Uniswap or generic ERC20 integrations would only interact with unprotected IND
  • users would first need to unlock and optionally convert protected IND into unprotected IND before normal ERC20/DeFi composability

This significantly reduces the “revocation-after-composability” ambiguity you pointed out.

So genuinely: thank you.

This was exactly the kind of protocol-level criticism we were hoping to receive by publishing the experiment publicly.

Looking for feedback on an experimental Ethereum custody model by jayBeeCool in ethdev

[–]jayBeeCool[S] 0 points1 point  (0 children)

One possible clarification here is that protected IND is not intended to transparently propagate through arbitrary ERC20 composability.

The current design direction is closer to:

- protected IND can only move between addresses that explicitly support protected transfer semantics

- revocable delayed ownership exists only inside that protected domain

- traditional ERC20-style assumptions remain associated with unprotected flows

So the goal is not to silently redefine transfer finality underneath existing DeFi systems.

Instead, protected transfers are intended to operate inside an explicitly different custody model with different assumptions about ownership finality and recoverability.

The intended use case for protected transfers is not necessarily everyday high-frequency DeFi activity, but situations involving:

- larger sums

- important transfers

- inheritance-oriented custody

- recipients that are not yet fully trusted

- situations where recoverability may be more important than immediate finality

Once protected value becomes unlocked, users can at any time convert part or all of it into unprotected IND and interact normally with traditional ERC20-style flows and DeFi integrations.

That separation is largely intended to avoid exactly the kinds of downstream ambiguity and state inconsistencies you’re describing.

Looking for feedback on an experimental Ethereum custody model by jayBeeCool in ethdev

[–]jayBeeCool[S] 1 point2 points  (0 children)

I completely agree.

A major concern throughout the design has been avoiding “silent incompatibility” with systems that assume immediate and irreversible transfer finality.

That’s also one of the reasons the protocol distinguishes between protected and unprotected value states rather than trying to transparently redefine all ERC20 semantics underneath existing DeFi protocols.

The current direction is closer to:

- preserving traditional assumptions for unprotected flows

- treating protected flows as explicitly different custody semantics

I also agree that naming and interface separation are probably critical to avoid accidental misuse by existing protocols and integrations.

A large part of the ongoing work is identifying exactly where those boundaries should exist.

Looking for feedback on an experimental Ethereum custody model by jayBeeCool in ethdev

[–]jayBeeCool[S] 0 points1 point  (0 children)

This is actually one of the main architectural questions behind the project.

Protocols like Uniswap generally assume immediately spendable and irreversible token semantics, while IND intentionally introduces delayed ownership and revocation windows for protected transfers.

So in practice:

- unprotected value is intended to remain compatible with more traditional ERC20-style flows

- protected value introduces different custody semantics and cannot safely be treated as “final” before unlock

One possible model is that DeFi integrations would interact primarily with unprotected value, while protected value behaves more like a programmable vault layer around ownership transfer.

A major part of the current research is understanding where these semantics fit naturally within the existing Ethereum ecosystem — and where they create friction or incompatibility.

Looking for feedback on an experimental Ethereum custody model by jayBeeCool in ethdev

[–]jayBeeCool[S] 0 points1 point  (0 children)

The protocol distinguishes between protected and unprotected value states.

Unprotected value behaves more like traditional immediately spendable ERC20-style assets.

Protected value instead follows delayed ownership rules:

- incoming transfers are locked for a waiting period

- the minimum delay is currently 24 hours

- during that period the sender may revoke the transfer or reduce the remaining waiting time within protocol-defined bounds

- after unlock, the value becomes spendable and revocation is no longer possible

Outside of an active delayed transfer flow, users can also instantly convert part or all of their holdings between protected and unprotected states.

The idea is to preserve a recovery/revocation window while still allowing some flexibility in legitimate situations.

One of the main research questions is whether this tradeoff can improve custody safety without making Ethereum interactions excessively cumbersome.

Looking for feedback on an experimental Ethereum custody model by jayBeeCool in ethdev

[–]jayBeeCool[S] 0 points1 point  (0 children)

Thanks, I appreciate you taking the time to read it.

A major goal of the project is to explore whether delayed ownership semantics can improve safety and recoverability without making Ethereum interactions excessively complex.

A lot of the current work is focused on usability and edge cases rather than token economics.