Skip to main content
PulseScanner.io

Address

0x9d5e085633b520bb4fea6f18a755c49d4e169123
Current Holdings
$2.80
TXs sent
not counted
First Active
2025-11-03
block 24,929,429
Last Active
319 days ago
block 24,929,834
Funded By
0x2451…a84d

Net worth historyi

2 snapshots · to block 27,556,985coverage change 26 Augcoverage change 27 Augcoverage change 27 Augcoverage change 27 Augcoverage change 27 Aug
exact matchPulseIndexsolc 0.8.20+commit.a1b79de6runtime exact · creation exact
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

// Basic ERC20 implementation (self-contained, no OpenZeppelin import)
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }
}

interface IERC20 {
    function totalSupply() external view returns (uint256);
    function balanceOf(address account) external view returns (uint256);
    function transfer(address recipient, uint256 amount) external returns (bool);
    function allowance(address owner, address spender) external view returns (uint256);
    function approve(address spender, uint256 amount) external returns (bool);
    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
    event Transfer(address indexed from, address indexed to, uint256 value);
    event Approval(address indexed owner, address indexed spender, uint256 value);
}

contract ERC20 is Context, IERC20 {
    mapping(address => uint256) private _balances;
    mapping(address => mapping(address => uint256)) private _allowances;
    uint256 private _totalSupply;
    string private _name;
    string private _symbol;

    constructor(string memory name_, string memory symbol_) {
        _name = name_;
        _symbol = symbol_;
    }

    function name() public view virtual returns (string memory) {
        return _name;
    }

    function symbol() public view virtual returns (string memory) {
        return _symbol;
    }

    function decimals() public view virtual returns (uint8) {
        return 18;
    }

    function totalSupply() public view virtual override returns (uint256) {
        return _totalSupply;
    }

    function balanceOf(address account) public view virtual override returns (uint256) {
        return _balances[account];
    }

    function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
        _transfer(_msgSender(), recipient, amount);
        return true;
    }

    function allowance(address owner, address spender) public view virtual override returns (uint256) {
        return _allowances[owner][spender];
    }

    function approve(address spender, uint256 amount) public virtual override returns (bool) {
        _approve(_msgSender(), spender, amount);
        return true;
    }

    function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) {
        _transfer(sender, recipient, amount);
        uint256 currentAllowance = _allowances[sender][_msgSender()];
        require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance");
        unchecked {
            _allowances[sender][_msgSender()] = currentAllowance - amount;
        }
        return true;
    }

    function _transfer(address sender, address recipient, uint256 amount) internal virtual {
        require(sender != address(0), "ERC20: transfer from the zero address");
        require(recipient != address(0), "ERC20: transfer to the zero address");
        uint256 senderBalance = _balances[sender];
        require(senderBalance >= amount, "ERC20: transfer amount exceeds balance");
        unchecked {
            _balances[sender] = senderBalance - amount;
        }
        _balances[recipient] += amount;
        emit Transfer(sender, recipient, amount);
    }

    function _mint(address account, uint256 amount) internal virtual {
        require(account != address(0), "ERC20: mint to the zero address");
        _totalSupply += amount;
        _balances[account] += amount;
        emit Transfer(address(0), account, amount);
    }

    function _burn(address account, uint256 amount) internal virtual {
        require(account != address(0), "ERC20: burn from the zero address");
        uint256 accountBalance = _balances[account];
        require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
        unchecked {
            _balances[account] = accountBalance - amount;
            _totalSupply -= amount;
        }
        emit Transfer(account, address(0), amount);
    }

    function _approve(address owner, address spender, uint256 amount) internal virtual {
        require(owner != address(0), "ERC20: approve from the zero address");
        require(spender != address(0), "ERC20: approve to the zero address");
        _allowances[owner][spender] = amount;
        emit Approval(owner, spender, amount);
    }
}

// Ownable (self-contained)
abstract contract Ownable is Context {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    constructor() {
        _transferOwnership(_msgSender());
    }

    function owner() public view virtual returns (address) {
        return _owner;
    }

    modifier onlyOwner() {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
        _;
    }

    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _transferOwnership(newOwner);
    }

    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

// Uniswap-like interfaces (PulseX V2 is Uniswap V2 compatible)
interface IUniswapV2Factory {
    function getPair(address tokenA, address tokenB) external view returns (address pair);
}

interface IUniswapV2Pair {
    function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
    function token0() external view returns (address);
    function token1() external view returns (address);
}

interface IUniswapV2Router02 {
    function factory() external pure returns (address);
    function WETH() external pure returns (address); // WPLS on PulseChain
    function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline) external payable returns (uint[] memory amounts);
    function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline) external returns (uint[] memory amounts);
    function addLiquidityETH(address token, uint amountTokenDesired, uint amountTokenMin, uint amountETHMin, address to, uint deadline) external payable returns (uint amountToken, uint amountETH, uint liquidity);
}

contract PulseIndex is ERC20, Ownable {
    address public immutable routerAddress;
    address public immutable wplsAddress;
    address[] public basketTokens; // PLSX, INC, HEX, eHEX, WBTC, WETH

    constructor() ERC20("Pulse Index", "PINDEX") {
        routerAddress = 0x165C3410fC91EF562C50559f7d2289fEbed552d9; // PulseX V2 router
        wplsAddress = 0xA1077a294dDE1B09bB078844df40758a5D0f9a27; // WPLS

        basketTokens = [
            0x95B303987A60C71504D99Aa1b13B4DA07b0790ab, // PLSX
            0x2fa878Ab3F87CC1C9737Fc071108F904c0B0C95d, // INC
            0x2b591e99afE9f32eAA6214f7B7629768c40Eeb39, // HEX
            0x57fde0a71132198BBeC939B98976993d8D89D225, // eHEX
            0xb17D901469B9208B17d916112988A3FeD19b5cA1, // WBTC (bridged)
            0x02DcdD04e3F455D838cd1249292C58f3B79e3C3C  // WETH (bridged)
        ];
    }

    receive() external payable {}

    function deposit() external payable {
        uint256 amount = msg.value;
        require(amount > 0, "No PLS deposited");

        // Mint PINDEX 1:1 to user
        _mint(msg.sender, amount);

        uint256 seventyPercent = amount * 70 / 100;
        uint256 thirtyPercent = amount - seventyPercent;

        // Buy basket with 70% (hold 10% as PLS, swap 10% to each of 6 tokens)
        uint256 part = seventyPercent / 7;
        for (uint256 i = 0; i < basketTokens.length; i++) {
            address[] memory path = new address[](2);
            path[0] = wplsAddress;
            path[1] = basketTokens[i];
            IUniswapV2Router02(routerAddress).swapExactETHForTokens{value: part}(0, path, address(this), block.timestamp + 300);
        }
        // Remaining part (for PLS) is automatically held as contract balance

        // Thicken LP with 30%
        address factory = IUniswapV2Router02(routerAddress).factory();
        address pair = IUniswapV2Factory(factory).getPair(wplsAddress, address(this));

        uint256 reservePLS;
        uint256 reservePINDEX;
        bool isInitial = (pair == address(0));

        if (!isInitial) {
            (uint112 r0, uint112 r1,) = IUniswapV2Pair(pair).getReserves();
            address token0 = IUniswapV2Pair(pair).token0();
            reservePLS = (token0 == wplsAddress) ? r0 : r1;
            reservePINDEX = (token0 == wplsAddress) ? r1 : r0;
            if (reservePLS == 0 && reservePINDEX == 0) isInitial = true;
        }

        if (isInitial) {
            // Bootstrap LP at 1:1 price
            uint256 lpPindex = thirtyPercent;
            _mint(address(this), lpPindex);
            _approve(address(this), routerAddress, lpPindex);
            IUniswapV2Router02(routerAddress).addLiquidityETH{value: thirtyPercent}(
                address(this),
                lpPindex,
                0,
                0,
                address(0), // Burn LP tokens
                block.timestamp + 300
            );
        } else {
            // Approximate single-sided add (swap part to PINDEX, add balanced)
            uint256 amountToSwap = _calculateSwapAmount(reservePLS, reservePINDEX, thirtyPercent);
            if (amountToSwap > 0 && amountToSwap < thirtyPercent) {
                address[] memory path = new address[](2);
                path[0] = wplsAddress;
                path[1] = address(this);
                IUniswapV2Router02(routerAddress).swapExactETHForTokens{value: amountToSwap}(
                    0,
                    path,
                    address(this),
                    block.timestamp + 300
                );

                // Received PINDEX is now in contract balance
                uint256 received = balanceOf(address(this)); // All from swap since we minted none here
                uint256 remainingPLS = thirtyPercent - amountToSwap;
                _approve(address(this), routerAddress, received);
                IUniswapV2Router02(routerAddress).addLiquidityETH{value: remainingPLS}(
                    address(this),
                    received,
                    0,
                    0,
                    address(0), // Burn LP tokens
                    block.timestamp + 300
                );
            }
        }
    }

    function redeem(uint256 amount) external {
        require(amount > 0, "Zero amount");

        uint256 total = totalSupply();
        uint256 initialBalance = address(this).balance;
        uint256 plsShare = initialBalance * amount / total;

        for (uint256 i = 0; i < basketTokens.length; i++) {
            address token = basketTokens[i];
            uint256 tokenBal = IERC20(token).balanceOf(address(this));
            uint256 tokenShare = tokenBal * amount / total;
            if (tokenShare > 0) {
                IERC20(token).approve(routerAddress, tokenShare);
                address[] memory path = new address[](2);
                path[0] = token;
                path[1] = wplsAddress;
                IUniswapV2Router02(routerAddress).swapExactTokensForETH(tokenShare, 0, path, address(this), block.timestamp + 300);
            }
        }

        uint256 finalBalance = address(this).balance;
        uint256 addedFromSwaps = finalBalance - initialBalance;
        uint256 totalToSend = plsShare + addedFromSwaps;

        _burn(msg.sender, amount);
        payable(msg.sender).transfer(totalToSend);
    }

    function _calculateSwapAmount(uint256 reservePLS, uint256 reservePINDEX, uint256 amountIn) private pure returns (uint256) {
        uint256 fee = 997;
        uint256 num = amountIn * fee * reservePINDEX;
        uint256 den = reservePLS * 1000 + amountIn * fee;
        return num / den;
    }
}