// SPDX-License-Identifier: MIT
pragma solidity 0.8.21;
import {IStoneVault} from "../interfaces/IStoneVault.sol";
import {IStone} from "../interfaces/IStone.sol";
import {ReentrancyGuard} from "@openzeppelin/contracts/security/ReentrancyGuard.sol";
contract DepositBridge is ReentrancyGuard {
address public immutable stone;
address payable public immutable vault;
uint16 public immutable dstChainId;
event BridgeTo(
address indexed srcAddr,
bytes dstAddr,
uint256 etherAmount,
uint256 stoneAmount,
uint256 gasPaid
);
constructor(address _stone, address payable _vault, uint16 _dstChainId) {
stone = _stone;
vault = _vault;
dstChainId = _dstChainId;
}
function bridgeTo(
uint256 _amount,
bytes calldata _dstAddress,
uint256 _gasPaidForCrossChain
) public payable returns (uint256 stoneMinted) {
stoneMinted = bridge(
msg.sender,
_amount,
_dstAddress,
_gasPaidForCrossChain
);
}
function bridge(
address _srcAddr,
uint256 _amount,
bytes calldata _dstAddress,
uint256 _gasPaidForCrossChain
) public payable nonReentrant returns (uint256 stoneMinted) {
require(msg.value >= _amount + _gasPaidForCrossChain, "wrong amount");
IStoneVault stoneVault = IStoneVault(vault);
stoneMinted = stoneVault.deposit{value: _amount}();
IStone stoneToken = IStone(stone);
stoneToken.sendFrom{value: _gasPaidForCrossChain}(
address(this),
dstChainId,
_dstAddress,
stoneMinted,
payable(_srcAddr),
address(0),
bytes("")
);
emit BridgeTo(
_srcAddr,
_dstAddress,
_amount,
stoneMinted,
_gasPaidForCrossChain
);
}
function estimateSendFee(
uint256 _amount,
bytes calldata _dstAddress
) public view returns (uint nativeFee, uint zroFee) {
return
IStone(stone).estimateSendFee(
dstChainId,
_dstAddress,
_amount,
false,
bytes("")
);
}
receive() external payable {
bytes memory dstAddr = abi.encodePacked(msg.sender);
(uint nativeFee, ) = this.estimateSendFee(msg.value, dstAddr);
require(msg.value > nativeFee, "too little");
uint256 amount = msg.value - nativeFee;
this.bridge{value: msg.value}(msg.sender, amount, dstAddr, nativeFee);
}
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.21;
interface IStone {
function sendFrom(
address _from,
uint16 _dstChainId,
bytes calldata _toAddress,
uint _amount,
address payable _refundAddress,
address _zroPaymentAddress,
bytes calldata _adapterParams
) external payable;
function estimateSendFee(
uint16 _dstChainId,
bytes calldata _toAddress,
uint _amount,
bool _useZro,
bytes calldata _adapterParams
) external view returns (uint nativeFee, uint zroFee);
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.21;
interface IStoneVault {
function deposit() external payable returns (uint256 mintAmount);
function requestWithdraw(uint256 _shares) external;
function instantWithdraw(
uint256 _amount,
uint256 _shares
) external returns (uint256 actualWithdrawn);
function cancelWithdraw(uint256 _shares) external;
function rollToNextRound() external;
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)
pragma solidity ^0.8.0;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be _NOT_ENTERED
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
}
function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == _ENTERED;
}
}
{
"compilationTarget": {
"project:/contracts/mining/DepositBridge.sol": "DepositBridge"
},
"evmVersion": "shanghai",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 10
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"_stone","type":"address"},{"internalType":"address payable","name":"_vault","type":"address"},{"internalType":"uint16","name":"_dstChainId","type":"uint16"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"srcAddr","type":"address"},{"indexed":false,"internalType":"bytes","name":"dstAddr","type":"bytes"},{"indexed":false,"internalType":"uint256","name":"etherAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"stoneAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"gasPaid","type":"uint256"}],"name":"BridgeTo","type":"event"},{"inputs":[{"internalType":"address","name":"_srcAddr","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bytes","name":"_dstAddress","type":"bytes"},{"internalType":"uint256","name":"_gasPaidForCrossChain","type":"uint256"}],"name":"bridge","outputs":[{"internalType":"uint256","name":"stoneMinted","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bytes","name":"_dstAddress","type":"bytes"},{"internalType":"uint256","name":"_gasPaidForCrossChain","type":"uint256"}],"name":"bridgeTo","outputs":[{"internalType":"uint256","name":"stoneMinted","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"dstChainId","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bytes","name":"_dstAddress","type":"bytes"}],"name":"estimateSendFee","outputs":[{"internalType":"uint256","name":"nativeFee","type":"uint256"},{"internalType":"uint256","name":"zroFee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stone","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vault","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]