Synapse Protocol API Docs
Synapse Protocol API Docs
The Synapse Interchain Network (SIN) is an optimistic proof-of-stake interchain network. SIN allows trustless communication & settlement between chains, making all blockchain data &
liquidity accessible and transferable across all chains. The protocol builds on previous research used for Optimistic Layer 2 technologies and is inspired by the work of the Optimism team.
Our design principles:
Trustless — A single honest actor maintains network security, as long as there is at least one honest guard, fraudulent messages aren't executed. The network doesn’t
rely on centralized oracles or permissioned relayers to validate transactions.
Permissionless — Anyone can run an agent, strengthening network security & competing for fees. Furthermore, agents can permissionlessly support new chains.
Modular Security — Different types of use cases have different security needs. SIN’s security architecture supports them all. Apps can leverage the customizable optimistic
period to ensure interchain integrity. This flexible design enables the full range of interchain use cases, from multi-billion dollar Dapp governance to NFT bridging, to all use the
same system with no tradeoffs.
Use Cases
SIN's decentralization and censorship-resistance enables a wide range of new use cases, including:
Chain Abstraction - No more switching chains. Interact with smart contracts and Dapps connected to the Interchain Network regardless of what chain they’re on or where you have
assets.
Unified Liquidity - Liquidity for tokens and lending is fragmented across dozens of chains. SIN allows for interchain transactions on multiple chains at once allowing a user to tap into total
onchain liquidity without leaving their preferred chain.
Interchain Connectivity - Seamlessly connect blockchains with SIN’s permissionless architecture. New chains can onboard users, assets and call smart contracts on any chain.
Table of Contents
Note: The above is a vast oversimplification of the system, which includes multiple ways to report fraud (some permissionless). For a more comprehensive overview, please see the
contracts.
At their core, optimistic protocols operate under the assumption that most network participants will act honestly, but that if they don't, dishonesty can always be proven. To date, this type of
design has been implemented within Optimistic Layer 2 Rollups, which work by posting transactions submitted to the rollup to Ethereum L1. Once data has been posted to Ethereum, the
L2 transactions can be proven trustlessly that it did occur, and any dishonest transactions submitted would be disproven.
However, this design is not only restricted to two chains - it is also possible between chains, in an interchain communication context. Anyone is always able to prove that a transaction
occurred on the origin chain, and by submitting it to the destination chain, it creates a ‘base truth’ to prove honest action against.
In this example, Alice submits a transaction to Chain A, and wants Chain B to know what the transaction is.
This basic example works well on a single transaction, but is not suitable as the basis for a scalable interchain network. For one thing, messages have arbitrary value. What kind of bond
would we require the off-chain agent to put up for a governance vote and how would the situation be corrected in the event that the agent was dishonest?
The first: an optimistic period, that is, a wait period between which Bob, the optimistic agent from the example above (who we call a Notary, going forward), sends the transaction data to
Chain B, to be reviewed, and in what period of time it can be executed (and finalized).
The second: a Guard. The Guard is an independent agent who institutes checks and balances on the Notary. The Guard can temporarily pause the transaction on the destination chain if
the data the notary is providing is incorrect. Now, in the event of a dispute, both agents can go back to chain A, and at least one of the two agents will have their bond slashed; Either the
Notary for providing invalid data, or the guard for filing a false report, since there cannot be two truths.
But what happened to the transaction on chain B that has now been paused? We've proved fraud on chain A, and slashed an agent, but as of right now we have no way to trustlessly
communicate whether or not the message on chain B was valid.
Instead of the Notary relaying the state of the origin chain straight to the destination chain, first, any of the Guards in the network submit a message attesting to the state of the origin chain
and the state of Synapse Chain in one message, which is posted and to Synapse Chain. This ensures at least 1 guard is always online and continuously validating the state of every chain.
Only after a guard attests to the state of both the origin chain and the Interchain network as a whole, the Notary bonded to the chain a submit its attestation to Synapse chain, updating the
state of the network with a proof that both a guard and a notary have attested to the state of Chain A (as well as attestations from any other chains in the system).Once a guard attests to
the state of both the origin chain and the entire Interchain network, the bonded Notary on the origin chain can submit its attestation to the Synapse Chain. This updates the state of the
network via a proof, confirming that both a Guard and a Notary have attested to the status of Chain A, along with attestations from any other chains within the system.
A snapshot of the Synapse Chain state is then taken and posted to the destination chain, initiating the "optimistic seconds" countdown until the message is eligible for execution. During
this period, if the notary and the guard colluded to commit fraud, any guard within the system can present a fraud proof to all chains, temporarily blacklisting agents on every chain while the
dispute is resolved.
Only after another Notary & Guard on the origin chain attest that fraud has not been committed, and post it to Synapse Chain (using a longer optimististic period for increased safety), with
the results of the dispute can the message be executed.
The pending disputed message can only be resolved after a separate notary and guard on the Origin Chain both verify that no fraud has occurred, and report this to the Synapse Chain.
This employs a prolonged "optimistic seconds" timeframe to enhance security, and once complete, the dispute is resolved and the message is executed.
By making the results of these disputes globally accessible, the safety of the system increases as more chains are added. This guarantees that every bonded actor in the system will be
looking for fraud all the time, since everyone is forced to attest to the state of the network as whole.
Crucially, bond amounts are set differently for Guards and Notaries to incentivize participation. Since Guards can only grief messages, but cannot independently commit fraud, they are
required to post a much smaller bond compared to notaries. This is because at least one guard is necessary to verify the condition of every message.
On the other hand, Notaries are required to post a substantially larger bond to participate in the consensus. This not only minimizes the chances of a notary committing fraud by raising the
potential financial penalty for notaries, but it also establishes a significant bounty for guards who promptly report any fraud, thus encouraging swift reporting of any fraud.
Synapse Interchain Network Testnet
The Synapse Interchain Network Testnet is live, deployed to the Synapse Chain Testnet, Arbitrum Sepolia, and Ethereum Sepolia. Reach out in Discord for additional testnet chain
support.
Agents stake to start validating SIN transactions and participating in the network. As users and Dapps make interchain calls, they pay fees to the network similar to L1 gas fees. These fees
are split among honest agents(Notaries, Guards & Executor) involved in processing that transaction.
This ecosystem of dapps and users paying fees for interchain compute and agents staking to earn fees opens the opportunity for an economic ecosystem built around interchain compute
fees.
For example, in the future, the network could support an LSD (liquid staking derivative) of the token used for staking. As well as a DPOS (delegated proof of stake) model where token
holders who want to earn fees can delegate their tokens to those running agents.
Note: In today's Synapse Interchain Network testnet, fees are paid in origin chain gas and staking is disabled.
Proof Of Stake
Both Notaries and Guards are required to stake prior to participating in the system with guards submitting the smaller of the two stakes since the guards stake serves primarily to
disincentivize griefing attacks (filing incorrect fraud reports).
All stakes are posted on Synapse Chain and recorded as part of the global state of the SIN using the BondingManager.
In the event agents submit invalid attestations they will be reported and slashed with the reporter receiving the stake of the agent that commited fraud.
Stakers also have to wait a period of time before being able to unstake. How long this ends up being will decided when the staking module is activated.
Note: The terms tips and SIN fees are used interchangeably.
In SIN contracts, fees are referred to as Tips. This terminology is used to reflect that while the nature of compensation for off chain agents is dynamic, it does have a lower bound much
the way the base fee & tip cap work in dynamic fee transactions on Ethereum.
All transactions that go through SIN require multiple participants to be compensated for their participation in consensus and gas fees and infrastructure costs. This process is completely
trustless and happens on a per-transaction basis. Fees are dynamically adjusted based on gas prices using the GasOracle with a markup value defined in the oracle contract on a
per-chain basis.
Tip values returned by the GasOracle represent the minimum value required for messages to be included. Client contracts can pay additional fees to ensure faster execution by agents.
Tips are eligible for collection only after the first valid attempt at message execution.
You can also consider using BaseClient to avoid implementing any receiver checks yourself.
The contract also does some basic checks for us when receiving a message. Let's take a look at the receiveBaseMessage related functions which are used to receive a message from a
destination:
Copy
/**
* @dev Message recipient needs to ensure that merkle proof for the message
* Note: as this point it is checked that the "message optimistic period" has passed,
* however the period value itself could be anything, and thus could differ from the one
*/
function receiveBaseMessage(
uint32 origin_,
uint32 nonce,
bytes32 sender,
uint256 proofMaturity,
uint32 version,
) external payable {
/**
* @dev Child contracts should implement the logic for receiving a Base Message in an "unsafe way".
*/
function _receiveBaseMessageUnsafe(
uint32 origin_,
uint32 nonce,
bytes32 sender,
uint256 proofMaturity,
uint32 version,
) internal virtual;
This means in our test client we're going to have to implement some checks. The first thing you'll notice is both the origin and destination are pre-defined so you'll have to define those in
the constructor like so using the appropriate origin and destination chain addresses for your chain.
Copy
// SPDX-License-Identifier: MIT
Next up, you're going to want to define the sender checks and make sure the optimistic seconds period is set correctly. Let's define _receiveBaseMessageUnsafe
Copy
uint256 private constant REQUIRED_OPTIMISTIC_SECONDS = 20
error ProofMaturityTooLow();
error InvalidSender();
function _receiveBaseMessageUnsafe(
uint32 origin_,
uint32 nonce,
bytes32 sender,
uint256 proofMaturity,
uint32 version,
if Typecast.addressToBytes32(0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045) != sender {
revert InvalidSender();
// and we want to make sure the optimistic seconds period has exceeded
if (proofMaturity != REQUIRED_OPTIMISTIC_SECONDS) {
revert ProofMaturityTooLow();
Now we're ready to receive a message, but we still have to send one. Let's define a sendMessage function:
Copy
function sendMessage(
uint32 destination_,
address recipientAddress,
uint32 optimisticSeconds,
uint64 gasLimit,
uint32 version,
) external payable {
// if you want the user to get dropped gas on the destination chain, can define that here
Feel free to reach out in Discord for more help integrating these contracts. As the ecosystem matures, more dev docs will be released as well as more integrations.
Message Lifecycle
This document provides a quick overview of the lifecycle of a successful cross-chain message.
An application calls sendMessage on the Origin and specifies a destination chain, contract address, optimisticSeconds timer, and call data.
The message is encoded, assigned a nonce, and added to the origin merkle tree. The merkle state at this nonce is then saved.
Any guard observes the new state of the origin chain and creates a state snapshot of the origin chain. This message is then submitted back to the origin chain (which can
confirm its validity).
Any notary bonded to the origin chain can post an "Attestation" of the state of the origin chain to Synapse Chain. This must include the guards signed snapshot.
Any notary for the destination chain proposes the attestation above to the destination chain. The optimistic seconds period timer has now started and guards are verifying
the validity of the update.
Assuming no fraud proof has been presented that would cause the message to be quarantined, and the optimistic seconds period has elapsed, the message is executed. A
message receipt is generated.
The receipt is posted back to Synapse Chain where tips can be claimed by the notary, guard, and executor involved in the given transaction.
Contracts
A variety of contracts power the Synapse Interchain Network, contained in the contracts-core section on GitHub (generated docs available here). The core of the protocol consists of a few
different components:
The Synapse Interchain Network Testnet is now live, get started here: Synapse Interchain Network Testnet
Origin - Interface for sending messages to other chains. Also serves as the source of truth for resolving disputes since the origin chain is the only place where fraud can be
proven with absolute certainty.
Destination - Interface for executing messages sent on other chains. Also has an interface for submitting fraud reports from Guards.
Summit - Contains all states from the entire network, resolves disputes and allows agents to bond.
Gas Oracle - Used for cross-chain dynamic gas pricing.
Agent Manager - used to keep track of all the bonded agents and their statuses.
Bonding Manager - keeps track of all existing agents on the Synapse Chain
Light Manager - Replicates the state of the bonding manager using a single Merkle root.
Inbox - Accepts snapshots & receipts from various chains and passes them to summit
LightInbox - Replicates inbox on other chains to pass messages into Origin and Destination
Security
The contracts have been audited by both Zellic and Trail of bits + reviewed extensively internally. Synapse employs extremely intensive unit, fuzz, and integration tests for the contracts &
has an extremely comprehensive foundry test suite. A full overview of the test suite can be found here.
In addition to automated testing & manual review, Slither, a static analysis tool is ran on each commit & suggestions are considered carefully prior to merge. Other tools, including snyk +
sonarqube are also used to scan for malignant dependencies.
This section will be updated with reporting guidelines for security issues + bounty program once SIN is live. Community members & contributors are encouraged to review protocol critical
changes on github.
Origin
Overview
The Origin contract is deployed on all chains in the interchain network. Each origin contract represents the state of messages sent to that chain at any given time.
The origin contract serves an extremely important role in the optimistic system akin to the L1 in ORU's like optimism. It's the only place where fraud on destination chains can be proven.
This is because the sending chain in any cross-chain system is the only place it can be proven, with absolute certainty, that something actually happened. So, when a fraud report occurs,
this is the only place that the fraud report can be resolved.
Responsibilities
Formatting the sent message payloads, and inserting their hashes into the Origin Merkle Tree.
Keeping track of the historical Origin Merkle Tree containing all the message hashes.
Enforcing minimum tips (fees) values for sent base messages based on the provided execution requests. This is done using a Gas Oracle
Distributing the collected tips upon request from a local contract.
Destination
Overview
The destination contract is used for receiving messages from remote chains and executing them. This is where the last leg of any interchain transaction happens.
Responsibilities:
Summit
The Summit contract is deployed on Synapse Chain and acts as the "rollup" of SIN for the attested states of all remote chains in the system. The snapshot root of the contract determines
the source of truth for snapshots for all chains and is attested to by every actor in the system every time they perform an action.
The contract works hand in hand with the BondingManager to keep remote chains up-to-date on the state of the agents & forces all agents to attest to the validity of the agents in every
snapshot and ultimately serves as a global state of the interchain network.
Responsibilities
AgentManager
Overview
The AgentManager is deployed on all chains and is used to keep track of the status of all Off Chain Agents and resolve disputes. This contract is also used by the Origin, Destination, and
the Summit to determine whether or not an off-chain actor has permissions to perform different actions on the contracts.
The agent manager also has a mechanism for permissionlessly updating its own record of the agents involved in the system using snapshots.
Responsibilities
Agent updates are propagated via the agent root which represents the current off-chain agents that have posted a bond on Synapse Chain at any given time.
This root is contained in the Attestations posted by Notaries to summit so the agent set can be updated on every chain as soon as a message is sent on any chain.
Much like messages passed by developers building on top of the protocol. the agent root itself has an optimistic period before it can be considered valid, and as such, represents a critical
part of the protocol security.
The propagation of this root at SynChain is necessary since only SynChain knows the state of the agent set at any given time.
Gas Oracle
Gas Oracle
The Gas Oracle is a Smart Contract deployed on each of the chains in the network that tracks the estimated gas prices on other chains. This is needed to estimate the cost of gas to send
a message in the messaging system. The sender of the message pays up front for the transactions required on both the Synapse Chain and the Destination.
Responsibilities
Future work
In the future, the gas oracle will use tools like tx.gasprice to track time-averaged values for different gas stats.
Deployment
Right now, the easiest way to deploy the agents is with our helm charts available on artifact hub. Work is being done on a one-click devnet in the meantime that uses docker-compose
instead of helm.
Making Changes
Because of the careful incentives around speed & security implicit in the system, it's likely client diversity will emerge very quickly. To enable this, the codebase exports as much
functionality as possible through godoc (including our e2e go-based contract testing suite in ethergo & custom github actions to minimize the probability of issues.
Devcontainers are built daily to enable one click runs from github codespaces for any developer interested in contributing to or hacking on the synapse interchain network standard.
Developers can reach out through GitHub issues or the Synapse Discord with questions.
Security
Supply Chain Security
Similarly to contract security, a number of automated & manual systems are used to minimize risks of root of trust compromise when running any of the off-chain agents.
These include:
Snyk, Sonarqube and Codeql are all used for static analysis + dependency analysis on every pull request and issues are carefully reviewed.
Software Bill of Materials are exported with every release & scanned continuously
All containers are built using either distroless or scratch containers in order to minimize the risk of supply chain attacks on docker images.
All binaries are built using a custom goreleaser image to avoid supply chain attacks in builder images
Devops security
We've also taken extraordinary steps to ensure users have a secure deployment environment for offchain agents. This has included the creation of 3 different terraform providers aimed at
using workload identity authorization for private key management:
Terraform-kubreproxy-provider: Allows the configuration of kubernetes clusters through terraform while utilziing an iap bastion host (something previously impossible)
Terraform-helmproxy-provider: Allows the configuration of deployment of helm charts while utilziing an iap bastion host (something previously impossible)
We've also open-sourced workload-identity based Ethereum ECDSA signers for both GCP and AWS.
RPC Security
One other root of trust in any interchain system is the place data is being received from the origin chain. To this end, we built OmniRPC, a way to specify a threshold of different RPC
providers that need to return the same data about a query before it's trusted.
Operational Security
In order to enable operators of off-chain agents to operate as seamlessly as possible, extensive work has been done around the introduction of distributed tracing through otel + jaeger to
quickly identify & remediate any issues that might result in slashing of offchain agents. This includes a custom pyroscope + Jaeger image for especially hard to find issues + dockerized
tracing.
Additionally, all modules export metrics via Prometheus + Grafana to make setting up alerts as easy as possible.
Executor
Overview
Executors are permissionless & trustless actors responsible for executing messages on the Destination chain once the optimistic seconds period has elapsed. The executors receive tips
(fees) in exchange for processing messages.
Responsibilities
Listen for messages sent on the Origin & store a list of merkle proofs for these messages
Listen for snapshots being submitted to the destination chain and execute messages once the optimistic period has elapsed.
Optional: Report fraud on Origin chains, as this kind of fraud report is completely permissionless
Collect Fees by submitting tip proofs in order to claim tips.
Guard
Overview
Guards are off-chain agents that detect fraud and attest to state on many chains. Guards listen for new messages on the Origin chain and create snapshots that contain the state of the
Origin contract (provable on the origin chain) and the state of Synchain (which contains provable updates from the gas oracle, a list of agents, etc). Once this snapshot is created, it is
posted to Synchain where a notary can attest to its validity or other guards can report fraud.
Responsibilities
Report Types
Notary
Overview
A Notary is an off-chain agent assigned to at most 1 chain. The notary is bonded on Synapse Chain and posts a stake in exchange for a percentage of tips (fees) for attesting to messages.
The notary is akin to the sequencer in an L2 blockchain in that they are responsible for posting state to the L1. While they can refuse to post state temporarily, they cannot permanently
censor the network, and they can never lie about the state of a chain in a way that cannot be detected on the destination.
The notary must also first have a snapshot signed by a guard before attesting to state updates and can therefore not unilaterally perform any action, even optimistically.
Responsibilities
Synapse Chain
Synapse Chain is an Ethereum-based Optimistic Rollup, built on the Syn OP Stack, inspired by OP Stack.
Synapse Chain is an Etherum-based optimistic rollup built on the SYN OP stack.
Synapse Chain is EVM compatible, leveraging the rich infrastructure and developer ecosystem built around it. Like Optimism, Synapse Chain settles to Ethereum, enabling the scalable &
trustless environment of Optimistic Rollups. Transactions on Synapse Chain are near instant and cost a fraction of what they would on Ethereum.
Unlike other rollups, by building on the SYN OP Stack, Synapse Chain is a natively interchain rollup, able to communicate other supported chains by the Synapse Interchain Network.
This enables interchain deposits to Synapse Chain and fast withdraws from the Synapse Chain Bridge.
It serves as the data availability layer of the Synapse Interchain Network and as a soverign execution environment for interchain applications.
Synapse Chain contains the state of all chains within the SIN. Anytime a message is sent through SIN, it is settled to Synapse Chain and attested to by off-chain agents inside of a global
Merkle tree. Thus, Synapse Chain serves as the data availability layer for the Interchain Network. All messages sent, attestations made, and agent information can be accessed through
Synapse Chain. Since Synapse Chain is an rollup, all of the SIN data gets settled to Ethereum, resulting in the following Synapse stack:
This is why Synapse Chain serves as an interchain data availability layer for the SIN, and is the first interchain rollup.
By serving as the hub of the Interchain Network, Synapse Chain enables application developers to create new primitive applications previously not possible.
Learn more about Building on Synapse Chain & building on the Synapse Interchain Network (SIN).
Currently, transaction fees on Synapse Chain are paid in ETH. In the future, this could be paid in any token. See below for additional transaction fee information.
SYN OP Stack
The Syn OP Stack is a natively interchain rollup stack, built on top of Optimism's OP Stack.
The SYN OP Stack is a modified version of Optimism's OP Stack, enabling natively interchain rollups.
The SYN OP Stack has all of the standard benefits of the OP stack, but enshrines the Synapse Interchain Network at the root of the rollup, allowing any SYN OP chain to communicate
with all other supported chains by the Synapse Interchain Network.
Modularized L2 Bridging
The SYN Op Stack allows for interchain deposits and fast withdraws from the standard L2 Bridge via the Synapse Interchain Network. The standard 7-day L2 bridge withdrawal period
works fine for some execution environments, however, many rollups need to be able to customize withdraw periods based on the activities on the rollup. The SYN OP Stack enables rollups
to modularize their bridge logic, whether by token, amount bridged, or throughput.
The Synapse Interchain Network is in built in the SYN OP Stack. Applications are increasingly interchain and require interacting with other chains. The standard OP Stack only allows for
Ethereum ↔ L2 communication. This was built under the design of one all-encompassing rollup and Ethereum, but 1000s of new blockchains have launched, and rollup must allow
application developers to onboard users and assets from all other chains, not just Ethereum.
Permissionless Interoperability
Due to the permissionless nature of SIN, the SYN OP Stack allows rollups to immediately have native interchain communication with all chains supported by SIN. Any rollup developer can
run their own agents, enabling communication, strengthening network security, and competing for fees.
Network information can be found below. As a developer, to bridge to Synapse Sepolia, see Bridging to Synapse Chain.
Chain ID 444
Gas Fees
Currently, transaction fees on Synapse Chain are paid in ETH. In the future, this could be modified to use any token.
Transaction fees function similarly to Ethereum in many ways, with some differences.
Every Synapse Chain transaction consists of two costs: an L2 (execution) fee and an L1 (security) fee. The L2 fee is the cost to execute your transaction on the L2, and the L1 fee is the
estimated cost to publish the transaction on the L1. Typically the L1 security fee is higher than the L2 execution fee.
The L1 fee will vary depending on the amount of transactions on the L1. If the timing of your transaction is flexible, you can save costs by submitting transactions during periods of lower
gas on the L1.
Similarly, the L2 fee can increase and decrease depending on how many transactions are being submitted to the L2.
For additional details about fee calculation on Synapse Chain, please refer to the op-stack developer documentation.
As a user, you should, set up your wallet to support Synapse Chain, acquire Sepolia ETH, and bridge to Synapse Chain.
Wallet Setup
Faucet
Bridging to Synapse Chain
As a user, you should, set up your wallet to support Synapse Chain, acquire Sepolia ETH, and bridge to Synapse Chain.
Wallet Setup
Faucet
Bridging to Synapse Chain
Faucet
To interact with the Synapse Chain testnet, you'll first need testnet Sepolia ETH, to bridge to the Synapse Sepolia testnet.
https://sepoliafaucet.com
https://faucet.quicknode.com/drip
https://faucet.chainstack.com
https://www.infura.io/faucet/sepolia
Once you receive ETH on Sepolia, you should see it in your wallet on the Sepolia Network. It may take a few seconds for them to appear, but you can check the status by looking for a
transaction to your address on a Sepolia Block Explorer.
L2 Contract Addresses
Synapse Testnet (Sepolia)
Name Address
WETH9 0x4200000000000000000000000000000000000006
L2CrossDomainMessenger 0x4200000000000000000000000000000000000007
L2StandardBridge 0x4200000000000000000000000000000000000010
SequencerFeeVault 0x4200000000000000000000000000000000000011
OptimismMintableERC20Factory 0x4200000000000000000000000000000000000012
GasPriceOracle 0x420000000000000000000000000000000000000F
L1Block 0x4200000000000000000000000000000000000015
L2ToL1MessagePasser 0x4200000000000000000000000000000000000016
L2ERC721Bridge 0x4200000000000000000000000000000000000014
OptimismMintableERC721Factory 0x4200000000000000000000000000000000000017
ProxyAdmin 0x4200000000000000000000000000000000000018
BaseFeeVault 0x4200000000000000000000000000000000000019
L1FeeVault 0x420000000000000000000000000000000000001a
L1 Contract Addresses
Ethereum Testnet (Sepolia)
Name Address
AddressManager 0x3727ef5C3CF38685b1759df99A83D4d229a80199
L1CrossDomainMessenger 0x49ADa0E5AE1FbdAE15A0bFa8CfE2e396Df529c2f
L1ERC721Bridge 0x45d61c43bd26D92a631bebe17A340181AFf78A29
L1StandardBridge 0x0eA234cFd2074Bf5eC64b15637Af8a68e0b2bFab
L2OutputOracle 0x174B9593CaD503D789ebA6dF2CCfce51649c2CC1
OptimismMintableERC20Factory 0xE287c226DC58fd5322B8f292A99793d7203a3A1C
OptimismPortal 0x643B10E697f2763168B810b65d29704b51Df69f2
ProxyAdmin 0x81e95329cCFa3e004633b758cbb2932686188555
SystemConfig 0x15F763Fd4eB94201B7227cfEfe7460b62910AF4f
thirdweb
Using thirdweb to build on Synapse Chain Testnet
Thirdweb is a web3 infrastructure developer suite that gives developers out-of-the-box tooling to easily deploy contracts on Synapse Chain Testnet.
Use the CLI to deploy your contracts directly to Synapse Chain by running
Copy
npx thirdweb deploy
_symbol
_royaltyRecipient
_royaltyBps
Alternative Options
You can deploy a prebuilt contract for NFTs, tokens, or marketplace directly from the thirdweb Explore page:
Navigate to the thirdweb Explore page: https://thirdweb.com/explore
Choose the type of contract you want to deploy from the available options: NFTs, tokens, marketplace, and more.
Follow the on-screen prompts to configure and deploy your contract.
Synapse Bridge
The Synapse Bridge is the first user-facing product built on top of the cross-chain communication network.
Synapse Bridge allows users to seamlessly swap on-chain assets across 15+ EVM and non-EVM blockchains in a safe and secure manner. The bridge supports two types of bridging:
Synapse Bridge is also available for developers who want to integrate cross-chain asset swapping natively into their application. By leveraging the bridge, developers can build truly
cross-chain DeFi applications including cross-chain DEX, lending platforms, margining systems, derivatives markets, yield aggregators, and much more. The cross-chain AMM gives users
access to the deep liquidity, low fees, and minimal slippage.
In a short span of time, the Synapse Bridge has become one of the most widely used and trusted bridges, processed nearly $14 billion in total volume, serviced hundreds of thousands of
users as well as mass scale dapps like DeFi Kingdoms.
After signing a transaction from your wallet, gas fees are collected, and the transaction is initiated on the origin chain. Once accepted, the bridged asset is removed from your portfolio, and
a progress bar shows the estimated confirmation time.
Once confirmed on the destination chain, the asset is added to your portfolio, and a link to the destination hash can be accessed from the progress menu. The transaction is then indexed
by the Synapse explorer and will appear with your transaction history in the Activity tab.
Gas token airdrops and rebates are delivered to your wallet automatically. However, only bridgeable assets will appear in your Synapse portfolio.
How assets move between chains depends on the router being used. Synapse automatically selects the appropriate router based on the tokens and chains being used.
Synapse Bridge
The origin token is added to a Pool on the origin chain where it’s swapped for a compatible destination chain asset, which is then sent to the destination chain.
RFQ
Relayers on the destination chain bid to provide the best exchange rate for a given route. After delivering the destination asset, the winning bidder receives the origin token.
CCTP
A native USDC contract burns and re-mints the token on its respective origin and destination chains.
Troubleshooting
Did my transaction initiate?
Transactions that fail to initiate will return an error message, and your funds will remain in your portfolio. If a transaction fails to initiate, you may safely retry the transaction.
Origin chain activity volume may occasionally prevent a transaction from being accepted. These transactions return an error message, and funds remain safely in your wallet on their
original chain. You may safely retry your transaction at any time; activity spikes will usually return to normal within 30-60 minutes.
Advanced techniques
Activity levels can be tracked on the native block explorers for your source or destination chains (e.g https://etherscan.io/gastracker).
You can update your wallet’s gas settings to make transactions from Ethereum more likely to be accepted during times of peak activity.
Synapse estimates are based on destination block times. At times, high levels of activity may cause transactions to post in a later block than expected. The block explorer links in the
transaction progress dropdown menu can confirm whether a slow transaction is actually confirmed but not yet updated on the Synapse website.
Transactions that fail to complete are not lost, and are manually addressed by the Synapse support team. You can reach out to them regarding your specific case on the Synapse Discord
channel, which will also have alerts regarding slow or unresponsive chains and resolution times.
For DeFi Kingdoms users: Bridging an NFT may sometimes take up to twice as long as bridging an asset. Contact Synapse Support on Discord if an NFT transaction has been pending for
more than two hours.
In the event of a sudden increase in slippage on the destination chain, Synapse prevents unexpected loss by simply delivering the intermediate asset used for the Bridge transaction
instead. This asset will appear in your portfolio and can be safely swapped for the asset of your choice from the destination chain.
While rebates and airdrops appear in your wallet automatically, only bridgeable assets are shown in your Synapse portfolio. If you don’t see an asset you should have received, first check
your wallet while connected to the destination chain for your bridge transaction.
Help!
Don’t panic! Contact Synapse Support on Discord to answer any other questions you might have.
Bridge Liquidity
The engine behind Synapse's cross-chain infrastructure.
What is nUSD?
nUSD, or "nexus" USD, is a cross-chain stablecoin fully backed by the nexus stablecoin liquidity pool on Ethereum consisting of DAI, USDC, and USDT.
The nexus stablecoin pool is a liquidity pool incentivized on every destination chain Synapse offers. LPs accrue value through bridge fees and SYN emissions, giving end users access to
deep liquidity and low slippage on stable pairs
When a stablecoin is bridged between Synapse-enabled chains, the funds are automatically converted to nUSD, and bridged to the destination chain. Once there, this nUSD can be
auto-swapped to that chain's native stablecoins using the local nUSD pool.
What is nETH?
nETH, or "nexus" ETH, is a cross-chain asset pegged to ETH and fully backed by the nexus ETH liquidity pool on Ethereum that consists solely (for now) of ETH.
Synapse's nETH multi-chain ETH-pegged asset, paired with native chain ETH
nETH is used to enable fast bridging of ETH to and from L2 networks such as Arbitrum, Boba, and Optimism.
Contract Addresses
Addresses for all relevant Synapse Protocol contracts.
Due to the number of deployments & contracts across multiple chains, this is not currently an exhaustive list.
An exhaustive list as well as all Synapse Protocol contracts & deployment addresses can be found on Github.
The Synapse Router Contract is 0x7E7A0e201FD38d3ADAA9523Da6C109a07118C96a on all chains and the Synapse CCTP Router is 0xd5a597d6e7ddf373a92c8f477daaa673b0902f48 on all chains
that support CCTP. Additionally, the Synapse RFQ Router is 0x00cD000000003f7F682BE4813200893d4e690000 on all chains that support RFQ.
Synapse Token
Chain Address
Arbitrum 0x080f6aed32fc474dd5717105dba5ea57268f46eb
Aurora 0xd80d8688b02B3FD3afb81cDb124F188BB5aD0445
Avalanche 0x1f1E7c893855525b303f99bDF5c3c05Be09ca251
Base 0x432036208d2717394d2614d6697c46DF3Ed69540
Blast 0x9592f08387134e218327E6E8423400eb845EdE0E
Boba 0xb554A55358fF0382Fb21F0a478C3546d1106Be8c
BSC 0xa4080f1778e69467e905b8d6f72f6e441f9e9484
Canto 0x555982d2E211745b96736665e19D9308B615F78e
Cronos 0xFD0F80899983b8D46152aa1717D76cba71a31616
DFK 0xB6b5C854a8f71939556d4f3a2e5829F7FcC1bf2A
Dogechain 0xDfA53EeBA61D69E1D2b56b36d78449368F0265c1
Ethereum 0x0f2D719407FdBeFF09D87557AbB7232601FD9F29
Fantom 0xE55e19Fb4F2D85af758950957714292DAC1e25B2
Harmony 0xE55e19Fb4F2D85af758950957714292DAC1e25B2
Moonbeam 0xF44938b0125A6662f9536281aD2CD6c499F22004
Moonriver 0xd80d8688b02B3FD3afb81cDb124F188BB5aD0445
Optimism 0x5A5fFf6F753d7C11A56A52FE47a177a87e431655
Polygon 0xf8f9efc0db77d8881500bb06ff5d6abc3070e695
Metis 0x67c10c397dd0ba417329543c1a40eb48aaa7cd00
nUSD Token
Chain Address
Arbitrum 0x2913e812cf0dcca30fb28e6cac3d2dcff4497688
Aurora 0x07379565cD8B0CaE7c60Dc78e7f601b34AF2A21c
Avalanche 0xCFc37A6AB183dd4aED08C204D1c2773c0b1BDf46
Blast 0x3194B0A295D87fDAA54DF852c248F7a6BAF6c6e0
Boba 0x6B4712AE9797C199edd44F897cA09BC57628a1CF
BSC 0x23b891e5c62e0955ae2bd185990103928ab817b3
Cronos 0x396c9c192dd323995346632581BEF92a31AC623b
DFK 0x52285D426120aB91F378b3dF4A15a036a62200aE
Ethereum 0x1B84765dE8B7566e4cEAF4D0fD3c5aF52D3DdE4F
Fantom 0xed2a7edd7413021d440b09d654f3b87712abab66
Harmony 0xed2a7edd7413021d440b09d654f3b87712abab66
Optimism 0x67C10C397dD0Ba417329543c1a40eb48AAa7cd00
Polygon 0xb6c473756050de474286bed418b77aeac39b02af
Metis 0x961318fc85475e125b99cc9215f62679ae5200ab
nETH Token
Chain Address
Arbitrum 0x3ea9B0ab55F34Fb188824Ee288CeaEfC63cf908e
Base 0xb554A55358fF0382Fb21F0a478C3546d1106Be8c
Blast 0xce971282faac9fabcf121944956da7142cccc855
Boba 0x96419929d7949D6A801A6909c145C8EEf6A40431
Optimism 0x809DC529f07651bD43A172e8dB6f4a7a0d771036
Metis 0x931b8f17764362a3325d30681009f0edd6211231
SynapseBridge
Chain Address
Arbitrum 0x6F4e8eBa4D337f874Ab57478AcC2Cb5BACdc19c9
Aurora 0xaeD5b25BE1c3163c907a471082640450F928DDFE
Avalanche 0xC05e61d0E7a63D27546389B7aD62FdFf5A91aACE
Base 0xf07d1C752fAb503E47FEF309bf14fbDD3E867089
Blast 0x55769baf6ec39b3bf4aae948eb890ea33307ef3c
Boba 0x432036208d2717394d2614d6697c46DF3Ed69540
BSC 0xd123f70AE324d34A9E76b67a27bf77593bA8749f
Canto 0xDde5BEC4815E1CeCf336fb973Ca578e8D83606E0
Cronos 0xE27BFf97CE92C3e1Ff7AA9f86781FDd6D48F5eE9
DFK 0xE05c976d3f045D0E6E7A6f61083d98A15603cF6A
Dogechain 0x9508BF380c1e6f751D97604732eF1Bae6673f299
Ethereum 0x2796317b0fF8538F253012862c06787Adfb8cEb6
Fantom 0xAf41a65F786339e7911F4acDAD6BD49426F2Dc6b
Harmony 0xAf41a65F786339e7911F4acDAD6BD49426F2Dc6b
Klaytn 0xAf41a65F786339e7911F4acDAD6BD49426F2Dc6b
Metis 0x06Fea8513FF03a0d3f61324da709D4cf06F42A5c
Moonriver 0xaeD5b25BE1c3163c907a471082640450F928DDFE
Moonbeam 0x84A420459cd31C3c34583F67E0f0fB191067D32f
Optimism 0xAf41a65F786339e7911F4acDAD6BD49426F2Dc6b
Polygon 0x8F5BBB2BB8c2Ee94639E55d5F41de9b4839C1280
MiniChef
Chain Address
Avalanche 0x3a01521F8E7F012eB37eAAf1cb9490a5d9e18249
Aurora 0x809DC529f07651bD43A172e8dB6f4a7a0d771036
Arbitrum 0x73186f2Cf2493f20836b17b21ae79fc12934E207
Base 0xfFC2d603fde1F99ad94026c00B6204Bb9b8c36E9
Blast 0x3100dC8464A8523306c3C5034de24a8927d6E590
Boba 0xd5609cD0e1675331E4Fb1d43207C8d9D83AAb17C
BSC 0x8F5BBB2BB8c2Ee94639E55d5F41de9b4839C1280
Canto 0x93124c923dA389Bc0f13840fB822Ce715ca67ED6
Ethereum 0xd10eF2A513cEE0Db54E959eF16cAc711470B62cF
Fantom 0xaeD5b25BE1c3163c907a471082640450F928DDFE
Harmony 0xaeD5b25BE1c3163c907a471082640450F928DDFE
Metis 0xaB0D8Fc46249DaAcd5cB36c5F0bC4f0DAF34EBf5
Moonriver 0x432036208d2717394d2614d6697c46DF3Ed69540
Optimism 0xe8c610fcb63A4974F02Da52f0B4523937012Aaa0
Polygon 0x7875Af1a6878bdA1C129a4e2356A3fD040418Be5
Chain Address
Arbitrum 0x37f9aE2e0Ea6742b9CAD5AbCfB6bBC3475b3862B
Aurora 0x2D8Ee8d6951cB4Eecfe4a79eb9C2F973C02596Ed
Avalanche 0x0EF812f4c68DC84c22A4821EF30ba2ffAB9C2f3A
Boba 0x64B4097bCCD27D49BC2A081984C39C3EeC427a2d
BSC 0x749F37Df06A99D6A8E065dd065f8cF947ca23697
Canto 0x8671A0465844a15eb7230C5dd8d6032c26c655B7
Cronos 0x991adb00eF4c4a6D1eA6036811138Db4379377C2
DFK 0x75224b0f245Fe51d5bf47A898DbB6720D4150BA7
Dogechain 0x544450Ffdfa5EA20528F21918E8aAC7B2C733381
Ethereum 0x6571d6be3d8460CF5F7d6711Cd9961860029D85F
Fantom 0xB003e75f7E0B5365e814302192E99b4EE08c0DEd
Harmony 0xB003e75f7E0B5365e814302192E99b4EE08c0DEd
Optimism 0x470f9522ff620eE45DF86C58E54E6A645fE3b4A7
Moonbeam 0x73783F028c60D463bc604cc53852C37C31dEC5e9
Moonriver 0x06Fea8513FF03a0d3f61324da709D4cf06F42A5c
Polygon 0x1c6aE197fF4BF7BA96c66C5FD64Cb22450aF9cC8
ETH Pools
Chain Address
Arbitrum 0xa067668661C84476aFcDc6fA5D758C4c01C34352
Avalanche 0x77a7e60555bC18B4Be44C181b2575eee46212d44
Base 0x6223bD82010E2fB69F329933De20897e7a4C225f
Blast 0x999fcd13C54B26E02a6Ccd185f71550b3a4641c0
Metis 0x09fEC30669d63A13c666d2129230dD5588E2e240
Optimism 0xE27BFf97CE92C3e1Ff7AA9f86781FDd6D48F5eE9
Stableswap Pools
Chain Address
Arbitrum 0x9Dd329F5411466d9e0C488fF72519CA9fEf0cb40
Aurora 0x3CE7AAD78B9eb47Fd2b487c463A17AAeD038B7EC
Avalanche 0xED2a7edd7413021d440b09D654f3b87712abAB66
Blast 0xa4bd1AAD7cF04567c10f38FC4355E91bba32aC9c
Boba 0x75FF037256b36F15919369AC58695550bE72fead
Canto 0x07379565cD8B0CaE7c60Dc78e7f601b34AF2A21c
Ethereum 0x1116898DdA4015eD8dDefb84b6e8Bc24528Af2d8
Fantom 0x85662fd123280827e11C59973Ac9fcBE838dC3B4
Metis 0x555982d2E211745b96736665e19D9308B615F78e
Optimism 0xF44938b0125A6662f9536281aD2CD6c499F22004
Polygon 0x85fCD7Dd0a1e1A9FCD5FD886ED522dE8221C3EE5
Synapse CCTP
Chain Address
Arbitrum 0x12715a66773bd9c54534a01abf01d05f6b4bd35e
Avalanche 0x12715a66773bd9c54534a01abf01d05f6b4bd35e
Base 0x12715a66773bd9c54534a01abf01d05f6b4bd35e
Ethereum 0x12715a66773BD9C54534a01aBF01d05F6B4Bd35E
Optimism 0x12715a66773bd9c54534a01abf01d05f6b4bd35e
Polygon 0x12715a66773bd9c54534a01abf01d05f6b4bd35e
Synapse RFQ
Chain Address
Arbitrum 0x5523D3c98809DdDB82C686E152F5C58B1B0fB59E
Base 0x5523D3c98809DdDB82C686E152F5C58B1B0fB59E
Blast 0x34F52752975222d5994C206cE08C1d5B329f24dD
Ethereum 0x5523D3c98809DdDB82C686E152F5C58B1B0fB59E
Linea 0x34F52752975222d5994C206cE08C1d5B329f24dD
Optimism 0x5523D3c98809DdDB82C686E152F5C58B1B0fB59E
Scroll 0x5523D3c98809DdDB82C686E152F5C58B1B0fB59E
Bridge SDK
The quickest & simplest way to access cross-chain liquidity
The Synapse Router SDK is the easiest way for any developer to integrate cross-chain token & liquidity transfers into their application. The SDK is built to support full-fledged frontend
applications, but is fully isomorphic, able to be used both client & server-side.
The Router SDK is built on top of the Synapse Router Contract. To learn more see this page
The Synapse SDK allows protocols to own the user experience within their own dApp
Quick Start
Installation
Pre-reqs: Node v16+. The SDK is only fully tested on Node 16+ or greater. Earlier versions may have errors.
Depending on the package manager of your choice, install the SDK using one of the following:
NPMYarn
Copy
npx install @synapsecns/sdk-router
The SDK package relies on the following dependencies installed from NPM.
Copy
@ethersproject
ethers
Usage
How to use the SDK to create quotes and bridge transactions
'https://arb1.arbitrum.io/rpc'
'https://api.avax.network/ext/bc/C/rpc'
or
Copy
npm install @ethersproject/providers@^5.7.2
Copy
import {
JsonRpcProvider,
} from '@ethersproject/providers'
'https://arb1.arbitrum.io/rpc'
'https://api.avax.network/ext/bc/C/rpc'
)
Getting a bridge quote returns all relevant information regarding a possible transaction. A quote returns important instructions for the bridge in a data type called "Query". The Query type is
defined as follows.
minAmountOut (Ethers BigNumber): The min amount of value exiting the transaction.
For more information on the Query data type, refer to this page. To access these Queries along with a quote for the estimated amount out, we call the function bridgeQuote() with the
relevant args.
amount (Ethers BigNumber): The amount (with the correct amount of decimals specified by the token on the origin chain)
deadline (Ethers BigNumber): Deadline for the transaction to be initiated on the origin chain, in seconds (optional)
excludedModules (array): List of bridge modules to exclude from the result, optional
originUserAddress (string): Address of the user on the origin chain, optional, mandatory if a smart contract is going to initiate the bridge operation
maxAmountOut (Ethers BigNumber): The maximum output amount resulting from the bridge transaction.
Copy
maxAmountOut is the value produced after fees
If the permutation of chains and tokens is not supported, the SDK will inform the user. Note that every bridge transaction requires this step.
routerAddress
42161, // Origin Chain
BigNumber.from('20000000') // Amount in
// Deadline for the transaction to be initiated on the origin chain, in seconds (optional)
deadline: 1234567890,
// MANDATORY if a smart contract is going to initiate the bridge operation on behalf of the user.
originUserAddress: '0x1234567890abcdef1234567890abcdef12345678',
Once bridge quotes are retrieved, the Origin and Destination Queries can be used to execute the transaction.
routerAddress (string): The 0x contract address on the origin chain of the bridge router contract.
amount (Ethers BigNumber): The amount (with the correct amount of decimals specified by the token on the origin chain)
'0x0AF91FA049A7e1894F480bFE5bBa20142C6c29a9', // To Address
BigNumber.from('20000000'), // Amount
)
Once this function is called the bridge transaction is initiated and the user should soon receive their funds on the destination chain.
The allBridgeQuotes() function returns a list of all the possible bridge quotes, with the first item in the array being the cheapest route. This function allows for quotes to be returned from
any of the bridge "types" such as RFQ or CCTP. Discover more here.
If you were previously using excludeCCTP parameter in bridgeQuote, you can now use synapseSDK.bridgeQuote(originChainId, destChainId, tokenIn, tokenOut, amountIn,
{excludedModules: ["SynapseCCTP"]})
It's possible to exclude multiple modules by providing a list with their names. The supported values are SynapseBridge, SynapseCCTP, SynapseRFQ
If a smart contract is going to initiate the bridge transaction on behalf of the user, you have to pass the user's address on the origin chain in bridgeQuote or allBridgeQuotes like
These three options could be combined in any way the consumer desires by excluding/including these in the options object
Old FastBridgeRouter deployment is deprecated, if your integration is using the hardcoded address, please make sure to check the router deployments/deprecated deployments
table here
Example
An implemented example of the Bridge SDK
Example 1:
A basic implementation
Copy
import { JsonRpcProvider } from '@ethersproject/providers'
// quote
43114, // To Chain
'0xa7d7079b0fead91f3e65f86e8915cb59c1a4c664', // To Token
BigNumber.from('20000000'), // Amount
{
deadline: 1234567890,
excludedModules: ['SynapseRFQ'],
originUserAddress: '0x1234567890abcdef1234567890abcdef12345678',
// bridge
await Synapse.bridge(
'0x0AF91FA049A7e1894F480bFE5bBa20142C6c29a9', // To Address
BigNumber.from('20000000'), // Amount
Example 2
import '@styles/global.css'
import '@rainbow-me/rainbowkit/styles.css'
import {
mainnet,
arbitrum,
aurora,
avalanche,
bsc,
canto,
fantom,
harmonyOne,
metis,
moonbeam,
moonriver,
optimism,
polygon,
} from 'wagmi/chains'
import {
getDefaultWallets,
RainbowKitProvider,
darkTheme,
} from '@rainbow-me/rainbowkit'
arbitrum,
aurora,
avalanche,
bsc,
canto,
fantom,
harmonyOne,
metis,
moonbeam,
moonriver,
optimism,
polygon], [
publicProvider(),
])
appName: 'ExampleApp',
chains,
})
autoConnect: true,
connectors,
provider,
})
chains.map((chain) => {
synapseProviders.push(rpc)
})
return (
<WagmiConfig client={wagmiClient}>
<SynapseProvider
providers={synapseProviders}
>
</SynapseProvider>
</RainbowKitProvider>
</WagmiConfig>
}
Copy
//@/utils/SynapseProvider.tsx
children,
chainIds,
providers,
}: {
children: React.ReactNode
chainIds: number[]
providers: Provider[]
}) => {
return (
<SynapseContext.Provider value={sdk}>{children}</SynapseContext.Provider>
import {
DEFAULT_FROM_CHAIN,
DEFAULT_TO_CHAIN,
DEFAULT_FROM_TOKEN,
DEFAULT_TO_TOKEN,
} from '@/constants/bridge'
outputAmountString: '',
})
useEffect(() => {
}, [])
// Suggestion: this function should be triggered from an useEffect when amount or to/from token/chain is altered
SynapseSDK.bridgeQuote(
fromChainId,
toChainId,
fromToken,
toToken,
amount,
excludedModules: [],
originUserAddress = address
.then(
setBridgeQuote({
quotes: {
originQuery,
destQuery,
},
})
// do something
.catch((err) => {
// do something
})
await Synapse.bridge(
toAddress, // To Address
amount, // Amount
// do something
.catch((err) => {
// do something
})
// ...
}
Widget
Implement the Synapse Bridge into your dApp frontend
The Synapse Widget is a trivial implementation of the current Synapse bridge that enables protocols to integrate the bridge into their Frontend with little to no Engineering resources.
Example Widget
This explains how to integrate the bridge widget into your dApp in just a few minutes. This widget enables users to bridge tokens directly on your site, utilizing the Synapse Protocol.
This guide shows how to customize the widget to seamlessly blend with your app's theme by altering colors, fonts, and the token list. Learn to make the widget appear as an integral part of
your application.
Implementation
npm:
Copy
npm install @synapsecns/widget
yarn:
Copy
yarn add @synapsecns/widget
Get Started
To get started, import the Widget React component into your App. You will need a web3Provider parameter to pass to the widget. The demo landing page app, for example, defines this
provider from the ethers library. However, the component supports any similar provider:
Copy
import { Bridge } from '@synapsecns/widget'
Your site should now display a fully operational bridge widget integrating the routes and tokens supported by the Synapse protocol. By utilizing Synapse's multiple routers, you will be able
to find the best quotes to support your bridging use case.
The widget accepts a number of props to customize its functionality and appearance. Below is a quick summary with more detailed explanations later on.
customRpcs Custom JSON-RPC endpoints for your consumer application. Optional but recommended.
customTheme Custom theme for the widget. Optional. If not provided, defaults to light theme.
container HTML element to render the widget in. Optional. If not provided, false.
targetChainIds List of chain IDs for the destination side of your consumer app. Optional. If not provided, defaults to all Synapse Protocol supported networks.
targetTokens List of tokens to display in the widget. These tokens are imported from the widget package. Optional. If not provided, defaults to all Synapse Protocol supported tokens.
protocolName A short name for users of the widget to identify the protocol. Optional. If not provided, defaults to 'Target'.
hideConsoleErrors Boolean to enable suppressing Synapse (SDK, Widget) console.error messages in your consumer app's browser. If not provided, defaults to logging error messages.
ethers v6
Copy
const web3Provider = new ethers.BrowserProvider(window.ethereum)
ethers v5
Copy
const web3Provider = new ethers.providers.Web3Provider(window.ethereum, 'any')
The bridge widget is a React component designed for straightforward integration into any React-based project. Engineered for immediate functionality, and apart from a web3Provider, it
requires no initial parameters or web3 setup to begin operation. The widget facilitates bridging across all networks where the Synapse Protocol is active.
While the widget is primed for immediate use without configuration as it provides some basic primary and fallback JSON-RPC endpoints, we encourage developers to specify their own for
enhanced performance. This can be done by including a customRpcs parameter in the format of an object with chain ids as keys and their associated RPC endpoints as values.
Copy
import { Bridge, CustomRpcs } from '@synapsecns/widget'
1: 'https://ethereum.my-custom-rpc.com',
10: 'https://optimism.my-custom-rpc.com',
42161: 'https://arbitrum.my-custom-rpc.com',
return (
<Bridge
web3Provider={web3Provider}
targetChainIds={[42161, 43114]}
/>
Note: Token naming convention is based on the tokens provided by @synapsecns/widget. For example, USDC on Metis is METISUSDC instead of simply USDC. The package's
src/constants/bridgeable.ts file contains a detailed list of supported tokens and the chains they live on. Additionally, to see a detailed list of Synapse Protocol supported chains, please
see src/constants/chains.ts.
useBridgeSelections Hook
The widget also provides a useBridgeSelections hook that can be used to access the selected tokens and chains. This hook returns an object of type BridgeSelections which has fields of
originChain, originToken, destinationChain, and destinationToken.
id,
name,
symbol,
address
useBridgeSelections()
Theme Customization
The widget is designed to be easily customized to match your app's theme. The widget accepts an optional customTheme configurable bgColor parameter for 'dark', 'light', and custom
color modes:
Copy
<Bridge web3Provider={web3Provider} customTheme={{ bgColor: 'light' }} />
Additionally, the widget supports more complex custom themes with the customTheme property. This allows for more fine-grained control over the widget's colors and fonts.
Copy
const customTheme = {
bgColor: '#08153a',
// Basic customization
'--synapse-text': 'white',
'--synapse-secondary': '#ffffffb3',
'--synapse-root': '#16182e',
'--synapse-border': 'transparent',
'--synapse-focus': 'var(--synapse-secondary)',
'--synapse-select-bg': 'var(--synapse-root)',
'--synapse-select-text': 'var(--synapse-text)',
'--synapse-select-border': 'var(--synapse-border)',
'--synapse-button-bg': 'var(--synapse-surface)',
'--synapse-button-text': 'var(--synapse-text)',
'--synapse-button-border': 'var(--synapse-border)',
<Bridge
web3Provider={web3Provider}
customTheme={customTheme}
/>
Container Customization
The widget additionally supports a container property of true or false to adjust its width to the container it's in.
Copy
<Bridge web3Provider={web3Provider} container={true} />
Example Apps
Within the repository's /examples folder, there are three example apps. The landing-page folder contains a fully functional demo with customizations of the widget. The with-react and
with-next folders contain a simple implementation of the widget using React and Next.js, respectively.
If you have any questions or need help implementing the widget, feel free to reach out to the team in Discord!
REST API
Synapse REST API
The Synapse REST API V2 is now live at https://synapse-rest-api-v2.herokuapp.com/
The API supports read-only actions from any on-chain Synapse contracts and generates Swap and Bridge quotes along with additional information. Some use cases this caters to, are for
application front-ends integrating the cross-chain bridge, liquidity providers, or cross-chain arbitragers.
Additionally, if you're unable to integrate the Synapse JavaScript SDK because your app is another language (Python, Rust, etc.), use the REST API.
Please read the FAQs and instructions carefully before reaching out to the on Discord for questions.
Usage
How to interact with the Rest API
The REST API V2 currently has four methods :
GET /swap
Parameters:
Example Request:
Copy
/swap?chain=1&fromToken=USDC&toToken=DAI&amount=100
Returns:
maxAmountOut (object) - The maximum amount of tokens that can be swapped out. Contains:
deadline (object) - Deadline parameter for the swap (same structure as maxAmountOut)
GET /bridge
Parameters:
/bridge?fromChain=1&toChain=42161&fromToken=USDC&toToken=USDC&amount=1000000
Returns:
maxAmountOut (object) - Maximum amount receivable from swap, structure same as above
destQuery (object) - Destination swap query parameters, structure similar to originQuery above.
bridgeModuleName (string) - the bridge module the transaction will be routed through
gasDropAmount (BigNumber) - the amount of gas airdropped to the user on the dest chain.
GET /swapTxInfo
Example:
Copy
/swapTxInfo?chain=1&fromToken=USDC&toToken=DAI&amount=100
Returns:
data: The binary data that forms the input to the transaction.
to: The address of the Synapse Router (the synapse bridge contract)
GET /bridgeTxInfo
Example:
Copy
/bridgeTxInfo?fromChain=1&toChain=42161&fromToken=USDC&toToken=USDC&amount=1000000&destAddress=0xcc78d2f004c9de9694ff6a9bbdee4793d30f3842
Returns:
data: The binary data that forms the input to the transaction.
to: The address of the Synapse Router (the synapse bridge contract)
Please read the FAQs and instructions carefully before reaching out to the on Discord for questions.
Examples
Examples of using the REST API with Javascript
Example 1:
fromChain,
toChain,
fromToken,
toToken,
amountFrom
){
`https://synapse-rest-api-v2.herokuapp.com/bridge?${query_string}`
);
estimateBridgeOutput(
1, // Ethereum Chain ID
"USDC",
"USDC",
"1000"
);
Example 2:
fromChain,
toChain,
fromToken,
toToken,
amountFrom,
destAddress
){
const query_string = `fromChain=${fromChain}&toChain=${toChain}&fromToken=${fromToken}&toToken=${toToken}&amount=${amountFrom}&destAddress=${addressTo}`;
`https://synapse-rest-api-v2.herokuapp.com/bridgeTxInfo?${query_string}`
);
generateUnsignedBridgeTxn(
1, // Ethereum Chain ID
"USDC",
"USDC",
"1000"
"0x2D2c027E0d1A899a1965910Dd272bcaE1cD03c22"
);
Example 3:
--url 'https://synapse-rest-api-v2.herokuapp.com/swap?chain=1&fromToken=USDC&toToken=DAI&amount=100'
Synapse Router
A quick overview of the Synapse Router
Overview
The Synapse Router is an overhaul of current Synapse Bridge contracts that abstracts much of the complexity around liquidity based bridging to one simple bridge() function. Previously,
different functions would be used for different types of transactions which made it very complex to bridge at the contract level.
The new Router is comprised of one bridge() function and three supporting functions that help to construct a bridge transaction. All of the mentioned are organized by an important struct
called a “Query”. Before diving into these functions, a deeper understanding of how the bridge actually works is fundamental.
Most Synapse Bridge transactions require an “intermediary token” which is a token the protocol has mint/burn permissions over. Any third-party bridge necessitates such a structure to
properly account for bridged tokens. Find out more about Synapse intermediary tokens nUSD and nETH in the docs.
Thus, when users are not bridging or receiving an intermediary token, their transaction is routed through a liquidity pool on both chains. Determining what is the optimal route is not trivial
most times because of certain considerations: slippage in pools, expected tokenOut/tokenIn. The router condenses this complexity into a “query”.
What is a Query:
A query is a data structure that describes generic swap instructions, containing two items [token, amountReceived]. Given the desired token to bridge, a query identifies what “swap” needs
to happen on the respective chain in order for the bridge to:
A: Identify a route(s) for tokenIn to be swapped into an intermediary token
B: Identify a route(s) for the intermediary token to be swapped into the desired tokenOut on the destination chain.
// returns us a list of "Queries" that would enable the desired bridging transaction on the Origin chain
// This should be called on the origin chain for every attempt to construct a bridge transaction
getDestinationAmountOut()
// returns us a list of "Queries" that would enable the desired bridging transaction on the Desitnation chain
// This should be called on the destination chain (after calling getOriginAmountOut on the origin chain) for every attempt to construct a bridge transaction
Note that these functions return a list of queries. This is because their can be several different routes for a bridge transaction. At the application level, a developer can decide which
route(which query) to utilize. In examples further down, the cheapest route is chosen. The developer must generate and select one query for both the Origin and Destination chains to
properly format a bridge() call.
Specify the tokenIn and its amount elsewhere and will transfer it before calling adapterSwap()
*Note that the resulting SwapQuery could be "empty" -- this only happens if the tokenIn or tokenOut is already a bridge token (e.g. nUSD or nETH)
See the Example Page for further information (and arguments) that the functions above require. It is imperative that the program uses the functions here to construct Queries instead of
manually doing so -- this guarantees that the transaction won't be reverted for misconfigured parameters.
To construct a bridge transaction there are two main parts, the off-chain to submit the transaction, and the on-chain transaction construction . Here we explore all on-chain interactions to
properly setup a bridge transaction at a high level.
The first step is utilizing the getConnectedBridgeTokens() supporting function to help structure getOriginAmountOut() — our method for generating the list of queries for the origin chain. We
call this function with the desired output token and are returned a list of tokens and their symbols.
Once we have our list of supported bridge token symbols we can generate a list of queries for the Origin chain by calling getOriginAmountOut() with the desired input token, the result from
getConnectedBridgeTokens(), and the amount of tokens being bridged. Now for every bridge token from the above list we know the amount of tokens being bridged, if this token is selected
as the intermediary token.
After reformatting the output from the above, we can get our Destination queries by calling getDestinationAmountOut(). The Synapse Router V1 only supports swaps via one of the
Synapse pools are available. Passing other instructions to the Router could result in failed transactions. Additionally, this function doesn't include tokenIn or token amount because those
variables can be populated by the bridge given the arguments to getOriginAmountOut(). By passing the list of bridge tokens together with their bridged amount, we can determine the
amount of tokens a user will receive at the end of the bridge transaction; each possible path having their own respective amount.
Now we have a list of queries for the Origin and Destination chain and need to select one (originQuery, destinationQuery) pair. Below is a simple function to extract the queries with the
lowest slippage (cheapest route).
Copy
maxIndex = destQueries.indexOf(destQueries.maxBy, (query) => { return query.minAmountOut });
originQuery = originQueries[maxIndex];
// destQuery.minAmountOut is the full quote for tokenIn => tokenOut cross-chain swap
destQuery = destQueries[maxIndex];
Finally, the developer can apply slippage and deadline parameters using the applyUserSettings(), and then call the bridge() function with the relevant parameters. Basic examples
displaying this setup can be found here.
Note that these are view functions that live on every supported chain, thus the program needs to call each function on its respective chain using off-chain services (such as an RPC).
At a High Level
On-chain we have two main objective, identify all possible routes (queries) for a specific bridging transaction, and then choose the desired routes so that we can call the bridge() function.
To actually bridge funds we need to call the bridge function using a web3 client.
Synapse Adapter
Exploring the Synapse Adapter
Overview
The SynapseAdapter is a configurable mechanism that facilitates the "swap" action on both the Origin and Destination chains. In SynapseRouterV1, the Adapter only supports Synapse
hosted pools. In future versions, additional Adapters will be configured to support aggregators on different chains. This will enable Any asset to Any asset bridging through the Synapse
Bridge.
Function
The SynapseAdapter provides a custom wrapper around standard "swaps" from one token to another given certain parameters. The Adapter also exposes useful methods to get Quotes
and the Swap Query struct. Additional methods provide views into the supported pools, tokens, and more.
Example
An example of a direct contract integration
Copy
/**
* @param symbol Bridge token symbol: unique token ID consistent among all chains
*/
type BridgeToken = {
symbol: String;
token: Address;
};
/**
* @param symbol Bridge token symbol: unique token ID consistent among all chains
* @param amountIn Amount of bridge token to start with, before the bridge fee is applied
*/
type DestRequest = {
symbol: String;
amountIn: BigInt;
};
/**
* @param swapAdapter Adapter address that will perform the swap. Address(0) specifies a "no swap" query.
* @param minAmountOut Minimum amount of tokens to receive after the swap, or tx will be reverted.
* @param deadline Latest timestamp for when the transaction needs to be executed, or tx will be reverted.
* @param rawBytes ABI-encoded params for the swap that will be passed to `swapAdapter`.
*/
type SwapQuery = {
swapAdapter: Address;
tokenOut: Address;
minAmountOut: BigInt;
deadline: BigInt;
rawParams: BytesLike;
};
type UserSettings = {
maxSlippage: BigInt;
deadlineOrigin: BigInt;
deadlineDest: BigInt;
};
interface SynapseRouter {
/**
* Initiate a bridge transaction with an optional swap on both origin and destination chains
* @param token Initial token for the bridge transaction to be pulled from the user
* @param amount Amount of the initial tokens for the bridge transaction
* @param originQuery Origin swap query. Empty struct indicates no swap is required
* @param destQuery Destination swap query. Empty struct indicates no swap is required
*/
bridge(
to: Address,
chainId: Number,
token: Address,
amount: BigInt,
originQuery: SwapQuery,
destQuery: SwapQuery
): null;
/**
* Gets the list of all bridge tokens (and their symbols), such that destination swap
*/
/**
* Finds the best path between `tokenIn` and every supported bridge token from the given list,
* treating the swap as "origin swap", without putting any restrictions on the swap.
*/
getOriginAmountOut(
tokenIn: Address,
tokenSymbols: String[],
amountIn: BigInt
): SwapQuery[];
/**
* Finds the best path between every supported bridge token from the given list and `tokenOut`,
* treating the swap as "destination swap", limiting possible actions to those available for every bridge token.
* Will take the bridge fee into account, when returning a quote for every bridge token.
* - amountIn: amount of bridge token to start with, before the bridge fee is applied
*/
getDestinationAmountOut(
requests: DestRequest[],
tokenOut: Address
): SwapQuery[];
function synapseBridge(
originChainId: Number,
destChainId: Number,
tokenIn: Address,
tokenOut: Address,
amountIn: BigInt,
userOrigin: Address,
userDest: Address,
userSettings: UserSettings
){
// Here we describe a list of actions to perform such a cross-chain swap, knowing only
// - SynapseRouter deployments
// 1. Determine the set of bridge tokens that could enable "receive tokenOut on destination chain"
// 2. Get the list of Queries with possible swap instructions for origin chain
// This gets us the quotes from tokenIn to every bridge token (one quote per bridge token in the list)
tokenIn,
symbols,
amountIn
);
// 3. Get the list of Queries with possible swap instructions for destination chain
symbol: value,
amountIn: originQueries[index].minAmountOut,
};
return request;
});
// This gets us the quotes from every bridge token to tokenOut (one quote per bridge token in the list)
// These quotes will take into account the fee for bridging the token to destination chain
// In this example we are picking the pair that yeilds the best overall quote
if (tokenIn == "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE") {
// If user selected "native ETH" as tokenIn, we would need to modify msg.value for the call
amountETH = amountIn;
} else {
amountETH = 0
// tokenIn.approve(routerOrigin, amountIn)
routerOrigin.bridge{value: amountETH}(
userDest,
destChainId,
tokenIn,
amountIn,
originQuery,
destQuery
);
Contracts
All of the code for the SynapseRouter is open source on Github
For event indexing, see the SynapseBridge Contract. Events that start with "TokenMint" or "TokenWithdraw" are emitted when the bridge transaction is completed on the destination chain.
The contracts that emit these events can be found in the deployments folder in the respective chain's "SynapseBridge.json"
Ethereum
BNB Chain
Polygon
Fantom
Optimism
Arbitrum
Avalanche
Moonriver
Moonbeam
Cronos
Boba