Welcome to the new Provenance Blockchain developer documentation portal!
logo

Summary

The marker module implements complex transfer mechanics for restricted coins through bank module integration using SendRestrictionFn, supporting transfer permissions, force transfers, required attributes, deposits, withdrawals, bypass accounts, and specialized quarantine interactions, with detailed validation flows for ensuring proper authorization and compliance across various transfer scenarios and account types.

There are some complex interactions involved with transfers of restricted coins.

General

Accounting of restricted coins is handled by the bank module. Restricted funds can be moved using the bank module's MsgSend or MsgMutliSend. They can also be moved using the marker module's MsgTransferRequest.
During such transfers several things are checked using a SendRestrictionFn injected into the bank module. This restriction is applied in almost all instances when funds are being moved between accounts. The exceptions are delegations, undelegations, minting, burning, and marker withdrawals. A MsgTransferRequest also bypasses the SendRestrictionFn in order to include the admin account in the logic.

Definitions

Transfer Permission

One permission that can be granted to an address is transfer. The transfer permission is granted to accounts that represent a "Transfer Agent" or "Transfer Authority" for restricted marker tokens. An address with transfer permission can utilize MsgTransferRequest to move restricted funds from one account to another. The source account must be the admin's own account, or else there must be a MarkerTransferAuthorization grant (in the authz module) from the source account to the admin.
MsgSend and MsgMultiSend can also be used by an address with transfer permission to move funds out of their own account.

Force Transfer Permission

If a restricted marker allows forced transfers, the force_transfer permission grants an account the ability to use the Transfer endpoint to move marker funds out of almost any account. An account with force_transfer cannot use other means to move marker funds (e.g. MsgSend) unless they also have transfer access.

Forced Transfers

A restricted coin marker can be configured to allow forced transfers. If allowed, an account with force_transfer permission can use a MsgTransferRequest to transfer the restricted coins out of almost any account to another. Forced transfer cannot be used to move restricted coins out of module accounts or smart contract accounts, though. Forced transfers can only be made using a MsgTransferRequest.

Required Attributes

Required attributes allow a marker Transfer Authority to define a set of account attestations created with the name/attribute modules to certify an account as an approved holder of the token. Accounts that possess all of the required attributes are considered authorized by the Transfer Authority to receive the token from normal bank send operations without a specific Transfer Authority approval. Required attributes are only supported on restricted markers.
For example, say account A has some restricted coins of a marker that has required attributes. Also say account B has all of those required attributes, and account C does not. Account A could use a MsgSend to send those restricted coins to account B. However, account B could not send them to account C (unless B also has transfer permission).
If a restricted coin marker does not have any required attributes defined, the only way the funds can be moved is by someone with transfer permission.

Individuality

If multiple restricted coin denoms are being moved at once, each denom is considered separately.
For example, if the sender has transfer permission on one of them, it does not also apply to the other(s).

Deposits

A deposit is when any funds are being sent to a marker's account. The funds being sent do not have to be in the denom of the destination marker.
Whenever funds are being deposited into a marker, the sender (or transfer authority) must have deposit permission on the target marker. If the funds to deposit are restricted coins, the sender (or transfer authority) also needs transfer permission on the funds being moved; required attributes are not taken into account.

Withdraws

A withdrawal is when any funds are being sent out of a marker's account. The funds being sent do not have to be in the denom of the source marker.
Withdraws can be made using the Withdraw endpoint, or another endpoint that utilizes a transfer agent (e.g. the exchange module's MarketCommitmentSettle).
Whenever funds are being withdrawn, the transfer agent must have withdraw permission on the source marker. If the funds to withdraw are of the source marker's denom, the source marker must be active. The transfer agent must also have transfer permission on any restricted coins being moved.

Bypass Accounts

There are several hard-coded module account addresses that are given special consideration in the marker module's SendRestrictionFn:
  • authtypes.FeeCollectorName - Allows paying fees with restricted coins.
  • reward - Allows reward programs to use restricted coins.
  • quarantine - Allows quarantine and acceptance of quarantined coins.
  • gov - Allows deposits to have quarantined coins.
  • distribution - Allows collection of delegation rewards in restricted coins.
  • stakingtypes.BondedPoolName - Allows delegation of restricted coins.
  • stakingtypes.NotBondedPoolName - Allows delegation of restricted coins.
All of these are treated equally in the application of a marker's send restrictions.
For restricted markers without required attributes:
  • If the toAddr is a bypass account, the fromAddr must have transfer authority.
  • If the fromAddr is a bypass account, it's assumed that the funds got where they currently are because someone with transfer authority got them there, so this transfer is allowed.
For restricted markers with required attributes:
  • If the toAddr is a bypass account, the transfer is allowed regardless of whether the fromAddr has transfer authority. It's assumed that the next destination's attributes will be properly checked before allowing the funds to leave the bypass account.
  • If the fromAddr is a bypass account, the toAddr must have the required attributes.
Bypass accounts are not considered during a MsgTransferRequest.

Send Restrictions

The marker module injects a SendRestrictionFn into the bank module. This function is responsible for deciding whether any given movement of funds (e.g. a MsgSend) is allowed from the marker module's point of view. However, it is bypassed for movements initiated within the marker module (e.g. during a Transfer).

Flowcharts

The SendRestrictionFn

The SendRestrictionFn uses the following flow to decide whether a send is allowed. It utilizes the checkSenderMarker, checkReceiverMarker, and validateSendDenom flows.
The process includes:
  1. Checking for bypass conditions or special sender accounts
  1. Checking if receiver is fee collector
  1. Checking for restricted coins in amount
  1. Getting transfer agent from context
  1. Validating sender marker permissions
  1. Validating receiver marker permissions
  1. Validating each denomination in the transfer amount

checkSenderMarker

This flow checks that, if this is a withdrawal, nothing (yet) prevents the send. It verifies:
  1. Whether sender is a marker
  1. Transfer agent availability and withdraw access
  1. Whether amount includes sender marker's denom
  1. Whether sender marker is active

checkReceiverMarker

This flow checks that, if this is a deposit, nothing (yet) prevents the send. It verifies:
  1. Whether receiver is a restricted marker
  1. Transfer agent availability
  1. Deposit access permissions for sender or transfer agent

validateSendDenom

Each Denom is checked using validateSendDenom, which validates:
  1. Marker existence and active status for the denom
  1. Restricted coin status and fee collector exceptions
  1. Transfer agent permissions
  1. Deny list restrictions
  1. Required attributes compliance
  1. Bypass account considerations
Note that force_transfer access is not considered at all in the SendRestrictionFn. Only a MsgTransferRequest can be used to force a transfer.

MsgTransferRequest

A MsgTransferRequest bypasses the SendRestrictionFn and applies its own logic. A MsgTransferRequest only allows for a single coin amount, i.e. there's only one Denom to consider. It makes use of the checkReceiverMarker flow.
The process includes:
  1. Checking if denom is a restricted coin
  1. Verifying admin has transfer or force-transfer permissions
  1. Running checkReceiverMarker validation
  1. Checking admin/sender relationship and authorization
  1. Validating forced transfer permissions and restrictions
  1. Checking for blocked addresses

Quarantine Complexities

There are some notable complexities involving restricted coins and quarantined accounts.

Sending Restricted Coins to a Quarantined Account

The marker module's SendRestrictionFn is applied before the quarantine module's. So, when funds are being sent to a quarantined account, the marker module runs its check using the original Sender and Receiver (i.e. the Receiver is not QFH).
If the Receiver is a quarantined account, the validateSendDenom flow checks:
  1. Whether sender has transfer permission for the denom
  1. Whether denom has required attributes
  1. Whether receiver has those required attributes
If the Send is allowed, and the Receiver is a quarantined account, the quarantine module's SendRestrictionFn will then change the Send's destination to QFH (the Quarantined-funds-holder account) and make a record of the transfer.

Accepting Quarantined Restricted Coins

Once funds have been sent to QFH, the Receiver will probably want to accept them, and have them sent to their account. They issue an Accept to the quarantine module which utilizes the bank module's Send functionality to try to transfer funds from QFH to the Receiver.
QFH is a bypass account. Since Receiver is a quarantined account, the validateSendDenom flow checks:
  1. Whether denom has required attributes
  1. Whether receiver has those required attributes
An important subtle part of this process is the rechecking of Receiver attributes. It's possible for the initial send to be okay (causing funds to be quarantined), then later, during this Accept, the send is not okay, and the quarantined funds are effectively locked with QFH until the Receiver gets the required attributes.
If the marker does not have required attributes though, it's assumed that they were originally sent by someone with transfer authority, so they are allowed to continue from here too.

Successful Quarantine and Accept Sequence

When restricted coin funds are sent to a quarantined account, the marker's SendRestrictionFn is called using the original Sender and Receiver. Then, the quarantine's SendRestrictionFn is called which will return QFH for the new destination. Funds are then transferred from Sender to QFH.
When the Receiver attempts to Accept those quarantined funds, the marker's SendRestrictionFn is called again, this time using QFH (as the sender) and Receiver. The quarantine's SendRestrictionFn is bypassed, so the destination is not changed. Funds are then transferred from QFH to Receiver.