SIP-260: Rate Limiting

ProposalLoading status...

Simple Summary

Reduce the impact of a possible security breach in the bridge by implementing simple rate limiting functionality on all transfers processed by the bridge.


Bridges are notorious for and large profile loss of funds. To prevent from being another sorrowful statistic on this regard, this SIP proposes implementation of a system for limiting the amount of transfers a bridge can process. This will give the CC team a chance to react if an attacker emerges and attempts to drain large amounts of value from the system.


In the case of a bridge exploit (within or outside of our control), an attacker could withdraw protocol-killing levels of funds from either the sUSD or SNX bridges.

It was previously thought that rate limiters would be very difficult to implement reliably. However, due to optimism's bridge behavior of allowing replays on failed messages, rate limiters become a lot more practical and simple to implement.


Technical Specification

BaseSynthetixBridge will be modified to have a new field:

  • mapping(bytes32 => RateLimitInfo) private limits -- tracks rate limiting info for a particular token/direction combination transferred by the bridge

The struct RateLimitInfo has the following definition:

struct RateLimitInfo {
  uint128 amountUsable;          // Amount of token allowed to be received or sent per period. Configurable via SCCP
  uint128 periodLength;          // Time in seconds between the rate limit being reset. Configurable via SCCP

  uint128 limitUsed;             // tracks amount of the limit used in the current period. automatically reset when the period changes.
  uint128 lastPeriod;            // used to determine if the `rateLimitAmountReceived` should be reset. Tracks the period that the limit is applicable to

Additionally, some functions will be added:

interface IBaseSynthetixBridge {
  function isExceedingRateLimit(bytes32 id, uint amount);
  function getNextLimitResetTime(bytes32 id);

Additionally, the BaseSynthetixBridge will have a new internal function probeRateLimit(uint amount) for modifying the limit while increasing amountUsed, for use by subclasses. This call reverts if the limit is exceeded.

SynthetixBridgeToOptimism deposit (and all its variants) and finalizeWithdrawal will be modified to call probeRateLimit.

SynthetixBridgeToBase withdraw (and all its variants) and finalizeDeposit wille be modified to call probeRateLimit.

BaseSynthetixBridge initiateSynthTransfer and finalizeSynthTransfer will be modified similarly to call probeRateLimit.

User Experience Impact

To prevent users from potentially being locked out of their funds because the transaction sent from the source layer is larger than the limit on the destination, it is recommended that the layer 1 and layer 2 layers be set to the same value. The code will then enforce the limit at the source side, preventing unnecessary amounts of tokens remaining in transit between the two layers.

We will need to create documentation to make clear to users the behavior of the rate limit, and the UIs (3rd party or not) for sending sUSD or SNX will need to be updated to understand the behavior of the rate limit and explain to the user if an error occurs due to rate limit (on either the souce or the destination side).

Of particular note, whatever the SC sets as the value for amountUsablePerPeriod is effectively the maximum size of a single transfer which can be sent. This is because, if a user sends an amount larger than this, it will never be receivable on the destination becuase the limit is lower than the absolute size of the transaction.

If the pdao needs to unlock a very large transaction for whatever reason, it can safely do so by creating a sandwhich transaction to temporarily raise the limit, call the optimism forward txn, and lower the transaction back to normal.

Alerts on high usage of the rate limiter

The purpose of the rate limiters is to reduce the impact of a potential bridge attack. However, this will be much less effictive if we don't actively track brideg activity and make sure that the system is suspended if unusual activity is detected. If, for example the rate limit period is set to 6 hours, we want to make sure action can be taken to protect the system withint that window if unusual activity is detected. At the same time, we want to set the limits as high as possible to minimize chances of bad UX, so risk analysis should be taken to determine what the limit and period should be.

Test Cases


  • isExceedingRateLimit
    • verify correct behavior when 0 used and smaller than amountUsable specified
    • verify correct behavior when max used and any amount of amountUsable specified
    • verify correct behavior when some used and some amount of amountUsable is specified
  • initiateSynthTransfer
    • verify the probe works
  • `finalizeSynthTransfer
    • verify the probe works
  • setRateLimitPeriod
    • verify only owner
    • verify it sets the value
  • setRateLimitAmountUsable
    • verify only owner
    • verify it sets the value


  • deposit
    • verify the probe works
  • finalizeWithdrawal
    • verify the probe works


  • withdraw
    • verify the probe works
  • finalizeDeposit
    • verify the probe works

Configurable Values (Via SCCP)

New SCCP parameters will be implemented to allow the SC to adjust risk of the bridge as necessary for the market conditions. It is advised that these values be kept the same on both layers since a mismatch in limits could lead to bad user experience.

  • SynthetixBridgeToOptimism.setRateLimitPeriod(bytes32 currencyKey, uint value) -- number of seconds between when the amount received gets reset
  • SynthetixBridgeToOptimism.setRateLimitAmountUsable(bytes32 currencyKey, uint value) -- amount of token which can be received or sent every period term

Initially, the following limits will be automatically applied as part of deployment of this SIP:

  • period(SNX): 21600 (6 hours)
  • amountUsable(SNX): 250000000000000000000000 (250000 SNX)
  • period(SNX): 86400 (6 hours)
  • amountUsable(SNX): 1000000000000000000000000 (1000000 sUSD)

Copyright and related rights waived via CC0.