PoV: Do not use ICRC-28 for Defi

tl;dr: Do not implement ICRC-28 on defi canisters. If you want to use ICRC-34 in defi canisters, use relying-party delegations, not account delegations.

Authenticated sessions vs. transaction approval

Web2 applications are based on the concept of authenticated sessions. The user initially logs in, the authenticity of the user is checked once, and both client and server maintain some data that represents the active session. While the session is active, the user can perform many individual actions without the requirement of (explicitly) authenticating again.

In Gen-1 and Gen-2 blockchains such as Bitcoin and Ethereum, transactions are slow and expensive, and state stored on the blockchain is limited. Thus, transactions are used sparsely and generally only to move significant value. An explicit approval of the user for each action (e.g., using a hardware wallet) is thus appropriate.

Due to the efficiency and decentralization of ICP, dapps built on ICP may share characteristics with both of the above cases. When participating in a discussion on OpenChat, I want the characteristics of a session; I do not want to explicitly approve each and every emoji reaction I make on other people’s posts. On the other hand, when managing my liquidity pool positions on ICP AMMs, I definitely want the additional safety of a dedicated wallet with transaction approval. Some dapps – like OpenChat with its inbuilt swap options – even share both characteristics of sessions and value transactions simultaneously.

II has been widely used for implementing session-like behavior in many ICP dapps, although admittedly some characteristics of traditional sessions are lacking. (One cannot securely “terminate” a session other than waiting for it to expire.) On the other end, wallets like Plug and more recently the ICRC-21 wallet standard have embodied the transaction approval characteristics.

Defi on ICP

In (most) defi applications built on ICP, the backend application canister will technically control user tokens for at least some duration. This is obvious in AMMs, where the liquidity pools that consist of users’ tokens are maintained by a canister. But due to the lack of cross-canister atomicity, it’s also required for any type of atomic swap (like exchanging an NFT for tokens); some canister has to technically control both assets for some amount of time, in order to guarantee that both parties in the trade receive their desired outcome.

I deliberately use the term technically control here since I want to highlight that the canister is a smart contract and will only act on my behalf, I as a user still ultimately own (and indirectly, by instructing the canister, control) the tokens. The canister technically controlling the tokens on the ledger is just a means to an end.

While the canister technically controls (or is authorized to do so, e.g. via an ICRC-2 approval) the user’s assets, the user will often need to call that canister with additional instructions. For instance, after sending some ckBTC to a DEX, do I want to add it to a liquidity pool? If so, which one? Do I want to swap it for some other token? Which one, with what slippage? And to what address do I want to send the tokens I receive in exchange?

The wallet standards

The main purpose of a dedicated wallet is to securely hold assets and be able to use them across different applications; in ICP lingo, the assets are controlled by the (main) wallet principal. ICRC-21 then allows transaction-approval semantics for that main wallet principal.

ICRC-34, by contrast, uses the delegation mechanisms underlying II to build session semantics. It comes in two flavors:

  • In relying-party delegation mode, an ICRC-34 wallet will provide session-like semantics to applications, while using – just like II – a different principal for each application.
  • In account delegation mode, an ICRC-34 wallet will provide session-like semantics to applications, while using the main wallet principal.

Note that, without further safety measures, account delegations would be horrendously insecure: the application could use the delegation to steal all tokens owned by the user on any ledger. For this reason, ICRC-34 account delegations require canisters to implement ICRC-28, which basically states that the canister opts into the use of account delegations. (Delegations can be scoped to specific target canisters.)

Why ICRC-28 is should not be used for defi

To understand why I advise against the use of ICRC-28 in defi canisters, consider the concrete example of a DEX. The use of ICRC-28/34 on a DEX could look as follows: The DEX backend, which maintains the liquidity pools, implements ICRC-28 and authorizes the DEX frontend to receive an account delegation from an ICRC-34 compliant wallet. Now a swap would work as follows:

  1. The user sends tokens via ICRC-1 transfer or ICRC-2 approval. This requires an explicit wallet interaction.
  2. The front end uses the ICRC-34 delegation to call the swap function on the backend canister. The function call specifies the target token, the slippage, and the address the received tokens are supposed to be received at. (This could be one or multiple calls.)

The problem with the above flow is that, with the account delegation, the front-end application obtains full control over the user’s assets technically controlled by the DEX canister! No further user interaction would be required for, for instance, liquidating all of the user’s liquidity pool positions and sending all tokens to some external address. That violates two major objectives of using a wallet:

  • Control/transparency: The user no longer has full control and transparency over what happens to their tokens, the front-end application can move them without user consent.
  • Security: The security of the user’s tokens degrades to the security level of a web front end, whereas a dedicated wallet (especially a hardware wallet) can offer a significantly higher level of security.

Such a use of account delegation also contradicts ICRC-34, which defines:

Account Delegation: an identity that has restricted access to the signer’s identity, such that it is stable across many relying parties but cannot be used to operate on tradable assets and shared infrastructure.

At least in my reading, issuing an account delegation scoped to the DEX backend canister provides access to the tradable assets held by the user on that exchange (while technically controlled by the canister), and thus contradicts the above definition.

So how should we do things?

If you are building a defi application on ICP, I advise against implementing ICRC-28 endpoints on any canister that controls (significant) value on behalf of a user. For these cases, ICRC-21 is the appropriate mechanism, and in many defi applications such as AMMs all authenticated calls will (potentially) move significant value, and thus deserve explicit approval via ICRC-21. For applications that share both session and transaction semantics, make the difference explicit: Implement session semantics via one dedicated mechanism (e.g. II), and have the user explicitly maintain their assets by an ICRC-21 wallet.

In my opinion, in order to smoothen defi flows that rely on a sequence of multiple ICRC-21 transactions, it also seems promising to proceed with (at least a restricted version of) ICRC-39 for batch approvals, in which at least sequences of the type “ICRC-2, …, ICRC-2, something else” can be approved in one go, since that seems to be the most common case in defi and failure/success can be handled gracefully by the wallet.

15 Likes

You’re overlooking some critical points with a tl;dr: If you’re a developer wanting a better UX than DEXs on other networks, a similar UX to ICP’s flagship app the NNS, and to enable network effects for your application while keeping user assets safe in their wallet, use ICRC-28/34.

  1. Session keys are not unique to ICP: Ethereum already has and are actively extending them for more widespread adoption. ICP has an advantage on this for now because we skipped entirely the concept of transaction approvals. Your comparison is misleading, and I’m afraid will detract from ICP’s competitive advantage.
  2. Transaction approvals are still required even with ICRC-28/34. Surely you’re aware NFID Wallet still requires approvals via ICRC-49 for any calls to any canister outside of the context of the application (and incorporates ICRC-21 where available). While I don’t believe you were doing this intentionally, ignoring the possibility of having it all may mislead the community.
  3. The most-used ICP DeFi app, with by far the highest value locked, requires no approvals (at all): The NNS operates without approval prompts and performs the most financially (and network security) sensitive actions than any you claim are insecure in DeFi. Why privilege the NNS with such amazing functionality while restricting other apps?
  4. Wallets can be drained even in the way you propose: There’s nothing anyone can do about a user approving an ICRC-2 approve call for more than the amount they actually want to transfer. We can’t be the user’s parent in all cases–all we can do is ensure assets in their wallet remain secure from drain attacks, which ICRC-28/34 do.
  5. Trust is the user’s choice: Preventing users from using session keys even when they trust the app limits their autonomy and is counterproductive to Web3’s principles. Whatever they do outside their wallet is self-sovereign and up to them.
  6. Loss of interoperability and the possibility of network effects for apps: Forcing developers to use a different caller than the user breaks composability. For instance, a wallet will not be able to show the user’s swap activity if a DEX uses an unknown relying party delegation. This opacity stifles innovation because a subset of a user’s on-chain activity is unavailable for the ecosystem of devs to query and build upon.
  7. Unnecessary complexity: Most DeFi users today rely on Internet Identity, which already grants 100% technical control to dApp canisters. Your approach doubles down on this while adding unnecessary developer overhead for stable principals.
  8. Misleading terminology: ICRC-21 is a consent message standard, not a “type of wallet.” Misusing this term could mislead the community—clarity is important.
  9. ICRC-39 is in draft: Batch calls are hard on ICP because of a lack of atomicity, therefore this standard was deprioritized in favor of getting the others finished. (i.e. what should wallets do with 3 calls in the batch where the 2nd one fails?)
  10. Let’s collaborate, not criticize: I’m sure you know writing standards is a thankless job and that we’ve been doing it for over a year now. I hope you to join a meeting in the future to discuss over an asynchronous conversation rather than synchronous posts! There’s been a long-standing community concern that development is too hard without the ability to easily build composable apps with a stable identity–would be great for the community to feel understood on this point.
9 Likes

Thank you for your response!

If you read my message carefully, you may have seen that all I am doing is advocating for compliance with ICRC-34, which rightfully mandates to avoid the confusion between control over tradable assets and other uses of a principal. In several discussions I had over the past weeks, the aspect that canisters may allow a user to indirectly control their tradable assets – and the severe security implications of this – were viewed a quite subtle, which is why I decided to write this post with a bit more context and a concrete example.

I am not advising against any other use of the standards or against the use of any products, whether built on those standards or not. I am also not advising against the use of session keys or delegations – they aren’t perfect, but they are still the most practical tool we have today for many application scenarios. (I was the one to write the specification for delegations, so blame all their shortcomings on me.)

With respect to the NNS front-end dapp, you may have seen me advocating for the use of hardware wallets for the control of larger token amounts at various times here in the forum or on social media, whether in combination with that dapp or without. But also without a hardware wallet, the use of the NNS front-end dapp, or similarly built dapps, does not even contradict my above advice. (Still, for managing larger amounts, use a hardware wallet!)

Speaking about the hardware wallet: Together with our partner Zondax, we’ve been working on ICRC-21 support for the hardware wallet, which has been quite a ride. We hope that this functionality can be shipped as part of the next release; unfortunately, it won’t be supported on all devices, at least the old Nano S is completely out of reach. (Maybe even the Nano X, while it works on the S+.) And it is technically not possible to securely support ICRC-34 on that wallet. Anyway, this new functionality may allow to perform operations like providing liquidity on AMMs with the security of a hardware wallet, which is a request that was mentioned to us by potential liquidity providers repeatedly in the past. All enabled by ICRC-21, and I am a big fan!

Let me use this opportunity to congratulate you & the entire NFID team for the successful Solidstate review you’ve received – that’s really fantastic news!

6 Likes

Thank you!

I wonder if you’d be willing to join a working group session next week to communicate your security concerns to us standards writers? I’m still not understanding how an account delegation and a DEX is different from II and NNS or II and Oisy.

What I am understanding is the desire to support hardware wallets, which are unlikely(?) to ever issue delegations, but that can be handled separately anyway.

2 Likes

Will try next week, added it to my calendar!

2 Likes