Skip to content

Commit

Permalink
Merge branch 'master' into feat/sdk-rfq-endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
ChiTimesChi committed Nov 19, 2024
2 parents 1501333 + aec6dce commit 192fb72
Show file tree
Hide file tree
Showing 78 changed files with 1,635 additions and 422 deletions.
3 changes: 3 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,11 @@
# ignore ifacemaker files
*_generated.go linguist-generated
contrib/opbot/generated/* linguist-generated
*.contractinfo.json linguist-generated=true


# svg should be treated as a binary https://git.io/JE2VK
*.svg binary
*.sol linguist-language=Solidity

.vscode/*.json linguist-language=jsonc
5 changes: 5 additions & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ jobs:
with:
pattern: '.github/renovate.json' # Regular expression for filename to validate, default to *.json

- name: jsonc-syntax-check
uses: stevieb9/jsonc-syntax-check@1.02
with:
pattern: .vscode/*.json'


- name: yaml-lint
uses: ibiqlik/action-yamllint@v3
Expand Down
11 changes: 9 additions & 2 deletions .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
{
// This file (like all vscode metadata files) uses JSON with Comments (JSONC) format, which supports:
// - Comments (both single and multi-line)
// - Trailing commas
// - More lenient syntax than standard JSON

// See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations.
// Extension identifier format: ${publisher}.${name}. Example: vscode.csharp

// List of extensions which should be recommended for users of this workspace.
"recommendations": [
"dbaeumer.vscode-eslint",
"editorconfig.editorconfig",
"juanblanco.solidity",
"golang.go",
"bierner.markdown-mermaid",
"bpruitt-goddard.mermaid-markdown-syntax-highlighting",
],
}
}
8 changes: 8 additions & 0 deletions docs/bridge/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.

## [0.5.4](https://github.com/synapsecns/sanguine/compare/@synapsecns/bridge-docs@0.5.3...@synapsecns/bridge-docs@0.5.4) (2024-11-13)

**Note:** Version bump only for package @synapsecns/bridge-docs





## [0.5.3](https://github.com/synapsecns/sanguine/compare/@synapsecns/bridge-docs@0.5.2...@synapsecns/bridge-docs@0.5.3) (2024-11-07)

**Note:** Version bump only for package @synapsecns/bridge-docs
Expand Down
2 changes: 1 addition & 1 deletion docs/bridge/docusaurus.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const config: Config = {
favicon: 'brand-assets/synapse-mark.svg',

// Set the production url of your site here
url: 'https://docs.bridge.synapseprotocol.com',
url: 'https://docs.synapseprotocol.com',
// Set the /<baseUrl>/ pathname under which your site is served
// For GitHub pages deployment, it is often '/<projectName>/'
baseUrl: '/',
Expand Down
2 changes: 1 addition & 1 deletion docs/bridge/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@synapsecns/bridge-docs",
"version": "0.5.3",
"version": "0.5.4",
"private": true,
"scripts": {
"docusaurus": "docusaurus",
Expand Down
19 changes: 19 additions & 0 deletions packages/contracts-rfq/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,25 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.

# [0.13.0](https://github.com/synapsecns/sanguine/compare/@synapsecns/contracts-rfq@0.12.1...@synapsecns/contracts-rfq@0.13.0) (2024-11-18)


### Features

* **contracts-rfq:** rework permisionless cancellation [SLT-489] ([#3382](https://github.com/synapsecns/sanguine/issues/3382)) ([7932f41](https://github.com/synapsecns/sanguine/commit/7932f416341a227db295c33f232efde89fd2c50c))





## [0.12.1](https://github.com/synapsecns/sanguine/compare/@synapsecns/contracts-rfq@0.12.0...@synapsecns/contracts-rfq@0.12.1) (2024-11-11)

**Note:** Version bump only for package @synapsecns/contracts-rfq





# [0.12.0](https://github.com/synapsecns/sanguine/compare/@synapsecns/contracts-rfq@0.11.0...@synapsecns/contracts-rfq@0.12.0) (2024-11-04)


Expand Down
104 changes: 104 additions & 0 deletions packages/contracts-rfq/contracts/AdminV2.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import {IAdminV2} from "./interfaces/IAdminV2.sol";
import {IAdminV2Errors} from "./interfaces/IAdminV2Errors.sol";

import {AccessControlEnumerable} from "@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol";
import {SafeERC20, IERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {Address} from "@openzeppelin/contracts/utils/Address.sol";

contract AdminV2 is AccessControlEnumerable, IAdminV2, IAdminV2Errors {
using SafeERC20 for IERC20;

/// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)
address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;

/// @notice Role identifier for Quoter API's off-chain authentication.
/// @dev Only addresses with this role can post FastBridge quotes to the API.
bytes32 public constant QUOTER_ROLE = keccak256("QUOTER_ROLE");

/// @notice Role identifier for Prover's on-chain authentication in FastBridge.
/// @dev Only addresses with this role can provide proofs that a FastBridge request has been relayed.
bytes32 public constant PROVER_ROLE = keccak256("PROVER_ROLE");

/// @notice Role identifier for Guard's on-chain authentication in FastBridge.
/// @dev Only addresses with this role can dispute submitted relay proofs during the dispute period.
bytes32 public constant GUARD_ROLE = keccak256("GUARD_ROLE");

/// @notice Role identifier for Canceler's on-chain authentication in FastBridge.
/// @dev Only addresses with this role can cancel a FastBridge transaction without the cancel delay.
bytes32 public constant CANCELER_ROLE = keccak256("CANCELER_ROLE");

/// @notice Role identifier for Governor's on-chain administrative authority.
/// @dev Only addresses with this role can perform administrative tasks within the contract.
bytes32 public constant GOVERNOR_ROLE = keccak256("GOVERNOR_ROLE");

/// @notice Denominator for fee rates, represents 100%.
uint256 public constant FEE_BPS = 1e6;
/// @notice Maximum protocol fee rate: 1% on origin amount.
uint256 public constant FEE_RATE_MAX = 0.01e6;

/// @notice Minimum cancel delay that can be set by the governor.
uint256 public constant MIN_CANCEL_DELAY = 1 hours;
/// @notice Default cancel delay set during the contract deployment.
uint256 public constant DEFAULT_CANCEL_DELAY = 1 days;

/// @notice Protocol fee rate taken on origin amount deposited in origin chain
uint256 public protocolFeeRate;

/// @notice Protocol fee amounts accumulated
mapping(address => uint256) public protocolFees;

/// @notice Delay for a transaction after which it could be permisionlessly cancelled
uint256 public cancelDelay;

/// @notice This is deprecated and should not be used.
/// @dev Use ZapNative V2 requests instead.
uint256 public immutable chainGasAmount = 0;

constructor(address _owner) {
_grantRole(DEFAULT_ADMIN_ROLE, _owner);
_setCancelDelay(DEFAULT_CANCEL_DELAY);
}

/// @notice Allows the contract governor to set the cancel delay. The cancel delay is the time after the transaction
/// deadline after which it can be permissionlessly cancelled, if it hasn't been proven by any of the Relayers.
function setCancelDelay(uint256 newCancelDelay) external onlyRole(GOVERNOR_ROLE) {
_setCancelDelay(newCancelDelay);
}

/// @notice Allows the contract governor to set the protocol fee rate. The protocol fee is taken from the origin
/// amount only for completed and claimed transactions.
/// @dev The protocol fee is abstracted away from the relayers, they always operate using the amounts after fees:
/// what they see as the origin amount emitted in the log is what they get credited with.
function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {
if (newFeeRate > FEE_RATE_MAX) revert FeeRateAboveMax();
uint256 oldFeeRate = protocolFeeRate;
protocolFeeRate = newFeeRate;
emit FeeRateUpdated(oldFeeRate, newFeeRate);
}

/// @notice Allows the contract governor to sweep the accumulated protocol fees in the contract.
function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {
uint256 feeAmount = protocolFees[token];
if (feeAmount == 0) return; // skip if no accumulated fees

protocolFees[token] = 0;
emit FeesSwept(token, recipient, feeAmount);
/// Sweep the fees as the last transaction action
if (token == NATIVE_GAS_TOKEN) {
Address.sendValue(payable(recipient), feeAmount);
} else {
IERC20(token).safeTransfer(recipient, feeAmount);
}
}

/// @notice Internal function to set the cancel delay. Security checks are performed outside of this function.
function _setCancelDelay(uint256 newCancelDelay) private {
if (newCancelDelay < MIN_CANCEL_DELAY) revert CancelDelayBelowMin();
uint256 oldCancelDelay = cancelDelay;
cancelDelay = newCancelDelay;
emit CancelDelayUpdated(oldCancelDelay, newCancelDelay);
}
}
80 changes: 40 additions & 40 deletions packages/contracts-rfq/contracts/FastBridgeV2.sol
Original file line number Diff line number Diff line change
@@ -1,33 +1,27 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

import {SafeERC20, IERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {Address} from "@openzeppelin/contracts/utils/Address.sol";

import {BridgeTransactionV2Lib} from "./libs/BridgeTransactionV2.sol";

import {Admin} from "./Admin.sol";
import {AdminV2} from "./AdminV2.sol";
import {IFastBridge} from "./interfaces/IFastBridge.sol";
import {IFastBridgeV2} from "./interfaces/IFastBridgeV2.sol";
import {IFastBridgeV2Errors} from "./interfaces/IFastBridgeV2Errors.sol";
import {IZapRecipient} from "./interfaces/IZapRecipient.sol";

import {MulticallTarget} from "./utils/MulticallTarget.sol";

import {SafeERC20, IERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {Address} from "@openzeppelin/contracts/utils/Address.sol";

/// @notice FastBridgeV2 is a contract for bridging tokens across chains.
contract FastBridgeV2 is Admin, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {
contract FastBridgeV2 is AdminV2, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {
using BridgeTransactionV2Lib for bytes;
using SafeERC20 for IERC20;

/// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)
address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;

/// @notice Dispute period for relayed transactions
uint256 public constant DISPUTE_PERIOD = 30 minutes;

/// @notice Delay for a transaction after which it could be permisionlessly refunded
uint256 public constant REFUND_DELAY = 7 days;

/// @notice Minimum deadline period to relay a requested bridge transaction
uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;

Expand All @@ -47,7 +41,7 @@ contract FastBridgeV2 is Admin, MulticallTarget, IFastBridgeV2, IFastBridgeV2Err
/// @notice the block the contract was deployed at
uint256 public immutable deployBlock;

constructor(address _owner) Admin(_owner) {
constructor(address _owner) AdminV2(_owner) {
deployBlock = block.number;
}

Expand Down Expand Up @@ -104,33 +98,10 @@ contract FastBridgeV2 is Admin, MulticallTarget, IFastBridgeV2, IFastBridgeV2Err
emit BridgeProofDisputed(transactionId, disputedRelayer);
}

/// Note: this function is deprecated and will be removed in a future version.
/// @inheritdoc IFastBridge
function refund(bytes calldata request) external {
request.validateV2();
bytes32 transactionId = keccak256(request);
BridgeTxDetails storage $ = bridgeTxDetails[transactionId];
// Can only refund a REQUESTED transaction after its deadline expires
if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();
uint256 deadline = request.deadline();
// Permissionless refund is only allowed after REFUND_DELAY on top of the deadline
if (!hasRole(REFUNDER_ROLE, msg.sender)) deadline += REFUND_DELAY;
if (block.timestamp <= deadline) revert DeadlineNotExceeded();
// Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.
// The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.
// Note: this is a storage write
$.status = BridgeStatus.REFUNDED;

address to = request.originSender();
address token = request.originToken();
uint256 amount = request.originAmount() + request.originFeeAmount();
// Emit the event before any external calls
emit BridgeDepositRefunded(transactionId, to, token, amount);
// Complete the user refund as the last transaction action
if (token == NATIVE_GAS_TOKEN) {
Address.sendValue(payable(to), amount);
} else {
IERC20(token).safeTransfer(to, amount);
}
cancel(request);
}

/// @inheritdoc IFastBridge
Expand Down Expand Up @@ -306,7 +277,7 @@ contract FastBridgeV2 is Admin, MulticallTarget, IFastBridgeV2, IFastBridgeV2Err
}

/// @inheritdoc IFastBridgeV2
function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {
function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(PROVER_ROLE) {
BridgeTxDetails storage $ = bridgeTxDetails[transactionId];

// Can only prove a REQUESTED transaction
Expand Down Expand Up @@ -363,6 +334,35 @@ contract FastBridgeV2 is Admin, MulticallTarget, IFastBridgeV2, IFastBridgeV2Err
}
}

/// @inheritdoc IFastBridgeV2
function cancel(bytes calldata request) public {
request.validateV2();
bytes32 transactionId = keccak256(request);
BridgeTxDetails storage $ = bridgeTxDetails[transactionId];
// Can only cancel a REQUESTED transaction after its deadline expires
if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();
uint256 deadline = request.deadline();
// Permissionless cancel is only allowed after `cancelDelay` on top of the deadline
if (!hasRole(CANCELER_ROLE, msg.sender)) deadline += cancelDelay;
if (block.timestamp <= deadline) revert DeadlineNotExceeded();
// Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.
// The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.
// Note: this is a storage write
$.status = BridgeStatus.REFUNDED;

address to = request.originSender();
address token = request.originToken();
uint256 amount = request.originAmount() + request.originFeeAmount();
// Emit the event before any external calls
emit BridgeDepositRefunded(transactionId, to, token, amount);
// Complete the user cancel as the last transaction action
if (token == NATIVE_GAS_TOKEN) {
Address.sendValue(payable(to), amount);
} else {
IERC20(token).safeTransfer(to, amount);
}
}

/// @inheritdoc IFastBridgeV2
function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {
return bridgeTxDetails[transactionId].status;
Expand All @@ -383,8 +383,8 @@ contract FastBridgeV2 is Admin, MulticallTarget, IFastBridgeV2, IFastBridgeV2Err
}

/// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later
/// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,
/// should no one complete the relay.
/// claimed by the relayer who completed the relay on destination chain, or transferred back to the user
/// via the cancel function should no one complete the relay.
function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {
if (token == NATIVE_GAS_TOKEN) {
// For the native gas token, we just need to check that the supplied msg.value is correct.
Expand Down
2 changes: 1 addition & 1 deletion packages/contracts-rfq/contracts/interfaces/IAdmin.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
pragma solidity ^0.8.4;

interface IAdmin {
// ============ Events ============
Expand Down
14 changes: 14 additions & 0 deletions packages/contracts-rfq/contracts/interfaces/IAdminV2.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

interface IAdminV2 {
event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay);
event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);
event FeesSwept(address token, address recipient, uint256 amount);

function setCancelDelay(uint256 newCancelDelay) external;

function setProtocolFeeRate(uint256 newFeeRate) external;

function sweepProtocolFees(address token, address recipient) external;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

interface IAdminV2Errors {
error CancelDelayBelowMin();
error FeeRateAboveMax();
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
pragma solidity ^0.8.4;

interface IFastBridge {
struct BridgeTransaction {
Expand Down
Loading

0 comments on commit 192fb72

Please sign in to comment.