WJU 包装代币

WJU(Wrapped JU)是JuChain原生代币JU的ERC-20包装版本。由于AMM系统需要所有代币都遵循ERC-20标准,WJU合约提供了JU代币与ERC-20代币之间的无缝转换功能,使得JU代币能够参与JAMM DEX的所有交易活动。

合约实现

基本信息

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

WJU合约完全实现了ERC-20标准,具有以下特性:

  • 名称: "Wrapped JU"

  • 符号: "WJU"

  • 精度: 18位小数

  • 1:1兑换: 1 JU = 1 WJU

核心功能

包装功能(Deposit)

用户可以通过两种方式将JU代币包装为WJU:

方式1:直接发送JU

receive() external payable {
    deposit();
}

用户直接向WJU合约地址发送JU代币,合约会自动调用deposit()函数。

方式2:调用deposit函数

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

包装过程

  1. 用户发送JU代币到合约

  2. 合约增加用户的WJU余额

  3. 增加WJU总供应量

  4. 触发Deposit事件

解包装功能(Withdraw)

用户可以将WJU代币换回JU代币:

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

解包装过程

  1. 检查用户WJU余额是否足够

  2. 减少用户的WJU余额

  3. 向用户转账相应数量的JU代币

  4. 触发Withdrawal事件

ERC-20标准实现

转账功能

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

授权转账功能

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

授权功能

function approve(
    address spender,
    uint amount
) public override returns (bool) {
    allowance[msg.sender][spender] = amount;
    emit Approval(msg.sender, spender, amount);
    return true;
}

事件系统

Deposit事件

event Deposit(address indexed sender, uint amount);

记录JU代币包装为WJU的操作。

Withdrawal事件

event Withdrawal(address indexed sender, uint amount);

记录WJU代币解包装为JU的操作。

ERC-20标准事件

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

在JAMM DEX中的应用

Router集成

JAMMRouter合约与WJU深度集成,提供便捷的JU代币交易功能:

address public immutable override WJU;

constructor(address _factory, address _WJU) {
    factory = _factory;
    WJU = _WJU;
}

receive() external payable {
    assert(msg.sender == WJU); // 只接受来自WJU合约的ETH
}

JU代币交易

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

交易流程

  1. 用户发送JU代币

  2. Router将JU包装为WJU

  3. 将WJU转入交易对

  4. 执行交换逻辑

  5. 用户收到目标代币

卖出代币换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]);
}

交易流程

  1. 用户授权并转入代币

  2. 执行交换得到WJU

  3. Router将WJU解包装为JU

  4. 向用户转账JU代币

流动性管理

添加JU流动性

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);
    // 退还多余的JU
    if (msg.value > amountETH)
        TransferHelper.safeTransferETH(msg.sender, msg.value - amountETH);
}

移除JU流动性

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

使用示例

基本包装/解包装

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

// 包装JU为WJU
const depositTx = await wju.deposit({ value: ethers.utils.parseEther("1.0") });
await depositTx.wait();

// 或者直接发送JU到WJU合约地址
const directTx = await signer.sendTransaction({
    to: WJU_ADDRESS,
    value: ethers.utils.parseEther("1.0")
});
await directTx.wait();

// 解包装WJU为JU
const withdrawTx = await wju.withdraw(ethers.utils.parseEther("1.0"));
await withdrawTx.wait();

查询余额

// 查询WJU余额
const wjuBalance = await wju.balanceOf(userAddress);
console.log("WJU余额:", ethers.utils.formatEther(wjuBalance));

// 查询JU余额
const juBalance = await provider.getBalance(userAddress);
console.log("JU余额:", ethers.utils.formatEther(juBalance));

监听事件

// 监听包装事件
wju.on("Deposit", (sender, amount, event) => {
    console.log(`${sender} 包装了 ${ethers.utils.formatEther(amount)} JU`);
});

// 监听解包装事件
wju.on("Withdrawal", (sender, amount, event) => {
    console.log(`${sender} 解包装了 ${ethers.utils.formatEther(amount)} WJU`);
});

安全考虑

合约安全

  1. 简单设计: WJU合约逻辑简单,减少了安全风险

  2. 无管理员: 合约没有管理员功能,完全去中心化

  3. 1:1兑换: 严格的1:1兑换比例,无法被操纵

使用安全

  1. 余额检查: 所有操作都会检查余额是否足够

  2. 溢出保护: 使用Solidity 0.8.21的内置溢出保护

  3. 事件记录: 所有操作都有相应的事件记录

Last updated