NRC-4: Nexa Special Purpose BIP-44 Accounts

To address some of the difficulties dApps encounter with managing the multi-address architecture of UTXO chains, a few of us have come together to draft a specification for Nexa that aims to extend BIP44. This extension reserves accounts 1-99 in BIP44 compliant Nexa wallets to be used for special purposes. Any and all feedback or input is welcome on our initial draft of the spec.


NRC: 4
title: Nexa Special Purpose BIP-44 Accounts
author: dolaned, griffith, vgrunner, yendy
status: Draft
type: Standards Track
created: 2025-02-16

Abstract

This NRC defines an extension of the BIP44 allocating account numbers 1 - 99 for special use within the Nexa ecosystem.

Specification

The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “NOT RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC 2119 and RFC 8174.

This NRC uses the account numbers 1-99 in an otherwise BIP44 compliant wallet for special specific purposes that might have slightly different behaviour on the Nexa network.

Account 0 and 100+ - Default Accounts

Account 0 is the default account and uses BIP44 with no alterations. To create a second account that functions identically to this one on Nexa, skip to account 100 rather than simply incrementing to 1 as accounts 1-99 are reserved for special use.

Default Account Examples

coin account chain address path
Nexa first external first m / 44’ / 29223’ / 0’ / 0 / 0
Nexa first external second m / 44’ / 29223’ / 0’ / 0 / 1
Nexa first change first m / 44’ / 29223’ / 0’ / 1 / 0
Nexa first change second m / 44’ / 29223’ / 0’ / 1 / 1
Nexa second external first m / 44’ / 29223’ / 100’ / 0 / 0
Nexa second external second m / 44’ / 29223’ / 100’ / 0 / 1
Nexa second change first m / 44’ / 29223’ / 100’ / 1 / 0
Nexa second change second m / 44’ / 29223’ / 100’ / 1 / 1

Account 1 - HODL Vaults

m/44'/29223'/1'/*/*
Account 1 is used specifically for HODL vaults.

Account 2 - Single Address DApp Accounts

m/44'/29223'/2'/0/*
Account 2 is used for dApp accounts. A dApp account does not follow typical BIP44 conventions with regards to chain and index. All addresses in Account 2 are in the external chain. All addresses on the Account 2 external chain are intended to be handled as if they were each unique accounts. A dApp account intentionally only uses one address with change being returned back to the same address. Inputs for a dApp account should only ever come from one address.

DApp Account Examples

Path Address
m/44’/29223’/2’/0/0 DApp account 1
m/44’/29223’/2’/0/1 DApp account 2
m/44’/29223’/2’/0/2 DApp account 3

Acccount 3-99

m/44'/29223'/3-99'/*/*
These numbers are reserved for future use.

Account discovery

When the master seed is imported from an external source the software should
start to discover the accounts in the following manner:

  1. derive the first account’s node (index = 0)
  2. derive the external chain node of this account
  3. scan addresses of the external chain; respect the gap limit described below
  4. if the account index is less than 100, increase the account index by 1 and go to step 1
  5. else if no transactions are found on the external chain, stop discovery
  6. else if there are some transactions, increase the account index by 1 and go to step 1

This algorithm is successful because software should disallow creation of new
accounts if previous one has no transaction history, as described in chapter
“Account” above.

Please note that the algorithm works with the transaction history, not account
balances, so you can have an account with 0 total coins and the algorithm will
still continue with discovery.

Rationale

Traditionally, Defi has been primarily a feature of EVM based blockchains which use the accounting model rather than the UTXO model. In the accounting model a user typically only has a single address that they use to store funds where as BIP44 compliant wallets on a UTXO blockchains have accounts with multiple addresses. Bringing Defi to UTXO blockchains has its own set of problems and some adjustments to the existing BIP44 wallet scheme is necessary to facilitate activity that was not present at the time BIP44 was written.

Backwards Compatibility

Checking if the next account has addresses in the BIP44 spec is only supposed to occur when the previous account has had usage. Because accounts 1 through 99 are reserved in this spec, a second normal account would be placed in account number 100. Moving from a wallet that follows this NRC to one that is only BIP44 compliant might result in that BIP44 only wallet not checking account number 100 for use.

Test Cases

Reference Implementation

Security Considerations

Reusing a single address multiple times for a single dApp account has privacy implications. It will be very easy to track the dApp usage of that account compared to effort it takes to track other Nexa addresses.

Copyright

Copyright and related rights waived via CC0.

2 Likes

why not just use the “default” account for DeFi purposes like every EVM chain does today and avoid breaking existing wallets, specifically hardware wallets that i’m pretty sure are going to have a tough time implementing this “reserved address” scheme that breaks from UTXO norms.

what is the rationale for NOT using (default) account index 0’ for DeFi like everyone else?

(indexes greater than ZERO would continue to be used as psuedo-privacy until better alternatives like ZK privacy become available for users)

what applications would benefit from this new 100 “reserved” addresses scheme vs simply continuing to use the “single” address approach that works PERFECTLY for DeFi on Nexa today?

thank you!

1 Like

Good questions.

Note: The reason account 1 is hodl vaults is purely historical because otoplo wallet currently uses account 0 for normal transactions and account 1 for hodl vaults. I can elaborate on why this is necessary if desired.

The idea is to have the behaviour of nexa dApp accounts mimic the behaviour of EVM accounts. Each address is its own account. We are proposing that specifically account 2 (m/44’/29223’/2’/0/*) be used for this purpose.

There are 2 problems with using the default account(0)

  1. We consider it a requirement that it be possible for a user to generate multiple dApp addresses/accounts. It is also a requirement that they are independent in the same way that BIP44 and EVM accounts are independent. Reusing account(0) would not be good for this independence because it would change the default behaviour of that account which is already in use unless it is a brand new wallet.
  2. if your wallet interacts with other apps or performs normal transactions it probably uses that default account. Ideally we would have a specific account dedicated to the dApp activities because they should behave as if a single index is an account rather than the account being at the account level.

As for the reserved accounts (m/44’/29223’/3’/*/* … m/44’/29223’/99’/*/*) the idea is to simply reserve them for future special use.

I am confused on what you mean by this. We want to use a single address for DeFi. This was the purpose for dApp accounts. The reservation of accounts was at the level higher than the dApp accounts.

2 Likes

I’d like to understand better your rationale behind using this area of the namespace, and for this proposal to be fleshed out more. I don’t see a clearly stated goal/purpose for example.

First, a dApp in this case would be a particular contract (a specific script), right?

So you are thinking that some contracts would effectively be associated with just one pubkey in the sense that every time the contract is spent as an input, it would also create an output controlled by that same pubkey? And then to make the “address” the same (as the spec states), the contract itself (the script template hash) also must not change.

I originally kept the searchable address space as minimal as possible to make it easier to do wallet recovery. The “fast-forward” recovery time grows proportionally to the address search space, and although the block-based recovery time remains constant, its bloom filter will grow proportionally.

So an important goal is to minimize that. The proposal might first appear to make it worse, but actually it could minimize the search space.

If we imagine just handing pubkeys out to dApps from “account 0” (not reusing, just giving the next one), then on recovery, we need to “fast-forward” search every (contract, address) pair. Today we effectively have 1 contract (pay-to-pubkey-template) so we just search every address. But if we had 10 possible contracts, fast-forward recovery time would increase by 10x.

By placing dapps in specific locations, as you are suggesting, we can avoid this.

However, if that is your aim, I think that there is a permissioned problem. We need to provide a location for wallets and devs when they create a new contract.

For an example of the problem, look at the BTC text addresses. There was no way to specify a contract (without getting a number assigned to you, and every wallet manually hard coding that number to a specific contract). In practice, this meant 2 contracts p2pkh and p2sh (and the latter was kind of a meta-contract that could encapsulate other contracts so problem kind of solved).

But I digress; the point is we ought to have a way for a wallet to see a contract and find which location to start searching for contract activity from.

Maybe the first 2 bytes of the contract hash (as placed in the script output), define the “account” field (or something similar).

2 Likes

okay fantastic, thank you for making time to provide clarity to the rationale behind this specification :folded_hands:

sure! imo that account assignment works perfectly fine – as the Otoplo HODL contract can be seen as “application-specific”; which mirrors the behavior of NexID reserved namespace :backhand_index_pointing_down:

The crypto-identity app has the concept of “common identities” and “unique identities”. A common identity is deliberately used across multiple domains to link accounts. A unique identity is probabilistically given to just one web site

imo reserving the 1-99? namespace for “unique identities”, i.e. individual dApps, would follow the same usage pattern.

BUT… the way I see it now, you’re aim is to restrict ALL DeFi applications to Account #2, which doesn’t make much sense to me (especially as an EVM user who intentionally chooses to segregate multiple DeFi applications across multiple accounts).

As it stands, this scheme would probably implement further restrictions, e.g., all GameFi at Account #3 or all DePIN at Account #4, etc.

i 100% agree that restricting DeFi on Nexa to a single address is desirable, however, restricting DeFi to a single Account, imo is NOT (and AGAIN that’s definitely not how it works in EVM, where the user has full control over how they assign/designate their accounts)

if there’s more to this proposal that i’m missing, i’d very much appreciate if you could provide a clear example of how this will benefit Nexa’s dApp builders now and in the future…

thanks again!

yeesss!! :clap:

making the account index of a contract deterministic would be very cool :smiling_face_with_sunglasses:

The point in reserving is not to be reserved for specific apps. It is to reserved for specific purposes. for example… HODL valuts should not be mixed with any other dApp because they are locking assets for a long period of time. For example… Lets say a user locks their nexa in a vault for 5 years and in that 5 year time the magic of quantum computing has discovered a way to derive the private key from a pubkey. The pubkey for that HODL vault is not revealed until the funds are unlocked because pubkeys for addresses are revealed on transfer OUT of the address. If the HODL vault address was also used for other dApp stuff then the pubkey could be revealed by different usage sooner than the vault unlocking potentially resulting in funds getting stolen because someone used a QC to derive the privkey from your pubkey while the funds were still locked. Something like this warrants that specific app having its own section in the account list.

Not all DeFi, all dApps that are not specified to be stored elsewhere. This would include GameFi or DePIN in account #2.

The spec is outlining that all dApp accounts go into BIP44 account 2. But each index in Account 2 acts as its own segregated dApp account. If the wallet is following the spec properly then each address in BIP44 account 2 is separated as if they were in their own single address BIP44 accounts. This is the exact same system EVM uses, each address is its own account. The first account is index 0, second account is index 1. etc.

1 Like

This would completely remove the users ability to control how they assign and designate their accounts.

I have some edits to add to the draft spec based on provided feedback. I will do it soon

1 Like

ok, that makes it clear to me now as to “why” you want to do this in the first place :ok_hand:

iirc, there was no explanation as to “how” those accounts would be assigned to the individual dApps.

first question: would it be up to each dApp to scan the namespace for an empty slot before “claiming” an address for its use?

second question: what if another dApp writes to the same HODL slot and then spends from it, wouldn’t that defeat the entire purpose?

agreed! so perhaps each dApp author (or maybe even the user) should have the option to follow @andrewstone deterministic scheme or not.

i’ll have to think more about this can be “optional”… :thinking:

1 Like

user chooses. same system as something like metamask. you connect to the dApp with the dApp account you want to use. multiple dApps can use the same account, no problems there. It is up to the user which dApps they use on which dApp accounts.

dApp accounts are in BIP44 account 2. HODL is always in BIP44 account 1. it is a special case. you would not connect to a dApp with a HODL address.

1 Like

sure, i understand now what you are looking to achieve by segregating the HODL address, as you stated for “security reasons”

however, i don’t see how this scheme achieves that desired protection. if EVERY HODL dApp is using the same space (account #1), then imo you’re making some unreasonable assumptions:

  1. how do you prevent different dApps from using the same pubkey (again, i don’t see where this is explained in the spec)?
  2. (more importantly) how do you prevent the pubkey from getting exposed from a “short-lived” HODL contract that’s on the same address?

also, it’s worth asking, “what are your plans for the other reserved spaces 2-99?”

i believe there are better ways to achieve your security goal for the HODL contract. namely, by restricting the pubkey of the contract in a way to prevent it from being exposed by another dapp (or similar contract) – i don’t see how this scheme achieves that…

1 Like

You are mixing two different things together here.

BIP44 account 1 is HODL vaults.

BIP44 account 2 is dApp accounts.

BIP44 accounts 3-99 are reserved for some future use if needed.

The scheme states how a wallet that is NRC4 compliant MUST treat the address space inside each BIP44 account. It does not outline how it must do it, only the end result behaviour. How it achieves it is up to the wallet developers.

I should better outline exactly what the behaviour in each special designated BIP44 accounts is. I will expand on that. Thank you for pointing that out.

vgrunner implemented them in otoplo. from what i understand every vault uses the next available, unused address index in BIP44 account 1 (starting at index 0) and they are never reused.

HODL vaults are not the point of this NRC. The entire point is to outline some BIP44 accounts where the behaviour in those accounts is to be different than the behaviour described in BIP44.

Accounts 3-99 have no current plans. they are simply reserved for future use at this time

1 Like

perhaps i wasn’t very clear, but my issue is that of “collisions” between HODL clients using the same Account #1.

even if each individual client (e.g. Otoplo wallet) indexes their HODL contract to prevent a collision, what’s to prevent the next HODL client from re-using the same indexes of Account #1?

if this is not clearly defined in your specification, then it’s fair to assume that the next client will just start deploying from Account #1, Address #0 (possibly causing a collision – breaking your security protection)

an application-specific scheme would handle the collisions, but I understand you’re looking for a purpose-based scheme – however, i have yet to fully understand “why”

edit:
changed “dapp” to “client” to avoid the confusion of having “dapps” assigned to account #2

1 Like

just to be super succinct in my question/concern, “how do you determine the various assignments for {clientid}?”

it’s not mentioned in the NRC-4 specification and that could lead to collisions between clients; and a break the quantum security protection that you’re seeking for the HODL vaults

edit:
changed “dapp” to “client” to avoid the confusion of having “dapps” assigned to account #2

1 Like