Try   HackMD

Quarantine and Sanction

Problem Definitions

Account Quarantine

As an account owner, I want to prevent funds from being transferred to my account without my approval, so that I don't end up with funds that I don't want and which might even be problematic.

Sanctioned Accounts

As a regulated entity trying to do business using a blockchain, I want to be able to lock an account, preventing funds from being sent from it, so that the chain can comply with government sanctions and I can continue to use the blockchain within the law.

Proposal

  1. Create a x/quarantine module to facilitate management of quarantined accounts and funds.
  2. Create a x/sanction module to facilitate management of the list of sanctioned accounts.
  3. Update the x/bank module to quarantine funds sent to quarantined accounts and prevent funds from leaving sanctioned accounts.

The x/quarantine Module

The x/quarantine module will house the stuff needed to allow users to opt-in/out of quarantine, accept/decline quarantined funds, and manage auto-responses for specific senders.

Concepts

By default, accounts are not quarantined. An account owner can choose to quarantine their account. Account owners can also choose to un-quarantine their account.

While an account is quarantined, any funds sent to the account will instead be sent to a quarantined-funds-holder account (most likely the x/quarantine module account), and a record of the quarantined funds will be made.

The intended recipient can then either accept, deny, or ignore those funds.

  • If the funds are accepted, they are sent from the quarantined-funds-holder account to the recipient and the quarantine record is deleted.
  • If the funds are declined, the quarantine record is updated to indicate this, and the entry is omitted from some query results (noted below). The funds still remain in the quarantined-funds-holder account and can later be accepted.
  • If the funds are ignored (i.e. the recipient does nothing), they remain held by the quarantined-funds-holder account.

Quarantined account owners can also set up auto-responses for specific senders. An auto-response is for a specific sender (to the account owner) and can either be auto-accept or auto-decline. An auto-response can also be deactivated.

  • If the owner has auto-accept set up for a sender, funds sent from that sender happen as if the recipient is not quarantined.
  • If the owner has auto-decline setup for a sender, funds sent from that sender are automatically marked as "declined" in the quarantine record.

Tx Endpoints

  1. Opt into quarantine
    Input: The address to quarantine (also the signer of the tx).
  2. Opt out of quarantine
    Input: The address to un-quarantine (also the signer of the tx).
  3. Accept quarantined funds
    Input: The recipient (signer), the original sender(s), and whether to make this accept permanent (set up auto-accept).
  4. Decline quarantined funds
    Input: The recipient (signer), the original sender(s), and whether to make this decline permanent (set up auto-decline).
  5. Update auto-responses
    Input: The recipient (signer) and a list of updates. Each update entry has a sender address and the auto-response setting, either auto-accept, auto-decline, or unspecified (to deactivate an existing auto-response).

Query Endpoints

  1. Is Quarantined?
    Input: An address.
    Output: True if quarantined, false if not.
  2. Quarantined funds
    Input: A recipient and sender. Both are optional, but if a sender is provided, a recipient is required.
    Output: A list of quarantined funds. Each entry contains the amount quarantined, the unaccepted sender(s) and an indicator of whether they've been declined.
    • If neither a recipient nor sender is provided, all non-declined quarantined funds are returned.
    • If only a recipient is provided, all non-declined funds quarantined for just that recipient are returned.
    • If both a recipient and sender are provided, all quarantined funds to the recipient from the sender are returned, regardless of whether they've been declined or not.
    • If only a sender is provided, an error is returned.
      Note: If a quarantined funds entry had multiple senders, and one or more (but not all) senders have been accepted by the recipient, those accepted senders will not be included in the unaccepted sender(s) list for that entry.
  3. Auto-Responses
    Input: A recipient (required) and sender (optional).
    Output: A list of auto-response entries. Each entry has a sender, it's auto-response.
    • If only a recipient is provided, all auto-responses set up for that recipient (from any sender) are returned. In this case, each entry will either be auto-accept or auto-decline.
    • If both a recipient and sender is provided, a single entry is returned that can be either auto-accept, auto-decline, or unspecified.

Handling of MultiSend

Because of the ability to do complex transfers using the MultiSend Tx, or InputOutputCoins keeper function, there isn't always a single sender. Funds to be sent to a quarantined account as part of one of those are treated as having come from all input accounts. The quarantine account owner must accept funds from each of them. This can be done either in a single Accept Tx or part of multiple Accept Txs.

Quarantine is evaluated individually for each address in the outputs. All addresses in the inputs are considered the senders.

Only funds going to quarantined accounts are quarantined. For example, account Q is quarantined, and N is not. Account A uses a MultiSend to send 5atom to Q and 1atom to N. The 1atom is transferred normally to N and the 5atom are transferred to the quarantined-funds-holder and marked as quarantined awaiting a response from Q.

Auto-responses still apply too:

  • If the recipient has auto-accept set up for ALL senders, the funds are transferred to the recipient as if it weren't quarantined.
  • If the recipient has auto-accept set up for one or more (but not all) senders, those senders are marked as having been accepted for the funds in question. The recipient then only needs to issue an Accept for the other senders.
  • If the recipient has auto-decline set up for ANY senders, the funds are automatically marked as declined.

When querying for quarantined funds, if both a recipient and sender are provided, all records to the recipient involving the sender are returned. For example, sender A sends 5atom to recipient R, and as part of a multi-send, sender A and B send 11atom to R; results of a query for quarantined funds to recipient R from sender A will contain both records. If sender B is used in the query instead, the results will only contain the 11atom entry.

Complexities

  1. Opting out of quarantine does not affect any quarantined funds. The account owner must still accept any previously quarantined funds, but future sends to the account will not be quarantined.
  2. Declined funds can still be accepted.
  3. Setting up auto-accept or auto-decline does not affect any existing quarantined funds.
  4. When accepting or declining funds for a sender, it affects all funds from that sender. For example, recipient R has auto-accept set up for sender B. Sender A sends funds to recipient R three times in the amounts 1atom, 3atom, 7atom, and was part of a MultiSend to R from both A and B in the amount of 19atom. When R accepts the funds from A, they will receive all 30atom that has been quarantined.
  5. Funds are recorded in a single entry for a given recipient and sender(s). In the previous example, there would have been two records, one to R from A in the amount of 11atom, and one to R from both A and B in the amount of 19atom. If a second MultiSend to R from A and B in the amount of 55atom happened (prior to the funds being accepted), that record would be updated to indicate 74atom quarantined.
  6. If funds have been previously declined, but aren't set to auto-decline, and the sender sends more, the new funds are combined with the previously declined funds, and are no longer marked as declined.
  7. If quarantined funds are part of a MultiSend where one or more (but not all) senders have been accepted, and another MultiSend is done to the recipient from the same senders, the senders that were previously marked as having been accepted (on those funds), are changed to unaccepted again.

The x/sanction Module

The x/sanction module will house the stuff needed to manage a list of sanctioned accounts. Sanctioning accounts will be done through a governance proposals.

Concepts

Sanctioning an account often needs to happen faster than a governance proposal vote period though. As such, this module provides the ability to make sanctions happen immediately upon proposal, but require a significantly larger deposit. If the proposal passes, the sanction stands and the deposit is returned. If the proposal does not pass, the effects are undone and the deposit is burned.

The module will also contain a list of unsanctionable addresses. This is to prevent, e.g. the primary fee pool from being sanctioned. This list is provided to the module/keeper when it is created and is not manageable through any interactions, e.g. Txs.

When an address is sanctioned, no funds can be removed from the account.

The immediate sanction and immediate unsanction tx endpoints are separated so that different deposits can be required for each.

The ability to immediately unsanction an address exists to counteract a bad actor that issues an immediate sanction against a critical account, even though they expect the vote will fail and they will lose their deposit. However, the deposit required for it should be higher even than an immediate sanction in order to prevent a sanctioned bad actor from having their account unsanctioned, even if only temporarily while it's being voted on. For the same reason, an immediate unsanction only affects addresses that are part of an immediate sanction that hasn't finished it's voting period.

Governance Proposals

  1. Sanction Addresses
    Contents: A list of addresses
  2. Unsanction Addresses
    Contents: A list of addresses

Tx Endpoints

  1. Immediate Sanction
    Input: A list of addresses to sanction.
  2. Immediate unsanction
    Input: A list of addresses to unsanction.

Query Endpoints

  1. Is Sanctioned
    Input: An address.
    Output: True if sanctioned, false if not.
  2. Sanctioned addresses
    Input: None
    Output: All sanctioned addresses.

Complexities

  1. The most recent action takes precedence. For example, if an immediate sanction is issued for an address, and before voting ends, an immediate unsanction is issued for it, the address becomes unsanctioned again. If the sanction vote then passes, it will again be sanctioned. Following that, if the unsanction vote also passes, it will again be unsanctioned.
  2. When doing an immediate unsanction, any addresses provided that are not currently part of an immediate sanction, are ignored (i.e. nothing happens immediately). However, if the proposal passes, that address will then be unsanctioned.

Updates to x/bank

  1. The SendCoins method on the SendKeeper is renamed to SendCoinsBypassQuarantine. A replacement SendCoins function is created with the exact same function signature. The new version checks if the recipient is quarantined. If not, it calls SendCoinsBypassQuarantine with the same arguments it was given. If it is quarantined, the recipient is changed to the quarantined-funds-holder account, the funds are transferred using SendCoinsBypassQuarantine, and a record of the quarantined funds is made. Events issued for transfers that are quarantined will indicate the quarantined-funds-holder as the recipient (and not the intended recipient).
  2. The InputOutputCoins method on the SendKeeper is altered. While looping through the outputs, each output address is checked for quarantine, and handled appropriately. Here too, the recipient noted in events are the quarantined-funds-holder (for quarantined transfers).
  3. The subUnlockedCoins method on the SendKeeper is updated to check for a sanction. If the account is sanctioned, an error is returned.
  4. Two new methods are added to the SendKeeper that define the quarantine and sanction keepers that the SendKeeper should use, e.g. SetQuarantineKeeper and SetSanctionKeeper. The changes above take into account the possibility that one or both keepers have not been provided. In such cases, that functionality is effectively disabled. E.g. if the SendKeeper doesn't have a defined QuarantineKeeper, it behaves just like it does today.
    • The x/quarantine and x/sanction modules are optional. If they aren't to be used, users of the x/bank module don't need to do anything.
    • The QuarantineKeeper needs to have the ability to transfer funds, e.g. when funds are accepted. The SendKeeper needs to be able to identify and record quarantined accounts and funds. The SetQuarantineKeeper method allows the bank keeper to be created first, and if the quarantine module is to be used, it can be created later. The NewQuarantineKeeper function takes in a bank keeper, stores it, and also calls SetQuarantineKeeper providing itself to the bank keeper.
    • The SanctionKeeper does not need to do things with the x/bank module and could be provided as an argument to NewBankKeeper.
    • Reasons to create a SetSanctionKeeper function instead of providing the SanctionKeeper as an argument to NewBankKeeper:
      • Changing the function signature of NewBankKeeper causes problems due to its use in other libraries/packages.
      • As an argument, it's not clear that it's optional.
      • Many other modules depend on the BankKeeper. As such, it's one of a small number of keepers that needed to be created first; most of the rest can be created in any order. As an argument, the sanction keeper would need to be created before the bank keeper.
      • It matches what was added to handle the x/quarantine module.

Questions

  1. Should the x/quarantine and x/sanction modules be separate or combined?
    • As separate modules, it's easier to have one without the other, but I don't know how desirable that is.
    • There isn't much code that they'd have in common.
    • Sanctioning accounts will have some more complex blockchain interaction needs (e.g. take immediate effect) that quarantine doesn't care about. Having them separate can help isolate that complexity.
  2. Should the changes to the x/bank module be more generic in some way? E.g. have a way to inject restrictions to be run a certain points, or even set up an antehandler-like chain to replace the SendCoins and InputOutputCoins functions.
    • For quarantined accounts, the sender address(es) need to be considered, so the consideration can't be injected into addCoins. The lowest level it can go is SendCoins, and InputOutputCoins. The SendCoins function is used significantly more than InputOutputCoins and takes notably less processing. InputOutputCoins cannot be refactored to use SendCoins, and doing the opposite is not desirable due to the extra processing it would require. Therefore, to handle quarantined accounts, two different things would need to be injected.
    • For quarantined accounts, a "restriction" might not be sufficient unless they are defined in a way that it can alter the receiving address.
    • Basically, handling quarantine requires altering the behavior of a sand and knowledge of the recipient and sender(s). Handling sanction requires knowledge of only the sender(s) and the result can be the presence/absence of an error. There isn't a lot of commonality between the two.
  3. Is there a need to create a curated list of auto-accept or auto-decline addresses that can be shared by multiple accounts? If so, can the x/groups module facilitate this already or would this require special attention in the quarantine module?
    • For example, an institution has 10 accounts and wants all of them to auto-accept from each other. Later, they add an 11th account that they also want auto-accept set up between it and all the other accounts. This is simpler if there's just a single list than having to do a Tx for 11 accounts.
  4. For the immediate unsanction, are there other restrictions that can be added to prevent it from being used to bypass a sanction?
    • For example, maybe a pre-defined list of addresses that are allowed to do an immediate unsanction. Maybe also only allow a single (or some other small number) immediate unsanction at any given time.
    • I feel like any limitation tied to the originator of the request wouldn't be worthwhile since accounts are so easy to create. It would need to be something affecting the whole chain. E.g. only allow 2 active immediate unsanction proposals at a single time as opposed to only allowing 2 per account at any given time; the latter feels worthless to me.
  5. For the immediate sanction, are there other restrictions that should be added to prevent it from being used maliciously?
    • A pre-defined list of addresses allowed to do so might help. Would probably want it to be updatable via governance proposal though, but that might be desirable.
  6. Should there be a limitation to the number of addresses that can be sanctioned in a single proposal? Or maybe only a limitation on immediate actions?
    • Putting the limit on the governance proposal level would be difficult to enforce since proposals can have multiple messages, each of which would be processed separately. E.g. limiting each message to 5 addresses could be easily circumvented by just having two sanction messages in the governance proposal.
    • Also, it's unknown how often addresses will need to be sanctioned. And even if we knew that amount right now, it's difficult to anticipate for the future.