ICRC-1 Account Human Readable Format

Of course, the working group can have its own decision. I just wish ICRC1 was better.

My preference would be for the Account to be a 32-byte hash value with a check digit, which is the format that users are used to.
There are a lot of things that can happen when users copy addresses, and they can easily lose assets. For example, if the address has a “.” etc., by double-clicking to select them, some of the characters may be lost.

2 Likes

This issue can be avoided by encoding Account with base58 or bech32. It’s a problem only with plain strings. Would you find using base58 or bech32 a good solution @bitbruce ?

I agree. Encoding can improve the user experience.

As mentioned above, ICP will be compatible with Account-id. In a dapp, for example a wallet, three address formats will appear in the UI for better compatibility: Principal, AccountId (It is being used by CEX), ICRC1Address.

The question is, is this an acceptable outcome?

History is a burden. Don’t change it so easily unless you have no choice but to do so.

1 Like

One of the benefits of base32 from that link is The mixed case in base58 makes it inconvenient to reliably write down, type on mobile keyboards, or read out loud.
So it’s basically removing the uppercase characters. This will also make addresses look better in UIs

Bech32 consists of (custom text) 1 (data) - where 1 is the separator and the custom text can be anything. For example: “bc”- main net, “tb”- test net, “avax”. Cosmos addresses are Bech32 too and each network has a different prefix.

In our case, we have one network, but the wallet is different. Maybe not a good idea to put the location there as I originally thought.

We could always let users copy a special unrelated to the address pairing code to connect both frontends or just enter the domain without the address. Then one of the sites opens the other in a window or Iframe and uses postMessage for secure communication (The same one used in extension wallets).

We end up needing an open protocol for site-to-site (you can also say wallet-to-wallet) communication. Right now every wallet has a different protocol and they ask you to insert their js library to interface with their end. What we can do next is IC site-to-site frontend protocol so it’s standardized and permissionless.

At some point when users acquire soulbound tokens like certificates, fungible scores, awards, badges, and proof of humanity. Then if site X won’t integrate wallet Y directly at signup, there will be a need for communication so that the user can sign/make non-transferring transactions with the soulbound tokens to prove to site X they own them.

Edit: It’s actually a very common request right now “I have collected 1000 Plug addresses for my airdrop” I am getting and my dapps will only ever use Internet Identity or my own identity. So I need the user to prove they are the Plug address owner, while linking it securely to their new address. Anyway, that’s for another thread

3 Likes

Or is it? Apparently you have lost the support of psychedelic, who openly criticized icrc-1 and decided to continue push its own DIP-20 without subaccount.

Now you are about to lose other people who supports subaccount but wanted a uniform & opaque AccountId. Reason is simple: no CEX will bother to support your custom address.

Happy sailing your lonesome ship!

While this is important, if the ic is to be successful it will come from users that have never seen an address before. 95%(or more) of the world is a blank canvas here. Our system has more power and it will lol like nothing before when it is successful.

My mom had a phone number when she was a kid that was 5 digits long and you had to talk to the operator if you wanted to call someone out side of your zip code. The system got better and people who thought they’d never be able to remember 7 number were just fine.

2 Likes

Agreed but this isn’t a step in that direction, currently IC addresses are even more confusing than BTC’s, maybe encoding can help, but we’re far from something the average user can understand.

So let’s fix it. Why not a phone book subnet/canister that does nothing but translate something like @savage_wolf_banana to accounts. We are already taking about dns right? A couple groups have tried .icp, but this seems like one of those things that is more protocol level. Random addresses could be freeish(maybe they can only be handed to canisters and there is a cycle charge) and if you want a custom one you stake some ICP.

In fact if you really wanted a good SNS test ballon it would be with a very basic utility that does just one thing. If we can govern that then maybe we can govern something more complicated.

I’ve thought about it, some chains already do something similar but I assumed it’d be out of scope for icrc1 and some might even complain such a feature isn’t something Dfinity should build but it should be up to the community, which is understandable but I’d like to avoid another icns situation.

If ICRC1 uses a bech32 encoded address, called ICRC1Address. then how much we can gain.
1, Contract developers can write a few lines of code less. (At the cost of the agent sdk having to deal with the new encoding)
2. More transparency and easier traceability. (sometimes a benefit, sometimes a disadvantage)
3, It will bring some sense of achievement?
(hopefully someone will give additions, and I’m in favour of change if the benefits are large enough)

So how much trouble does it bring.
1, the wallet will contain three address formats: Principal, AccountId, ICRC1Address. Users will be more confused. (The wallet developer had to provide them in order to be compatible with previous versions of the asset)
2, CEX access to assets is more difficult and some will be rejected.
3, It will be more troublesome when testing on the command line.
4, To be account-id compatible, ICP’s Canister code will introduce complexity, which is a potential risk.
5, Loss of privacy protection. (Sometimes a benefit, sometimes a disadvantage)

Some things can be felt as gains when you start thinking about them, but when you start doing them, you find that a lot of new problems are introduced. Is this the time to rethink?

Going back to the beginning, if ICRC1 used the Account-id directly, compared to ICRC1Address, and reconsidered the benefits and disadvantages, what would then be the answer?

A central question is, what problem is ICRC1 trying to solve?
Does it want to unify the Token standard? (This seems to be an unachievable goal at the moment)
Is it to have minimal common interfaces for assets and to create a commonality between different standards? (This is something that is needed for wallet, SNS, CEX and makes huge sense. These needs only require asset sending functionality, and Account-id doesn’t prevent you from achieving this)

So, could you rethink the positioning and reconsider the requirements? What we need is to solve the problem, not introduce complexity.

One of the most significant advantages of the ICRC-1 addressing scheme is that we can send funds to principals directly without needing any tools (beyond the Candid text parser) to construct the payload.

Let’s take advantage of this vital feature.

I propose we make each principal a valid ICRC-1 address. Most applications don’t need subaccounts (including Coinbase and all exchanges relying on the Rosetta API), so (unjustified statistics ahead) 98% of users will never need to learn anything beyond principals, which they have to know anyway.

Since we’re worried about shortening long addresses, we can move the subaccount part to the front. This way, each address will end with the principal’s checksum:

// Principal encoding scheme
Encode(data) := Group(LowerCase(Base32(data || CRC32(data))))

I suggest we make the following valid ICRC-1 textual account representations:

// No subaccount, 98% of users will see this

4kydj-ryaaa-aaaag-qaf7a-cai
jlcmz-cojlk-zdm46-mshzl-dtlre-ricph-khpzu-tqxrk-qo3ow-7jdsw-tae

// Short subaccount, some geeks might use them:

0x0a.4kydj-ryaaa-aaaag-qaf7a-cai
0x01.jlcmz-cojlk-zdm46-mshzl-dtlre-ricph-khpzu-tqxrk-qo3ow-7jdsw-tae

// Long subaccounts, should be rarely displayed to humans
0xf2ca1bb6c7e907d06dafe4687e579fce76b37e4e93b7605022da52e6ccc26fd2.4kydj-ryaaa-aaaag-qaf7a-cai
0x5891b5b522d5df086d0ff0b110fbd9d21bb4fc7163af34d08286a2e846f6be03.jlcmz-cojlk-zdm46-mshzl-dtlre-ricph-khpzu-tqxrk-qo3ow-7jdsw-tae

These addresses also look like domain names, complementing one of the original design goals of principal encoding.

Another benefit is that if you copy only a prefix of the address, the resulting string is unlikely to be a valid address.

4 Likes

I will reply to you in their thread - I am dev from the community

More Bech32 Pros:

  • When someone sends you their “address” you will know how to request proof of ownership. It’s commonly used in this manner. When you ask on Twitter or Discord for users to give you their addresses, they start pasting principals and you don’t really know where they are coming from.

nns10yg27sw98nwmxxrz7razcvwt6kxmjezajrlmsaw840yvj.
anvil1xz7nt4vv3k2fakyfetm6p6qyaymnta742qdyh4fyq799y
plug10yg27sw98nwmxxrz7razcvwt6kxmjezajrlmsaw840yvj
stoic158gkn9x77r4usmdxtlrnhy27aypsk7stkh49rkh7hlz7k

  • There are already bulletproof libraries in all languages so we won’t need to create our own bech32 - npm

Playground here Bech32 Demo
Looks like Bech32m supports 90bytes (what we need) and bech32 supports only 32 (won’t fit subaccounts)

1 Like

ICRC-1 goal is to establish a common interface for fungible tokens that is decided by the community and the Foundation instead of single entities. This was a direct answer to many complains from our userbase regarding fragmentation and issues with existing standards.
In practical terms, ICRC-1 binds the Foundation to support it as much as it can and gives the community a stable framework for the IC that is future-proof and can be extended.

ICRC-1 goal is not to unify standards. That’s not possible but also not something we want to do. If ICRC-1 has to be adopted then it should be because it’s a good standard and not because it’s the only standard. Conversely additional standards with better ideas for IC may still emerge in future.

About the problems:

Having multiple address formats is not ideal but I think it’s unavoidable. Improvements happen, mistakes can be done and feedback can lead to better ideas. Bitcoin for instance has different formats and new formats were created for excellent reasons.

We have some opportunities here to limit the pain. AccountId and ICRC1Address represent the same info and it wouldn’t be hard to migrate from one to the other. AccountId can be deprecated over time. Principal is also part of the ICRC1Address so it should be too hard to explain that ICRC1Address is an “extended” Principal. Also depending on the encoding of ICRC1Address, Principal would be a valid ICRC1Address (see what Roman proposes above). This fact can be a very compelling reason to pick one format instead of another one.

My job as team lead of the Financial Integration team at DFINITY includes talking with CEXs. Most CEX don’t really care but I can assure you they would love to have single format for all Ledgers and the only one that exists is ICRC1Address. Both Principal and AccountId don’t fit the bill.

I also think CEX would like us to use a good charset similarly to bech32 for the encoding because it’s easier to display.

I assume you are talking about the ICRC1Account type and not the format discussed here because the latter is just a string.
I’ve been testing this a lot and ICRC1Account is much easier to use from the command line than AccountId and a little more complicated than working with Principal because instead of writing principal "aaaa.aa" would have to write record { owner: principal "aaaa.aa" }. Yes it’s more chars but definitely usable.

I agree that adding more code introduces potential risks. The additional code would be a tiny layer on top of the existing ICP API. AccountId are already created from principal and subaccount which means there is always a function from ICRC1Account to AccountId and it’s always safe to call. That’s really the only “complex” thing the ICP would have to do.

I agree with this but isn’t that invalidated by publishing the blocks of the subnet? At that point, isn’t obfuscating principal and subaccount just a disadvantage?

Ideas should always be challenged. I was hoping the working group could be used for that but it’s fine to do it also here in the forum and on discord. Sadly talking on the forum is often disconnected from the working group meaning that we need more synch between the two. We are working to improve this.

Talking about rethinking, AccountId was challenged by the community, not the Foundation. For DFINITY it made sense to use AccountId and not ICRC1Account because switching to ICRC1Account is a huge amount of work on our side. This challenging didn’t happen only in the working group and didn’t start there. On the forum, for example, you can find many posts against AccountId, even recent ones claiming that hashing two arrays of bytes is cumbersome.

Rethinking also means listening and it made sense to create ICRC1Account after all the negative feedback AccountId got. Sure it will be a lot of work on the Foundation side to support it but it’s for good reasons. Rethinking is what lead us to ICRC1.

A small final note: AccountId won’t have the property to obfuscate principals because the subnet blocks will be published as requested by the community. If you drop that then the only advantage AccountId has over ICRC1Account is that it’s smaller. That’s it. ICRC1Account is superior in every other way and opens to new use cases. To give you an idea, ICRC1Account allows you to find all subaccounts of a principal by scanning the blocks. This allows a canister to keep an eye on potential orphan accounts it owns that were created due to bugs. It would even be possible to create a canister whose job is to publish all the accounts of a principal as a service. There are other examples like this one of how more powerful ICRC1Account is compared to AcccountId and the price for that is to keep a bit more data per block.

1 Like

Just created a new thread about that. Frontend-to-Frontend Identity Protocol (F2FI)

It’s connected to this one in a way.

Account-id is consistent with engineering theory and with the conventions of the cryptographic community; it is not flawed. Some people think it is flawed because they cannot get the Principal from Account-id, which is precisely the advantage of Account-id, an advantage that is found everywhere in the cryptographic project.

It is short-sighted to think that Account-id is flawed.
I think it is an act of business architectural laziness. the great thing about Account-id is that no one knows the Principal behind the Account-id when he is not accessing the contract. if one does need the Account-id to associate a Principal, then it is easily available when the Account first accesses the contract.

The above are my views on Account-id.


Some of the voices of the community are mixed, some are short-sighted, and some do more harm than good.

The community’s challenges are based on the needs of their own projects, and each project’s domain is different and their needs are different, which requires the working group to take stock.

I hope the working group has its own goals and principles, following technical principles, architectural principles, engineering principles, and not being swayed by the voices of the community, including not necessarily adopting my suggestions.

2 Likes

This is clean and clear.
I love how the principal-text itself is part of the valid ICRC-1 id. Users of the IC must learn about principals somehow and this is a great way to do it.
The subaccount must start with a 0x and end with a . so that makes sure the user copies the subaccount correct.
A dapp/rosetta-api can validate the principal is copied correct by the crc32-checksum built into the principal-textual-representation.
This gives a simple way for users to construct their own subaccounts-ids on the fly without a computer. like at a coffee shop.

When a dapp wants a user to send some tokens to the user’s-subaccount of the dapp - a common senario -, the one possible thing that can go wrong with the above encoding is that a user can only copy the principal and forget/leave-out the subaccount. Let’s make this 100% and cover that hole, lets make the subaccount a must, so for a main-account (default-subaccount), the account-id will start with 0x. for a sample: 0x.4kydj-ryaaa-aaaag-qaf7a-cai . This way we can be 100% certain that the beginning and end of the account-id are copied correct. The users can comprehend the concept of a subaccount, show them @roman-kashitsyn 's blog-post.

// valid ICRC-1 textual account representations.

// Main-account (default subaccount)
0x.4kydj-ryaaa-aaaag-qaf7a-cai
0x.jlcmz-cojlk-zdm46-mshzl-dtlre-ricph-khpzu-tqxrk-qo3ow-7jdsw-tae

// Main-account (default subaccount)
0x00.4kydj-ryaaa-aaaag-qaf7a-cai
0x00.jlcmz-cojlk-zdm46-mshzl-dtlre-ricph-khpzu-tqxrk-qo3ow-7jdsw-tae

// Short subaccounts
0x0a.4kydj-ryaaa-aaaag-qaf7a-cai
0x01.jlcmz-cojlk-zdm46-mshzl-dtlre-ricph-khpzu-tqxrk-qo3ow-7jdsw-tae

// Long subaccounts
0xf2ca1bb6c7e907d06dafe4687e579fce76b37e4e93b7605022da52e6ccc26fd2.4kydj-ryaaa-aaaag-qaf7a-cai
0x5891b5b522d5df086d0ff0b110fbd9d21bb4fc7163af34d08286a2e846f6be03.jlcmz-cojlk-zdm46-mshzl-dtlre-ricph-khpzu-tqxrk-qo3ow-7jdsw-tae

Sorry, I took this scheme from an outdated specification for principal encoding. As @levi correctly pointed out, the actual encoding starts with the checksum:

Encode(b) = Grouped(Base32(CRC32(b) · b))

So it makes more sense to put the subaccount on the right, as in Mario’s original proposal. Such placement will maximize the information density in the prefix and the suffix of the account identifier.

I’m unsure whether we should require the subaccount prefix/suffix as or leave it out by default.

I don’t want to come off the wrong way, but even assuming your opinion is the right one (not saying it isn’t, just trying to make a point), don’t you believe its unfair to complain about the WGs choice after it has already been agreed upon for more than month? Why hasn’t this discussion happened during the WG?