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.
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.
x/quarantine
module to facilitate management of quarantined accounts and funds.x/sanction
module to facilitate management of the list of sanctioned accounts.x/bank
module to quarantine funds sent to quarantined accounts and prevent funds from leaving sanctioned accounts.x/quarantine
ModuleThe 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.
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.
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.
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:
Accept
for the other senders.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.
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.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.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.x/sanction
ModuleThe x/sanction
module will house the stuff needed to manage a list of sanctioned accounts. Sanctioning accounts will be done through a governance proposals.
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.
x/bank
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).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).subUnlockedCoins
method on the SendKeeper
is updated to check for a sanction. If the account is sanctioned, an error is returned.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.
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.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.SanctionKeeper
does not need to do things with the x/bank
module and could be provided as an argument to NewBankKeeper
.SetSanctionKeeper
function instead of providing the SanctionKeeper
as an argument to NewBankKeeper
:
NewBankKeeper
causes problems due to its use in other libraries/packages.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.x/quarantine
module.x/quarantine
and x/sanction
modules be separate or combined?
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.
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.x/groups
module facilitate this already or would this require special attention in the quarantine module?