WJU Contract

Overview

WJU (Wrapped JU) is the ERC-20 wrapped version of JuChain's native token JU. As an important component of the JAMM DEX ecosystem, WJU enables JU tokens to seamlessly participate in all DeFi activities. The WJU contract is designed to be simple and secure, providing 1:1 bidirectional exchange functionality.

Contract 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;
}

Token Information:

  • Name: "Wrapped JU"

  • Symbol: "WJU"

  • Decimals: 18 decimal places (same as JU)

  • Exchange Rate: 1 JU = 1 WJU

Core Functions

Wrapping Function (Deposit)

Direct JU Transfer

receive() external payable {
    deposit();
}

Users can directly send JU tokens to the WJU contract address, and the contract will automatically call the deposit() function for wrapping.

Active Wrapping Call

function deposit() public payable override {
    balanceOf[msg.sender] += msg.value;
    totalSupply += msg.value;
    emit Deposit(msg.sender, msg.value);
}

Wrapping Process:

  1. Receive JU tokens sent by user

  2. Increase user's WJU balance

  3. Increase WJU total supply

  4. Emit Deposit event

Features:

  • 1:1 exchange rate

  • Instant execution

  • No fees

  • No minimum/maximum limits

Unwrapping Function (Withdraw)

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:

  1. Check if user has sufficient WJU balance

  2. Decrease user's WJU balance

  3. Transfer corresponding amount of JU tokens to user

  4. Emit Withdrawal event

Security Checks:

  • Balance sufficiency check

  • Uses Solidity 0.8.21's built-in overflow protection

  • Safe ETH transfer

ERC-20 Standard Implementation

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;
}

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;
}

Security Features:

  • Balance sufficiency check

  • Custom error messages

  • Standard event emission

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;
}

Double Checks:

  • Allowance amount check

  • Balance sufficiency check

  • Automatic allowance reduction

Event System

Deposit Event

event Deposit(address indexed sender, uint amount);

Records JU token wrapping to WJU operations, containing:

  • sender: Initiator of wrapping operation

  • amount: Amount wrapped

Withdrawal Event

event Withdrawal(address indexed sender, uint amount);

Records WJU token unwrapping to JU operations, containing:

  • sender: Initiator of unwrapping operation

  • amount: Amount unwrapped

ERC-20 Standard Events

event Transfer(address indexed from, address indexed to, uint value);
event Approval(address indexed owner, address indexed spender, uint value);

Integration in JAMM DEX

Router Integration

JAMMRouter contract deeply integrates WJU 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
}

Automatic Wrapping/Unwrapping

Router automatically performs wrapping/unwrapping when handling JU-related transactions:

Automatic Wrapping in Swaps

// Internal process when user calls swapExactETHForTokens
function swapExactETHForTokens(...) external payable {
    // 1. Wrap received JU to WJU
    IWJU(WJU).deposit{value: amounts[0]}();
    
    // 2. Transfer WJU to trading pair
    assert(IWJU(WJU).transfer(pairAddress, amounts[0]));
    
    // 3. Execute swap
    _swap(amounts, path, fees, to, referrer);
}

Automatic Unwrapping in Swaps

// Internal process when user calls swapExactTokensForETH
function swapExactTokensForETH(...) external {
    // 1. Execute swap to get WJU
    _swap(amounts, path, fees, address(this), referrer);
    
    // 2. Unwrap WJU to JU
    IWJU(WJU).withdraw(amounts[amounts.length - 1]);
    
    // 3. Transfer JU to user
    TransferHelper.safeTransferETH(to, amounts[amounts.length - 1]);
}

Usage Examples

Basic Wrapping/Unwrapping Operations

const wju = new ethers.Contract(WJU_ADDRESS, wjuABI, signer);

// Method 1: Call deposit function for wrapping
const depositTx = await wju.deposit({ 
    value: ethers.utils.parseEther("1.0") 
});
await depositTx.wait();
console.log("Wrapping successful");

// Method 2: Directly send JU to WJU contract
const directTx = await signer.sendTransaction({
    to: WJU_ADDRESS,
    value: ethers.utils.parseEther("1.0")
});
await directTx.wait();
console.log("Direct wrapping successful");

// Unwrap WJU to JU
const withdrawTx = await wju.withdraw(ethers.utils.parseEther("1.0"));
await withdrawTx.wait();
console.log("Unwrapping successful");

Balance Queries

// 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));

// Query WJU total supply
const totalSupply = await wju.totalSupply();
console.log("WJU Total Supply:", ethers.utils.formatEther(totalSupply));

ERC-20 Operations

// Approve
const approveTx = await wju.approve(spenderAddress, ethers.utils.parseEther("10"));
await approveTx.wait();

// Transfer
const transferTx = await wju.transfer(recipientAddress, ethers.utils.parseEther("1"));
await transferTx.wait();

// Query allowance
const allowance = await wju.allowance(ownerAddress, spenderAddress);
console.log("Allowance:", ethers.utils.formatEther(allowance));

Event Listening

// Listen to wrapping events
wju.on("Deposit", (sender, amount) => {
    console.log(`${sender} wrapped ${ethers.utils.formatEther(amount)} JU`);
});

// Listen to unwrapping events
wju.on("Withdrawal", (sender, amount) => {
    console.log(`${sender} unwrapped ${ethers.utils.formatEther(amount)} WJU`);
});

// Listen to transfer events
wju.on("Transfer", (from, to, value) => {
    console.log(`Transfer: ${from} -> ${to}, Amount: ${ethers.utils.formatEther(value)}`);
});

Batch Operations

// Batch wrap JU for multiple users
async function batchWrap(users, amounts) {
    const promises = users.map((user, index) => {
        const userSigner = new ethers.Wallet(user.privateKey, provider);
        const userWJU = wju.connect(userSigner);
        return userWJU.deposit({ value: amounts[index] });
    });
    
    const results = await Promise.all(promises);
    console.log("Batch wrapping completed");
    return results;
}

Last updated