ICRC-1 Token Standard Ledger

ICRC-1 uses Principal plus subaccount. It’s similar and compatible to ICP account identifier except for the block format.
What that means is that any Principal on the IC has multiple accounts on an ICRC-1 Ledger. This is done because Canisters have single Principal but should be able to have multiple accounts.

In none of the standards on the IC this can happen. The only authorised Principal that can call transfer from an account is the owner of the account or an approved Principal. In both cases the owner is in control. ICRC-1 goes one step further by trying to make the approval more secure (this is still under discussion though).

The one in the ICRC-1 repository. That’s the one you should believe. It’s still WIP.

DFINITY implementation is a prototype developed while we are working on the standard. When the standard will be completed, our implementation will align with the standard.

Sorry for the confusion @jzxchiang .

1 Like

Can we see what the new Account Identifier ( a merged Principal + subaccount) looks like?
If one user wants to send tokens to another, what do they copy/paste?

Or no AccountIdentifiers at all and users work with Principals only and subaccounts are reserved for canisters usage under the hood. But then this would mean a canister can’t be a multi-user wallet, because it can produce only one UI level address.
Or when users send funds to another user they fill in two boxes, Principal and subaccount?

I means if user use a principal as his dapp account, and use this principal to hold tokens, like ICP. Then the dapp can invoke the transfer method with javascript code to send his token to others.

1 Like

Yes, it looks like this:

type Account = record {
    of : principal;
    subaccount : opt Subaccount;
};

If this is just a direct transfer via dfx from the main account of user1 to the main account of user2 and user2 principal is pcotu-nluuc-vzney-2ugxz-y2uis-duoyw-unfos-x6uyo-lnvgj-ohijr-sae then they would write

dfx canister call icrc-1-ledger icrc1_transfer '(record {
  to_principal=principal "pcotu-nluuc-vzney-2ugxz-y2uis-duoyw-unfos-x6uyo-lnvgj-ohijr-sae",
  amount=10
},)'

For more advanced example where user1 transfers tokens to an account of user2 that is not the default, e.g. account 1, the subaccount needs to be specified:

dfx canister call icrc-1-ledger icrc1_transfer '(record {
  to_principal=principal "pcotu-nluuc-vzney-2ugxz-y2uis-duoyw-unfos-x6uyo-lnvgj-ohijr-sae",
  to_subaccount=opt vec {0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;};
  amount=10
},)'

Finally, an even more advanced example is moving tokens between non-default accounts. Let’s say user2 now wants to move 4 tokens from its account 1 to its account 2, then it needs to specify both the from_subaccount and the to_subaccount:

dfx canister call icrc-1-ledger icrc1_transfer '(record {
  from_subaccount=opt vec {0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;};
  to_principal=principal "pcotu-nluuc-vzney-2ugxz-y2uis-duoyw-unfos-x6uyo-lnvgj-ohijr-sae";
  to_subaccount=opt vec {0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;2;};
  amount=4;
})'

All the transfers above look simpler when done programmatically via rust or motoko.

I am interested in how this will change end-user interfaces. I guess our ecosystem was the only one using the addresses NNS used, along with EXT NFT tokens used by Entrepot.

Now there are few cons if the UI level address is a Principal:

  • end-users can’t manually send tokens to subaccounts, they can only target the main account, unless we give them a second input field to put things in.
  • a canister can’t be a multi-user wallet/proxy anymore, it only has one UI level address - its Principal.
  • Internet Identity gives us only one pub/private key, which means one UI level account
  • You cant have a canister offering multi-sig to thousands of users, each wallet has to be its own canister

Can’t we agree on a UI-level address all wallets will understand and split properly, so a user can target them easily?

main account: pcotu-nluuc-vzney-2ugxz-y2uis-duoyw-unfos-x6uyo-lnvgj-ohijr-sae
second account: pcotu-nluuc-vzney-2ugxz-y2uis-duoyw-unfos-x6uyo-lnvgj-ohijr-sae-y2uis-duoyw-unfos-x6uyo-lnvgj

1 Like

Ok, let’s see how we can encode the account record {Principal, Subaccount} for better UX. The requirement is that every client(browser) can decode the address easily into Principal 29bytes and Subaccount 32bytes

Which one do you like most?

  • using Principal encoding
    7oxcw-qurpx-fcebq-q5ocd-gvdyn-2pf2n-vec43-o5f4a-zx43m-d6uln-tqe-miyz7-tabae-aqcai-baeaq-caiba-eaqca-ibaea-qcaib-aeaqc-aibae-aqcai-bae
  • using Principal encoding adaptive*
    miyz7-tabae-aqcai-baeaq-caiba-eaqca-ibaea-qcaib-aeaqc-aibae-aqcai-baeae-aqcai
  • using base58 (Bitcoin)
    2xoMuudmMrMNJHVXhij52NfjKUDNk3rZgT5tqjQ1RPmtJfa8P4yjZDufTP4kejWnmNR5oomvjBcSKe9xXYnL
  • adaptive * base58 (Bitcoin)
    AnwNBG7a4rVJizGXQWTSQc69pFCUTCQJTC951zbLUCaY

0 voters

*The adaptive one doesn’t show zeroes. The size will increase and match non-adaptive one if fully used, but such addresses will probably will be used only by canisters internally, so the perceived size will be small.

Does moving funds between subaccounts require a fee?

I suppose yes if it uses the same transfer function. It depends on the implementation I guess, not the standard.

I see, how about the ICP ledger? Does it have a fee?

Yes. Everything that creates a block has a fee.

I understand, that might be a problem for some use cases and perhaps is one of the reasons some don’t like subaccounts. Say I have a dApp where lots of users deposit funds and only one can withdraw them, with subaccounts you’d have to pay for N transfers based on the number of users.

N needs to be very big in order to really affect the service. The fee can also be split between user and service. The fee was designed to have basically no impact on normal transfers.

True but that also depends on how high the fees are in case of custom tokens, considering many have expressed their concerns about having to pay fees, even a small amount might be an issue for some, especially if the number isn’t predictable.

There is also the scenario where the dApp frequently moves funds between subaccount, the fee even if small will eventually add up.

Mario, sir,

I understand that projects need NNS approval before they can access SNS services.

However, if a project wants to issue a ICRC-1 token, will they be able to implement this without requiring an SNS (and therefore NNS approval)?

i.e. will the community have access to issue tokens under the ICRC-1 standard in a permissionless/non-gated way?

Thank you

For visibility

@Zane the double fee for the payment flow is true for all the flows (except the one that checks blocks). With approve/transferFrom you still have to pay two fees: one to approve and one to transferFrom. The amount of total fee is the same. I don’t see the fact that you have to pay fees a good reason to not use subaccounts.

The icrc1 ledger, like all the code from DFINITY, is open source and available to be used by anybody. You deploy your ledger and issue your tokens. No NNS nor SNS involved. It’s your decision.

2 Likes

Allowing subaccounts doesn’t mean you have to use them.

You could simply use the default subaccount for each principal and then you have the exact same behaviour as if subaccounts didn’t exist.

1 Like