WYAM

0x7f3aecc694f298e0010f8a31ec49250506bb3b7c

Verification
Verified
v0.8.24+commit.e11b9ed9
Type
Contract
2,220 bytes
ABI entries
19
7 read · 5 write
License
none

Contract information

Address
0x7f3aecc694f298e0010f8a31ec49250506bb3b7c
Chain
Robinhood Chain (4663)
Compiler
v0.8.24+commit.e11b9ed9
Optimization
Enabled
Creation tx
0xd525dcd98c…cc8ab4a2eb

Token

Name
YAM
Symbol
YAM
Decimals
18
Holders
243

Read contract (7)

allowance(address, address)uint256
balanceOf(address)uint256
decimals()uint8
name()string
symbol()string
totalSupply()uint256
yam()address

Events (4)

ApprovalTransferUnwrapWrap

ABI

[
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "_yam",
        "type": "address"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "constructor"
  },
  {
    "inputs": [],
    "name": "InsufficientAllowance",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "InsufficientBalance",
    "type": "error"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "owner",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "spender",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "value",
        "type": "uint256"
      }
    ],
    "name": "Approval",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "from",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "to",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "value",
        "type": "uint256"
      }
    ],
    "name": "Transfer",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "user",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "wyamIn",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "yamOut",
        "type": "uint256"
      }
    ],
    "name": "Unwrap",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "user",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "yamIn",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "wyamOut",
        "type": "uint256"
      }
    ],
    "name": "Wrap",
    "type": "event"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "name": "allowance",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "spender",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "amount",
        "type": "uint256"
      }
    ],
    "name": "approve",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "name": "balanceOf",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "decimals",
    "outputs": [
      {
        "internalType": "uint8",
        "name": "",
        "type": "uint8"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "name",
    "outputs": [
      {
        "internalType": "string",
        "name": "",
        "type": "string"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "symbol",
    "outputs": [
      {
        "internalType": "string",
        "name": "",
        "type": "string"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "totalSupply",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "to",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "amount",
        "type": "uint256"
      }
    ],
    "name": "transfer",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "from",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "to",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "amount",
        "type": "uint256"
      }
    ],
    "name": "transferFrom",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "wyamAmount",
        "type": "uint256"
      }
    ],
    "name": "unwrap",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "yamAmount",
        "type": "uint256"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "yamAmount",
        "type": "uint256"
      }
    ],
    "name": "wrap",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "wyamAmount",
        "type": "uint256"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "yam",
    "outputs": [
      {
        "internalType": "contract IYAM",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  }
]

Source code

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

/// @notice Minimal ERC20 interface for YAM.
interface IYAM {
    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);
    function toInternal(uint256 effectiveAmount) external view returns (uint256);
    function toEffective(uint256 internalAmount) external view returns (uint256);
    function scalingFactor() external view returns (uint256);
    function internalBalanceOf(address account) external view returns (uint256);
}

/// @title WYAM — non-rebasing wrapper around YAM
/// @notice Sushi V3 (and most DEX/lending) can't handle rebasing tokens because pool
///         accounting reads balanceOf; a rebase would silently change the pool's YAM balance.
///         WYAM tracks internal (pre-scalingFactor) units. 1 WYAM at deploy = 1 YAM at deploy.
///         As scalingFactor grows, redeeming WYAM returns MORE YAM.
///
///         Wrap: send N YAM → mint N * BASE / scalingFactor WYAM
///         Unwrap: burn N WYAM → send N * scalingFactor / BASE YAM
contract WYAM {
    // NOTE: filename is WYAM.sol for repo consistency, but SYMBOL is "YAM".
    // This is the static, DEX-facing token — what Sushi pools hold and wallets show.
    // YAM.sol (rebasing) has symbol "sYAM". Users buy YAM (this), convert to sYAM for rebase.
    string public constant name = "YAM";
    string public constant symbol = "YAM";
    uint8 public constant decimals = 18;

    IYAM public immutable yam;
    uint256 public totalSupply;
    mapping(address => uint256) public balanceOf;
    mapping(address => mapping(address => uint256)) public allowance;

    event Transfer(address indexed from, address indexed to, uint256 value);
    event Approval(address indexed owner, address indexed spender, uint256 value);
    event Wrap(address indexed user, uint256 yamIn, uint256 wyamOut);
    event Unwrap(address indexed user, uint256 wyamIn, uint256 yamOut);

    error InsufficientBalance();
    error InsufficientAllowance();

    constructor(address _yam) {
        yam = IYAM(_yam);
    }

    /// @notice Wrap YAM into WYAM. Pulls `yamAmount` from caller.
    function wrap(uint256 yamAmount) external returns (uint256 wyamAmount) {
        // Take YAM from user first, then measure delta in internal units
        uint256 before = yam.internalBalanceOf(address(this));
        yam.transferFrom(msg.sender, address(this), yamAmount);
        uint256 delta = yam.internalBalanceOf(address(this)) - before;
        wyamAmount = delta; // 1 WYAM = 1 internal YAM unit
        balanceOf[msg.sender] += wyamAmount;
        totalSupply += wyamAmount;
        emit Transfer(address(0), msg.sender, wyamAmount);
        emit Wrap(msg.sender, yamAmount, wyamAmount);
    }

    /// @notice Unwrap WYAM into YAM. Burns `wyamAmount` from caller.
    function unwrap(uint256 wyamAmount) external returns (uint256 yamAmount) {
        if (balanceOf[msg.sender] < wyamAmount) revert InsufficientBalance();
        unchecked { balanceOf[msg.sender] -= wyamAmount; }
        totalSupply -= wyamAmount;
        yamAmount = yam.toEffective(wyamAmount);
        yam.transfer(msg.sender, yamAmount);
        emit Transfer(msg.sender, address(0), wyamAmount);
        emit Unwrap(msg.sender, wyamAmount, yamAmount);
    }

    // ─── ERC20 core ─────────────────────────────────────────────────────

    function transfer(address to, uint256 amount) external returns (bool) {
        if (balanceOf[msg.sender] < amount) revert InsufficientBalance();
        unchecked { balanceOf[msg.sender] -= amount; }
        balanceOf[to] += amount;
        emit Transfer(msg.sender, to, amount);
        return true;
    }

    function transferFrom(address from, address to, uint256 amount) external returns (bool) {
        uint256 current = allowance[from][msg.sender];
        if (current < amount) revert InsufficientAllowance();
        if (current != type(uint256).max) allowance[from][msg.sender] = current - amount;
        if (balanceOf[from] < amount) revert InsufficientBalance();
        unchecked { balanceOf[from] -= amount; }
        balanceOf[to] += amount;
        emit Transfer(from, to, amount);
        return true;
    }

    function approve(address spender, uint256 amount) external returns (bool) {
        allowance[msg.sender][spender] = amount;
        emit Approval(msg.sender, spender, amount);
        return true;
    }
}
Chain explorer4313msChain node74ms