Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ src/
├── base
│ ├── Nonce.sol // Utility contract to safely sequence multiple pending transactions
│ └── ResourceManager.sol. // Utility contract for defining the `RESOURCE` token and its amount requirements
├── crosschain/ // Work-in-progress crosschain logic
├── feeAdapters
│ ├── V3FeeAdapter.sol // Logic for Uniswap v3 fee-setting and collection
│ └── V4FeeAdapter.sol // Work-in-progress logic for Uniswap v4 fee-setting and collection
Expand All @@ -212,6 +213,7 @@ src/

test
├── TokenJar.t.sol
├── CrossChainFirepit.t.sol
├── Deployer.t.sol // Test Deployer configures the system properly
├── ExchangeReleaser.t.sol
├── Firepit.t.sol
Expand Down
8 changes: 4 additions & 4 deletions snapshots/V3FeeAdapterTest.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"batchTriggerFeeUpdate_allLeaves": "277996773",
"triggerFeeUpdate_0": "57728",
"triggerFeeUpdate_4500": "57704",
"triggerFeeUpdate_8999": "55136"
"batchTriggerFeeUpdate_allLeaves": "277997793",
"triggerFeeUpdate_0": "57680",
"triggerFeeUpdate_4500": "57656",
"triggerFeeUpdate_8999": "55112"
}
67 changes: 67 additions & 0 deletions src/crosschain/FirepitDestination.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.29;

import {Owned} from "solmate/src/auth/Owned.sol";
import {Currency} from "v4-core/types/Currency.sol";
import {IL1CrossDomainMessenger} from "../interfaces/IL1CrossDomainMessenger.sol";
import {TokenJar} from "../TokenJar.sol";
import {Nonce} from "../base/Nonce.sol";

error UnauthorizedCall();

/// @notice a contract for receiving crosschain messages. Validates messages and releases assets
/// from the TokenJar
contract FirepitDestination is Nonce, Owned {
/// @notice the source contract that is allowed to originate messages to this contract i.e.
/// FirepitSource
/// @dev updatable by owner
address public allowableSource;

/// @notice the local contract(s) that are allowed to call this contract, i.e. Message Relayers
/// @dev updatable by owner
mapping(address callers => bool allowed) public allowableCallers;

TokenJar public immutable TOKEN_JAR;
uint256 public constant MINIMUM_RELEASE_GAS = 100_000;

event FailedRelease(uint256 indexed _nonce, address indexed _claimer);

constructor(address _owner, address _tokenJar) Owned(_owner) {
TOKEN_JAR = TokenJar(payable(_tokenJar));
}

modifier onlyAllowed() {
require(
allowableCallers[msg.sender]
&& allowableSource == IL1CrossDomainMessenger(msg.sender).xDomainMessageSender(),
UnauthorizedCall()
);
_;
}

/// @notice Calls Token Jar to release assets to a destination
/// @dev only callable by the messenger via the authorized L1 source contract
function claimTo(uint256 _nonce, Currency[] calldata assets, address claimer)
external
onlyAllowed
handleNonce(_nonce)
{
if (gasleft() < MINIMUM_RELEASE_GAS) {
emit FailedRelease(_nonce, claimer);
return;
}
try TOKEN_JAR.release(assets, claimer) {}
catch {
emit FailedRelease(_nonce, claimer);
return;
}
}

function setAllowableCallers(address callers, bool isAllowed) external onlyOwner {
allowableCallers[callers] = isAllowed;
}

function setAllowableSource(address source) external onlyOwner {
allowableSource = source;
}
}
38 changes: 38 additions & 0 deletions src/crosschain/FirepitSource.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.29;

import {Currency} from "v4-core/types/Currency.sol";
import {ERC20} from "solmate/src/tokens/ERC20.sol";
import {SafeTransferLib} from "solmate/src/utils/SafeTransferLib.sol";
import {Nonce} from "../base/Nonce.sol";
import {ResourceManager} from "../base/ResourceManager.sol";

abstract contract FirepitSource is ResourceManager, Nonce {
using SafeTransferLib for ERC20;

uint256 public constant DEFAULT_BRIDGE_ID = 0;

/// TODO: Move threshold to constructor. It should not default to 0.
constructor(address _owner, address _resource)
ResourceManager(_resource, 69_420, _owner, address(0xdead))
{}

function _sendReleaseMessage(
uint256 bridgeId,
uint256 destinationNonce,
Currency[] calldata assets,
address claimer,
bytes memory addtlData
) internal virtual;

/// @notice Torches the RESOURCE by sending it to the burn address and sends a cross-domain
/// message to release the assets
function release(uint256 _nonce, Currency[] calldata assets, address claimer, uint32 l2GasLimit)
external
handleNonce(_nonce)
{
RESOURCE.safeTransferFrom(msg.sender, RESOURCE_RECIPIENT, threshold);

_sendReleaseMessage(DEFAULT_BRIDGE_ID, _nonce, assets, claimer, abi.encode(l2GasLimit));
}
}
34 changes: 34 additions & 0 deletions src/crosschain/OPStackFirepitSource.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.29;

import {Currency} from "v4-core/types/Currency.sol";
import {IL1CrossDomainMessenger} from "../interfaces/IL1CrossDomainMessenger.sol";
import {IFirepitDestination} from "../interfaces/IFirepitDestination.sol";
import {FirepitSource} from "./FirepitSource.sol";

contract OPStackFirepitSource is FirepitSource {
IL1CrossDomainMessenger public immutable MESSENGER;
address public immutable L2_TARGET;

constructor(address _resource, address _messenger, address _l2Target)
FirepitSource(msg.sender, _resource)
{
MESSENGER = IL1CrossDomainMessenger(_messenger);
L2_TARGET = _l2Target;
}

function _sendReleaseMessage(
uint256, // bridgeId
uint256 destinationNonce,
Currency[] calldata assets,
address claimer,
bytes memory addtlData
) internal override {
(uint32 l2GasLimit) = abi.decode(addtlData, (uint32));
MESSENGER.sendMessage(
L2_TARGET,
abi.encodeCall(IFirepitDestination.claimTo, (destinationNonce, assets, claimer)),
l2GasLimit
);
}
}
8 changes: 8 additions & 0 deletions src/interfaces/IFirepitDestination.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.29;

import {Currency} from "v4-core/types/Currency.sol";

interface IFirepitDestination {
function claimTo(uint256 _nonce, Currency[] calldata assets, address claimer) external;
}
7 changes: 7 additions & 0 deletions src/interfaces/IL1CrossDomainMessenger.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.29;

interface IL1CrossDomainMessenger {
function sendMessage(address _target, bytes calldata _message, uint32 _minGasLimit) external;
function xDomainMessageSender() external view returns (address);
}
Loading
Loading