Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

status/proof mapping packing [SLT-186] #3173

Merged
merged 13 commits into from
Sep 27, 2024
58 changes: 30 additions & 28 deletions packages/contracts-rfq/contracts/FastBridgeV2.sol
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,8 @@ contract FastBridgeV2 is Admin, IFastBridgeV2 {
/// @notice Minimum deadline period to relay a requested bridge transaction
uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;

enum BridgeStatus {
NULL, // doesn't exist yet
REQUESTED,
RELAYER_PROVED,
RELAYER_CLAIMED,
REFUNDED
}

/// @notice Status of the bridge tx on origin chain
mapping(bytes32 => BridgeStatus) public bridgeStatuses;
/// @notice Proof of relayed bridge tx on origin chain
mapping(bytes32 => BridgeProof) public bridgeProofs;
mapping(bytes32 => BridgeTxDetails) public bridgeTxDetails;
parodime marked this conversation as resolved.
Show resolved Hide resolved
/// @notice Whether bridge has been relayed on destination chain
mapping(bytes32 => bool) public bridgeRelays;

Expand All @@ -43,6 +33,17 @@ contract FastBridgeV2 is Admin, IFastBridgeV2 {
// @dev the block the contract was deployed at
uint256 public immutable deployBlock;

function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {
return bridgeTxDetails[transactionId].status;
}
parodime marked this conversation as resolved.
Show resolved Hide resolved

function bridgeProofs(bytes32 transactionId) public view returns (BridgeProof memory proof) {
return BridgeProof({
timestamp: bridgeTxDetails[transactionId].proof.blockTimestamp,
relayer: bridgeTxDetails[transactionId].proof.relayer
});
}
parodime marked this conversation as resolved.
Show resolved Hide resolved

constructor(address _owner) Admin(_owner) {
deployBlock = block.number;
}
Expand Down Expand Up @@ -109,7 +110,7 @@ contract FastBridgeV2 is Admin, IFastBridgeV2 {
})
);
bytes32 transactionId = keccak256(request);
bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;
bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;
ChiTimesChi marked this conversation as resolved.
Show resolved Hide resolved

emit BridgeRequested(
transactionId,
Expand Down Expand Up @@ -183,9 +184,10 @@ contract FastBridgeV2 is Admin, IFastBridgeV2 {
function prove(bytes memory request, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {
bytes32 transactionId = keccak256(request);
// update bridge tx status given proof provided
if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();
bridgeStatuses[transactionId] = BridgeStatus.RELAYER_PROVED;
bridgeProofs[transactionId] = BridgeProof({timestamp: uint96(block.timestamp), relayer: relayer}); // overflow ok
if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();
bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;
bridgeTxDetails[transactionId].proof =
ProofDetail({blockTimestamp: uint40(block.timestamp), blockNumber: uint48(block.number), relayer: relayer}); // overflow ok

emit BridgeProofProvided(transactionId, relayer, destTxHash);
}
Expand All @@ -196,16 +198,16 @@ contract FastBridgeV2 is Admin, IFastBridgeV2 {
/// proof.timestamp < type(uint96).max via unchecked statement
/// @param proof The bridge proof
/// @return delta Time delta since proof submitted
function _timeSince(BridgeProof memory proof) internal view returns (uint256 delta) {
function _timeSince(ProofDetail memory proof) internal view returns (uint256 delta) {
unchecked {
delta = uint96(block.timestamp) - proof.timestamp;
delta = uint40(block.timestamp) - proof.blockTimestamp;
}
}

/// @inheritdoc IFastBridge
function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {
if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();
BridgeProof memory proof = bridgeProofs[transactionId];
if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();
ProofDetail memory proof = bridgeTxDetails[transactionId].proof;
if (proof.relayer != relayer) revert SenderIncorrect();
return _timeSince(proof) > DISPUTE_PERIOD;
}
Expand All @@ -221,9 +223,9 @@ contract FastBridgeV2 is Admin, IFastBridgeV2 {
BridgeTransaction memory transaction = getBridgeTransaction(request);

// update bridge tx status if able to claim origin collateral
if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();
if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();

BridgeProof memory proof = bridgeProofs[transactionId];
ProofDetail memory proof = bridgeTxDetails[transactionId].proof;

// if "to" is zero addr, permissionlessly send funds to proven relayer
if (to == address(0)) {
Expand All @@ -234,7 +236,7 @@ contract FastBridgeV2 is Admin, IFastBridgeV2 {

if (_timeSince(proof) <= DISPUTE_PERIOD) revert DisputePeriodNotPassed();

bridgeStatuses[transactionId] = BridgeStatus.RELAYER_CLAIMED;
bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;
ChiTimesChi marked this conversation as resolved.
Show resolved Hide resolved

// update protocol fees if origin fee amount exists
if (transaction.originFeeAmount > 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;
Expand All @@ -249,12 +251,12 @@ contract FastBridgeV2 is Admin, IFastBridgeV2 {

/// @inheritdoc IFastBridge
function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {
if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();
if (_timeSince(bridgeProofs[transactionId]) > DISPUTE_PERIOD) revert DisputePeriodPassed();
if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();
if (_timeSince(bridgeTxDetails[transactionId].proof) > DISPUTE_PERIOD) revert DisputePeriodPassed();

// @dev relayer gets slashed effectively if dest relay has gone thru
bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;
delete bridgeProofs[transactionId];
bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;
delete bridgeTxDetails[transactionId].proof;

emit BridgeProofDisputed(transactionId, msg.sender);
}
Expand All @@ -273,8 +275,8 @@ contract FastBridgeV2 is Admin, IFastBridgeV2 {
}

// set status to refunded if still in requested state
if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();
bridgeStatuses[transactionId] = BridgeStatus.REFUNDED;
if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();
bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;
parodime marked this conversation as resolved.
Show resolved Hide resolved

// transfer origin collateral back to original sender
address to = transaction.originSender;
Expand Down
29 changes: 28 additions & 1 deletion packages/contracts-rfq/contracts/interfaces/IFastBridgeV2.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ pragma solidity ^0.8.20;
import {IFastBridge} from "./IFastBridge.sol";

interface IFastBridgeV2 is IFastBridge {

/// @notice Relays destination side of bridge transaction by off-chain relayer
/// @param request The encoded bridge transaction to relay on destination chain
/// @param relayer The address of the relaying entity which should have control of the origin funds when claimed
Expand All @@ -20,4 +19,32 @@ interface IFastBridgeV2 is IFastBridge {
/// @param request The encoded bridge transaction to claim on origin chain
function claim(bytes memory request) external;

enum BridgeStatus {
NULL, // doesn't exist yet
REQUESTED,
RELAYER_PROVED,
RELAYER_CLAIMED,
REFUNDED
}
parodime marked this conversation as resolved.
Show resolved Hide resolved

struct ProofDetail {
uint40 blockTimestamp;
uint48 blockNumber;
address relayer;
}

struct BridgeTxDetails {
BridgeStatus status;
ProofDetail proof;
}

/// @notice Returns the status of a bridge transaction
/// @param transactionId The ID of the bridge transaction
/// @return The status of the bridge transaction
function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);

/// @notice Returns the timestamp and relayer of a bridge proof
/// @param transactionId The ID of the bridge transaction
/// @return The timestamp and relayer address of the bridge proof
function bridgeProofs(bytes32 transactionId) external view returns (BridgeProof memory);
}
Loading
Loading