Kingdomswap Rug Pull
What happened
Kingdomswap's MasterKingdom contract (0xFDF9cAE8…2747bd on BNB Smart Chain) is a MasterChef-style farm that pays CROWN rewards for staked LP tokens and has an owner-only deposit-fee setter. set() writes depositFeeBP with no upper bound, and deposit() sends that share of every deposit to feeAddress. At 10000 basis points the entire deposit goes to feeAddress and the depositor is credited zero.
The owner also controls a launch-date gate that blocks deposit, withdraw, enterStaking and leaveStaking for everyone else while the date is in the future. De.Fi's REKT database lists Kingdomswap as an exit scam/rugpull dated 2021-08-25 with no loss figure or description; the source code alone does not show which of these powers, if any, was used.
How it happened
These steps describe what the code allows, not a recorded sequence of transactions.
- A user stakes an LP token with
deposit(_pid, _amount), which pulls the tokens in withpool.lpToken.safeTransferFrom(address(msg.sender), address(this), _amount);. - The owner can call
set(_pid, _allocPoint, _depositFeeBP, _withUpdate), which doespoolInfo[_pid].depositFeeBP = _depositFeeBP;. Unlikeadd(), which requires_depositFeeBP <= 10000,set()has no check at all. - With a fee of 10000,
deposit()computesuint256 depositFee = _amount.mul(pool.depositFeeBP).div(10000);, sends it withpool.lpToken.safeTransfer(feeAddress, depositFee);and creditsuser.amount = user.amount.add(_amount).sub(depositFee);, which is zero. The whole deposit goes tofeeAddressand the depositor has nothing to withdraw. Values above 10000 make the subtraction underflow and the deposit revert. setLaunchDate()isonlyOwnerand only requireslaunchDate < now. Every user-facing function carriesonlyOwnerOrLaunched, which requiresowner() == _msgSender() || (now > launchDate && launchDate > 0). Once a launch date has passed, the owner can set a new future date and non-owner calls todeposit,withdraw,enterStakingandleaveStakingrevert until it arrives.emergencyWithdraw(uint256 _pid)has noonlyOwnerOrLaunchedmodifier and returnsuser.amountof staked LP tokens, so principal that was credited stays reachable through it even while the launch gate blocks the other functions. It forfeits pending rewards.- Reward emission is also owner-tunable:
updateMultiplierAtDate(uint256 multiplierNumber, uint256 date)accepts any multiplier, andupdatePool()mintscrown.mint(devaddr, crownReward.div(10));pluscrown.mint(address(serf), crownReward);scaled by it.
Protocol details
Build your security review skills
Work through hands-on labs covering real exploit mechanics, review techniques, and defensive patterns.