Skip to content

Commit

Permalink
Draft implementation of the L2BitcoinDepositor contract
Browse files Browse the repository at this point in the history
Here we present a draft implementation of the `L2BitcoinDepositor` contract
that acts as an entrypoint of the tBTC direct bridging feature on the given
L2 chain. This contract exposes the `initializeDeposit` function that takes the
deposit data (funding tx, reveal info, original depositor) and relays it to the
`L1BitcoinDepositor` contract using the Wormhole Relayer infrastructure.
  • Loading branch information
lukasz-zimnoch committed Feb 28, 2024
1 parent 9e047d1 commit dbeb072
Showing 1 changed file with 139 additions and 0 deletions.
139 changes: 139 additions & 0 deletions solidity/contracts/l2/L2BitcoinDepositor.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
// SPDX-License-Identifier: GPL-3.0-only

// ██████████████ ▐████▌ ██████████████
// ██████████████ ▐████▌ ██████████████
// ▐████▌ ▐████▌
// ▐████▌ ▐████▌
// ██████████████ ▐████▌ ██████████████
// ██████████████ ▐████▌ ██████████████
// ▐████▌ ▐████▌
// ▐████▌ ▐████▌
// ▐████▌ ▐████▌
// ▐████▌ ▐████▌
// ▐████▌ ▐████▌
// ▐████▌ ▐████▌

pragma solidity ^0.8.17;

import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";

import "../integrator/IBridge.sol";

/// @title IWormholeRelayer
/// @notice Wormhole Relayer interface. Contains only selected functions
/// used by L2BitcoinDepositor.
/// @dev See: https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/2b7db51f99b49eda99b44f4a044e751cb0b2e8ea/src/interfaces/IWormholeRelayer.sol#L74
interface IWormholeRelayer {
/// @dev See: https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/2b7db51f99b49eda99b44f4a044e751cb0b2e8ea/src/interfaces/IWormholeRelayer.sol#L122
function sendPayloadToEvm(
uint16 targetChain,
address targetAddress,
bytes memory payload,
uint256 receiverValue,
uint256 gasLimit,
uint16 refundChain,
address refundAddress
) external payable returns (uint64 sequence);

/// @dev See: https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/2b7db51f99b49eda99b44f4a044e751cb0b2e8ea/src/interfaces/IWormholeRelayer.sol#L442
function quoteEVMDeliveryPrice(
uint16 targetChain,
uint256 receiverValue,
uint256 gasLimit
)
external
view
returns (
uint256 nativePriceQuote,
uint256 targetChainRefundPerGasUnused
);
}

// TODO: Document this contract.
contract L2BitcoinDepositor is OwnableUpgradeable {
// TODO: Document state variables.
IWormholeRelayer public wormholeRelayer;
uint16 public l2ChainId;
uint16 public l1ChainId;
address public l1BitcoinDepositor;
uint256 public l1InitializeDepositGasLimit;

event DepositInitialized(
bytes32 payloadHash,
uint64 sequence,
address indexed depositOwner,
address indexed sender
);

event L1InitializeDepositGasLimitUpdated(uint256 l1InitializeDepositGasLimit);

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

function initialize(
address _wormholeRelayer,
uint16 _l2ChainId,
uint16 _l1ChainId,
address _l1BitcoinDepositor
) external initializer {
__Ownable_init();

wormholeRelayer = IWormholeRelayer(_wormholeRelayer);
l2ChainId = _l2ChainId;
l1ChainId = _l1ChainId;
l1BitcoinDepositor = _l1BitcoinDepositor;
l1InitializeDepositGasLimit = 200_000;
}

// TODO: Document this function.
function updateL1InitializeDepositGasLimit(uint256 _l1InitializeDepositGasLimit)
external
onlyOwner
{
l1InitializeDepositGasLimit = _l1InitializeDepositGasLimit;
emit L1InitializeDepositGasLimitUpdated(_l1InitializeDepositGasLimit);
}

// TODO: Document this function.
function initializeDeposit(
IBridgeTypes.BitcoinTxInfo calldata fundingTx,
IBridgeTypes.DepositRevealInfo calldata reveal,
address depositOwner
) external payable {
// Cost of requesting a `initializeDeposit` message to be sent to
// `l1Chain` with a gasLimit of `l1InitializeDepositGasLimit`.
uint256 cost = quoteInitializeDeposit();

require(msg.value == cost, "Payment for Wormhole Relayer is too low");

bytes memory payload = abi.encode(fundingTx, reveal, depositOwner);

uint64 sequence = wormholeRelayer.sendPayloadToEvm{value: cost}(
l1ChainId,
l1BitcoinDepositor,
payload,
0, // No receiver value needed.
l1InitializeDepositGasLimit,
l2ChainId, // Set this L2 chain as the refund chain.
msg.sender // Set the caller as the refund receiver.
);

emit DepositInitialized(
keccak256(payload),
sequence,
depositOwner,
msg.sender
);
}

// TODO: Document this function.
function quoteInitializeDeposit() public view returns (uint256 cost) {
(cost, ) = wormholeRelayer.quoteEVMDeliveryPrice(
l1ChainId,
0, // No receiver value needed.
l1InitializeDepositGasLimit
);
}
}

0 comments on commit dbeb072

Please sign in to comment.