-
Notifications
You must be signed in to change notification settings - Fork 84
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add SIP: Composable Fungible Tokens with Allowance #154
base: main
Are you sure you want to change the base?
Changes from 2 commits
9ccc7e1
e64d427
41ad33e
4ee00d1
e392b1c
9dbdd0d
ef9c451
c7f7325
3cee6da
f37ae0c
36cbc74
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
# SIP-0XX: Composable Fungible Tokens with Allowance | ||
|
||
## Preamble | ||
|
||
SIP Number: 0XX | ||
Title: Composable Fungible Tokens with Allowance | ||
Author: Jose Orlicki <jose@trustmachines.co> | ||
Consideration: Technical | ||
Type: Standard | ||
Status: Draft | ||
Created: [Date] | ||
License: CC0-1.0 | ||
Sign-off: [Sign-off Name] <signoff@example.com> | ||
|
||
## Abstract | ||
|
||
This proposal extends the SIP-010 standard trait for fungible tokens on the Stacks blockchain to support composable fungible tokens with allowances. It addresses the limitations of the previous standard, which did not provide sufficient support for composability and security. The new trait includes functions for transferring tokens, approving allowances, checking allowances, and transferring tokens using allowances. The recommended implementation of `approve` used incremental allowances to avoid rance conditions and double transfering. | ||
|
||
jio-gl marked this conversation as resolved.
Show resolved
Hide resolved
|
||
## Motivation | ||
|
||
The previous fungible token standard (SIP-010) had limitations that hindered composability in decentralized finance (DeFi) contracts. Specifically, it lacked a mechanism for users to grant allowances to other users or contracts, similar to signing a check or how POS Debit Card systems work. Additionally, the previous standard's resulted in applications including de-facto checks based on `tx-sender` that could lead to security vulnerabilities. | ||
|
||
This proposal aims to enhance the fungible token standard to enable safer and more flexible composability in DeFi and other applications on the Stacks blockchain. | ||
|
||
## Specification | ||
|
||
### Extended Trait Functions | ||
|
||
This proposal extends the SIP-010 trait with the following functions: | ||
|
||
#### transfer | ||
|
||
`(transfer (from principal) (to principal) (amount uint) (response bool uint))` | ||
jio-gl marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
Transfer the specified amount of tokens from one principal to another. The `from` principal must always match the contract caller `contract-caller`, ensuring that only authorized parties can initiate transfers. Do not check and allow the execution if `sender` is `tx-sender`, this results in security weaknesses that make phishing and arbitrary token execution very dangerous (read https://www.coinfabrik.com/blog/tx-sender-in-clarity-smart-contracts/). | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We have post-conditions. Therefore, not very dangerous IMO, but it is useful to allow implementation of send-many contracts. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This security model (no transfers for tx-sender) limits composability. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here is another reference: https://app.sigle.io/friedger.id.stx/HuOT9tNQC8fTXOsK28D7e There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. no transfer for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
||
#### transfer-from | ||
|
||
`(transfer-from (from principal) (to principal) (amount uint) (response bool uint))` | ||
|
||
Transfer a specified amount of tokens from one principal to another using an allowance. The `from` principal must have previously approved the allowance for the `to` principal to transfer tokens on their behalf. This function facilitates composability by allowing third-party transfers within the approved limits. | ||
|
||
#### approve | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. seems too long, what about |
||
|
||
`(approve (spender principal) (amount uint) (response bool uint))` | ||
|
||
Approve an incremental allowance for a specific principal or contract to spend a certain amount of tokens on behalf of the sender. This function is similar to signing a check, granting permission for a third party to make token transfers within the specified limit. This allowance must be incremental (it adds on top of previous allowances) to avoid race condition situations where and `transfer-from` call is executed before the `approve` and then another after the `approve` call. | ||
|
||
#### revoke | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. seems a bit long, maybe |
||
|
||
`(revoke (spender principal) (response bool uint))` | ||
|
||
Revoke an existing allowance granted to a specific principal or contract. This function sets the allowance for the specified spender to 0, effectively removing their permission to spend tokens on behalf of the sender. It provides a mechanism for the sender to revoke previously granted permissions when they are no longer needed or desired. You usually give a limited or exact allowance to a DeFi service, this service will grab the amount of token you approved and then do provide some financial service. Is common practice in Web3 to give infinite or large allowance to Dapps to do only one `approve` call per token. But if you have given an infinite or large allowance to the Defi contract (a convenient common practice) and after the DeFi services has grabbed your tokens, you can revoke the infinite allowance by calling `revoke`. This helps mitigates the impact of bugs found in the DeFi contract in the future where an attacker might try to grab more of you tokens. If you intent to use the DeFi services only once or you no longer trust the service, you should call `revoke` inmediately. | ||
|
||
#### allowance | ||
|
||
`(allowance (owner principal) (spender principal) (response uint uint))` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Better There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ok sounds good. Do we want the standards to always return a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Trait can't have functions that returns anything but |
||
|
||
Check the remaining allowance of tokens that the `spender` principal is authorized to transfer on behalf of the `owner` principal. This function is useful for applications that need to verify the available allowance before initiating token transfers. | ||
|
||
### Other Trait Functions | ||
|
||
The new trait should also include the functions defined in SIP-010, including `get-name`, `get-symbol`, `get-decimals`, `get-balance`, `get-total-supply`, and `get-token-uri`. | ||
|
||
## Trait Implementation | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would defined only the newly added functions in the trait. Contracts can implement both the sip-10 trait and this trait. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I though about doing that, but I felt it was better to replace the whole trait altogether to avoid the hazzle of implementing 2 traits and avoid the confusion with There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Currently, I think I might limit this Improve Proposal to newly added functions, then the market can decide if they want to use allowances or limit to current approach. We can publish Best Practices for SIP10 that should be a combination of: |
||
|
||
The extended trait `sip-0xx-trait` that includes the functions from `sip-010-trait` and the new functions introduced in SIP-0XX: | ||
|
||
```clarity | ||
(define-trait sip-0xx-trait | ||
( | ||
;; Transfer from the caller to a new principal | ||
;; first principal, sender, must be always equal to contract-caller | ||
(transfer (uint principal principal (optional (buff 34))) (response bool uint)) | ||
|
||
;; the human readable name of the token | ||
(get-name () (response (string-ascii 32) uint)) | ||
|
||
;; the ticker symbol, or empty if none | ||
(get-symbol () (response (string-ascii 32) uint)) | ||
|
||
;; the number of decimals used, e.g. 6 would mean 1_000_000 represents 1 token | ||
(get-decimals () (response uint uint)) | ||
|
||
;; the balance of the passed principal | ||
(get-balance (principal) (response uint uint)) | ||
|
||
;; the current total supply (which does not need to be a constant) | ||
(get-total-supply () (response uint uint)) | ||
|
||
;; an optional URI that represents metadata of this token | ||
(get-token-uri () (response (optional (string-utf8 256)) uint)) | ||
|
||
;; Transfer from one principal to another using an allowance | ||
(transfer-from (uint principal principal uint) (response bool uint)) | ||
|
||
;; Approve an incremental allowance for a specific principal to spend tokens | ||
(approve (principal uint) (response bool uint)) | ||
|
||
;; Revoke an allowance, goes to 0, for a specific principal to spend tokens | ||
(revoke (principal) (response bool uint)) | ||
|
||
;; Check the remaining allowance of tokens for a spender | ||
(allowance (principal principal) (response uint uint)) | ||
) | ||
) | ||
``` | ||
|
||
This extended trait, `sip-0xx-trait`, includes the functions from the original `sip-010-trait` and adds the new functions introduced in SIP-0XX: `transfer-from`, `approve`, `revoke`, and `allowance`. Developers can use this trait as a reference when implementing composable fungible tokens with allowances on the Stacks blockchain. | ||
|
||
## Rationale | ||
|
||
The extension of the SIP-010 trait with allowances and the ability to transfer tokens using allowances addresses the limitations of the previous standard. By introducing allowances, users can grant explicit permission for third parties to spend tokens on their behalf, improving the security and composability of DeFi contracts. The inclusion of additional functions from SIP-010 ensures compatibility with existing standards. | ||
|
||
### Limiting Phishing | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is Phishing? Could you elaborate? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I will include more information in the doc. |
||
|
||
With this new approach that has only a check for `sender == contract-caller`, and in case of successful phishing attemp, the malicious Dapp has to ask for allowance for the specific token an drain that token, so the they have to request 2 transactions and can only drain 1 token. The previous standard, and the de-facto check of `sender == tx-sender`, and the phishing attemp is successful, with a single transaction they can drain all of our standard tokens (several contracts) that only check the `tx-sender`. | ||
jio-gl marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
### DeFi Composability Pattern | ||
|
||
The most common DeFi pattern, that is supported by this new standard is: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't see how this can't be done with SIP-10. In 5. the user could also transfer the amount of tokens required for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it can be done with SIP10 with There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So, why do we need allowances? Is it only about the issue of tx with allow mode? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. if you have DeFiA is a YieldAggregator and DeFiB is a YieldService, then the following 3 current approaches does not work I think: a) User calls a) User calls a) User calls There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In 1. c) DeFiA can use In 3. c) Similarily, DeFiA can use In 3. DeFiA could not do b) (transfer tokens from User to DeFiA), but let DeFiB do it in d). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. okey, so the solution for you is to change There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
|
||
1. The Dapp (decentralized application) _D_ generates a `approve` transaction for a single standard token _T_ and a single Dapp contract _C_. | ||
2. The User signs the `approve` transaction and submits to blockchain. | ||
3. The token _T_ get the allowance updated when the transactions ends on-chain. | ||
4. The Dapp (decentralized application) _D_ generates a service `example-defi-service` transaction to start the service. | ||
5. The User sign the `example-defi-service` and submits to blockchain. | ||
6. The Dapp _D_ executes `example-defi-service` on-chain, this includes calling `transfer-from` to retrieve the tokens from User and, eventually, forwarding the tokens to a third-party service with `approve`, thus allowing for _Composability_. | ||
|
||
## Backwards Compatibility | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There are SIP-10 token contracts on mainnet like vibe tokens There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What I see is that without allowances you are giving total control to any DeFi service (that only checks There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Cool, there are 40 contracts with There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For that we have post conditions @jo-tm There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. only 5 tokens seems to have |
||
|
||
This proposal aims to maintain compatibility with the existing SIP-010 standard while introducing new functionality. Existing fungible token contracts can continue to use the SIP-010 functions without modification. Contracts that wish to utilize allowances and composable fungible tokens can implement the extended trait. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not clear whether SIP-10 tokens that use tx-sender are compatible with this SIP. Could you elaborate? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Initially I wanted to limit the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The signature is the same but the security model is not, therefore it is not compatible any more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The current SIP10 Tokens are only compatibles in that they both will work on Leather Wallet using the same There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. improved backwards compatiblity section |
||
|
||
## Activation | ||
|
||
The activation of this proposal will require deployment to the Stacks blockchain's mainnet. The activation criteria and timeline should be defined in accordance with the Stacks Improvement Proposal process. | ||
|
||
## Reference Implementations | ||
|
||
Reference implementations of this extended trait should be provided to assist developers in implementing fungible tokens with allowances on the Stacks blockchain. These implementations should follow the specifications outlined in this SIP. | ||
|
||
* Trust Machines's [implementation](https://github.com/Trust-Machines/clarity-smart-contracts/blob/main/contracts/composable-fungible-token.clar) (based on [@friedger's](https://github.com/friedger/clarity-smart-contracts/blob/main/contracts/tokens/fungible-token.clar)). | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That contract is not sip-10 compatible. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i have to improve that. |
||
|
||
## Copyright | ||
|
||
This SIP is made available under the terms of the Creative Commons CC0 1.0 Universal license. | ||
|
||
## Acknowledgments | ||
|
||
The author acknowledges Trust Machines and the Stacks community and contributors for their input and feedback in the development of this proposal. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SIP-10 is the bare minimum to have a standard for a fungible token. It allows to implement anything you want. I'd highlight the features and uses cases of the new standard, that is to let third parties control parts of your tokens.
The recommended implementation of
approve
uses incremental allowances to avoid race conditions and double transferring.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ran a spell checking now
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will mention that SIP10 allows your to do basic transfers but the payments is limited or unsafe in the current form.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
improved abstract. Can I include you as a co-author, the Reference implementation if heavily based on your implementation?, although it has some syntax errors still.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I improved the Rationale with 3 current approaches to Compose DeFi that Fails if i am not wrong.