hBTC

Contract: hBTC Inherits: ERC20, Blacklistable, AccessControl, Ownable Decimals: 8

hBTC is the ERC-20 representation of Bitcoin allocated into Syntetika's BTC Basis+ Strategy and redeemable 1:1.

  • Role-gated minting: only MINTER_ROLE may mint.

  • Admin burn authority: the owner can burn from any address without allowance.

  • Blacklist enforcement: transfers and mints/burns involving blacklisted addresses are blocked; the owner can perform administrative movements even if parties are blacklisted.

  • 8-decimal accounting to match Bitcoin denominations.

State & roles

bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
address public minter; // convenience pointer to the current designated minter
  • Owner (Ownable): initial admin. May change the blacklister (via Blacklistable) and, due to the token’s _update override, can move/burn tokens even if addresses are blacklisted (for administrative recoveries).

  • DEFAULT_ADMIN_ROLE (AccessControl): can grant/revoke roles (incl. MINTER_ROLE) and call setMinter.

  • Blacklister (Blacklistable): manages the blacklist set (see events below).

  • Minter (MINTER_ROLE): typically the Minter contract; can call mint.

Constructor

constructor(
  string memory _name,
  string memory _symbol,
  address _initialAdmin,
  address _minter
) ERC20(_name, _symbol) Ownable(_initialAdmin)
  • Sets owner = _initialAdmin, blacklister = _initialAdmin.

  • Grants DEFAULT_ADMIN_ROLE to _initialAdmin.

  • Sets minter = _minter and grants MINTER_ROLE to _minter.

Functions

Decimals

function decimals() public pure override returns (uint8) { return 8; }

Always 8. All mint/burn/transfer amounts are in satoshi-like units.


Set minter

function setMinter(address newMinter)
  external onlyRole(DEFAULT_ADMIN_ROLE)
  • Requires: newMinter != address(0).

  • Effect: revokes MINTER_ROLE from minter, updates minter, and grants MINTER_ROLE to newMinter.

Usage: rotate the system minter safely (e.g., to a new Minter contract).


Mint

function mint(address to, uint256 amount) external onlyRole(MINTER_ROLE)
  • Access: MINTER_ROLE only.

  • Reverts if: to is blacklisted and the caller is not the owner (blacklist is enforced in _update).

  • Emits: standard Transfer(address(0), to, amount).

Integration note: The Minter contract is granted MINTER_ROLE and calls this after receiving the base asset.


Burn (self)

function burn(uint256 amount) external
  • Burns amount from msg.sender.

  • Emits: Transfer(msg.sender, address(0), amount).


Burn (from)

function burnFrom(address from, uint256 amount) external
  • If msg.sender is neither from nor the owner, the function spends allowance using _spendAllowance(from, msg.sender, amount).

  • Then burns from from.

Important integration detail: Minter.redeem() calls hBTC.burnFrom(msg.sender, amount). Since the Minter contract is not the token owner, users must first call:

hBTC.approve(MINTER_ADDRESS, amount)

before redeeming, otherwise burnFrom will revert due to insufficient allowance.


Transfer & blacklist enforcement (internal)

function _update(address from, address to, uint256 amount) internal override {
  if (msg.sender != owner()) {
    require(!_isBlacklisted(from) && !_isBlacklisted(to), "Blacklistable: account is blacklisted");
  }
  super._update(from, to, amount);
}
  • Blacklist applies to all movements (transfers, mints, burns) unless the caller is the owner.

  • The owner bypass allows administrative recovery/seizure actions when required by policy.


Blacklist management (from Blacklistable)

  • blacklist(address account)onlyBlacklister; emits Blacklisted(account).

  • unBlacklist(address account)onlyBlacklister; emits UnBlacklisted(account).

  • updateBlacklister(address newBlacklister)onlyOwner; emits BlacklisterChanged(newBlacklister).

  • isBlacklisted(address account) → bool — view.

Effect on transfers/mint/burn: when the caller is not the owner, any move involving a blacklisted from or to reverts with Blacklistable: account is blacklisted.

Events

  • ERC-20: Transfer, Approval.

  • AccessControl: RoleGranted, RoleRevoked (when roles change).

  • Blacklistable: Blacklisted, UnBlacklisted, BlacklisterChanged.

Common patterns

  • Grant minter to Minter contract

    hBTC.setMinter(MINTER_ADDRESS); // caller has DEFAULT_ADMIN_ROLE
  • User redeem flow

    // 1) Approve the Minter to burn
    hBTC.approve(MINTER_ADDRESS, amount);
    
    // 2) Redeem through Minter (burns & returns base asset; BTC leg handled by custody ops)
    Minter.redeem(amount);
  • Admin rotation

    • Use setMinter(new) to atomically revoke old minter and grant the new address.

    • Use updateBlacklister(new) from the owner to rotate blacklister.

Security & invariants

  • Supply control: Only MINTER_ROLE can mint; only holders (or owner/minter with allowance) can burn.

  • Compliance at the edge: Blacklisting is enforced on token movements; the owner can execute administrative moves even when addresses are blacklisted.

  • Unit consistency: 8 decimals across hBTC, Minter base-asset pairing, and StakingVault (constructor checks enforce matching decimals).

Last updated