Skip to content

Commit

Permalink
feat: Add source and destination portal ERC20s, and a minting and bur…
Browse files Browse the repository at this point in the history
…ning mechanism
  • Loading branch information
mgnfy-view committed Dec 29, 2024
1 parent fcbbe20 commit 383ee92
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 16 deletions.
11 changes: 5 additions & 6 deletions src/Portal.sol → src/DestinationPortal.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,15 @@ pragma solidity 0.8.24;
import { OFT } from "@layerzerolabs/oft-evm/contracts/OFT.sol";
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";

contract MyOFT is OFT {
contract DestinationPortal is OFT {
uint8 private constant DECIMALS = 6;

constructor(
string memory _name,
string memory _symbol,
address _lzEndpoint
address _lzEndpoint,
address _globalOwner
)
OFT(_name, _symbol, _lzEndpoint, _delegate)
Ownable(msg.sender)
OFT("Portal", "PORTAL", _lzEndpoint, _globalOwner)
Ownable(_globalOwner)
{ }

function decimals() public pure override returns (uint8) {
Expand Down
37 changes: 31 additions & 6 deletions src/MultiAssetVault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,23 @@ import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.s
import { IAssetRegistry } from "./interfaces/IAssetRegistry.sol";
import { IMultiAssetVault } from "./interfaces/IMultiAssetVault.sol";

import { IPortal } from "./interfaces/IPortal.sol";
import { IPythOracle } from "./interfaces/IPythOracle.sol";
import { ISourcePortal } from "./interfaces/ISourcePortal.sol";

contract MultiAssetVault is IMultiAssetVault {
using SafeERC20 for IERC20;

IAssetRegistry private immutable i_assetRegistry;
IPythOracle private immutable i_pythOracle;
IPortal private immutable i_portal;
ISourcePortal private immutable i_sourcePortal;
mapping(address user => mapping(address asset => Position position)) private s_positions;

constructor(address _assetRegistry, address _pythOracle) {
constructor(address _assetRegistry, address _pythOracle, address _sourcePortal) {
if (_assetRegistry == address(0) || _pythOracle == address(0)) revert MultiAssetVault__AddressZero();

i_assetRegistry = IAssetRegistry(_assetRegistry);
i_pythOracle = IPythOracle(_pythOracle);
i_sourcePortal = ISourcePortal(_sourcePortal);
}

function depositCollateral(address _asset, uint256 _amount, address _for) external {
Expand Down Expand Up @@ -55,9 +56,33 @@ contract MultiAssetVault is IMultiAssetVault {
emit AmountWithdrawn(msg.sender, _asset, _amount, _to);
}

function mint() external { }
function mint(address _asset, uint256 _amount, address _to) external {
_revertIfAssetNotWhitelisted(_asset);
if (_amount == 0) revert MultiAssetVault__AmountZero();
if (_to == address(0)) revert MultiAssetVault__AddressZero();

Position memory position = s_positions[msg.sender][_asset];
position.amountMinted += _amount;
s_positions[msg.sender][_asset] = position;

if (!_isPositionHealthy(_asset, position)) revert MultiAssetVault__MinimumCollateralisationRatioBreached();
i_sourcePortal.mint(_to, _amount);

emit PortalMinted(msg.sender, _asset, _amount, _to);
}

function burn() external { }
function burn(address _asset, uint256 _amount) external {
_revertIfAssetNotWhitelisted(_asset);
if (_amount == 0) revert MultiAssetVault__AmountZero();

Position memory position = s_positions[msg.sender][_asset];
position.amountMinted -= _amount;
s_positions[msg.sender][_asset] = position;

i_sourcePortal.burn(msg.sender, _amount);

emit PortalBurned(msg.sender, _asset, _amount);
}

function _revertIfAssetNotWhitelisted(address _asset) internal view {
if (!i_assetRegistry.isAssetWhitelisted(_asset)) revert MultiAssetVault__AssetNotWhitelisted(_asset);
Expand All @@ -75,7 +100,7 @@ contract MultiAssetVault is IMultiAssetVault {
function _getCollateralisationRatio(address _asset, Position memory _position) internal view returns (uint256) {
if (_position.amountMinted == 0) return type(uint256).max;
return _getDepositedAmountValueInUsd(_asset, _position.amountDeposited)
* 10 ** IERC20Metadata(address(i_portal)).decimals() / _position.amountMinted;
* 10 ** IERC20Metadata(address(i_sourcePortal)).decimals() / _position.amountMinted;
}

function _getDepositedAmountValueInUsd(address _asset, uint256 _depositedAmount) internal view returns (uint256) {
Expand Down
41 changes: 41 additions & 0 deletions src/SourcePortal.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

import { OFT } from "@layerzerolabs/oft-evm/contracts/OFT.sol";
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";

import { ISourcePortal } from "./interfaces/ISourcePortal.sol";

contract SourcePortal is OFT, ISourcePortal {
uint8 private constant DECIMALS = 6;

address private immutable i_multiAssetVault;

modifier onlyMultiAssetVault() {
if (msg.sender != i_multiAssetVault) revert SourcePortal__NotMultiAssetVault(msg.sender, i_multiAssetVault);
_;
}

constructor(
address _lzEndpoint,
address _globalOwner,
address _multiAssetVault
)
OFT("Portal", "PORTAL", _lzEndpoint, _globalOwner)
Ownable(_globalOwner)
{
i_multiAssetVault = _multiAssetVault;
}

function mint(address _to, uint256 _amount) external onlyMultiAssetVault {
_mint(_to, _amount);
}

function burn(address _to, uint256 _amount) external onlyMultiAssetVault {
_burn(_to, _amount);
}

function decimals() public pure override returns (uint8) {
return DECIMALS;
}
}
2 changes: 2 additions & 0 deletions src/interfaces/IMultiAssetVault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ interface IMultiAssetVault {

event AmountDeposited(address by, address indexed asset, uint256 indexed amount, address indexed onBehalfOf);
event AmountWithdrawn(address indexed by, address indexed asset, uint256 indexed amount, address to);
event PortalMinted(address indexed by, address indexed asset, uint256 indexed amount, address to);
event PortalBurned(address indexed by, address indexed asset, uint256 indexed amount);

error MultiAssetVault__AddressZero();
error MultiAssetVault__AssetNotWhitelisted(address asset);
Expand Down
4 changes: 0 additions & 4 deletions src/interfaces/IPortal.sol

This file was deleted.

10 changes: 10 additions & 0 deletions src/interfaces/ISourcePortal.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

interface ISourcePortal {
error SourcePortal__NotMultiAssetVault(address caller, address multiAssetVault);

function mint(address _to, uint256 _amount) external;

function burn(address _to, uint256 _amount) external;
}

0 comments on commit 383ee92

Please sign in to comment.