WJU Wrapped Token
Overview
WJU (Wrapped JU) is the ERC-20 wrapped version of JuChain's native token JU. Since AMM systems require all tokens to follow the ERC-20 standard, the WJU contract provides seamless conversion functionality between JU tokens and ERC-20 tokens, enabling JU tokens to participate in all JAMM DEX trading activities.
Contract Implementation
Basic Information
contract WJU is IWJU {
string public constant override name = "Wrapped JU";
string public constant override symbol = "WJU";
uint8 public constant override decimals = 18;
uint public override totalSupply;
mapping(address => uint) public override balanceOf;
mapping(address => mapping(address => uint)) public override allowance;
}
The WJU contract fully implements the ERC-20 standard with the following characteristics:
Name: "Wrapped JU"
Symbol: "WJU"
Decimals: 18 decimal places
1:1 Exchange: 1 JU = 1 WJU
Core Functions
Wrapping Function (Deposit)
Users can wrap JU tokens into WJU through two methods:
Method 1: Direct JU Transfer
receive() external payable {
deposit();
}
Users directly send JU tokens to the WJU contract address, and the contract automatically calls the deposit()
function.
Method 2: Call deposit Function
function deposit() public payable override {
balanceOf[msg.sender] += msg.value;
totalSupply += msg.value;
emit Deposit(msg.sender, msg.value);
}
Wrapping Process:
User sends JU tokens to the contract
Contract increases user's WJU balance
Increases WJU total supply
Triggers Deposit event
Unwrapping Function (Withdraw)
Users can convert WJU tokens back to JU tokens:
function withdraw(uint amount) public override {
require(balanceOf[msg.sender] >= amount);
balanceOf[msg.sender] -= amount;
payable(msg.sender).transfer(amount);
emit Withdrawal(msg.sender, amount);
}
Unwrapping Process:
Check if user has sufficient WJU balance
Decrease user's WJU balance
Transfer corresponding amount of JU tokens to user
Trigger Withdrawal event
ERC-20 Standard Implementation
Transfer Function
function transfer(address to, uint amount) public override returns (bool) {
require(balanceOf[msg.sender] >= amount, "WJU: INSUFFICIENT_BALANCE");
balanceOf[msg.sender] -= amount;
balanceOf[to] += amount;
emit Transfer(msg.sender, to, amount);
return true;
}
Authorized Transfer Function
function transferFrom(
address from,
address to,
uint amount
) public override returns (bool) {
require(
allowance[from][msg.sender] >= amount,
"WJU: INSUFFICIENT_ALLOWANCE"
);
require(balanceOf[from] >= amount, "WJU: INSUFFICIENT_BALANCE");
allowance[from][msg.sender] -= amount;
balanceOf[from] -= amount;
balanceOf[to] += amount;
emit Transfer(from, to, amount);
return true;
}
Approval Function
function approve(
address spender,
uint amount
) public override returns (bool) {
allowance[msg.sender][spender] = amount;
emit Approval(msg.sender, spender, amount);
return true;
}
Event System
Deposit Event
event Deposit(address indexed sender, uint amount);
Records JU token wrapping into WJU operations.
Withdrawal Event
event Withdrawal(address indexed sender, uint amount);
Records WJU token unwrapping into JU operations.
ERC-20 Standard Events
event Transfer(address indexed from, address indexed to, uint value);
event Approval(address indexed owner, address indexed spender, uint value);
Application in JAMM DEX
Router Integration
The JAMMRouter contract is deeply integrated with WJU, providing convenient JU token trading functionality:
address public immutable override WJU;
constructor(address _factory, address _WJU) {
factory = _factory;
WJU = _WJU;
}
receive() external payable {
assert(msg.sender == WJU); // only accept ETH from WJU contract
}
JU Token Trading
Buy Tokens with JU
function swapExactETHForTokens(
uint amountOutMin,
address[] calldata path,
uint24[] calldata fees,
address to,
address referrer,
uint deadline
) external payable virtual override ensure(deadline) returns (uint[] memory amounts) {
require(path[0] == WJU, "JAMMRouter: INVALID_PATH");
amounts = JAMMLibrary.getAmountsOut(factory, msg.value, path, fees);
require(
amounts[amounts.length - 1] >= amountOutMin,
"JAMMRouter: INSUFFICIENT_OUTPUT_AMOUNT"
);
IWJU(WJU).deposit{value: amounts[0]}();
assert(
IWJU(WJU).transfer(
JAMMLibrary.pairFor(factory, path[0], path[1], fees[0]),
amounts[0]
)
);
_swap(amounts, path, fees, to, referrer);
}
Trading Flow:
User sends JU tokens
Router wraps JU into WJU
Transfer WJU to trading pair
Execute swap logic
User receives target tokens
Sell Tokens for JU
function swapExactTokensForETH(
uint amountIn,
uint amountOutMin,
address[] calldata path,
uint24[] calldata fees,
address to,
address referrer,
uint deadline
) external virtual override ensure(deadline) returns (uint[] memory amounts) {
require(path[path.length - 1] == WJU, "JAMMRouter: INVALID_PATH");
amounts = JAMMLibrary.getAmountsOut(factory, amountIn, path, fees);
require(
amounts[amounts.length - 1] >= amountOutMin,
"JAMMRouter: INSUFFICIENT_OUTPUT_AMOUNT"
);
TransferHelper.safeTransferFrom(
path[0],
msg.sender,
JAMMLibrary.pairFor(factory, path[0], path[1], fees[0]),
amounts[0]
);
_swap(amounts, path, fees, address(this), referrer);
IWJU(WJU).withdraw(amounts[amounts.length - 1]);
TransferHelper.safeTransferETH(to, amounts[amounts.length - 1]);
}
Trading Flow:
User approves and transfers tokens
Execute swap to get WJU
Router unwraps WJU into JU
Transfer JU tokens to user
Liquidity Management
Add JU Liquidity
function addLiquidityETH(
address token,
uint24 fee,
uint amountTokenDesired,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) external payable virtual override ensure(deadline) returns (uint amountToken, uint amountETH, uint liquidity) {
(amountToken, amountETH) = _addLiquidity(
token,
WJU,
fee,
amountTokenDesired,
msg.value,
amountTokenMin,
amountETHMin
);
address pair = JAMMLibrary.pairFor(factory, token, WJU, fee);
TransferHelper.safeTransferFrom(token, msg.sender, pair, amountToken);
IWJU(WJU).deposit{value: amountETH}();
assert(IWJU(WJU).transfer(pair, amountETH));
liquidity = IJAMMPair(pair).mint(to);
// refund excess JU
if (msg.value > amountETH)
TransferHelper.safeTransferETH(msg.sender, msg.value - amountETH);
}
Remove JU Liquidity
function removeLiquidityETH(
address token,
uint24 fee,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) public virtual override ensure(deadline) returns (uint amountToken, uint amountETH) {
(amountToken, amountETH) = removeLiquidity(
token,
WJU,
fee,
liquidity,
amountTokenMin,
amountETHMin,
address(this),
deadline
);
TransferHelper.safeTransfer(token, to, amountToken);
IWJU(WJU).withdraw(amountETH);
TransferHelper.safeTransferETH(to, amountETH);
}
Usage Examples
Basic Wrapping/Unwrapping
const wju = new ethers.Contract(WJU_ADDRESS, wjuABI, signer);
// Wrap JU to WJU
const depositTx = await wju.deposit({ value: ethers.utils.parseEther("1.0") });
await depositTx.wait();
// Or directly send JU to WJU contract address
const directTx = await signer.sendTransaction({
to: WJU_ADDRESS,
value: ethers.utils.parseEther("1.0")
});
await directTx.wait();
// Unwrap WJU to JU
const withdrawTx = await wju.withdraw(ethers.utils.parseEther("1.0"));
await withdrawTx.wait();
Query Balances
// Query WJU balance
const wjuBalance = await wju.balanceOf(userAddress);
console.log("WJU Balance:", ethers.utils.formatEther(wjuBalance));
// Query JU balance
const juBalance = await provider.getBalance(userAddress);
console.log("JU Balance:", ethers.utils.formatEther(juBalance));
Listen to Events
// Listen to wrapping events
wju.on("Deposit", (sender, amount, event) => {
console.log(`${sender} wrapped ${ethers.utils.formatEther(amount)} JU`);
});
// Listen to unwrapping events
wju.on("Withdrawal", (sender, amount, event) => {
console.log(`${sender} unwrapped ${ethers.utils.formatEther(amount)} WJU`);
});
Security Considerations
Contract Security
Simple Design: WJU contract logic is simple, reducing security risks
No Admin: Contract has no admin functions, completely decentralized
1:1 Exchange: Strict 1:1 exchange ratio that cannot be manipulated
Usage Security
Balance Checks: All operations check if balance is sufficient
Overflow Protection: Uses Solidity 0.8.21's built-in overflow protection
Event Logging: All operations have corresponding event records
Best Practices
For Users
Timely Unwrapping: If not needed for DEX use, promptly unwrap WJU to JU
Balance Management: Maintain appropriate WJU balance for trading
Gas Optimization: Batch operations to save gas fees
For Developers
Path Validation: In JU-related trades, ensure path correctly includes WJU
Balance Display: Show both JU and WJU balances in UI
Auto Wrapping: Provide automatic wrapping/unwrapping functionality for users
Summary
WJU wrapped token is an important component of the JAMM DEX ecosystem:
Seamless Integration: Enables JU tokens to participate in all DEX functions
1:1 Exchange: Guarantees complete value parity
Automation: Router contract automatically handles wrapping/unwrapping
Standard Compliance: Fully compliant with ERC-20 standard
Decentralization: No need to trust third parties, completely managed by smart contracts
The existence of WJU enables JuChain users to conveniently use native tokens to participate in DeFi activities. In the next section, we will explore LP Token Mechanisms.