Skip to main content

Rules

Rules are programmable restrictions that can be applied to any action in the TokenPolicy. They are the tool of compliance, regulation and enforcement of certain business logic in the Closed Loop system.

Rule Structure

A Rule is represented as a witness - a type with a drop ability. It can be either encoded in application logic, or, for more modular setup, can be part of a separate module.

/// The Rule type
struct Rule has drop {}

Once added to an action in the TokenPolicy, the action will require a "stamp" of the Rule to pass confirmation.

See Approving Actions section for more details on how to approve an action.

Modular Rules

Rules can be published as separate reusable modules. This allows to create a library of rules that can be used in different token policies maximizing code reuse and minimizing the risk of errors.

A Rule module is a regular module with a verify-like function that typically takes a TokenPolicy, ActionRequest and a TxContext as arguments. The function is responsible for verifying the action and stamping the ActionRequest with the Rule type.

module example::pass_rule {
use sui::tx_context;
use sui::token::{Self, ActionRequest, TokenPolicy};

/// The Rule type
struct Pass has drop {}

/// Add approval from the Pass rule to the ActionRequest
public fun verify<T>(
_policy: &TokenPolicy<T>,
action_request: &mut ActionRequest<T>,
ctx: &mut TxContext,
) {
// ...
token::add_approval(Pass {}, action_request, ctx)
}
}

Rule Configuration

Some rules, such as "denylist" or "allowlist" require configuration. For example, a denylist rule may require a list of addresses that are not allowed to perform certain actions. A Rule module can define a configuration structure and provide functions to add, modify, retrieve and remove the configuration.

info

A single Rule has a single configuration, even when assigned to multiple actions. If there's a need to have configuration per action, a Rule module needs to define a storage structure that can hold and manage multiple configurations.

Configuration system comes with a set of guarantees to protect token owners from malicious actions (or upgrades) from Rule module developers:

  1. The type and the structure of the configuration are defined by the Rule module.
  2. Addition / modification and removal of the configuration are only available to the TokenPolicy owner.
  3. The configuration can be read only by a Rule.
  4. Rule cannot modify the configuration without the TokenPolicy owner's approval.

The only attack vector available to the Rule creator is upgrading the module and creating a function to bypass the restriction. Make sure to use Rules provided by a trusted developer.

Configuration API

The configuration API is defined in the sui::token module and has the following set of functions.

Add new Config

New configuration must be approved by a Rule (the Rule witness) and the TokenPolicy owner. The type of the configuration can be any as long as it has the store ability.

// module: sui::token
public fun add_rule_config<T, Rule: drop, Config: store>(
_rule: Rule,
policy: &mut TokenPolicy<T>,
policy_cap: &TokenPolicyCap<T>,
config: Config,
_ctx: &mut TxContext
);

Read the Config

Rule can read configuration stored in the TokenPolicy.

// module: sui::token
public fun rule_config<T, Rule: drop, Config: store>(
_rule: Rule, policy: &TokenPolicy<T>
): &Config;

Modify the Config

The configuration modification must be approved by a Rule (the Rule witness) and the TokenPolicy owner.

// module: sui::token
public fun rule_config_mut<T, Rule: drop, Config: store>(
_rule: Rule, policy: &mut TokenPolicy<T>, policy_cap: &TokenPolicyCap<T>
): &mut Config;

Remove Configuration

A good practice for a Rule is to provide method to remove the configuration as Rule can use a custom type for it. However, token owner can always remove the configuration by calling the remove_rule_config function.

// module: sui::token
public fun remove_rule_config<T, Rule, Config: store>(
policy: &mut TokenPolicy<T>,
policy_cap: &TokenPolicyCap<T>,
_ctx: &mut TxContext
): Config;

Because the configuration has store, the token owner can wrap and transfer or store the configuration somewhere else. If the Config type has drop, the value can be ignored.

Cheatsheet: Rule Configuration API

Method nameDescriptionNotes
add_rule_configAdds a new Config for the RuleRequires Rule witness and Token Owner approval
remove_rule_configRemoves Config object from the PolicyCan be performed any time by the Token Owner
rule_configAccess the Config immutablyOnly available to a Rule
rule_config_mutGet mutable reference to ConfigRequires Rule witness and Token Owner approval
has_rule_configCheck if the Rule has a Config set-
has_rule_config_with_typeCheck if the Rule has a Config with type-