Freeze Features

The Ripple Consensus Ledger gives accounts the ability to freeze non-XRP balances, which can be useful to comply with regulatory requirements, or while investigating suspicious activity. There are three settings related to freezes:

  • Individual Freeze - Freeze one counterparty.
  • Global Freeze - Freeze all counterparties.
  • No Freeze - Permanently give up the ability to freeze individual counterparties. Also gives up the ability to end a global freeze.

Because no party has a privileged place in the Ripple Consensus Ledger, the freeze feature cannot prevent a counterparty from conducting transactions in XRP or funds issued by other counterparties.

Individual Freeze

The Individual Freeze feature is a setting on a trust line. When an issuing account enables the Individual Freeze setting, the counterparty of that trust line can no longer send or receive issuances on the frozen trust line, except in transactions that go directly to and from the issuing account itself.

A gateway can freeze a counterparty if that counterparty shows suspicious activity or violates the gateway's terms of use.

If the counterparty has trust lines to the issuing account in more than one currency, the issuing account must freeze each trust line individually.

An account cannot enable the Individual Freeze setting if it has previously enabled the No Freeze setting.

Global Freeze

The Global Freeze feature is a setting on an account. When an issuing account enables the Global Freeze feature, all counterparties can only send and receive the issuing account's funds directly to and from the issuing account itself. (This includes any hot wallet accounts.)

It can be useful to enable Global Freeze on a gateway's cold wallet if a hot wallet is compromised, or immediately after regaining control of a compromised issuing account. This stops the flow of funds, preventing attackers from getting away with any more money or at least making it easier to track what happened.

It can also be useful to enable Global Freeze if a gateway intends to migrate its cold wallet to a new Ripple account, or if the gateway intends to cease doing business. This locks the funds at a specific point in time, so users cannot trade them away for other currencies.

An account can always enable the Global Freeze setting. However, if the account has previously enabled the No Freeze setting, it can never disable the Global Freeze.

No Freeze

The NoFreeze feature is a setting on an account that permanently gives up the ability to freeze counterparties. A business can use this feature to treat its issued funds as "more like physical money" in that the business cannot interfere with customers trading it among themselves. The NoFreeze setting has two effects:

  • The issuing account can no longer use tfSetFreeze to freeze an individual counterparty.
  • The issuing account can still enable asfGlobalFreeze to enact a global freeze, but the account cannot disable asfGlobalFreeze to end the global freeze.

The Ripple Consensus Ledger cannot force a gateway to honor the obligations that its issued funds represent, so giving up the ability to enable a Global Freeze cannot protect customers. However, giving up the ability to disable a Global Freeze ensures that the Global Freeze feature is not used unfairly against some customers.

Technical Details

Enabling or Disabling Individual Freeze

Using rippled

To enable or disable Individual Freeze on a specific trust line, send a TrustSet transaction. Use the tfSetFreeze flag to enable a freeze, and the tfClearFreeze flag to disable it. The fields of the transaction should be as follows:

Field Value Description
Account String The address of your Ripple account.
TransactionType String TrustSet
LimitAmount Object Object defining the trust line to freeze.
LimitAmount.currency String Currency of the trust line
LimitAmount.issuer String The Ripple address of the counterparty to freeze
LimitAmount.value String The amount of currency you trust this counterparty to issue to you, as a quoted number. From the perspective of a gateway, this is typically "0".
Flags Number To enable a freeze, use a value with the bit 0x00100000 (tfSetFreeze) enabled. To disable a freeze, use a value with the bit 0x00200000 (tfClearFreeze) enabled instead.

Set the Fee, Sequence, and LastLedgerSequence parameters in the typical way.

Example of submitting a TrustSet transaction to enable an individual freeze:

WebSocket request:

{
  "id": 12,
  "command": "submit",
  "tx_json": {
    "TransactionType": "TrustSet",
    "Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
    "Fee": "12000",
    "Flags": 1048576,
    "LastLedgerSequence": 18103014,
    "LimitAmount": {
      "currency": "USD",
      "issuer": "rsA2LpzuawewSBQXkiju3YQTMzW13pAAdW",
      "value": "110"
    },
    "Sequence": 340
  },
  "secret": "s████████████████████████████",
  "offline": false,
  "fee_mult_max": 1000
}

(Note: Never transmit your account secret to an untrusted server or over an insecure channel.)

WebSocket response:

{
  "id": 4,
  "status": "success",
  "type": "response",
  "result": {
    "engine_result": "tesSUCCESS",
    "engine_result_code": 0,
    "engine_result_message": "The transaction was applied. Only final in a validated ledger.",
    "tx_blob": "12001422000400002400000153201B01143A8263D503E871B540C0000000000000000000000000005553440000000000204288D2E47F8EF6C99BCC457966320D12409711684000000000002EE0732103AB40A0490F9B7ED8DF29D246BF2D6269820A0EE7742ACDD457BEA7C7D0931EDB7446304402206D3739439DC40BBECD45A02D627D4E0440CB8D583B10780DB73009118BA0B81402203691A664E2175A8B97608650EFCAB5701DB53E5C09DE07DFA2A96DC0DB356BD681144B4E9C06F24296074F7BC48F92A97916C6DC5EA9",
    "tx_json": {
      "Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
      "Fee": "12000",
      "Flags": 262144,
      "LastLedgerSequence": 18102914,
      "LimitAmount": {
        "currency": "USD",
        "issuer": "rsA2LpzuawewSBQXkiju3YQTMzW13pAAdW",
        "value": "110"
      },
      "Sequence": 339,
      "SigningPubKey": "03AB40A0490F9B7ED8DF29D246BF2D6269820A0EE7742ACDD457BEA7C7D0931EDB",
      "TransactionType": "TrustSet",
      "TxnSignature": "304402206D3739439DC40BBECD45A02D627D4E0440CB8D583B10780DB73009118BA0B81402203691A664E2175A8B97608650EFCAB5701DB53E5C09DE07DFA2A96DC0DB356BD6",
      "hash": "3EDDC21C710883B8B3F94D7954002AF8D8E27E7B1199B9862E6CA6BFF83B39B8"
    }
  }
}

Using RippleAPI

To enable or disable Individual Freeze on a specific trust line, prepare a Trustline transaction using the prepareTrustline method. The fields of the trustline parameter should be set as follows:

Field Value Description
currency String The currency of the trust line to freeze
counterparty String The Ripple address of the counterparty
limit String The amount of currency you trust this counterparty to issue to you, as a quoted number. From the perspective of a gateway, this is typically "0".
frozen Boolean true to enable Individual Freeze on this trust line. false to disable Individual Freeze.

The rest of the transaction flow is the same as any other transaction.

Example JavaScript (ECMAScript 6) code to enable Individual Freeze on a trust line:

const {RippleAPI} = require('ripple-lib');

const api = new RippleAPI({
  server: 'wss://s1.ripple.com' // Public rippled server hosted by Ripple, Inc.
});

const issuing_address = "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn";
const issuing_secret = "s████████████████████████████";
    //Best practice: get your secret from an encrypted config file instead
const address_to_freeze = "rUpy3eEg8rqjqfUoLeBnZkscbKbFsKXC3v";
const currency_to_freeze = "USD";

api.connect().then(() => {

  // Look up current state of trust line
  var options = {counterparty: address_to_freeze, currency: currency_to_freeze};
  console.log("looking up", currency_to_freeze, "trust line from", 
              issuing_address, "to", address_to_freeze);
  return api.getTrustlines(issuing_address, options);

}).then(data => {

  //Prepare a trustline transaction to enable freeze
  if (data.length != 1) {
    console.log("trustline not found, making a default one");
    var trustline = {
      currency: currency_to_freeze,
      counterparty: address_to_freeze,
      limit: 0
    };
  } else {
    var trustline = data[0].specification;
    console.log("trustline found. previous state:", trustline);
  }

  trustline.frozen = true;

  console.log("preparing trustline transaction for line:",trustline);
  return api.prepareTrustline(issuing_address, trustline);

}).then(prepared_tx => {

  //Sign and submit the trustline transaction
  console.log("signing tx:",prepared_tx.txJSON);
  var signed1 = api.sign(prepared_tx.txJSON, issuing_secret);
  console.log("submitting tx:", signed1.id);

  return api.submit(signed1.signedTransaction)
}).then(() => {
  return api.disconnect();
}).catch(console.error);

Enabling or Disabling Global Freeze

Using rippled

To enable Global Freeze on an account, send an AccountSet transaction with the asfGlobalFreeze flag value in the SetFlag field. To disable Global Freeze, put the asfGlobalFreeze flag value in the ClearFlag field instead.

Example of submitting an AccountSet transaction to enable Global Freeze:

TODO

Using RippleAPI

To enable or disable Global Freeze on an account, prepare a Settings transaction using the prepareSettings method. The settings parameter should be an object set as follows:

Field Value Description
globalFreeze Boolean true to enable a Global Freeze on this account. false to disable Global Freeze.

The rest of the transaction flow is the same as any other transaction.

Example code to enable Global Freeze on an account:

TODO

Enabling No Freeze

Using rippled

To enable No Freeze on an account, send an AccountSet transaction with the asfNoFreeze flag value in the SetFlag field. You must sign this transaction using the master key. Once enabled, you cannot disable No Freeze.

Example of submitting an AccountSet transaction to enable No Freeze:

TODO

Using RippleAPI

To enable No Freeze on an account, prepare a Settings transaction using the prepareSettings method. Once enabled, you cannot disable No Freeze. The settings parameter should be an object set as follows:

Field Value Description
noFreeze Boolean true

You must sign this transaction using the master key. The rest of the transaction flow is the same as any other transaction.

Example code to enable No Freeze on an account:

TODO

Checking for Individual Freeze

Using rippled

To see if a trust line has an Individual Freeze enabled, use the account_lines method with the following parameters:

Field Value Description
account String The Ripple address of the issuing account
peer String The Ripple address of the counterparty account
ledger_index String Use validated to get the most recently validated information.

The response contains an array of trust lines, for each currency in which the issuing account and the counterparty are linked. Look for the following fields in each trust line object:

Field Value Description
freeze Boolean (May be omitted) true if the issuing account has frozen this trust line. If omitted, that is the same as false.
freeze_peer (May be omitted) true if the counterparty has frozen this trust line. If omitted, that is the same as false.

Example of checking for an individual freeze:

WebSocket Request:

{
  "id": 15,
  "command": "account_lines",
  "account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
  "ledger": "validated",
  "peer": "rsA2LpzuawewSBQXkiju3YQTMzW13pAAdW"
}

WebSocket Response:

{
  "id": 15,
  "status": "success",
  "type": "response",
  "result": {
    "account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
    "lines": [
      {
        "account": "rsA2LpzuawewSBQXkiju3YQTMzW13pAAdW",
        "balance": "10",
        "currency": "USD",
        "freeze": true,
        "limit": "110",
        "limit_peer": "0",
        "peer_authorized": true,
        "quality_in": 0,
        "quality_out": 0
      }
    ]
  }
}

Using RippleAPI

To see if a trust line has an Individual Freeze enabled, use the getTrustlines method with the following parameters:

Field Value Description
address String The Ripple address of the issuing account
options.counterparty String The Ripple address of the counterparty account

The response contains an array of trust lines, for each currency in which the issuing account and the counterparty are linked. Look for the following fields in each trust line object:

Field Value Description
specification.frozen Boolean (May be omitted) true if the issuing account has frozen the trust line.
counterparty.frozen Boolean (May be omitted) true if the counterparty has frozen the trust line.

Example JavaScript (ECMAScript 6) code to check whether a trust line is frozen:

const {RippleAPI} = require('ripple-lib');

const api = new RippleAPI({
  server: 'wss://s1.ripple.com' // Public rippled server hosted by Ripple, Inc.
});

const my_address = "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn";
const counterparty_address = "rUpy3eEg8rqjqfUoLeBnZkscbKbFsKXC3v";
const frozen_currency = "USD";

api.connect().then(() => {

  // Look up current state of trust line
  var options = {counterparty: counterparty_address, currency: frozen_currency};
  console.log("looking up", frozen_currency, "trust line from", 
              my_address, "to", counterparty_address);
  return api.getTrustlines(my_address, options);

}).then(data => {

  if ( data.length > 1)
     throw "should only be 1 trust line per counterparty+currency pair";

  if ( data.length === 0 ) {
    console.log("No trust line found");
  } else {
      var trustline = data[0];
      console.log("Trust line frozen from our side?", 
                  trustline.specification.frozen === true);
      console.log("Trust line frozen from counterparty's side?", 
                  trustline.counterparty.frozen === true);
  }

}).then(() => {
  return api.disconnect();
}).catch(console.error);

Checking for Global Freeze and No Freeze

Using rippled

To see if an account has Global Freeze and/or No Freeze enabled, use the account_info method with the following parameters:

Field Value Description
account String The Ripple address of the issuing account
ledger_index String Use validated to get the most recently validated information.

Check the value of the account_data.Flags field of the response using the bitwise-AND operator:

  • If Flags AND 0x00400000 (lsfGlobalFreeze) is nonzero: Global Freeze is enabled.
  • If Flags AND 0x00200000 (lsfNoFreeze) is nonzero: No Freeze is enabled.

Example request:

TODO

Example response:

TODO

Using RippleAPI

To see if an account has Global Freeze and/or No Freeze enabled, use the getSettings method with the following parameters:

Field Value Description
address String The Ripple address of the issuing account

Look for the following values in the response object:

Field Value Description
noFreeze Boolean (May be omitted) true if No Freeze is enabled.
globalFreeze Boolean (May be omitted) true if Global Freeze is enabled.

Example code:

TODO

See Also

Gateway Bulletin GB-2014-02 New Feature: Balance Freeze