Skip to content

CIP-0113? | Programmable token-like assets#444

Open
michele-nuzzi wants to merge 88 commits intocardano-foundation:masterfrom
HarmonicLabs:master
Open

CIP-0113? | Programmable token-like assets#444
michele-nuzzi wants to merge 88 commits intocardano-foundation:masterfrom
HarmonicLabs:master

Conversation

@michele-nuzzi
Copy link
Copy Markdown

@michele-nuzzi michele-nuzzi commented Jan 20, 2023

Developers wishing to participate: please read & follow the definitive recommendations at #444 (comment) which include:

For lightweight discussions prior to posting, feel free to use the Discord CIP server channel #cip-113 (server invite on this page)


This CIP proposes a solution to CPS-0003 (Smart Tokens) implementable already with V2 Plutus contracts.

If adopted as a standard it would allow to emulate the behavior of account-based ledgers tokens on Cardano.


(rendered proposal in branch)

@michele-nuzzi
Copy link
Copy Markdown
Author

Please note that at this moment this is only a draft and may contain errors in the logic.

If you spot any or have suggestions on how to improve the logic contributions are more than welcome!

@matiwinnetou
Copy link
Copy Markdown
Contributor

matiwinnetou commented Jan 20, 2023

Question:
Would wallets have adhere to this standard, if no how would they know that they should show said ERC-20 alike asset in their wallets without it? If yes how could they do this?

@nielstron
Copy link
Copy Markdown
Contributor

@matiwinnetou How it works on EVM compatible chains is that the wallet stores locally a list of common tokens / users can manually add token addresses to track. Try installing Metamask and interacting with milkomeda.muesliswap.com

@michele-nuzzi
Copy link
Copy Markdown
Author

@matiwinnetou the solution proposed emulates the way tokens are used on EVM chains in many aspects

As @nielstron said the user of a wallet needs to manually add the contract to track

Wallets can find the user balance by the NFT associated with the payment credentials.

@matiwinnetou
Copy link
Copy Markdown
Contributor

I see, thanks, this helps a lot. So I guess it would be of course also possible to have some registry for those tokens so wallets could use it.

@rphair rphair changed the title meta-assets (ERC20-like assets) initial draft CIP-???? | ERC-20assets Jan 20, 2023
@rphair rphair changed the title CIP-???? | ERC-20assets CIP-???? | ERC20-like assets Jan 20, 2023
@rphair
Copy link
Copy Markdown
Collaborator

rphair commented Jan 20, 2023

thanks @michele-nuzzi - I just edited title to be specific & put the Draft status into the review stage itself; feel free to change back when you feel the drafting process is complete: https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/changing-the-stage-of-a-pull-request

Also I'm adding a link to the readable proposal into the original comment & please keep updated if it changes path 🙏

@rphair rphair marked this pull request as draft January 20, 2023 13:34
L-as
L-as previously requested changes Jan 21, 2023
Copy link
Copy Markdown
Contributor

@L-as L-as left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I've noted elsewhere, a system as described in this CIP is inherently centralised (but trustless) and thus can't support the throughput it would on account-model based ledgers.

A much simpler system which likely serves your needs is a system where the owner is noted in the token name of a token. Let's assume it's a PKH for simplicity, but in the future we want scripts + datums as owners too.
You then only own a token if you 1) actually hold it and 2) the token name includes your PKH. The token name can also contain extra information through hashing the PHK along with token-specific information. If necessary, a UTXO can be created to ensure the preimage is stored on Cardano itself. Then sending a token to someone would entail burning then minting it again. In this process, arbitrary checks can be done through the minting policy.
Implement royalties is trivial, and would be done by including the author name in the token name too.
Implementing freezing for USD stablecoins would include checking a centralised Merkle tree of frozen addresses and checking that yours is not included.

As for supporting scripts, I think just allowing a script + datum to be used as owner might be enough.

Also, unrelated to the idea itself, I would appreciate it if the CIP was better checked for grammatical/formatting errors/typos, etc.

@L-as
Copy link
Copy Markdown
Contributor

L-as commented Jan 21, 2023

@michaelpj might be interested

@michele-nuzzi
Copy link
Copy Markdown
Author

@L-as Thank you for helping with the CIP.

I like a lot the system you propose but from a first read I believe is missing an equivalent for the approve and transferFrom methods since the spending of a token always requires the owner to include them in a transaction.

Regarding throughput, it is only limited to the phase of the creation of a new account; while I understand it is a bottleneck it is an operation performed only once and it should not cause too many problems. Once an account is created it remembers its own state and multiple accounts can be used in parallel.

I recognize my writing is not the best and I'll try to put more effort into it.

@L-as
Copy link
Copy Markdown
Contributor

L-as commented Jan 21, 2023

@michele-nuzzi That is somewhat true, however, you could implement it by freezing the old tokens (ref inputs) and minting new ones, but this might not be any better than what you describe. How common is transferFrom and approve? The issue is a token that supports freezing would have transfer transactions that are more complex than the ones in this CIP AFAICT.

There is also the issue of complexity, the scheme described in this CIP is not simple, and also requires more effort from wallet developers to show the information.
A complex scheme also has a higher chance of bugs.

I'm not sure which scheme is better when taking that into account.

@michele-nuzzi
Copy link
Copy Markdown
Author

michele-nuzzi commented Jan 21, 2023

From what I can tell transferFrom is the preferred way for a smart contract to move those tokens.

It is true that for this first draft, it might be tricky to implement something like freezing; I was thinking to add a second field to the Account datum so that it can have additional arbitrary data:

const AccountManagerDatum = pstruct({
    Account: {
        amount: int,
        state: data
    },
    /* ... */
});

and then make sure that the state field is unchanged for all the standard redeemers (easily done with equalsData)

the account manager can have other redeemers after the standard one so that maybe a Freeze redeemer can be added and this will be able to freeze a given account by modifying the state field.

Regarding wallet implementation, it shouldn't be any harder than the current resolution of ADAHandles.

@MicroProofs
Copy link
Copy Markdown
Contributor

@L-as Thank you for helping with the CIP.

I like a lot the system you propose but from a first read I believe is missing an equivalent for the approve and transferFrom methods since the spending of a token always requires the owner to include them in a transaction.

Regarding throughput, it is only limited to the phase of the creation of a new account; while I understand it is a bottleneck it is an operation performed only once and it should not cause too many problems. Once an account is created it remembers its own state and multiple accounts can be used in parallel.

I recognize my writing is not the best and I'll try to put more effort into it.

I would say to avoid the ERC-20 approve function at all costs. It has plagued the Ethereum eco-system and even they are standardizing a new key signature method called permit to try to correct this terrible mistake. I'd recommend instead signatories be checked for transferFrom methods instead of the far outdated approve. I have not had the time to fully go through this. But I just want to warn against the mistake of implementing approve.

@michele-nuzzi
Copy link
Copy Markdown
Author

@MicroProofs If that's the case then there is no difference from the Transfer redeemer. Should we just drop Approve and TransferFrom and contracts will instead look only for Transfer redeemers to be used?

@MicroProofs
Copy link
Copy Markdown
Contributor

MicroProofs commented Jan 21, 2023

@michele-nuzzi
Yes since the whole idea of approve is you had no idea who is signing the transaction for a contract calling to an ERC-20 token contract. In Cardano we have easy access to that information. We should simplify it to just transfer. And I’ll review your draft tonight to give more feedback.

@L-as
Copy link
Copy Markdown
Contributor

L-as commented Jan 22, 2023

With those two removed is there any reason not to go for the token approach?

@michele-nuzzi
Copy link
Copy Markdown
Author

@L-as There would still be the problem of additional (trusted) data for script execution.

Implementing freezing for USD stablecoins would include checking a centralised Merkle tree of frozen addresses and checking that yours is not included

As you said implementing logic like freezing requires some external contract; this external contract would not be a standard, so someone else that wants to move around ERC20-like tokens would (and should) not know of this additional requirement

@L-as
Copy link
Copy Markdown
Contributor

L-as commented Jan 22, 2023

@michele-nuzzi It would always be the case that transferring tokens can fail. It should not be part of the interface in the first place. For wallets to support it seemlessly, you could have a helper untrusted script associated with the MP that tells you what you need to add to fix it. That would have to be the case even with your system to support arbitrary behaviour and keep the interface simple.

@michaelpj
Copy link
Copy Markdown
Contributor

I don't particularly have an opinion here and I'm not currently planning to review this. If this is a thing that people want then they can create it. I think it may not perform well (as @L-as says), and it sacrifices essentially all of the benefits of native tokens on Cardano.

A few thoughts:

  • No Rationale :(
  • Is this actually a CIP? It seems like a design for something that someone could build on Cardano. I'll leave it to the Editors.
  • I would strongly encourage some prototyping. Does it actually work? Is an implementation too expensive? Can you build other systems that actually interact with this?

@rphair
Copy link
Copy Markdown
Collaborator

rphair commented Jan 23, 2023

@michaelpj: Is this actually a CIP? It seems like a design for something that someone could build on Cardano. I'll leave it to the Editors.

After putting it in Draft stage I've been watching the feedback expecting that it will produce a Rationale and other CIP prerequisites to be added before @michele-nuzzi brings it into the "Ready for review" stage. I'm not recommending anything specifically yet in case a broader approach suggests presentation as a CPS instead. The discussion has been productive so far even without a mature proposal yet.

@michele-nuzzi
Copy link
Copy Markdown
Author

@michaelpj me and @L-as have had a very productive discussion

regarding performances, the only bottle neck is the Merkle tree which is there to guarantee the uniqueness of an account. This constraint is not really useful, there is no harm in having multiple accounts with the same credentials so it will be removed before the final CIP.

The implementation will only require the account manager.

@KtorZ KtorZ added the Category: Tokens Proposals belonging to the 'Tokens' category. label Mar 18, 2023
@rphair rphair added the State: Waiting for Author Proposal showing lack of documented progress by authors. label Apr 4, 2023
@rphair
Copy link
Copy Markdown
Collaborator

rphair commented Apr 4, 2023

Added Waiting for Author tag by consensus in today's CIP meeting while waiting for last feedback to be accommodated in the draft.

@rphair rphair added the State: Last Check Review favourable with disputes resolved; staged for merging. label Mar 4, 2026
@nemo83
Copy link
Copy Markdown
Contributor

nemo83 commented Mar 5, 2026

Thanks @rphair for the reply.

I think this strikes a good compromise for all reviewers and editors. On one side it shows momentum and consolidation, on the other signals maturity and urgency for developers and adopters to get their feedback in. My next few weeks will be all about this along with accompanying the code and the spec through a formal auditing process.

One lesson learned for me here and possibly the wider group is that, although I believe all CIPs are important CIPs, some might require additional social amplification, If it's not, it could be worth documenting it in the CIP process docs. This could be totally informal or a simple ☑️ that reads "requires CF/IO/Emurgo to post about this CIP on relevant socials".

I will continue to keep an eye on the convo of this CIP and attend CIP meetings in order to ensure questions and feedback are promptly addressed. In the interim my focus will shift on developing and improving tooling required to bring programmable tokens live as well as supporting partners and community teams in adopting the standard. All feedback gathered through this process will be funnelled here.

Thanks again everyone for the support and the work put into this. I apologise if I came across strong or a bit rough.

Keep up the good work.

@rphair
Copy link
Copy Markdown
Collaborator

rphair commented Mar 10, 2026

thanks @nemo83 ... I've read through all the communiqués and the central message seems to be the CF blog article. It conveys the overall message of a "we've done it / finished it" announcement (argued against at the CIP meeting), although the blog does contain these passages such as @colll78 recommended about still looking for feedback before considering complete:

Anyone can now explore, test, and give feedback on programmable tokens on Cardano.

The Foundation welcomes feedback on both the implementation and the CIP-0113 standard. In fact, as the standard is still being refined, input from builders will prove essential to getting it right.

The most immediate priorities focus on ... feedback: gathering inputs from developers, builders, and the broader Cardano community to refine both the standard and its implementation;

The editorial opinion is that @colll78 at least needs to say that document is final before we merge it. (We would also consider that PoC implementors themselves might be guided directly here with their own suggestions to update the document... which would be welcome as always in the CIP process.)

  • Given all the achievements so far — balanced against the huge need CF has to push out this framework as a product — I think waiting for unanimity of the active co-authors before merge is the only constant for this CIP PR in the overall timeline.
  • I'll recommend to @Ryun1 @perturbing that we merge this if, when, and only when we get Phil's stamp on the document... while the business world & the attention to the PoC implementation take their inevitable course in the meantime.

@nemo83 one thing I would strongly recommend based on many past experiences... especially if Phil doesn't post here saying "go ahead and merge this CIP" (at least as a baseline) before the highly publicised 19 March meeting...

Important

If this PR is still unmerged, the meeting promotion & content should refer to this as a CIP candidate rather than "CIP-0113" which does not exist until this document is merged. If that sense of finality is falsely conveyed, exactly as @colll78 emphasised at the meeting (backed up by years of CIP editor experience) we'll lose our last best opportunity to get any usable feedback here about the CIP document itself.

@nemo83
Copy link
Copy Markdown
Contributor

nemo83 commented Mar 10, 2026

thanks @nemo83 ... I've read through all the communiqués and the central message seems to be the CF blog article. It conveys the overall message of a "we've done it / finished it" announcement (argued against at the CIP meeting), although the blog does contain these passages such as @colll78 recommended about still looking for feedback before considering complete:

Anyone can now explore, test, and give feedback on programmable tokens on Cardano.

The Foundation welcomes feedback on both the implementation and the CIP-0113 standard. In fact, as the standard is still being refined, input from builders will prove essential to getting it right.

The most immediate priorities focus on ... feedback: gathering inputs from developers, builders, and the broader Cardano community to refine both the standard and its implementation;

From this point on, the editorial opinion is that @colll78 at least needs to say that document is final before we merge it. (We would also consider that PoC implementors themselves might be guided directly here with their own suggestions to update the document... which would be welcome as always in the CIP process.)

  • Given all the achievements so far — balanced against the huge need CF has to push out this framework as a product — I think waiting for unanimity of the active co-authors before merge is the only constant for this CIP PR in the overall timeline.
  • I'll recommend to @Ryun1 @perturbing that we merge this if, when, and only when we get Phil's stamp on the document... while the business world & the attention to the PoC implementation take their inevitable course in the meantime.

@nemo83 one thing I would strongly recommend based on many past experiences... especially if Phil doesn't post here saying "go ahead and merge this CIP" (at least as a baseline) before the highly publicised 19 March meeting...

Important

If this PR is still unmerged, the meeting promotion & content should refer to this as a CIP candidate rather than "CIP-0113" which does not exist until this document is merged. If that sense of finality is falsely conveyed, exactly as @colll78 emphasised at the meeting (backed up by years of CIP editor experience) we'll lose our last best opportunity to get any usable feedback here about the CIP document itself.

Hi @rphair

The tl;dr is: now that as proposers and editors, we believe we have a viable solution to programmable tokens, my current goal is to introduce the programmable token platform and the underlying suggested cip113 standard to as many people, companies and developers as possible, to ensure we have a sound design, a secure architecture and usable tooling.

The longer reply

I and CF have been working on several aspects of CIP 113. Two in particular are:

  1. a platform for experimenting and providing feedback
  2. contributing to progressing CIP113 in its path to active

In this round of comms we announced the platform and we requested feedback on both the platform itself and the standard.

The "we've done it / completed it" is more for the platform rather than the cip113 standard itself:

After months of work, we’re reaching another major milestone in the Cardano Foundation’s roadmap and releasing the Programmable Tokens Platform. This will be the key to unlocking tokenization and further growth of stablecoins on Cardano.

As you correctly highlighted in several places in the blogpost we invited people to provide feedback.

As a result of the announcement, a few people already working on it have interacted with the X post:

No worries, in the March 19th meeting (dev office hours) I will make plenty clear that the standard is still open for review and requires both functional and technical feedback. It's actually the whole purpose of the meeting:

  • introduce the standard
  • show it in action
  • request feedback

Meeting will also be recorded and shared on youtube to allow further reach

Given this wave of community and tech engagement has just taken place, I would expect and hope for feedback, and hopefully validation, in a few days or even a week or two. So on my side, as there wasn't before, there is still currently no urgency in getting this merged. At the same time, as previously mentioned, I would encourage everyone to chime in now that things have stabilised and calmed down a bit so that when the time comes to merge it, there will be no further delays.

I get your point about candidate but it's also true that it's a chicken and egg situation. Some people don't usually engage if a standard is not consolidated.

The spec for ThirdPartyTransferAct was incorrect. 

> `input_idxs`: A list of indices (in transaction inputs) pointing to the UTxOs from programmableLogicBase being acted upon

Is wrong in two critical ways. `input_idxs` is not a list of indices in the transaction inputs of the UTxOs spent from programmable logic base. It is a list of relative indices of ALL script inputs (not just those from `programmableLogicBase`) with respect to each-other.

This of-course means:
>  Each input at `input_idxs[i]` is paired with an output at `outputs_start_idx + i`. This allows batch processing of
  multiple UTxOs while maintaining a predictable structure.
is also incorrect.
@colll78
Copy link
Copy Markdown
Contributor

colll78 commented Mar 11, 2026

There is a critical issue in the spec, which I have submitted a PR to address (@michele-nuzzi review at your convenience).

Namely the following is incorrect:

The ThirdPartyAct constructor is used when a third party wants to execute actions on programmable tokens
without the explicit permission of the token owner. Third parties could be any Cardano user or specific groups (e.g.,
admins). This is commonly used for seizure operations but can support any custom logic defined by the token's
substandard.

This constructor supports multiple UTxOs in a single transaction for batch operations.

When using this constructor:

  1. registry_node_idx: The index (in reference inputs) of the RegistryNode for the token being acted upon
  2. input_idxs: A list of indices (in transaction inputs) pointing to the UTxOs from programmableLogicBase being acted
    upon
  3. outputs_start_idx: The index where corresponding outputs begin in the transaction outputs
  4. length_input_idxs: The expected length of input_idxs (used for validation)

Input/Output Pairing:
Each input at input_idxs[i] is paired with an output at outputs_start_idx + i. This allows batch processing of
multiple UTxOs while maintaining a predictable structure.

input_idxs is not a list of indices in the transaction inputs of the UTxOs spent from programmable logic base. It is a list of relative indices of ALL script inputs (not just those from programmableLogicBase) with respect to each-other.

The correct specification is:

When using this constructor:

  1. registry_node_idx: The index (in reference inputs) of the RegistryNode for the token being acted upon
  2. input_idxs: A list of integers encoding the selected transaction inputs as skip counts over
    tx.inputs
  3. outputs_start_idx: The index where corresponding outputs begin in the transaction outputs
  4. length_input_idxs: The expected length of input_idxs (used for validation)

Meaning of input_idxs

input_idxs is not a list of absolute transaction-input indices after the first element.

Instead, it encodes an ordered subsequence of tx.inputs incrementally:

  • input_idxs[0] is the absolute index of the first selected input in tx.inputs
  • for each i > 0, input_idxs[i] is the number of inputs to skip after the previously selected input before selecting
    the next one

Equivalently, if the selected inputs are at absolute positions

a0 < a1 < a2 < ... < an

then

input_idxs = [a0, a1 - a0 - 1, a2 - a1 - 1, ..., an - a(n-1) - 1]

Conversely, the absolute positions can be reconstructed as:

  • a0 = input_idxs[0]
  • ai = a(i-1) + input_idxs[i] + 1 for i > 0

In particular, for i > 0, a value of 0 means that the next selected input is immediately after the previous selected
input in tx.inputs (i.e. there are zero intervening inputs).

This encoding allows the validator to traverse tx.inputs incrementally by repeatedly dropping from the remaining suffix,
rather than restarting from the beginning for each selected input.

Input/Output Pairing

Let a0, a1, ..., an be the absolute input positions obtained by decoding input_idxs as described above.

Then the selected input at tx.inputs[ai] is paired with the output at:

tx.outputs[outputs_start_idx + i]

@rphair
Copy link
Copy Markdown
Collaborator

rphair commented Mar 16, 2026

@colll78 it appears that the problem you reported in #444 (comment) has been fixed with the commits that came after it. Would you be in favour of merging this at the CIP meeting tomorrow if there were a general call to do so?

@colll78
Copy link
Copy Markdown
Contributor

colll78 commented Mar 17, 2026

Almost, there are two outstanding changes that are needed:

  1. To modify the spec for TransferLogicAct to use the same indexing behavior of ThirdPartyTransferAct (add script_input_indices, script_inputs_count and outputs_start_idx to the TransferLogicAct redeemer) and modify the description of the validation logic accordingly.
  2. To modify the issuance script to remove the single output restriction, instead enforcing either: the programmableLogicBase script is invoked in the transaction or the total value minted is produced to the programmableLogicBase address.
  3. Modify programmable tokens issuance script to ensure that the associated programmable tokens registry node UTxO is either included as a reference input or inserted in this transaction; this is a critical security invariant that violates the assumptions of this protocol by allowing programmable tokens to exist outside of the mini-ledger, and thus allows malicious actors to perform token attacks similar to those in the earlier days of ethereum where you send someone a token that has no abnormal behavior (standard ERC-20) and then malicious logic is triggered and the user's other tokens are locked along with this token permanently until the user complies with the malicious logic (this logic often requires the user to send their entire wallet balance to the attacker's wallet - ie a wallet drain).

@rphair
Copy link
Copy Markdown
Collaborator

rphair commented Mar 18, 2026

Discussion at CIP meeting today covered:

  • the promise of current state of development, with some significant third-party software integrations @nemo83 mentioned are on the way (even those that are not confidential I'm not mentioning here, to allow social interest to be expressed elsewhere in due course);
  • some drastic consequences if currently unsolved problems would somehow make it into the mainstream (which will be solved in advance, as I understand, by @colll78's CIP-0113? | Programmable token-like assets #444 (comment) directly above);
  • the potential advantage (if not before merging this CIP, then soon after) of a LayerZero integration that would facilitate ERC tokens like Tether if & when the standard can be extended according to the message format they use (@colll78 mentioned he might discuss this with them).

Thanks again to both co-authors for the updates. Editors have again committed to following both co-authors' expertise in determining when this is ready & I've also urged @Ryun1 @perturbing to review the document itself so we can concur that it's ready to merge as soon as all known technical problems are confirmed solved & updated in the CIP text... to consider again to merge from Last Check at our next meeting: https://hackmd.io/@cip-editors/131

@nemo83
Copy link
Copy Markdown
Contributor

nemo83 commented Mar 18, 2026

Almost, there are two outstanding changes that are needed:

  1. To modify the spec for TransferLogicAct to use the same indexing behavior of ThirdPartyTransferAct (add script_input_indices, script_inputs_count and outputs_start_idx to the TransferLogicAct redeemer) and modify the description of the validation logic accordingly.
  2. To modify the issuance script to remove the single output restriction, instead enforcing either: the programmableLogicBase script is invoked in the transaction or the total value minted is produced to the programmableLogicBase address.
  3. Modify programmable tokens issuance script to ensure that the associated programmable tokens registry node UTxO is either included as a reference input or inserted in this transaction; this is a critical security invariant that violates the assumptions of this protocol by allowing programmable tokens to exist outside of the mini-ledger, and thus allows malicious actors to perform token attacks similar to those in the earlier days of ethereum where you send someone a token that has no abnormal behavior (standard ERC-20) and then malicious logic is triggered and the user's other tokens are locked along with this token permanently until the user complies with the malicious logic (this logic often requires the user to send their entire wallet balance to the attacker's wallet - ie a wallet drain).

GM, I took some time to review the points above and okay for 2 and 3 but I'm unsure about point 1.

What's the benefit of this? Would it fix any issues or is it a performance improvement? At this level of optimisation, I believe optimisation is possible but in the thousands of lovelaces, at the cost of a more complex and hence error prone redeemer.

Also for point (3), despite the fix, the attack will still unfortunately be possible, but the mitigation is to immediately and correctly mark the "bogus" token as programmable, signalling wallets and offchain infrastructure to prefer not to mix up with other programmable tokens unless strictly necessary (usually in defi protocols).

@colll78
Copy link
Copy Markdown
Contributor

colll78 commented Mar 18, 2026

Also for point (3), despite the fix, the attack will still unfortunately be possible, but the mitigation is to immediately and correctly mark the "bogus" token as programmable, signalling wallets and offchain infrastructure to prefer not to mix up with other programmable tokens unless strictly necessary (usually in defi protocols).

The attack (turning a non-programmable token into a programmable one) will be impossible after the fix. The fix would enforce that:
Any token minted through the issuance minting policy must either already be a registered programmable token or must be registered as a programmable token in the transaction in which the minting occurs. The problem with the current approach is that you can mint a token with the issuance minting policy without registering it in the programmable token directory as a programmable token, the token will be minted and included in some output to programmableLogicBase and because it is not yet registered as a programmable token, that UTxO can be spent from programmableLogicBase to any address outside of the programmable tokens mini-ledger (ie. my wallet address). Wallets will not mark this as a programmable token because it is not registered as a programmable token on the programmable token directory, indeed at that point in time the token would NOT be a programmable token because it can exit the mini-ledger freely and is not subjected to any programmable logic within the mini-ledger. During this time, wallets would include this token in other UTxOs with other programmable / non-programmable assets under the expectation that this token will always be a non-programmable asset. After this token has circulated and is present in UTxOs both inside and outside the programmable tokens mini-ledger, the attacker could register it as a programmable token at which point all the UTxOs with this token in the mini-ledger are subjected to its logic and thus bricked.

The key invariant this vulnerability breaks is that programmable tokens can never exist outside the mini-ledger, the problem is that you can mint a non-programmable token from the issuance policy, and then at your own convenience, register that token as a programmable token and brick any DEX pools / user UTxOs in the mini-ledger with that token.

@nemo83
Copy link
Copy Markdown
Contributor

nemo83 commented Mar 18, 2026

The attack (turning a non-programmable token into a programmable one) will be impossible after the fix.

Yup I got that and that's a great finding, but if someone manages to sneak a "bogus" programmable token into a utxo with other programmable tokens, he can still freeze the whole utxo and blackmail the user. For sure this is a super important fix.

What about the point (1)

  1. To modify the spec for TransferLogicAct to use the same indexing behavior of ThirdPartyTransferAct (add script_input_indices, script_inputs_count and outputs_start_idx to the TransferLogicAct redeemer) and modify the description of the validation logic accordingly.

EDIT: I also realise writing this on a public forum is not ideal... coz could give ideas... will eventually nuke or amend the post later...

@colll78
Copy link
Copy Markdown
Contributor

colll78 commented Mar 18, 2026

What's the benefit of this? Would it fix any issues or is it a performance improvement? At this level of optimisation, I believe optimisation is possible but in the thousands of lovelaces, at the cost of a more complex and hence error prone redeemer.

The main goal of script optimization is not to reduce transaction fees (although that is a meaningful byproduct), it's primarily to increase dApp throughput, and secondarily to expand the range of what features are possible and feasible to implement within dApps. This is critical for any production dApp which expects non-trivial onchain activity, which is why you see protocols like Minswap, SundaeSwap, Liqwid, and others that need to be able to facilitate more than a handful of concurrent users spend so much time and effort on micro-optimization. If a DEX processing contract hits the transaction ex-unit limits with 16 orders then the dApps throughput is less than 1 request / second, and with backlog users can end up waiting close to half an hour for their orders to process. All production dApps fall into one of two categories with respect to how they handle this:

  1. Dedicate significant effort into optimizing the ex-unit consumption of their contracts. Micro-optimizations, indexing, taking advantage of ledger invariants, witness-driven-complexity-collapse and all the other modern design patterns.
  2. Minimize onchain logic and move trust assumptions offchain (ex. the authority to process orders is limited to an admin key and as such the validators can afford to omit expensive validation logic by relying on the administrative authority to act honestly with respect to the components that aren't directly enforced on-chain)

The theoretical throughput limitations for most dApps right now are between 40-50 orders per block, this is around the threshold at which you have enough capacity to support most onchain activity right now and you only really see this threshold exceeded and the subsequent throttling become a UX issue for short bursts during very high interest launches or liquidation events; but for most onchain activity now, the current level of optimization in these dApps is sufficient.

The problem is that with programmable tokens they won't be able to achieve anywhere near that level of throughput because a huge percentage of the transaction ex-budget will be consumed by the core mini-ledger contracts, and the individual programmable token transfer logic contracts. For a programmableToken/Ada pool, without even considering the ex-unit costs of the token's transferLogicScript, you hit the ex-unit limit far before processing even 15 swaps in a block. At this point any non-trivial user activity hits this threshold and UX slows to a crawl. Ex-units are already a huge constraint for throughput and feature capabilities of dApps today, this issue becomes even more prominent for dApps on the programmable tokens mini-ledger since a huge portion of the budget is already consumed by the mini-ledger smart contracts which are entirely out of their control. If the ex-unit footprint of the mini-ledger isn't minimized to the absolute limit then programmable token dApps will be forced to gut logic or leave end users to suffer the UX downgrade of request bottlenecks.

Also transaction fees aren't the only fees that are impacted by throughput, dApp infrastructure costs are directly correlated to the amount of batches that must be processed, if 60 swap requests can be processed in a single batch, this results in substantially less work (especially with respect to coordination) for batchers than processing three batches of 20 swaps, and this difference can be reflected in the batcher fee.

We aren't talking about micro-optimizations; we are talking about an average difference in efficiency of 30-80% across every class of real-world use-cases.

@nemo83
Copy link
Copy Markdown
Contributor

nemo83 commented Mar 31, 2026

All, I've just addressed the issues raised in previous comments here: cardano-foundation/cip113-programmable-tokens#45.

@rphair
Copy link
Copy Markdown
Collaborator

rphair commented Mar 31, 2026

@colll78 if @nemo83's #444 (comment) fixes the issues you raised in #444 (comment) please post here so we can consider this confirmation at the upcoming meeting.

@rphair
Copy link
Copy Markdown
Collaborator

rphair commented Mar 31, 2026

p.s. to last comment, from CIP meeting: we've confirmed it's a newer, separate issue & will be waiting for this & any other "tying up loose ends" over the next 2-week cycle (remaining at Last Check). cc @colll78 @nemo83

@colll78
Copy link
Copy Markdown
Contributor

colll78 commented Apr 1, 2026

I added my review to the PR, there's a pending issue namely that issuance is limited to a single asset per policy, this kills a huge category of use-cases, ie. soulbound DIDs and so on which require minting multiple tokens under the same policy id.

@nemo83
Copy link
Copy Markdown
Contributor

nemo83 commented Apr 7, 2026

GM,

Few updates,

  1. issues recently raised have all been addressed with PR Fix/minting proof and composability 2 cip113-programmable-tokens#45
  2. as a result of the fixes above, some APIs in the validator scripts have changed. For this reason I've issued the follow PR Feat/final refinements HarmonicLabs/CIPs#6 so that people can review these changes in isolation. Some additional improvements in terms of simplified redeemers have been introduced which simplified transaction building, scripts size and script costs.

Thanks all for the continuous support.

@colll78
Copy link
Copy Markdown
Contributor

colll78 commented Apr 9, 2026

HarmonicLabs#6 Absolutely should not be merged as is. It deviates the interface of the standard to cater to the desires of a specific implementation, to circumvent of a constraint of their specific offchain library (it struggles with indexing), at the expense of huge negative impacts on efficiency and maximum throughput.

CIPs should not cater to any specific implementation, they should always prefer the option that is objectively best (via standardized measurable criteria). It is up to individual implementations to cater to the specification of the CIP, not vice-versa.

@nemo83
Copy link
Copy Markdown
Contributor

nemo83 commented Apr 10, 2026

Sorry, maybe I didn't communicate adequately.

The API/Interfaces are modified yes, but simplified to provide better overall user experience, ie. not having to care for indexes. Offchain code/library has nothing to do with this.

On top of this, additional benchmarking, has provided useful insights where overall costs are reduced, please check PR description cardano-foundation/cip113-programmable-tokens#46 for more details, but for handiness I'm gonna report the comment here:

📍 Minor optimisation: slightly more laziness when merging tokens.

📍 Remove length from 3rd party redeemer
Not actually needed for anything, it makes the redeemer more complicated than it needs to be, makes the code 2-3% worse and make the code ~60 bytes larger. So it's a triple win, albeit not super important.

@rphair
Copy link
Copy Markdown
Collaborator

rphair commented Apr 14, 2026

@colll78 @nemo83 since the last round of comments above suggest critical remaining issue(s), as per the previous agreement & public expectations we'll leave this at Last Check but wouldn't merge unless there is clear agreement from both parties that all such issues are resolved.

If I'm reading this wrong, please post here or clarify at the upcoming meeting discussion (in less than 1 hour: https://hackmd.io/@cip-editors/132) and it'll remain at Last Check so we can at least have a biweekly status check until confirmed ready to merge.

@rphair
Copy link
Copy Markdown
Collaborator

rphair commented Apr 14, 2026

Meeting resolved that @nemo83 would contact @colll78 by DM to confirm or dismiss the criticality of the latest problem identified: possibly "cosmetic" because of good performance measured in recent benchmarks. Editorial status — waiting for these 2 expert opinions to converge/agree (or at least lack of dispute) before merging — remains unchanged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Category: Tokens Proposals belonging to the 'Tokens' category. State: Last Check Review favourable with disputes resolved; staged for merging.

Projects

None yet

Development

Successfully merging this pull request may close these issues.