ICRC-1 Token Standard Ledger

Isn’t that statement valid for Rust, but invalid for Motoko? You don’t have to inspect dependencies with Motoko, because it’s not as powerful and can’t touch memory and ruin things like Rust?
Now when I think about it… I guess there are still ways. If I include SHA256 function it may wait for a secret sequence to start acting malicious. It won’t be changing the memory, but it still can result in a vulnerability.

A ledger needs to add transactions to an infinitely scalable cluster of history canisters. You can make these immutable. It won’t sacrifice upgradability. If the DAO goes and messes with the ledger state, this can be proven, because it won’t be matching the state you can rebuild from history. This means the DAO will lose trust and its token value will fall. So a DAO doing something like that is a public suicide. Or it could be interpreted as a hard fork. And someone could copy the whole thing (if it’s open-source and it should be) and spawn a new instance that is proveably legit.

@skilesare

Lets walk this through,

What do you mean by stranded tokens? At this point the user’s tokens are in the user’s-neuron’s-subaccount on the governance-canister. The user can re-try the claim-method with the neuron-number. The service managing the user’s-staking keeps track of the user’s-neuron-numbers like how the nns-dapp-canister works. (there is no need to refind a transaction)

What do you mean by ‘direct deposit function’? At this point the neuron is registered in the governance canister with a 0 dissolve-delay. The stake functionality is the IncreaseDissolveDelay function which makes sense to give the users.

What are the specific steps you have in mind for a service with an approval to take to get ‘ready’ for a commit-transfer? The service still has to 1.transfer, 2.claim, and 3.increase-dissolve-delay(stake). Steps 2 or 3 can still fail (if on a heavy load) even if a canister is calling them. the same senarios can happen.

A bit optimised version.

Receiver (Custodian) - can be made immutable and its code can be verified. Once it’s no longer viable, because of evolution, we stop using it and use something else. It doesn’t hold anything long-term so its easily replaceable. Because its immutable and verifiable, other canisters can trust it.

Maker - someone who has created an order and waits for it to be fulfilled by anyone. That could be a: person trying to swap ICP for BTC
a dex swapping ICP for ICP_BTC_LP
ICP+BTC for ICP_BTC_LP
staking ANV for ANV_VLP

We could also merge columns in the sequence diagram however we want and that will simplify things. It will make sense if you merge staking (TWO) with its ledger like this

And even merge Reciever + Market + Ledger, but it’s a different trust dynamic, you lose the easy Reciever immutability option, but gain speed. (ignore notes over TWO - wrong now)

And if we remove the internal canister messages from that diagram, we end up with…

Which is… what we started with and use already. The bigger (more complex diagram) is just giving us more options, but we can merge and remove them.

1 Like

What is the current state of the standard?

The core of the standard, e.g. address format and the basic functionalities, is pretty much done. DFINITY also has an implementation of the core that will be used by SNS and ckBTC.

We are discussing about more sophisticated functionalities now and how to proceed with them.

Overall services and users on the IC will be able to start using the standard very soon.

2 Likes

I’m very concerned about this question.
Does the ICRC-1 token standard have Approve and Transfer from methods like ERC20?

The standard doesn’t have them yet as you can see from its repository.

The working group which is responsible for the ICRC-1 Token Standard is discussing right now the possibility of adding something similar to ERC-20 approve/transferFrom but with some limitation. This new set of API has the name 2-steps transfer. You can find part of the discussion here. You can also see the 2-steps transfer methods in the interface of the ICRC1 Ledger implementation from DFINITY.

Do you have any specific concerns that I can try to answer?

This may be the way the NNS works, but the ogy governance and and origyn nfts work differently. In v1 all the governance canister funds are held in one account(the canister’s default account). Who owns what is managed with an internal ledger. To “claim” your deposit you give the governance canister the block height of your deposit and the canister checksnit and burns the block height if valid so you can only claim once. In v2 of the canister we will likely be moving to using subaccounts to keep better seperation of concerns.

From a canister’s standpoint the sub account is like magic and saves you a call. The one tough thing is that your client needs to know your sub account schema(ie. Hash of your principal) If everyone knows your schema them you lose a bit of privacy. With everying in one account we can keep your “internal to the canister” transactions more private(but it can also enable more funny business, so a double edged sword.)

Swapper - custodian in the previous posts. Calling it a Swapper, because “custodian” is already used heavily in crypto with a different negative meaning.
Participants put tokens in boxes (accounts controlled by the Swapper) according to order (description of the swap).
Cancelation is available to all participants anytime before the atomic swap.
If all participants placed correct contents in their boxes and nobody canceled, the swap is done.
From there on they can take their contents out.
Maybe this state machine diagram of how the Swapper works will also help.
Note - Swapper is a role, it can be in its own canister (possibly immutable) or inside another canister part of the swap.
Why did I put this in the token standard thread? It describes a solution to the problem (atomic swap) and the token standard is the foundation of the solution. Small changes to the standard cause huge changes ahead.

The standard specifies that the total supply value is Nat32. Does this mean that a total token supply can’t exceed 2^32 = 4 294 967 296 tokens ?

No, that was a mistake. I corrected it now, icrc1_totalSupply returns nat64.

While implementing the Swapper and trying to use that latest repo, I stumbled upon this change


Before you could query balance by passing AccountIdentifier, now you need to pass principal and subaccount.
This change makes the ledger pretty much use Zero-knowledge proof. If you know someone’s AccountIdentifier, you can’t query their balance, which is a bit weird. Is that intentional?
It pretty much becomes a private ledger and not a public one.
Going to post the Swapper soon

The ICRC-1 standard doesn’t define AccountIdentifiers for multiple reasons:

  1. Simpler mental model: We no longer need to explain what account ids are. With account ids, you had to learn about three entities (principals, subaccounts, account ids). With ICRC-1, you need just two entities (principals and subaccounts).
  2. Client code is simpler and easier to get right: you don’t need to link CRC-32 and SHA-224 libraries into each client anymore.
  3. Once we extend the interface to expose the block structure, dapps can scan the blocks to detect transactions to and from specific principals. Having principals and subaccounts explicitly will enable new flows (e.g., an app can proactively monitor the ledger transactions for transfers). The ICP ledger won’t support this extension.

If you’re working with the ICP ledger built around account identifiers, you can use its interface (instead of the ICRC-1 interface) to look up the balance by an account identifier.

1 Like

Valid reasons. I like the idea of not using sha-224 and crc-32.

Simpler mental mode, not so much. I am not explaining to users in my dapp what Principals are and not showing it at all and it works pretty well, not a single user complained.

But how will that work? Our accounts will always go in pairs Principal + subaccount. Currently, no blockchain requires two things to identify one account. So I guess we will end up creating a new AccountIdentifier, which has both pieces inside concatenated instead of hashed?

1 Like

Swapper working prototype is done :fireworks: :sparkler: :fireworks:
GitHub - infu/swapper

Also here (wont be updated) (Motoko playground): Motoko Playground - DFINITY

It works according to the diagrams shown above using only balance and transfer to achieve everything needed.
It’s not DoS resistant yet and may need a few more things to get easier to use

Realizations while making it: I think we need a fee function in the standard, each token may have a different fee even if using the same standard. The smart contract needs to query the fees for each token and add them to the requirements, otherwise, it won’t be able to transfer tokens out. You could return it in the balance query so only one call is made instead of two.

1 Like

If you are writing your own governance canister, you can write your own ledger canister where in the transfer-method, if the transfer is for the governance-canister, the ledger-canister first calls the governance-canister to stake, and if the call is success, makes the transfer.

Thanks so much.
One more question.
The tokens issued by ICRC -1 use Principal ID. But ICP uses Account ID.
Will users feel confused?

I think the biggest risk now is that token functions can be called directly. For example, in a game dapp, it is necessary to obtain Principal to mark a player. At this time, if there is a token in the player’s Principal, the game can directly call transfer to steal the player’s token without the player’s confirmation. Whether ICRC-1 solves this problem。

1 Like

@mariop Apologies if this has been asked before, but what is the difference between this ICRC interface and this one? Which should I believe? Why are there two?