Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
Benjimmutable committed Nov 1, 2023
1 parent 57cb487 commit 13e66f1
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 6 deletions.
21 changes: 15 additions & 6 deletions src/child/ChildAxelarBridgeAdaptor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,29 @@
pragma solidity ^0.8.21;

import {AxelarExecutable} from "@axelar-gmp-sdk-solidity/contracts/executable/AxelarExecutable.sol";
import {Initializable} from "@openzeppelin/contracts/proxy/utils/Initializable.sol";
import {IChildERC20Bridge} from "../interfaces/child/IChildERC20Bridge.sol";
import {IChildAxelarBridgeAdaptorErrors} from "../interfaces/child/IChildAxelarBridgeAdaptor.sol";

contract ChildAxelarBridgeAdaptor is AxelarExecutable, IChildAxelarBridgeAdaptorErrors {
contract ChildAxelarBridgeAdaptor is AxelarExecutable, Initializable, IChildAxelarBridgeAdaptorErrors {
/// @notice Address of bridge to relay messages to.
IChildERC20Bridge public immutable CHILD_BRIDGE;
IChildERC20Bridge public childBridge;
string public rootBridgeAdaptor;

constructor(address _gateway, address _childBridge) AxelarExecutable(_gateway) {
constructor(address _gateway) AxelarExecutable(_gateway) {}

/**
* @notice Initializes the contract.
* @param _childBridge Address of the child bridge contract.
* @dev Always sets the rootBridgeAdaptor to whatever the rootERC20BridgeAdaptor of the bridge contract is.
*/
function initialize(address _childBridge) external initializer {
if (_childBridge == address(0)) {
revert ZeroAddress();
}

CHILD_BRIDGE = IChildERC20Bridge(_childBridge);
childBridge = IChildERC20Bridge(_childBridge);
rootBridgeAdaptor = childBridge.rootERC20BridgeAdaptor();
}

// TODO tests for this
Expand All @@ -25,7 +34,7 @@ contract ChildAxelarBridgeAdaptor is AxelarExecutable, IChildAxelarBridgeAdaptor
* @dev Always sets it to whatever the rootERC20BridgeAdaptor of the bridge contract is.
*/
function setRootBridgeAdaptor() external {
rootBridgeAdaptor = CHILD_BRIDGE.rootERC20BridgeAdaptor();
rootBridgeAdaptor = childBridge.rootERC20BridgeAdaptor();
}

/**
Expand All @@ -36,6 +45,6 @@ contract ChildAxelarBridgeAdaptor is AxelarExecutable, IChildAxelarBridgeAdaptor
internal
override
{
CHILD_BRIDGE.onMessageReceive(sourceChain_, sourceAddress_, payload_);
childBridge.onMessageReceive(sourceChain_, sourceAddress_, payload_);
}
}
53 changes: 53 additions & 0 deletions src/child/ChildERC20Bridge.sol
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ contract ChildERC20Bridge is

bytes32 public constant MAP_TOKEN_SIG = keccak256("MAP_TOKEN");
bytes32 public constant DEPOSIT_SIG = keccak256("DEPOSIT");
bytes32 public constant WITHDRAW_SIG = keccak256("WITHDRAW");
address public constant NATIVE_ETH = address(0xeee);

IChildERC20BridgeAdaptor public bridgeAdaptor;
Expand Down Expand Up @@ -125,6 +126,58 @@ contract ChildERC20Bridge is
}
}


function withdraw(IChildERC20 childToken, uint256 amount) external {
_withdraw(childToken, msg.sender, amount);
}

function withdrawTo(IChildERC20 childToken, address receiver, uint256 amount) external {
_beforeTokenWithdraw();
_withdraw(childToken, receiver, amount);
_afterTokenWithdraw();
}

function _withdraw(IChildERC20 childToken, address receiver, uint256 amount) private {
if (address(childToken).code.length == 0) {
revert EmptyTokenContract();
}

address rootToken = childToken.rootToken();

if (rootTokenToChildToken[rootToken] != address(childToken)) {
revert NotMapped();
}

// A mapped token should never a root token unset
if (rootToken == address(0)) {
revert ZeroAddressRootToken();
}

// A mapped token should never have the bridge unset
if (childToken.bridge() != address(this)) {
revert BrigeNotSet();
}

if (!childToken.burn(msg.sender, amount)) {
revert BurnFailed();
}

// Encode the message payload
bytes memory payload = abi.encode(WITHDRAW_SIG, rootToken, msg.sender, receiver, amount);

// Send the message to the bridge adaptor and up to root chain
bridgeAdaptor.sendMessage(rootChain, rootERC20BridgeAdaptor, payload);

if (address(childToken) == childETHToken) {
childToken.burn(msg.sender, amount);
Address.sendValue(payable(receiver), amount);
} else {
childToken.burn(msg.sender, amount);
IERC20Metadata rootToken = IERC20Metadata(childToken.rootToken());
rootToken.safeTransfer(receiver, amount);
}
}

function _mapToken(bytes calldata data) private {
(, address rootToken, string memory name, string memory symbol, uint8 decimals) =
abi.decode(data, (bytes32, address, string, string, uint8));
Expand Down
6 changes: 6 additions & 0 deletions src/interfaces/child/IChildERC20Bridge.sol
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,10 @@ interface IChildERC20BridgeErrors {
error InvalidSourceChain();
/// @notice Error when the source chain's message sender is not a recognised address.
error InvalidSourceAddress();
/// @notice Error when a given child token's root token is the zero address.
error ZeroAddressRootToken();
/// @notice Error when a given child token's bridge address is not set.
error BrigeNotSet();
/// @notice Error when a call to the given child token's `burn` function fails.
error BurnFailed();
}

0 comments on commit 13e66f1

Please sign in to comment.