Address
0xcdea894d3d4aeb3ddefedac777dd2a949d2ce4acCurrent Holdings
$0.00
TXs sent
not counted
First Active
2026-06-17
block 26,811,982
Last Active
91 days ago
block 26,812,001
Funded By
not identified
Net worth historyi
3 snapshots · to block 27,427,957coverage change 26 Augcoverage change 27 Augcoverage change 27 Augcoverage change 27 Augcoverage change 27 Aug
exact matchPulseArbsolc 0.8.20+commit.a1b79de6runtime exact · creation exact
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
/// @title PulseArb — Low-gas atomic DEX arbitrage for PulseChain
///
/// Key design decisions:
/// - Contract-funded: WPLS is held inside the contract and reused across arb cycles.
/// No per-TX transferFrom wallet or final transfer back — eliminates 2 ERC-20 ops per route.
/// - Direct pair-to-pair routing: WPLS is sent once to pair[0];
/// each pair's swap() sends output directly to the next pair.
/// - zeroForOne[] is pre-computed off-chain — no token0() calls on-chain.
/// - WPLS is the exclusive start/end token; hardcoded to save calldata.
/// - executeMultiArb isolates each route in a self-call. A stale/FOT route rolls
/// back only its own swaps while other routes in the batch can still execute.
interface IERC20 {
function transfer(address to, uint256 amount) external returns (bool);
function transferFrom(address from, address to, uint256 amount) external returns (bool);
function balanceOf(address account) external view returns (uint256);
}
interface IUniswapV2Pair {
function swap(uint256 amount0Out, uint256 amount1Out, address to, bytes calldata data) external;
function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
}
contract PulseArb {
address public immutable owner;
// WPLS is always the start and end token of every arb cycle.
IERC20 internal constant WPLS = IERC20(0xA1077a294dDE1B09bB078844df40758a5D0f9a27);
error NotOwner();
error OnlySelf();
error InvalidPath();
error QuoteInsufficientProfit(uint256 got, uint256 need);
error InsufficientProfit(uint256 got, uint256 need);
error TransferFailed();
error NoRoutesExecuted();
/// Emitted when an isolated batch route reverts.
event RouteFailed(uint256 indexed routeIdx, bytes4 selector, bytes32 reasonHash);
/// Emitted when a route executes successfully.
event RouteExecuted(uint256 indexed routeIdx, uint256 amountIn, uint256 amountOut, uint256 profit);
modifier onlyOwner() {
if (msg.sender != owner) revert NotOwner();
_;
}
modifier onlySelf() {
if (msg.sender != address(this)) revert OnlySelf();
_;
}
constructor() { owner = msg.sender; }
// =========================================================================
// Capital management — deposit / withdraw WPLS trading capital
// =========================================================================
/// @notice Deposit WPLS from owner wallet into contract as trading capital.
/// Requires prior WPLS.approve(address(this), amount) from the wallet.
function depositWPLS(uint256 amount) external onlyOwner {
if (!WPLS.transferFrom(msg.sender, address(this), amount)) revert TransferFailed();
}
/// @notice Withdraw WPLS from contract back to owner.
function withdrawWPLS(uint256 amount) external onlyOwner {
if (!WPLS.transfer(owner, amount)) revert TransferFailed();
}
// =========================================================================
// executeArb — single funded route, fast path
// =========================================================================
/// @notice Execute one WPLS arb cycle using contract-held WPLS.
///
/// Gas profile vs wallet-funded design (3-hop example):
/// Old: transferFrom(wallet→pair) + 3×swap + transfer(contract→wallet) = 5 ERC-20 ops
/// New: transfer(contract→pair) + 3×swap = 4 ERC-20 ops
/// Profit stays inside the contract — no gas for the final return transfer.
///
/// @param pairs UniswapV2 pairs in swap order.
/// @param zeroForOne true if tokenIn == token0 of that pair (pre-computed off-chain).
/// @param feeBps Swap fee in basis points per pair (e.g. 29 for PulseX).
/// @param amountIn WPLS amount to arb (must already be in contract balance).
/// @param minProfit Minimum WPLS profit required (reverts if not met).
function executeArb(
address[] calldata pairs,
bool[] calldata zeroForOne,
uint256[] calldata feeBps,
uint256 amountIn,
uint256 minProfit
) external onlyOwner {
uint256 amount = _executeRoute(pairs, zeroForOne, feeBps, amountIn, minProfit);
emit RouteExecuted(0, amountIn, amount, amount - amountIn);
}
// =========================================================================
// executeMultiArb — batch multiple routes in one TX
// =========================================================================
/// @notice Execute multiple WPLS arb cycles atomically using contract-held WPLS.
///
/// Each route executes in an external self-call so a route-level revert restores
/// its WPLS and pair state without reverting successful sibling routes.
function executeMultiArb(
address[][] calldata pairs,
bool[][] calldata zeroForOne,
uint256[][] calldata feeBps,
uint256[] calldata amountsIn,
uint256[] calldata minProfits
) external onlyOwner {
uint256 n = pairs.length;
if (
n == 0 ||
zeroForOne.length != n ||
feeBps.length != n ||
amountsIn.length != n ||
minProfits.length != n
) revert InvalidPath();
uint256 executed;
for (uint256 i = 0; i < n; ) {
try this.executeRouteIsolated(
pairs[i],
zeroForOne[i],
feeBps[i],
amountsIn[i],
minProfits[i]
) returns (uint256 amount) {
emit RouteExecuted(i, amountsIn[i], amount, amount - amountsIn[i]);
unchecked { ++executed; }
} catch (bytes memory reason) {
bytes4 selector;
if (reason.length >= 4) {
assembly {
selector := mload(add(reason, 32))
}
}
emit RouteFailed(i, selector, keccak256(reason));
}
unchecked { ++i; }
}
if (executed == 0) revert NoRoutesExecuted();
}
// =========================================================================
// Batch isolation entry point
// =========================================================================
/// @dev Callable only by this contract through `try this...catch`.
function executeRouteIsolated(
address[] calldata pairs,
bool[] calldata zeroForOne,
uint256[] calldata feeBps,
uint256 amountIn,
uint256 minProfit
) external onlySelf returns (uint256) {
return _executeRoute(pairs, zeroForOne, feeBps, amountIn, minProfit);
}
// =========================================================================
// Token rescue
// =========================================================================
function withdraw(address token, uint256 amount) external onlyOwner {
if (!IERC20(token).transfer(owner, amount)) revert TransferFailed();
}
function withdrawAll(address token) external onlyOwner {
uint256 bal = IERC20(token).balanceOf(address(this));
if (bal > 0 && !IERC20(token).transfer(owner, bal)) revert TransferFailed();
}
// =========================================================================
// Internal helpers
// =========================================================================
function _executeRoute(
address[] memory pairs,
bool[] memory zeroForOne,
uint256[] memory feeBps,
uint256 amountIn,
uint256 minProfit
) internal returns (uint256 amount) {
uint256 n = pairs.length;
if (
n == 0 ||
zeroForOne.length != n ||
feeBps.length != n ||
WPLS.balanceOf(address(this)) < amountIn
) revert InvalidPath();
uint256 quoted = _quote(pairs, zeroForOne, feeBps, amountIn);
if (quoted < amountIn + minProfit) {
revert QuoteInsufficientProfit(quoted > amountIn ? quoted - amountIn : 0, minProfit);
}
if (!WPLS.transfer(pairs[0], amountIn)) revert TransferFailed();
amount = amountIn;
unchecked {
for (uint256 i = 0; i < n; ++i) {
address to = i + 1 < n ? pairs[i + 1] : address(this);
(uint112 r0, uint112 r1,) = IUniswapV2Pair(pairs[i]).getReserves();
bool z1o = zeroForOne[i];
uint256 out = _getAmountOut(
amount,
z1o ? r0 : r1,
z1o ? r1 : r0,
feeBps[i]
);
IUniswapV2Pair(pairs[i]).swap(
z1o ? 0 : out,
z1o ? out : 0,
to,
""
);
amount = out;
}
}
if (amount < amountIn + minProfit) {
revert InsufficientProfit(amount > amountIn ? amount - amountIn : 0, minProfit);
}
}
function _quote(
address[] memory pairs,
bool[] memory zeroForOne,
uint256[] memory feeBps,
uint256 amountIn
) internal view returns (uint256 amount) {
amount = amountIn;
unchecked {
for (uint256 i = 0; i < pairs.length; ++i) {
(uint112 r0, uint112 r1,) = IUniswapV2Pair(pairs[i]).getReserves();
bool z1o = zeroForOne[i];
amount = _getAmountOut(amount, z1o ? r0 : r1, z1o ? r1 : r0, feeBps[i]);
}
}
}
/// @dev UniswapV2 constant-product formula. Returns 0 on bad inputs (no revert).
function _getAmountOut(
uint256 amIn,
uint256 rIn,
uint256 rOut,
uint256 fee
) internal pure returns (uint256) {
if (amIn == 0 || rIn == 0 || rOut == 0) return 0;
unchecked {
uint256 k = 10000 - fee;
uint256 inFee = amIn * k;
return (inFee * rOut) / (rIn * 10000 + inFee);
}
}
}