Skip to main content
PulseScanner.io

Address

0xfb07da6c19f5b5aca1fa07c0762d60fbfc5f6fa1
Current Holdings
$0.00376000
TXs sent
not counted
First Active
2026-02-21
block 25,848,522
Last Active
205 days ago
block 25,848,857
Funded By
not identified

Net worth historyi

3 snapshots · to block 27,446,929coverage change 26 Augcoverage change 27 Augcoverage change 27 Augcoverage change 27 Augcoverage change 27 Aug
exact matchPulseSatoshiVaultsolc 0.8.29+commit.ab55807cruntime exact · creation exact
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";

// ── pSAT ── Fixed total supply, 0 decimals (big whole numbers)
contract STEST is ERC20 {
    uint256 public constant TOTAL_SUPPLY = 21_000_000_000_000;

    constructor() ERC20("STEST", "sTEST") {
        _mint(msg.sender, TOTAL_SUPPLY);
    }

    // ← Add this!
    function decimals() public view virtual override returns (uint8) {
        return 0;  // whole numbers only, no tiny pieces
    }
}

// ── PULSE SATOSHI VAULT ── Fixed ratio, no mint/burn, locked reserves
contract PulseSatoshiVault is Ownable, ReentrancyGuard {
    using SafeERC20 for IERC20;

    IERC20 public immutable wbtc;
    IERC20 public immutable stest;

    // Correct ratio: 1 WBTC unit (1 sat, 8 decimals) = 100,000,000 sTEST (0 decimals)
    uint256 public constant RATIO = 100_000_000;

    bool public paused;

    event Deposited(address indexed user, uint256 wbtcAmount, uint256 stestAmount);
    event Redeemed(address indexed user, uint256 stestAmount, uint256 wbtcAmount);

    constructor(address _wbtc, address _stest) Ownable(msg.sender) {
        wbtc = IERC20(_wbtc);
        stest = IERC20(_stest);

        // Safety check: sTEST must have correct fixed supply
        require(stest.totalSupply() == 21_000_000_000_000, "Invalid sTEST supply");
    }

    modifier whenNotPaused() {
        require(!paused, "Vault is paused");
        _;
    }

    // ── Deposit WBTC → receive pre-minted sTEST from vault balance
    function deposit(uint256 wbtcAmount) external nonReentrant whenNotPaused {
        require(wbtcAmount > 0, "Amount must be > 0");
        uint256 stestAmount = wbtcAmount * RATIO;

        // Vault must have enough sTEST to send
        require(stest.balanceOf(address(this)) >= stestAmount, "Insufficient sTEST in vault");

        wbtc.safeTransferFrom(msg.sender, address(this), wbtcAmount);
        stest.safeTransfer(msg.sender, stestAmount);

        emit Deposited(msg.sender, wbtcAmount, stestAmount);
    }

    // ── Redeem sTEST → receive WBTC from vault
    function redeem(uint256 stestAmount) external nonReentrant whenNotPaused {
        require(stestAmount > 0, "Amount must be > 0");
        uint256 wbtcAmount = stestAmount / RATIO;

        // Vault must have enough WBTC to pay out
        require(wbtc.balanceOf(address(this)) >= wbtcAmount, "Insufficient WBTC reserves");

        stest.safeTransferFrom(msg.sender, address(this), stestAmount);
        wbtc.safeTransfer(msg.sender, wbtcAmount);

        emit Redeemed(msg.sender, stestAmount, wbtcAmount);
    }

    // ── Emergency pause (owner only)
    function pause() external onlyOwner {
        paused = true;
    }

    function unpause() external onlyOwner {
        paused = false;
    }

    // ── View helpers (useful for site/dashboard)
    function vaultSTESTBalance() external view returns (uint256) {
        return stest.balanceOf(address(this));
    }

    function vaultWBTCBalance() external view returns (uint256) {
        return wbtc.balanceOf(address(this));
    }

    function circulatingSTEST() external view returns (uint256) {
        return stest.totalSupply() - stest.balanceOf(address(this));
    }
}