ETH Price: $1,965.44 (-0.77%)

Contract Diff Checker

Contract Name:
LTMigrator

Contract Source Code:

File 1 of 1 : contracts/LTMigrator.vy

{{
  "language": "Vyper",
  "sources": {
    "contracts/LTMigrator.vy": {
      "content": "# @version 0.4.3\n\"\"\"\n@title LTMigrator\n@notice Migration zap from one version of vault to another\n@author Scientia Spectra AG\n@license Copyright (c) 2025\n\"\"\"\nfrom ethereum.ercs import IERC20\n\n\ninterface MFOwner:\n    def lt_allocate_stablecoins(lt: LT, limit: uint256): nonpayable\n    def lt_in_factory(lt: LT) -> bool: view\n\ninterface Cryptopool:\n    def balances(i: uint256) -> uint256: view\n\ninterface Gauge:\n    def deposit(assets: uint256, receiver: address) -> uint256: nonpayable\n    def redeem(shares: uint256, receiver: address, owner: address) -> uint256: nonpayable\n    def previewDeposit(assets: uint256) -> uint256: view\n    def previewRedeem(shares: uint256) -> uint256: view\n\ninterface AMM:\n    def collect_fees() -> uint256: nonpayable\n\ninterface LT:\n    def deposit(assets: uint256, debt: uint256, min_shares: uint256, receiver: address) -> uint256: nonpayable\n    def withdraw(shares: uint256, min_assets: uint256) -> uint256: nonpayable\n    def balanceOf(user: address) -> uint256: view\n    def approve(_to: address, _amount: uint256) -> bool: nonpayable\n    def allowance(_from: address, _to: address) -> uint256: view\n    def transferFrom(_from: address, _to: address, _amount: uint256) -> bool: nonpayable\n    def ASSET_TOKEN() -> IERC20: view\n    def amm() -> AMM: view\n    def allocate_stablecoins(): nonpayable\n    def CRYPTOPOOL() -> Cryptopool: view\n    def preview_emergency_withdraw(shares: uint256) -> (uint256, int256): view\n    def preview_deposit(assets: uint256, debt: uint256, raise_overflow: bool) -> uint256: view\n    def preview_withdraw(tokens: uint256) -> uint256: view\n    def staker() -> Gauge: view\n\n\nSTABLECOIN: public(immutable(IERC20))\nFACTORY_OWNER: public(immutable(MFOwner))\n\n\n@deploy\ndef __init__(stablecoin: IERC20, factory_owner: MFOwner):\n    STABLECOIN = stablecoin\n    FACTORY_OWNER = factory_owner\n\n\n@internal\n@view\ndef _preview_migrate_plain(lt_from: LT, lt_to: LT, shares_in: uint256, debt_coefficient: uint256) -> uint256:\n    cpool: Cryptopool = staticcall lt_from.CRYPTOPOOL()\n    cpool_stables: uint256 = staticcall cpool.balances(0)\n    cpool_assets: uint256 = staticcall cpool.balances(1)\n\n    eassets: uint256 = (staticcall lt_from.preview_emergency_withdraw(shares_in))[0]\n    debt: uint256 = cpool_stables * eassets // cpool_assets\n\n    assets: uint256 = staticcall lt_from.preview_withdraw(shares_in)\n\n    return staticcall lt_to.preview_deposit(assets, debt * debt_coefficient // 10**18, False)\n\n\n@external\n@view\ndef preview_migrate_plain(lt_from: LT, lt_to: LT, shares_in: uint256, debt_coefficient: uint256 = 10**18) -> uint256:\n    return self._preview_migrate_plain(lt_from, lt_to, shares_in, debt_coefficient)\n\n\n@external\n@view\ndef preview_migrate_staked(lt_from: LT, lt_to: LT, shares_in: uint256, debt_coefficient: uint256 = 10**18) -> uint256:\n    gauge_from: Gauge = staticcall lt_from.staker()\n    gauge_to: Gauge = staticcall lt_to.staker()\n    lt_in: uint256 = staticcall gauge_from.previewRedeem(shares_in)\n    lt_out: uint256 = self._preview_migrate_plain(lt_from, lt_to, lt_in, debt_coefficient)\n    return staticcall gauge_to.previewDeposit(lt_out)\n\n\n@internal\ndef _migrate_plain(lt_from: LT, lt_to: LT, shares_in: uint256, min_out: uint256, debt_coefficient: uint256,\n                   _for: address) -> uint256:\n    # Check that LTs are in the factory\n    assert staticcall FACTORY_OWNER.lt_in_factory(lt_from)\n    assert staticcall FACTORY_OWNER.lt_in_factory(lt_to)\n\n    # Prepare asset approvals (e.g. WBTC etc)\n    asset: IERC20 = staticcall lt_from.ASSET_TOKEN()\n    if staticcall asset.allowance(self, lt_to.address) == 0:\n        extcall asset.approve(lt_to.address, max_value(uint256))\n    amm: AMM = staticcall lt_from.amm()\n\n    # Explicitly collect fees to cryptopool so that they don't screw our measurements\n    extcall amm.collect_fees()\n\n    # Withdraw from LT\n    debt: uint256 = staticcall STABLECOIN.balanceOf(amm.address)\n    assets: uint256 = extcall lt_from.withdraw(shares_in, 0)\n    debt = (staticcall STABLECOIN.balanceOf(amm.address)) - debt\n\n    # Now we freed up some stablecoins in the AMM\n    extcall FACTORY_OWNER.lt_allocate_stablecoins(lt_from, 0)  # Take what freed up from old allocation\n    extcall lt_to.allocate_stablecoins()  # Give these coins to the new AMM\n\n    debt = debt * debt_coefficient // 10**18\n\n    return extcall lt_to.deposit(assets, debt, min_out, _for)\n\n\n@external\ndef migrate_plain(lt_from: LT, lt_to: LT, shares_in: uint256, min_out: uint256,\n                  debt_coefficient: uint256 = 10**18):\n    extcall lt_from.transferFrom(msg.sender, self, shares_in)\n    self._migrate_plain(lt_from, lt_to, shares_in, min_out, debt_coefficient, msg.sender)\n\n\n@external\ndef migrate_staked(lt_from: LT, lt_to: LT, shares_in: uint256, min_out: uint256,\n                   debt_coefficient: uint256 = 10**18):\n    gauge_from: Gauge = staticcall lt_from.staker()\n    gauge_to: Gauge = staticcall lt_to.staker()\n\n    if staticcall lt_to.allowance(self, gauge_to.address) == 0:\n        extcall lt_to.approve(gauge_to.address, max_value(uint256))\n\n    lt_in: uint256 = extcall gauge_from.redeem(shares_in, self, msg.sender)\n    lt_out: uint256 = self._migrate_plain(lt_from, lt_to, lt_in, 0, debt_coefficient, self)\n    shares_out: uint256 = extcall gauge_to.deposit(lt_out, msg.sender)\n    assert shares_out >= min_out, \"not enough out\"\n",
      "sha256sum": "97383bc7ee787907b5ee67821dca038cc06a6c0aa50a4f2c41d2a7f82485e4ed"
    }
  },
  "settings": {
    "outputSelection": {
      "contracts/LTMigrator.vy": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "abi"
      ]
    },
    "search_paths": [
      "."
    ]
  },
  "compiler_version": "v0.4.3+commit.bff19ea2",
  "integrity": "89912c45489c2e42b0a98726bfbfdf996808472a91eacba14d5163478132932b"
}}

Please enter a contract address above to load the contract details and source code.

Context size (optional):