From 2c99f7360fcf41c815cf2ea6d6fc7b747d59dc8b Mon Sep 17 00:00:00 2001 From: colll78 Date: Wed, 4 Dec 2024 14:14:15 -0800 Subject: [PATCH 1/6] Introduce a new framework for programmable tokens --- .../README.md | 150 ++++++++++++++++++ 1 file changed, 150 insertions(+) create mode 100644 CIP-interoperable-programmable-tokens/README.md diff --git a/CIP-interoperable-programmable-tokens/README.md b/CIP-interoperable-programmable-tokens/README.md new file mode 100644 index 000000000..938d89dbe --- /dev/null +++ b/CIP-interoperable-programmable-tokens/README.md @@ -0,0 +1,150 @@ +--- +CIP: ??? +Title: Interoperable Programmable Tokens +Category: Plutus +Status: Proposed +Authors: + - Philip DiSarro +Implementors: [] +Discussions: + - https://github.com/cardano-foundation/CIPs/pull/444 +Created: 2024-12-3 +License: Apache-2.0 +--- + + + +## Abstract + +This CIP proposes a robust framework for the issuance of interoperable programmable tokens on Cardano. Unlike all its predecessors, this framework allows these tokens to be used in existing dApps, and does not require dApps to be developed specifically for these tokens. + +## Motivation: why is this CIP necessary? + +This CIP proposes a solution to Cardano Problem Statement 3 ([CPS-0003](https://github.com/cardano-foundation/CIPs/pull/382/files?short_path=5a0dba0#diff-5a0dba075d998658d72169818d839f4c63cf105e4d6c3fe81e46b20d5fd3dc8f)). + +With this framework we achieve programmability over the transfer of tokens (meta-tokens) and their lifecycle without sacrificing composability with existing dApps. + +Answers to the open questions of CPS-0003: + +1) How to support wallets to start supporting validators? + +For every user address you can easily derive the equivalent smart token address. So to obtain a users total wallet balance including their programmable tokens, the wallet can query their programmable token address and their normal address and combine the two results. + +2) How would wallets know how to interact with these tokens? - smart contract registry? + +For any given programmable token transfer, wallets can easily determine which stake script needs to be invoked (that contains the transfer logic) directly from the chain (no offchain registry required) by querying the original minting tx. + +3) Is there a possibility to have a transition period, so users won't have their funds blocked until the wallets start supporting smart tokens? + +This framework will not cause any funds to be blocked. Transfers of non-programmable tokens will remain unaffected. + +4) Can this be achieved without a hard fork? + +Yes, this framework has been possible since the Chang hard fork. + +5) How to make validator scripts generic enough without impacting costs significantly? + +The impact that the required script executions have on the cost of transactions is negligible. + + +## Specification + +# Smart Token Directory & Minting policy +This smart contracts is responsible for the minting / creation of new programmable tokens and for maintaining an merkle patricia forestry of all smart tokens and their respective transfer policies, we call this the `directoryRootHash`. + +```Haskell +-- directoryUTxO: a UTxO containing a state token NFT +-- address: ownScriptHash +-- value: ada <> directoryStateTokenNFT +-- datum: BuiltinByteString - the merkle patricia forestry root of the smart token directory + +-- Script Logic: +-- enforces that all minted tokens must be sent to instantiations of a base parameter script (the `ProgrammableLogicBaseScript` contract) +-- enforces that an entry with the key as `ownCurrencySymbol`, and the value as the script hash of it's `transferLogicScript` must be inserted into the merkle root in the datum of the directoryUTxO. +-- Enforces that the transaction only mints tokens with `ownScriptHash` as their currency symbol in this transaction (no other tokens are minted). +``` + +# Transfer Logic Scripts +The system guarantees that each programmable token must have a transfer logic script. The transfer logic script for a programmable token is the smart contract that must be executed in every transaction that spends the programmable token. For example to have a stable coin that supports freezing / arrestability this script might require a non-membership merkle proof in a blacklist. This must be a staking script (or an observer script once CIP-112 is implemented), see +[the withdraw-zero trick](https://github.com/Anastasia-Labs/design-patterns/blob/main/stake-validator/STAKE-VALIDATOR-TRICK.md) for an explanation. + +# Programmable Logic Base Script +This is a spending script that accepts 1 parameter, a credential which identifies the owner of the value that it locks. + +```Haskell +-- Script Logic: +-- Enforces that the witness associated with the credential `cred` is present in the transaction. +-- If the Credential is a PubKeyCredential then the public key hash must be present in txInfoSignatories +-- If the Credential is a ScriptCredential then the script must be present in txInfoWithdrawals (ie the script must be invoked in the tx) +-- For all non-ada tokens in the Spending script either: +-- a. A non-membership proof of the token in the `directoryRootHash` must be provided in the transaction (this proves that the token is not a programmable token) +-- b. A membership proof of the token in the `directoryRootHash` must be provided, and the associated `transferLogicScript` is present in `txInfoWithdrawals`. + +mkProgrammableBaseScript :: Credential -> ScriptContext -> () +mkProgrammableBaseScript cred ctx = ... +``` + +This framework doesn't require custom indexers to find user / script UTxOs, instead they can be easily queried by all existing indexers / wallets. For example, to obtain all the smart tokens in a user's wallet you can query their programmable token address (in the same way you would query any normal address). You can derive the user's programmable token address deterministically by applying their Credential to the `ProgrammableLogicBaseScript`. + +## Rationale: how does this CIP achieve its goals? + +The existing proposed frameworks for programmable tokens are: +1. Ethereum Account Abstraction (emulate Ethereum accounts via Plutus contract data) +2. Smart Tokens - CIP 113 +3. Arrestable assets - CIP 125 + +The issue with all of the above is that they are not interoperable with existing dApps. Thus entirely new dApps protocols would need to be developed specifically for transacting with the proposed smart tokens. They are not composable with existing DeFi, and so they will only work on smart-token enabled DeFi protocols. Furthermore, in some of the above CIPs, each smart-token enabled dApp must be thoroughly audited to ensure that it is a closed system (ie. there is no way for tokens to be smuggled to non-compliant addresses) and thus there needs to be a permissioned whitelist of which addresses are compliant. + +Additionally, these proposed solutions attempt to maintain interoperability: +1. CIP 68 Smart Tokens +2. Transfer Scripts (ledger changes required) + +The CIP 68 approach allows the tokens to be used anywhere but if the contract does not obey the logic then the token can be invalidated (ie revoked). So if you put it into a liquidity pool and the batcher does not obey the token logic then your tokens can be revoked and it wouldn't be your fault. +The transfer scripts proposal is to introduce a new Plutus script type that would need to be invoked in any transaction that spends a smart token (identified by the policy id). The issue with this approach is that it introduces a huge potential for vulnerabilities and exploits to the existing ledger and these vulnerabilities are responsible for the vast majority of exploits and centralization risks in ecosystems with fully programmable tokens (ie Ethereum). Regardless, this means that these tokens could not be used on existing dApps, since they would require a new Plutus version with new features, and the ledger does not allow contracts that use new features to co-exist in transactions with contract from previous versions where those features did not exist. + +Furthermore, all of the aforementioned proposals would require custom indexers and infrastructure to locate a user's (or smart contract's) programmable tokens. You could not simply query an address, instead you would need to query UTxOs from the contracts and check their datum / value (depending on the CIP) to determine the owner. + +The above factors motivated the design of this framework. Some of the core unique properties of this framework include: +1. Each users gets their own smart tokens address (that can be derived from staking keys, pub key hashes, and script hashes) +2. Interoperability with existing dApps +3. Introduces no new risk / vulnerabilities into existing protocols +4. Doesn't require changes to the ledger +5. Smart tokens cannot be revoked by dApps that fail to follow the standard (unlike the CIP 68 case in which they can) +6. Very low effort (relative to the existing proposals) to implement and get it to production / mainnet adoption +7. Completely permissionless and natively interoperable with other smart tokens. IE anyone can mint their own smart tokens with their own custom logic and the correctness of their behavior will be enforced. + + +## Path to Active + +### Acceptance Criteria + +Issuance of at-least one smart token via the proposed framework on the following networks: +1) preview testnet +2) preprod testnet +3) mainnet + +End-to-end tests of programmable token logic including arrestability, transfer fees, and blacklisting. + +Finally, a widely adopted wallet that can read and display programmable token balances to users and allow the user to conduct transfers of such tokens. + +### Implementation Plan + +Implement the contracts detailed in the specification, and implement the offchain code required to query programmable token balances and construct transactions to transfer such tokens. + + + +## Copyright + + +This CIP is licensed under [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0). From 37ab858b4e8b1a2498d852f3c07f887505a18327 Mon Sep 17 00:00:00 2001 From: colll78 Date: Wed, 4 Dec 2024 20:26:24 -0800 Subject: [PATCH 2/6] Address potential concurrency issues. --- .../README.md | 38 +++++++++++++++---- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/CIP-interoperable-programmable-tokens/README.md b/CIP-interoperable-programmable-tokens/README.md index 938d89dbe..d5bc8726e 100644 --- a/CIP-interoperable-programmable-tokens/README.md +++ b/CIP-interoperable-programmable-tokens/README.md @@ -61,7 +61,7 @@ The impact that the required script executions have on the cost of transactions ## Specification # Smart Token Directory & Minting policy -This smart contracts is responsible for the minting / creation of new programmable tokens and for maintaining an merkle patricia forestry of all smart tokens and their respective transfer policies, we call this the `directoryRootHash`. +This smart contracts is responsible for the minting / creation of new programmable tokens and for maintaining an merkle patricia forestry of all smart tokens and their respective transfer policies, we call this the `directoryRootHash`. ```Haskell -- directoryUTxO: a UTxO containing a state token NFT @@ -75,8 +75,21 @@ This smart contracts is responsible for the minting / creation of new programmab -- Enforces that the transaction only mints tokens with `ownScriptHash` as their currency symbol in this transaction (no other tokens are minted). ``` +Note that in this design there is only a single smart token directory UTxO. If we expect issuance of such token to be infrequent, then this is not an issue. However, if we expect issuance of programmable tokens to be a common occurrance than an [onchain linked list](https://github.com/Anastasia-Labs/plutarch-linked-list) data-structure should be used instead to prevent concurrency issues due to UTxO contention. In this case, each node on the linked list would contain the only Ada and a `nodeNFT` (which certifies that it is a valid linked list node, and as such the correctness of it's datum is enforced by the smart contract) and the datum of each node would contain: +``` +data ProgrammableTokenDirectoryNode = ProgrammableTokenDirectoryNode + { key :: CurrencySymbol + -- ^ Currency Symbol of the programmable token associated with this directory entry + , next :: CurrencySymbol + -- ^ Currency Symbol of the programmable token associated with the next node in this directory. + , transferLogicScript :: ScriptHash + -- ^ The transfer logic script that must be executed in every transaction that spends the programmable token associated with this directory entry. + } +``` +In either case, there is only a single directory (a single directory UTxO / single directory linked list) for all programmable tokens. + # Transfer Logic Scripts -The system guarantees that each programmable token must have a transfer logic script. The transfer logic script for a programmable token is the smart contract that must be executed in every transaction that spends the programmable token. For example to have a stable coin that supports freezing / arrestability this script might require a non-membership merkle proof in a blacklist. This must be a staking script (or an observer script once CIP-112 is implemented), see +The system guarantees that each programmable token must have a transfer logic script (located in either the directory UTxO or the directory linked list depending on the implementation). The transfer logic script for a programmable token is the smart contract that must be executed in every transaction that spends the programmable token. For example to have a stable coin that supports freezing / arrestability this script might require a non-membership merkle proof in a blacklist. This must be a staking script (or an observer script once CIP-112 is implemented), see [the withdraw-zero trick](https://github.com/Anastasia-Labs/design-patterns/blob/main/stake-validator/STAKE-VALIDATOR-TRICK.md) for an explanation. # Programmable Logic Base Script @@ -87,9 +100,19 @@ This is a spending script that accepts 1 parameter, a credential which identifie -- Enforces that the witness associated with the credential `cred` is present in the transaction. -- If the Credential is a PubKeyCredential then the public key hash must be present in txInfoSignatories -- If the Credential is a ScriptCredential then the script must be present in txInfoWithdrawals (ie the script must be invoked in the tx) --- For all non-ada tokens in the Spending script either: +-- For all non-ada tokens in the Spending script (directory UTxO implementation) either: -- a. A non-membership proof of the token in the `directoryRootHash` must be provided in the transaction (this proves that the token is not a programmable token) -- b. A membership proof of the token in the `directoryRootHash` must be provided, and the associated `transferLogicScript` is present in `txInfoWithdrawals`. +-- For all non-ada tokens in the Spending script (onchain linked list directory implementation) either: +-- a. Two adjacent node UTxOs in the onchain directory linked list such that the key of one is lexographically less than the currency symbol of the token, and the other is +-- lexographically greater than the currency symbol of the token must be provided as reference inputs (this proves that the token is not a programmable token) +-- b. The node UTxO in the onchain directory linked list associated with the currency symbol must be provided as a reference input, and the associated `transferLogicScript` is present -- in `txInfoWithdrawals`. +-- +-- Enforces that outputs containing programmable tokens must be instances of `ProgrammableLogicBaseScript` (this ensures that the system is closed and programmable tokens cannot be +-- smuggled). If the destination of a programmable token is a `ProgrammableLogicBaseScript` parameterized by a non-script credential (public key hash / public key staking credential) +-- then the output UTxO must only contain ada and the programmable token. This ensures that if a user's programmable token is frozen or otherwise ineligible for transfer due to its +-- transfer logic script, it will not cause other unaffiliated tokens to be locked. Note that such situations are unavoidable for dApp protocols (freezing a token in a liquidity pool +-- will cause the pool to be inoperable), as such we do not impose this restriction on transfers to script based instances of `ProgrammableLogicBaseScript`. mkProgrammableBaseScript :: Credential -> ScriptContext -> () mkProgrammableBaseScript cred ctx = ... @@ -104,7 +127,7 @@ The existing proposed frameworks for programmable tokens are: 2. Smart Tokens - CIP 113 3. Arrestable assets - CIP 125 -The issue with all of the above is that they are not interoperable with existing dApps. Thus entirely new dApps protocols would need to be developed specifically for transacting with the proposed smart tokens. They are not composable with existing DeFi, and so they will only work on smart-token enabled DeFi protocols. Furthermore, in some of the above CIPs, each smart-token enabled dApp must be thoroughly audited to ensure that it is a closed system (ie. there is no way for tokens to be smuggled to non-compliant addresses) and thus there needs to be a permissioned whitelist of which addresses are compliant. +The issue with all of the above is that they are not interoperable with existing dApps. Thus entirely new dApps protocols would need to be developed specifically for transacting with the proposed smart tokens. Furthermore, in some of the above CIPs, each smart-token enabled dApp must be thoroughly audited to ensure that it is a closed system (ie. there is no way for tokens to be smuggled to non-compliant addresses) and thus there needs to be a permissioned whitelist of which addresses are compliant. Additionally, these proposed solutions attempt to maintain interoperability: 1. CIP 68 Smart Tokens @@ -122,7 +145,7 @@ The above factors motivated the design of this framework. Some of the core uniqu 4. Doesn't require changes to the ledger 5. Smart tokens cannot be revoked by dApps that fail to follow the standard (unlike the CIP 68 case in which they can) 6. Very low effort (relative to the existing proposals) to implement and get it to production / mainnet adoption -7. Completely permissionless and natively interoperable with other smart tokens. IE anyone can mint their own smart tokens with their own custom logic and the correctness of their behavior will be enforced. +7. Completely permissionless and natively interoperable with other smart tokens. IE anyone can mint their own smart tokens with their own custom logic and the correctness of their behavior will be enforced ## Path to Active @@ -130,9 +153,8 @@ The above factors motivated the design of this framework. Some of the core uniqu ### Acceptance Criteria Issuance of at-least one smart token via the proposed framework on the following networks: -1) preview testnet -2) preprod testnet -3) mainnet +1) Preview testnet +2) Mainnet End-to-end tests of programmable token logic including arrestability, transfer fees, and blacklisting. From e2589ffcbb34604574a4d8cfb62001ebc6effa4a Mon Sep 17 00:00:00 2001 From: colll78 Date: Thu, 5 Dec 2024 18:44:27 -0800 Subject: [PATCH 3/6] Update README.md --- .../README.md | 24 +++---------------- 1 file changed, 3 insertions(+), 21 deletions(-) diff --git a/CIP-interoperable-programmable-tokens/README.md b/CIP-interoperable-programmable-tokens/README.md index d5bc8726e..dd5af1fd0 100644 --- a/CIP-interoperable-programmable-tokens/README.md +++ b/CIP-interoperable-programmable-tokens/README.md @@ -12,19 +12,6 @@ Created: 2024-12-3 License: Apache-2.0 --- - - ## Abstract This CIP proposes a robust framework for the issuance of interoperable programmable tokens on Cardano. Unlike all its predecessors, this framework allows these tokens to be used in existing dApps, and does not require dApps to be developed specifically for these tokens. @@ -60,7 +47,7 @@ The impact that the required script executions have on the cost of transactions ## Specification -# Smart Token Directory & Minting policy +### Smart Token Directory & Minting policy This smart contracts is responsible for the minting / creation of new programmable tokens and for maintaining an merkle patricia forestry of all smart tokens and their respective transfer policies, we call this the `directoryRootHash`. ```Haskell @@ -88,11 +75,11 @@ data ProgrammableTokenDirectoryNode = ProgrammableTokenDirectoryNode ``` In either case, there is only a single directory (a single directory UTxO / single directory linked list) for all programmable tokens. -# Transfer Logic Scripts +### Transfer Logic Scripts The system guarantees that each programmable token must have a transfer logic script (located in either the directory UTxO or the directory linked list depending on the implementation). The transfer logic script for a programmable token is the smart contract that must be executed in every transaction that spends the programmable token. For example to have a stable coin that supports freezing / arrestability this script might require a non-membership merkle proof in a blacklist. This must be a staking script (or an observer script once CIP-112 is implemented), see [the withdraw-zero trick](https://github.com/Anastasia-Labs/design-patterns/blob/main/stake-validator/STAKE-VALIDATOR-TRICK.md) for an explanation. -# Programmable Logic Base Script +### Programmable Logic Base Script This is a spending script that accepts 1 parameter, a credential which identifies the owner of the value that it locks. ```Haskell @@ -151,7 +138,6 @@ The above factors motivated the design of this framework. Some of the core uniqu ## Path to Active ### Acceptance Criteria - Issuance of at-least one smart token via the proposed framework on the following networks: 1) Preview testnet 2) Mainnet @@ -161,12 +147,8 @@ End-to-end tests of programmable token logic including arrestability, transfer f Finally, a widely adopted wallet that can read and display programmable token balances to users and allow the user to conduct transfers of such tokens. ### Implementation Plan - Implement the contracts detailed in the specification, and implement the offchain code required to query programmable token balances and construct transactions to transfer such tokens. - ## Copyright - - This CIP is licensed under [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0). From df276867ed686f060fc099b09bf476af287fb20d Mon Sep 17 00:00:00 2001 From: colll78 Date: Tue, 10 Dec 2024 13:58:23 -0800 Subject: [PATCH 4/6] Update category --- {CIP-interoperable-programmable-tokens => CIP-0143}/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename {CIP-interoperable-programmable-tokens => CIP-0143}/README.md (99%) diff --git a/CIP-interoperable-programmable-tokens/README.md b/CIP-0143/README.md similarity index 99% rename from CIP-interoperable-programmable-tokens/README.md rename to CIP-0143/README.md index dd5af1fd0..c170cd00f 100644 --- a/CIP-interoperable-programmable-tokens/README.md +++ b/CIP-0143/README.md @@ -1,7 +1,7 @@ --- -CIP: ??? +CIP: CIP-143 Title: Interoperable Programmable Tokens -Category: Plutus +Category: Tokens Status: Proposed Authors: - Philip DiSarro From aeca127e15cee23f0d8b241624ddd4ec47a5b6a8 Mon Sep 17 00:00:00 2001 From: Robert Phair Date: Wed, 11 Dec 2024 17:38:48 +0530 Subject: [PATCH 5/6] set proper syntax for CIP number (removing prefix) --- CIP-0143/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CIP-0143/README.md b/CIP-0143/README.md index c170cd00f..e0b2118c8 100644 --- a/CIP-0143/README.md +++ b/CIP-0143/README.md @@ -1,5 +1,5 @@ --- -CIP: CIP-143 +CIP: 143 Title: Interoperable Programmable Tokens Category: Tokens Status: Proposed From b8ea2032052fd8eb158f5367e692dffddbeabc2f Mon Sep 17 00:00:00 2001 From: Robert Phair Date: Wed, 11 Dec 2024 17:45:03 +0530 Subject: [PATCH 6/6] use tickboxes in Path to Active + break into individual points --- CIP-0143/README.md | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/CIP-0143/README.md b/CIP-0143/README.md index e0b2118c8..e42feb6ed 100644 --- a/CIP-0143/README.md +++ b/CIP-0143/README.md @@ -138,17 +138,15 @@ The above factors motivated the design of this framework. Some of the core uniqu ## Path to Active ### Acceptance Criteria -Issuance of at-least one smart token via the proposed framework on the following networks: -1) Preview testnet -2) Mainnet - -End-to-end tests of programmable token logic including arrestability, transfer fees, and blacklisting. - -Finally, a widely adopted wallet that can read and display programmable token balances to users and allow the user to conduct transfers of such tokens. +- [ ] Issuance of at-least one smart token via the proposed framework on the following networks: + - [ ] 1. Preview testnet + - [ ] 2. Mainnet +- [ ] End-to-end tests of programmable token logic including arrestability, transfer fees, and blacklisting. +- [ ] Finally, a widely adopted wallet that can read and display programmable token balances to users and allow the user to conduct transfers of such tokens. ### Implementation Plan -Implement the contracts detailed in the specification, and implement the offchain code required to query programmable token balances and construct transactions to transfer such tokens. - +- [ ] Implement the contracts detailed in the specification. +- [ ] Implement the offchain code required to query programmable token balances and construct transactions to transfer such tokens. ## Copyright This CIP is licensed under [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0).