Skip to content
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

XLS-39d: Clawback specification #104

Merged
merged 25 commits into from
May 25, 2023
Merged
Changes from 17 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
178 changes: 178 additions & 0 deletions XLS-39d-clawback/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
<pre>
Title: <b>Clawback Support</b>
Description: Extending clawback functionality into freeze
Revision: <b>5</b> (2023-5-08)
<hr> Author: <a href="mailto:nikb@bougalis.net">Nikolaos D. Bougalis</a>
<a href="mailto:shawnxie@ripple.com">Shawn Xie</a>
shawnxie999 marked this conversation as resolved.
Show resolved Hide resolved
<hr> Requires: XLS 39
<hr> core_protocol_changes_required: true
</pre>
shawnxie999 marked this conversation as resolved.
Show resolved Hide resolved

## 1. Abstract

Although the XRP Ledger offers rich support for [tokens](https://xrpl.org/tokens.html) (a.k.a. IOUs or issued assets), including offering issuers the ability to [freeze](https://xrpl.org/freezes.html) issuances, in order to meet regulatory requirements, some issuers need to be able to go further, by having the ability to "[clawback](https://en.wikipedia.org/wiki/Clawback)" their issued assets. **An counterparty can be clawed back if and only if `lsfAllowClawback` is set.**
shawnxie999 marked this conversation as resolved.
Show resolved Hide resolved

----------------------- -------------------------------------------------------
:bangbang: This proposal deals only with issued assets. **The proposed clawback
support _cannot_ be used to claw back XRP.**
----------------------- -------------------------------------------------------

### Advantages and Disadvantages

**Advantages**

- Issuers that are restricted from issuing on ledger because of regulatory requirements requiring the ability to clawback funds will be able to issue tokens.
- By being able to "clawback" issuers can ensure that the "on-chain" view is representative of the balance.
- Compared to other on-ledger features (e.g. freeze), clawback is minimal and trivial to implement.
- `Clawback` is disabled by default, this gives token holders more confidence that they won't be clawed back randomly.


**Disadvantages**

- Introduces an additional transaction, along with the complexity that comes with that.
- Issuers now get additional power, which may be concerning to token holders.
- Requires additional documentation, including highlighting the fact that clawback cannot be applied to XRP.

---

## 2. Motivation
Jurisdictions may require issuers of digital assets to have a way to recover funds in certain circumstances. The `Clawback` feature can provide a way to comply with these regulations.



---

## 3. Specification

### 3.1. On-Ledger Data Structures

This proposal introduces no new on ledger structures.



### 3.2. Account Root modifications

This proposal introduces 1 additional flag for the `Flags` field of `AccountRoot`:

| Flag Name | Flag Value |
|:---------------:|:------------:|
| `lsfAllowClawback` | `0x02000000` |
shawnxie999 marked this conversation as resolved.
Show resolved Hide resolved

Clawback is disabled by default. The account must set this flag through an `AccountSet` transaction, which is successful only if the account has an empty owner directory, meaning they have no trustlines, offers, escrows, payment channels, or checks. Otherwise, the `AccountSet` returns `tecHAS_OBLIGATIONS`. After this flag has been successfully set, it cannot reverted, and the account permanently gains the ability to clawback on frozen trustlines.

If the account attempts to set `lsfAllowClawback` while `lsfNoFreeze` is set, the transaction will return `tecNO_PERMISSION` because clawback cannot be enabled on an account that has already disclaimed the ability to freeze trustlines. Reversely, if an account attempts to set `lsfNoFreeze` while `lsfAllowClawback` is set, the transaction will also return `tecNO_PERMISSION`.


### 3.3. Transactions
This proposal introduces one new transaction: `Clawback`

#### 3.3.1. `Clawback` transaction
The **`Clawback`** transaction modifies a trustline object, by adjusting the balance accordingly and, if instructed to, by changing relevant flags. If possible (i.e. if the `Clawback` transaction would leave the trustline is in the "default" state), the transaction will also remove the trustline.

Choose a reason for hiding this comment

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

It looks like the Clawback transaction no longer affects trust line flags 🎉 . So I think the part of the sentence about "changing relevant flags" should be removed. Consider changing the sentence to something like...

The Clawback transaction modifies a trustline object by adjusting the balance. If the Clawback transaction leaves the trustline in the "default" state, the transaction also removes the trustline.


**An counterparty can be clawed back if and only if `lsfAllowClawback` is set.** If this transaction is attempted while `lsfAllowClawback` is unset, it will return with an error code `tecNO_PERMISSION`.
shawnxie999 marked this conversation as resolved.
Show resolved Hide resolved

The transaction supports all the existing "common" fields for a transaction.

##### Transaction-specific Fields

| Field Name | Required? | JSON Type | Internal Type |
|---------------------|:----------------:|:-------------:|:-----------------:|
| `TransactionType` |:heavy_check_mark:|`string` | `UINT16` |

Indicates the new transaction type **`Clawback`**. The integer value is `30`. The recommended name is `ttCLAWBACK`.

| Field Name | Required? | JSON Type | Internal Type |
|---------------|:----------------:|:-----------:|:-----------------:|
| `Account` |:heavy_check_mark:|`string` | `ACCOUNT ID` |

Indicates the account which is executing this transaction. The account **MUST** be the issuer of the asset being clawed back. Note that in the XRP Ledger, trustlines are bidirectional and, under some configurations, both sides can be seen as the "issuer" of an asset. In this specification, the term issuer is used to mean the side of the trustline that has an outstanding balance (i.e. 'owes' the issued asset) that it wishes to claw back.

---

| Field Name | Required? | JSON Type | Internal Type |
|------------|:----------------:|:---------:|:-------------:|
| `Amount` |:heavy_check_mark:| `object` | `AMOUNT` |

Indicates the amount being clawed back, as well as the counterparty from which the amount is being clawed back from. It is not an error if the amount exceeds the holder's balance; in that case, the maximum available balance is clawed back. It is not an error if the amount is zero; in this case, the transaction does not claw back any funds but may adjust flags, as indicated by the `Flags` field.

It is an error if the counterparty listed in `Amount` is the same as the `Account` issuing this transaction; the transaction should fail execution with `temBAD_AMOUNT`.
shawnxie999 marked this conversation as resolved.
Show resolved Hide resolved

If there doesn't exist a trustline with the counterparty or that trustline's balance is `0`, the error `tecNO_LINE` is returned.

:bangbang: The sub-field `issuer` within `Amount` represents the token holder's address instead of the issuer's.

---

| Field Name | Required? | JSON Type | Internal Type |
|----------------|:----------------:|:-----------:|:-----------------:|
| `Flags` |:heavy_check_mark:|`number` | `UINT32` |

Specifies the flags for this transaction. The universal transaction flags that are applicable to all transactions (e.g., `tfFullyCanonicalSig`) are valid. This proposal introduces the following new, transaction-specific flags:

>| Flag Name | Flag Value | Description |
>|---------------|:---------------------------------------------------------------------------------------------------------------------------:|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------:|
>| `tfSetFreeze` | `0x00000001` | If set, either the `lsfHighFreeze` or `lsfLowFreeze` flag (as appropriate) will be set in the trust line. It is not an error to request to set a flag that has already been set.|
>| `tfClearFreeze` | `0x00000002` | If set, either the `lsHighFreeze` or `lsfLowFreeze` flag (as appropriate) will be removed from the trust line. It is not an error to request to clear a flag that isn't set. |

The `tfSetFreeze` and `tfClearFreeze` flags are options that can be set in a `Clawback` transaction. They make the process more inconvinient in case the issuer wants to clawback and freeze at the same time.
shawnxie999 marked this conversation as resolved.
Show resolved Hide resolved


---

#### 3.3.2. Example **`Clawback`** transaction

```
{
"TransactionType": "Clawback",
"Account": "rp6abvbTbjoce8ZDJkT6snvxTZSYMBCC9S",
"Amount": {
"currency": "FOO",
"issuer": "rsA2LpzuawewSBQXkiju3YQTMzW13pAAdW",
"value": "314.159"
},
"Flags": 1,
"Fee": 10,
"Memos": [
{
"Memo": {
"MemoType": "526561736f6e",
"MemoData": "5468697320636c61776261636b2077617320617574686f72697a6564206279204a6f652e"
}
}
],
}
```

In execution, this transaction would freeze the trustline by setting the `Flag` to `1`, and claw back at most **314.159 FOO** issued by `rp6abvbTbjoce8ZDJkT6snvxTZSYMBCC9S` and held by `rsA2LpzuawewSBQXkiju3YQTMzW13pAAdW`. If `rsA2LpzuawewSBQXkiju3YQTMzW13pAAdW` did not have a trustline set up or that trustline's balance is `0` then the error `tecNO_LINE` would be returned and a fee would be consumed.

### 3.4. Amendment

This transaction will require an amendment. The proposed name is `XLS-39-Clawback`.
shawnxie999 marked this conversation as resolved.
Show resolved Hide resolved

---

## 4. Rationale

Clawback is disabled by default and requires the issuer to have an empty owner directory(no existing trustlines, offers, etc) before they are allowed to enable the feature. This is meant to be a conservative design, where the issuer needs to go through the major effort in order to enable this feature. This process is a huge safety measure to ensure the holders are aware of this feature if the the issuer wants to enable it.
shawnxie999 marked this conversation as resolved.
Show resolved Hide resolved

---

## 5. Backwards Compatibility
No backward compatbility issues found

---

## 6. Test Cases
Test cases need to ensure the following:

- The account that signs and submits `Clawback` transaction must be the token issuer
- Token issuer cannot clawback from themselves
- The `tfSetFreeze` and `tfClearFreeze` flags of the `Clawback` transaction perform the intended freeze behavior on the trustline
- `Clawback` adheres to account flags `lsfAllowClawback`, `lsfGlobalFreeze` and `lsfNoFreeze`
- The issuer is only able to claw back the specific amount of funds that specified in the transaction, but can't exceed the maximum amount of funds the holder has
- Test that the `Clawback` feature does not interfere with any other features of the token, such as Offers

## 7. Compatibility with Automated Market Maker (XLS-30)
The Automated Market Maker (AMM) gives an account the ability to deposit issued tokens into AMM instance pool, in the form of `LPToken`. As of the current `Clawback` spec, it only allows an issuer to claw back the funds that are _spendable_. This would mean that the funds deposited into the AMM pool cannot be clawed back.

If clawing back from AMM instance pool is something needed, this change will need a separate specification to address its feasibility, after AMM goes live on mainnet.
shawnxie999 marked this conversation as resolved.
Show resolved Hide resolved