Skip to content

Commit

Permalink
Merge pull request #3250 from synapsecns/master
Browse files Browse the repository at this point in the history
FE Release only for #3238
  • Loading branch information
trajan0x authored Oct 8, 2024
2 parents 4c073ff + 4b49879 commit 2f1565c
Show file tree
Hide file tree
Showing 50 changed files with 1,129 additions and 143 deletions.
1 change: 1 addition & 0 deletions .github/renovate.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"draftPR": true,
"cloneSubmodules": true,
"forkProcessing": "enabled",
"ignorePaths": ["packages/contracts-core/**"],
"packageRules": [
{
"matchUpdateTypes": [
Expand Down
7 changes: 7 additions & 0 deletions .github/workflows/labeler.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,10 @@ jobs:
with:
token: ${{ secrets.GITHUB_TOKEN }} # Optional
filesizelimit: 15MB

- name: Add 'fe-release' label
if: github.event.pull_request.base.ref == 'fe-release'
uses: actions-ecosystem/action-add-labels@v1
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
labels: 'fe-release'
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.3.8](https://github.com/synapsecns/sanguine/compare/@synapsecns/bridge-docs@0.3.7...@synapsecns/bridge-docs@0.3.8) (2024-10-07)

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





## [0.3.7](https://github.com/synapsecns/sanguine/compare/@synapsecns/bridge-docs@0.3.6...@synapsecns/bridge-docs@0.3.7) (2024-10-05)

**Note:** Version bump only for package @synapsecns/bridge-docs
Expand Down
7 changes: 7 additions & 0 deletions docs/bridge/docs/01-About/03-Routes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import Routes from '@site/src/components/Routes'

# Chains & Tokens

This page contains a list of supported tokens, listed per-chain. For a given pair, use the [Synapse Bridge](https://synapseprotocol.com) to see if a route between them exists.

<Routes />
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
---
sidebar_label: Sample Code
sidebar_label: Examples
---

# Sample Code
# Example Code

Example SDK & API implementations

Expand Down
14 changes: 0 additions & 14 deletions docs/bridge/docs/02-Bridge/05-Supported-Routes.md

This file was deleted.

17 changes: 0 additions & 17 deletions docs/bridge/docs/02-Bridge/_05-Supported-Routes.md

This file was deleted.

2 changes: 1 addition & 1 deletion docs/bridge/docs/02-Bridge/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import SVGBridge from '@site/src/components/SVGBridge'

# Synapse Bridge

The [Synapse Bridge](https://synapseprotocol.com) and [Solana Bridge](https://solana.synapseprotocol.com/) seamlessly swap on-chain assets between [20+ EVM and non-EVM blockchains](./Supported-Routes) in a safe and secure manner.
The [Synapse Bridge](https://synapseprotocol.com) and [Solana Bridge](https://solana.synapseprotocol.com/) seamlessly swap on-chain assets between [20+ EVM and non-EVM blockchains](/docs/About/Routes) in a safe and secure manner.

<br />

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.3.7",
"version": "0.3.8",
"private": true,
"scripts": {
"docusaurus": "docusaurus",
Expand Down
26 changes: 7 additions & 19 deletions docs/bridge/src/components/Routes.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,10 @@
import { BRIDGABLE_TOKENS, CHAINS } from '@synapsecns/synapse-constants'

const CHAINS_BY_ID = {}

for (const { chainImg, id, name } of Object.values(CHAINS)) {
if (id && name) {
CHAINS_BY_ID[id] = { name, chainImg }
}
}

export default () =>
Object.entries(BRIDGABLE_TOKENS).map(([id, tokens]) => {
const chain = CHAINS_BY_ID[id]
const chainImg = chain.chainImg({ width: 28, height: 28 })
const chain = CHAINS.CHAINS_BY_ID[id]
const chainImg = chain.chainImg

return (
<section key={id}>
<h2
Expand All @@ -22,16 +15,10 @@ export default () =>
alignItems: 'center',
}}
>
{chainImg} {chain.name} <code>{id}</code>
<img width="28" height="28" src={chainImg} alt={chain.name} />
{chain.name} <code>{id}</code>
</h2>
{Object.values(tokens).map((token) => {
const tokenImg =
typeof token.icon === 'string' ? (
<img width="16" height="16" src={token.icon} />
) : (
token.icon({ width: 16, height: 16 })
)

return (
<span
key={token.addresses[id]}
Expand All @@ -42,7 +29,8 @@ export default () =>
padding: '.25rem .5rem',
}}
>
{tokenImg} {token.symbol}
<img width="16" height="16" src={token.icon} alt={token.symbol} />{' '}
{token.symbol}
</span>
)
})}
Expand Down
11 changes: 11 additions & 0 deletions packages/contracts-rfq/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,17 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.

# [0.7.0](https://github.com/synapsecns/sanguine/compare/@synapsecns/contracts-rfq@0.6.2...@synapsecns/contracts-rfq@0.7.0) (2024-10-07)


### Features

* **contracts-rfq:** arbitrary calls without additional native value [SLT-233] ([#3215](https://github.com/synapsecns/sanguine/issues/3215)) ([6dc151c](https://github.com/synapsecns/sanguine/commit/6dc151c709970e2a891a56d10c8ffc67bdf95522))





## [0.6.2](https://github.com/synapsecns/sanguine/compare/@synapsecns/contracts-rfq@0.6.1...@synapsecns/contracts-rfq@0.6.2) (2024-10-03)


Expand Down
81 changes: 68 additions & 13 deletions packages/contracts-rfq/contracts/FastBridgeV2.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@
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 {UniversalTokenLib} from "./libs/UniversalToken.sol";

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

/// @notice FastBridgeV2 is a contract for bridging tokens across chains.
contract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {
Expand All @@ -24,6 +26,9 @@ contract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {
/// @notice Minimum deadline period to relay a requested bridge transaction
uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;

/// @notice Maximum length of accepted callParams
uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;

/// @notice Status of the bridge tx on origin chain
mapping(bytes32 => BridgeTxDetails) public bridgeTxDetails;
/// @notice Relay details on destination chain
Expand All @@ -45,7 +50,12 @@ contract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {
function bridge(BridgeParams memory params) external payable {
bridge({
params: params,
paramsV2: BridgeParamsV2({quoteRelayer: address(0), quoteExclusivitySeconds: 0, quoteId: bytes("")})
paramsV2: BridgeParamsV2({
quoteRelayer: address(0),
quoteExclusivitySeconds: 0,
quoteId: bytes(""),
callParams: bytes("")
})
});
}

Expand Down Expand Up @@ -117,6 +127,9 @@ contract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {

/// @inheritdoc IFastBridge
function getBridgeTransaction(bytes memory request) external pure returns (BridgeTransaction memory) {
// TODO: the note below isn't true anymore with the BridgeTransactionV2 struct
// since the variable length `callParams` was added. This needs to be fixed/acknowledged.

// Note: when passing V2 request, this will decode the V1 fields correctly since the new fields were
// added as the last fields of the struct and hence the ABI decoder will simply ignore the extra data.
return abi.decode(request, (BridgeTransaction));
Expand All @@ -132,6 +145,7 @@ contract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {
if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();
if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();
if (params.deadline < block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();
if (paramsV2.callParams.length > MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();
int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;
// exclusivityEndTime must be in range (0 .. params.deadline]
if (exclusivityEndTime <= 0 || exclusivityEndTime > int256(params.deadline)) {
Expand Down Expand Up @@ -163,7 +177,8 @@ contract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {
nonce: senderNonces[params.sender]++, // increment nonce on every bridge
exclusivityRelayer: paramsV2.quoteRelayer,
// We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast
exclusivityEndTime: uint256(exclusivityEndTime)
exclusivityEndTime: uint256(exclusivityEndTime),
callParams: paramsV2.callParams
})
);
bytes32 transactionId = keccak256(request);
Expand Down Expand Up @@ -214,18 +229,32 @@ contract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {
address token = transaction.destToken;
uint256 amount = transaction.destAmount;

uint256 rebate = chainGasAmount;
if (!transaction.sendChainGas) {
// forward erc20
rebate = 0;
// All state changes have been done at this point, can proceed to the external calls.
// This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.
if (transaction.callParams.length == 0) {
// No arbitrary call requested, so we just pull the tokens from the Relayer to the recipient,
// or transfer ETH to the recipient (if token is ETH_ADDRESS)
_pullToken(to, token, amount);
} else if (token == UniversalTokenLib.ETH_ADDRESS) {
// lump in gas rebate into amount in native gas token
_pullToken(to, token, amount + rebate);
} else {
// forward erc20 then forward gas rebate in native gas token
} else if (token != UniversalTokenLib.ETH_ADDRESS) {
// Arbitrary call requested with ERC20: pull the tokens from the Relayer to the recipient first
_pullToken(to, token, amount);
_pullToken(to, UniversalTokenLib.ETH_ADDRESS, rebate);
// Follow up with the hook function call
_checkedCallRecipient({
recipient: to,
msgValue: 0,
token: token,
amount: amount,
callParams: transaction.callParams
});
} else {
// Arbitrary call requested with ETH: combine the ETH transfer with the call
_checkedCallRecipient({
recipient: to,
msgValue: amount,
token: token,
amount: amount,
callParams: transaction.callParams
});
}

emit BridgeRelayed(
Expand All @@ -237,7 +266,8 @@ contract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {
transaction.destToken,
transaction.originAmount,
transaction.destAmount,
rebate
// chainGasAmount is 0 since the gas rebate function is deprecated
0
);
}

Expand Down Expand Up @@ -327,6 +357,31 @@ contract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {
}
}

/// @notice Calls the Recipient's hook function with the specified callParams and performs
/// all the necessary checks for the returned value.
function _checkedCallRecipient(
address recipient,
uint256 msgValue,
address token,
uint256 amount,
bytes memory callParams
)
internal
{
bytes memory hookData =
abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));
// This will bubble any revert messages from the hook function
bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msgValue});
// Explicit revert if no return data at all
if (returnData.length == 0) revert RecipientNoReturnValue();
// Check that exactly a single return value was returned
if (returnData.length != 32) revert RecipientIncorrectReturnValue();
// Return value should be abi-encoded hook function selector
if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {
revert RecipientIncorrectReturnValue();
}
}

/// @notice Calculates time since proof submitted
/// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization
/// _timeSince(proof) can accomodate rollover case when block.timestamp > type(uint40).max but
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface IFastBridgeRecipient {
function fastBridgeTransferReceived(
address token,
uint256 amount,
bytes memory callParams
)
external
payable
returns (bytes4);
}
3 changes: 3 additions & 0 deletions packages/contracts-rfq/contracts/interfaces/IFastBridgeV2.sol
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,12 @@ interface IFastBridgeV2 is IFastBridge {
/// @param quoteRelayer Relayer that provided the quote for the transaction
/// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit
/// @param quoteId Unique quote identifier used for tracking the quote
/// @param callParams Parameters for the arbitrary call to the destination recipient (if any)
struct BridgeParamsV2 {
address quoteRelayer;
int256 quoteExclusivitySeconds;
bytes quoteId;
bytes callParams;
}

/// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.
Expand All @@ -57,6 +59,7 @@ interface IFastBridgeV2 is IFastBridge {
uint256 nonce;
address exclusivityRelayer;
uint256 exclusivityEndTime;
bytes callParams;
}

event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,17 @@ pragma solidity ^0.8.0;

interface IFastBridgeV2Errors {
error AmountIncorrect();
error CallParamsLengthAboveMax();
error ChainIncorrect();
error ExclusivityParamsIncorrect();
error MsgValueIncorrect();
error SenderIncorrect();
error StatusIncorrect();
error ZeroAddress();

error RecipientIncorrectReturnValue();
error RecipientNoReturnValue();

error DeadlineExceeded();
error DeadlineNotExceeded();
error DeadlineTooShort();
Expand Down
2 changes: 1 addition & 1 deletion packages/contracts-rfq/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@synapsecns/contracts-rfq",
"license": "MIT",
"version": "0.6.2",
"version": "0.7.0",
"description": "FastBridge contracts.",
"private": true,
"files": [
Expand Down
Loading

0 comments on commit 2f1565c

Please sign in to comment.