Skip to content

Commit

Permalink
(fix) Check that the remote token manager exists before trying to use…
Browse files Browse the repository at this point in the history
… it.
  • Loading branch information
rrw-zilliqa committed Dec 23, 2024
1 parent 92ad6aa commit bec51bf
Show file tree
Hide file tree
Showing 4 changed files with 484 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity ^0.8.20;

import {TokenManagerUpgradeableV3, ITokenManager} from "contracts/periphery/TokenManagerV4/TokenManagerUpgradeableV4.sol";
import {IERC20} from "contracts/periphery/LockAndReleaseTokenManagerUpgradeable.sol";
import {IRelayer, CallMetadata} from "contracts/core/Relayer.sol";

interface ILockAndReleaseOrNativeTokenManager {
event Locked(address indexed token, address indexed from, uint amount);
event Released(
address indexed token,
address indexed recipient,
uint amount
);
}

contract LockAndReleaseOrNativeTokenManagerUpgradeableV3 is
ILockAndReleaseOrNativeTokenManager,
TokenManagerUpgradeableV3
{
address public constant NATIVE_ASSET_HASH = address(0);

/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}

/// @dev Allow this contract to receive native tokens.
receive() external payable {}

// Outgoing
function _handleTransfer(
address token,
address from,
uint amount
) internal override {
if (token == NATIVE_ASSET_HASH) {
(bool success, ) = payable(this).call{ value: amount }("");
require(success, "Native asset transfer failed");
} else {
IERC20(token).transferFrom(from, address(this), amount);
}
emit Locked(token, from, amount);
}

// Incoming
function _handleAccept(
address token,
address recipient,
uint amount
) internal override {
if (token == NATIVE_ASSET_HASH) {
(bool success, ) = recipient.call{value: amount}("");
require(success, "Native asset transfer failed");
} else {
IERC20(token).transfer(recipient, amount);
}
emit Released(token, recipient, amount);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity ^0.8.20;

import {TokenManagerUpgradeableV4, ITokenManager} from "contracts/periphery/TokenManagerV3/TokenManagerUpgradeableV4.sol";
import {BridgedToken} from "contracts/periphery/BridgedToken.sol";
import {IERC20} from "contracts/periphery/LockAndReleaseTokenManagerUpgradeable.sol";
import { ILockProxyTokenManagerStorage, LockProxyTokenManagerStorage } from "contracts/periphery/LockProxyTokenManagerStorage.sol";
import { ILockProxyExtensionTransfer } from "contracts/periphery/ILockProxyExtensionTransfer.sol";

interface ILockProxyTokenManager is ILockProxyTokenManagerStorage {
// Args in this order to match other token managers.
event SentToLockProxy(address indexed token, address indexed sender, uint amount);
event WithdrawnFromLockProxy(address indexed token, address indexed receipient, uint amount);
}

// This is the lock proxy token manager that runs on EVM chains. It talks to an EVM LockProxy.
contract LockProxyTokenManagerUpgradeableV4 is TokenManagerUpgradeableV4, ILockProxyTokenManager, LockProxyTokenManagerStorage {
address public constant NATIVE_ASSET_HASH = address(0);

constructor() {
_disableInitializers();
}

function reinitialize(uint fees) external reinitializer(2) {
_setFees(fees);
}

// Incoming currency - transfer into the lock proxy (directly!)
function _handleTransfer(address token, address from, uint amount) internal override {
address lockProxyAddress = getLockProxy();
// Just transfer value to the lock proxy.
if (token == NATIVE_ASSET_HASH) {
(bool success, ) = lockProxyAddress.call{value: amount}("");
emit SentToLockProxy(token, from, amount);
require(success, "Transfer failed");
return;
}

IERC20 erc20token = IERC20(token);
erc20token.transferFrom(from, address(lockProxyAddress), amount);
emit SentToLockProxy(token, from, amount);
}

// Withdrawals are processed via the lockProxyProxy.
function _handleAccept(address token, address recipient, uint amount) internal override {
address lockProxyProxyAddress = getLockProxyProxy();
address lockProxyAddress = getLockProxy();
ILockProxyExtensionTransfer lp = ILockProxyExtensionTransfer(payable(lockProxyProxyAddress));
// Sadly, extensionTransfer() takes the same arguments as the withdrawn event but in a
// different order. This will automagically transfer native token if token==0.

// Native tokens are transferred by the call; for everyone else, it sets an allowance and we
// then do the transfer from here.
if (token == address(0)) {
lp.extensionTransfer(recipient, address(0), amount);
} else {
lp.extensionTransfer(address(this), token, amount);
IERC20 erc20token = IERC20(token);
// Although the lockProxyProxy is the registered extension, the tokens are held by the actual
// lockProxy
erc20token.transferFrom(lockProxyAddress, recipient, amount);
}
emit WithdrawnFromLockProxy(token, recipient, amount);
}

function setLockProxyData(address lockProxy, address lockProxyProxy) external onlyOwner {
_setLockProxyData(lockProxy, lockProxyProxy);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity ^0.8.20;

import {TokenManagerUpgradeableV4, ITokenManager} from "contracts/periphery/TokenManagerV3/TokenManagerUpgradeableV4.sol";
import {BridgedToken} from "contracts/periphery/BridgedToken.sol";

interface IMintAndBurnTokenManager {
event Minted(address indexed token, address indexed recipient, uint amount);
event Burned(address indexed token, address indexed from, uint amount);
event BridgedTokenDeployed(
address token,
address remoteToken,
address remoteTokenManager,
uint remoteChainId
);
}

contract MintAndBurnTokenManagerUpgradeableV3 is
IMintAndBurnTokenManager,
TokenManagerUpgradeableV3
{
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}

function deployToken(
string calldata name,
string calldata symbol,
uint8 decimals,
address remoteToken,
address tokenManager,
uint remoteChainId
) external returns (BridgedToken) {
return
_deployToken(
name,
symbol,
decimals,
remoteToken,
tokenManager,
remoteChainId
);
}

function deployToken(
string calldata name,
string calldata symbol,
address remoteToken,
address tokenManager,
uint remoteChainId
) external returns (BridgedToken) {
return
_deployToken(
name,
symbol,
18,
remoteToken,
tokenManager,
remoteChainId
);
}

function _deployToken(
string calldata name,
string calldata symbol,
uint8 decimals,
address remoteToken,
address tokenManager,
uint remoteChainId
) internal onlyOwner returns (BridgedToken) {
// TODO: deployed counterfactually
BridgedToken bridgedToken = new BridgedToken(name, symbol, decimals);
RemoteToken memory remoteTokenStruct = RemoteToken(
remoteToken,
tokenManager,
remoteChainId
);

_registerToken(address(bridgedToken), remoteTokenStruct);

emit BridgedTokenDeployed(
address(bridgedToken),
remoteToken,
tokenManager,
remoteChainId
);

return bridgedToken;
}

function transferTokenOwnership(
address localToken,
uint remoteChainId,
address newOwner
) external onlyOwner {
BridgedToken(localToken).transferOwnership(newOwner);
_removeToken(localToken, remoteChainId);
}

// Outgoing
function _handleTransfer(
address token,
address from,
uint amount
) internal override {
BridgedToken(token).burnFrom(from, amount);
emit Burned(token, from, amount);
}

// Incoming
function _handleAccept(
address token,
address recipient,
uint amount
) internal override {
BridgedToken(token).mint(recipient, amount);
emit Minted(token, recipient, amount);
}
}
Loading

0 comments on commit bec51bf

Please sign in to comment.