Agent documentation index: llms.txt. Markdown versions of documentation pages are available by appending .md to the page URL.
Skip to main content

IBalanceDecreasingTransaction

An interface to detect transactions that decrease the balance of a specific address or are signed by that address on external blockchains.

Sourced from IBalanceDecreasingTransaction.sol on GitHub.

Overview​

The IBalanceDecreasingTransaction interface allows smart contracts to identify and verify transactions on external blockchains that either:

  1. Decrease the balance of a specific address, or
  2. Are signed by the address in question (even if the balance increases)

This attestation type is particularly useful for detecting when a party has violated an agreement by moving funds that were promised to be locked, providing grounds for liquidating collateral locked in a smart contract on Flare.

Supported Chains​

Network TypeSupported Chains
MainnetBTC (Bitcoin), DOGE (Dogecoin), XRP (XRP Ledger)
TestnettestBTC (Bitcoin Testnet 4), testDOGE, testXRP

Chain-Specific Implementation Details​

UTXO Chains (Bitcoin and Dogecoin)​

  • sourceAddressIndicator: Index of the transaction input in hex padded to a 0x-prefixed 32-byte string
  • sourceAddress: Address of the indicated transaction input
  • spentAmount: Sum of values of all inputs with sourceAddress minus sum of all outputs with sourceAddress (can be negative)
  • blockTimestamp: Mediantime of the block

Account-based Chains (XRPL)​

  • sourceAddressIndicator: Standard address hash of the address to monitor
  • sourceAddress: Address whose standard hash matches the sourceAddressIndicator
  • spentAmount: Difference between the balance after and before the transaction (can be negative)
  • blockTimestamp: close_time of the ledger converted to Unix time

Interface Definition​

// SPDX-License-Identifier: MIT
pragma solidity >=0.7.6 <0.9;

/**
* @custom:name IBalanceDecreasingTransaction
* @custom:id 0x02
* @custom:supported BTC, DOGE, XRP
* @author Flare
* @notice A detection of a transaction that either decreases the balance for some address or is
* signed by the source address.
* Such an attestation could prove a violation of an agreement and therefore provides grounds to liquidate
* some funds locked by a smart contract on Flare.
*
* A transaction is considered "balance decreasing" for the address, if the balance after the
* transaction is lower than before or the address is among the signers of the transaction
* (even if its balance is greater than before the transaction).
* @custom:verification The transaction with `transactionId` is fetched from the API of the
* source blockchain node or relevant indexer.
* If the transaction cannot be fetched or the transaction is in a block that does not have a
* sufficient number of confirmations, the attestation request is rejected.
*
* Once the transaction is received, the response fields are extracted if the transaction is balance
* decreasing for the indicated address.
* Some of the request and response fields are chain specific as described below.
* The fields can be computed with the help of a balance decreasing summary.
*
* ### UTXO (Bitcoin and Dogecoin)
*
* - `sourceAddressIndicator` is the the index of the transaction input in hex padded to a 0x prefixed 32-byte string.
* If the indicated input does not exist or the indicated input does not have the address,
* the attestation request is rejected.
* The `sourceAddress` is the address of the indicated transaction input.
* - `spentAmount` is the sum of values of all inputs with sourceAddress minus the sum of
* all outputs with `sourceAddress`.
* Can be negative.
* - `blockTimestamp` is the mediantime of a block.
*
* ### XRPL
*
* - `sourceAddressIndicator` is the standard address hash of the address whose balance has been decreased.
* If the address indicated by `sourceAddressIndicator` is not among the signers of the transaction and the balance
* of the address was not lowered in the transaction, the attestation request is rejected.
*
* - `spentAmount` is the difference between the balance of the indicated address after and before the transaction.
* Can be negative.
* - `blockTimestamp` is the close_time of a ledger converted to unix time.
*
* @custom:lut `blockTimestamp`
* @custom:lutlimit `0x127500`, `0x127500`, `0x127500`
*/
interface IBalanceDecreasingTransaction {
/**
* @notice Toplevel request
* @param attestationType ID of the attestation type.
* @param sourceId ID of the data source.
* @param messageIntegrityCode `MessageIntegrityCode` that is derived from the expected response.
* @param requestBody Data defining the request. Type and interpretation is determined by the `attestationType`.
*/
struct Request {
bytes32 attestationType;
bytes32 sourceId;
bytes32 messageIntegrityCode;
RequestBody requestBody;
}

/**
* @notice Toplevel response
* @param attestationType Extracted from the request.
* @param sourceId Extracted from the request.
* @param votingRound The ID of the FDC round in which the request was considered.
* This is a security measure to prevent a collision of attestation hashes.
* @param lowestUsedTimestamp The lowest timestamp used to generate the response.
* @param requestBody Extracted from the request.
* @param responseBody Data defining the response. The verification rules for the construction of the
* response body and the type are defined per specific `attestationType`.
*/
struct Response {
bytes32 attestationType;
bytes32 sourceId;
uint64 votingRound;
uint64 lowestUsedTimestamp;
RequestBody requestBody;
ResponseBody responseBody;
}

/**
* @notice Toplevel proof
* @param merkleProof Merkle proof corresponding to the attestation response.
* @param data Attestation response.
*/
struct Proof {
bytes32[] merkleProof;
Response data;
}

/**
* @notice Request body for IBalanceDecreasingTransaction attestation type
* @param transactionId ID of the payment transaction.
* @param sourceAddressIndicator The indicator of the address whose balance has been decreased.
*/
struct RequestBody {
bytes32 transactionId;
bytes32 sourceAddressIndicator;
}

/**
* @notice Response body for IBalanceDecreasingTransaction attestation type.
* @param blockNumber The number of the block in which the transaction is included.
* @param blockTimestamp The timestamp of the block in which the transaction is included.
* @param sourceAddressHash Standard address hash of the address indicated by the `sourceAddressIndicator`.
* @param spentAmount Amount spent by the source address in minimal units.
* @param standardPaymentReference Standard payment reference of the transaction.
*/
struct ResponseBody {
uint64 blockNumber;
uint64 blockTimestamp;
bytes32 sourceAddressHash;
int256 spentAmount;
bytes32 standardPaymentReference;
}
}

Structs​

Request​

Toplevel request structure.

Parameters​

  • attestationType: ID of the attestation type (0x02 for BalanceDecreasingTransaction)
  • sourceId: ID of the data source (e.g., BTC, DOGE, XRP)
  • messageIntegrityCode: MessageIntegrityCode derived from the expected response
  • requestBody: Data defining the request

Response​

Toplevel response structure.

Parameters​

  • attestationType: Extracted from the request
  • sourceId: Extracted from the request
  • votingRound: The ID of the FDC round in which the request was considered
  • lowestUsedTimestamp: The lowest timestamp used to generate the response
  • requestBody: Extracted from the request
  • responseBody: Data defining the response

Proof​

Toplevel proof structure for verification.

Parameters​

  • merkleProof: Merkle proof corresponding to the attestation response
  • data: Attestation response

RequestBody​

Request body specific to balance decreasing transactions.

Parameters​

  • transactionId: Unique identifier of the transaction to check
  • sourceAddressIndicator: Indicator of the address to monitor (interpretation varies by chain)

ResponseBody​

Response body containing details about the balance decreasing transaction.

Parameters​

  • blockNumber: Block number containing the transaction
  • blockTimestamp: Timestamp of the block containing the transaction
  • sourceAddressHash: Standard hash of the address indicated by sourceAddressIndicator
  • spentAmount: Amount spent by the source address (can be negative)
  • standardPaymentReference: Standard payment reference of the transaction

Implementation Notes​

  • Attestation ID: 0x02
  • The lowestUsedTimestamp parameter uses the value of blockTimestamp
  • The lutlimit (Lowest Used Timestamp limit) is 0x127500 (1,209,600 seconds = 14 days) for all supported chains
  • A negative spentAmount value indicates the address received more funds than it sent
  • The transaction is still considered "balance decreasing" if the address signed the transaction, even if the balance increased

Practical Applications​

  • Cross-chain Collateral Monitoring: Detect when funds that should be locked on one chain are moved, triggering liquidation of collateral on Flare
  • Agreement Enforcement: Verify if parties adhere to contractual agreements involving locking funds
  • Fraud Detection: Monitor specific addresses for suspicious outgoing transactions
  • Conditional Smart Contracts: Trigger contract actions based on external chain activity

Usage Example​

LockMonitor.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;

import {ContractRegistry} from "@flarenetwork/flare-periphery-contracts/coston2/ContractRegistry.sol";
import {IFdcVerification} from "@flarenetwork/flare-periphery-contracts/coston2/IFdcVerification.sol";
import {IBalanceDecreasingTransaction} from "@flarenetwork/flare-periphery-contracts/coston2/IBalanceDecreasingTransaction.sol";

contract LockMonitor {
// Business logic: stores which addresses are being monitored
mapping(bytes32 => bool) public lockedAddresses;
// Business logic: prevents re-processing the same violation proof
mapping(bytes32 => bool) public confirmedViolations;

event ViolationConfirmed(
bytes32 indexed transactionId,
bytes32 indexed sourceAddressHash
);

function registerLockedAddress(bytes32 sourceAddressHash) external {
lockedAddresses[sourceAddressHash] = true;
}
function processViolationProof(
IBalanceDecreasingTransaction.Proof calldata _proof
) external {
// 1. FDC Logic: Verify the proof's authenticity with the Flare network.
require(isProofValid(_proof), "Invalid transaction proof");

// 2. Business Logic: Execute actions based on the verified proof data.
bytes32 sourceAddressHash = _proof.data.responseBody.sourceAddressHash;
int256 spentAmount = _proof.data.responseBody.spentAmount;
bytes32 transactionId = _proof.data.requestBody.transactionId;

// Check if a monitored address spent funds (a violation).
if (lockedAddresses[sourceAddressHash] && spentAmount > 0) {
require(
!confirmedViolations[transactionId],
"Violation already confirmed"
);

// Take action: log the violation and update state.
confirmedViolations[transactionId] = true;
lockedAddresses[sourceAddressHash] = false; // Example: remove from monitoring after violation.

emit ViolationConfirmed(transactionId, sourceAddressHash);
}
}

function isProofValid(
IBalanceDecreasingTransaction.Proof memory _proof
) public view returns (bool) {
IFdcVerification fdcVerification = ContractRegistry
.getFdcVerification();
return fdcVerification.verifyBalanceDecreasingTransaction(_proof);
}
}