|
| 1 | +[id="StarkGate_architecture"] |
| 2 | += StarkGate |
| 3 | + |
| 4 | +== Overview |
| 5 | + |
| 6 | +https://starkgate.starknet.io[StarkGate^], developed by StarkWare, bridges ETH and ERC-20 tokens between Ethereum and Starknet. The following is an illustration of its overall architecture: |
| 7 | + |
| 8 | +image::sg-architecture.png[] |
| 9 | + |
| 10 | +As illustrated, while StarkGate is referred to as a single bridge, some xref:#legacy_bridge[legacy tokens] have their own bridge, each of which is defined in a corresponding pair of L1 and L2 contracts. Moreover, StarkGate also includes additional xref:#l1_components[L1 components], used for administrative purposes. To best understand the interplay between the different components, it's recommended to follow the xref:#lifecycles[lifecycles of a deposit and withdrawal]. |
| 11 | + |
| 12 | +[#legacy_bridge] |
| 13 | +== Legacy bridges |
| 14 | + |
| 15 | +Prior to StarkGate 2.0 (Mainnet: January 2024) tokens were bridged with a unique, custom pair of L1 and L2 bridge contracts, where the L1 contract is an instance of https://github.com/starknet-io/starkgate-contracts/blob/cairo-1/src/solidity/LegacyBridge.sol[`LegacyBridge.sol`^] and the L2 contract is an instance of https://github.com/starknet-io/starkgate-contracts/blob/cairo-1/src/cairo/legacy_bridge_eic.cairo[`legacy_bridge_eic.cairo`^]. These legacy token bridges are supported by StarkGate 2.0 in a fully backward-compatible fashion, as illustrated in the following example. |
| 16 | + |
| 17 | +[#example] |
| 18 | +=== Example: USDC |
| 19 | + |
| 20 | +[NOTE] |
| 21 | +==== |
| 22 | +For the complete list of legacy bridges, see the https://github.com/starknet-io/starknet-addresses/tree/master/bridged_tokens[`bridged_tokens`^] directory on GitHub. |
| 23 | +==== |
| 24 | + |
| 25 | +Consider the `deposit` functions for the L1 bridge contract for USDC on Etherscan: https://etherscan.io/address/0xf6080d9fbeebcd44d89affbfd42f098cbff92816#writeProxyContract[`0xf6080d9fbeebcd44d89affbfd42f098cbff92816#writeProxyContract`^] |
| 26 | + |
| 27 | +This contract has the following two `deposit` functions: `deposit (0x0efe6a8b)` and `deposit (0xe2bbb158)`, which shows that the bridge includes support for the legacy functionality as well as the modern functionality: |
| 28 | + |
| 29 | +[horizontal,labelwidth="25"] |
| 30 | +`deposit (0x0efe6a8b)`:: The multi-bridge contract, which includes support for all tokens within a single contract, requiring that you enter the address of the token in the deposit function. |
| 31 | +`deposit (0xe2bbb158)`:: The legacy contract, which is labeled *Support Legacy ABI*. This function does not include the `token (address)` parameter, because the contract that contains this function only supports USDC. Therefore, the address of the token is superfluous. |
| 32 | + |
| 33 | +== L1 components |
| 34 | + |
| 35 | +[cols=",", options="header"] |
| 36 | +|=== |
| 37 | +| Contract |
| 38 | +| Description |
| 39 | + |
| 40 | +| https://github.com/starknet-io/starkgate-contracts/tree/v2.0.1/src/solidity/StarkgateManager.sol[`StarkgateManager.sol`^] |
| 41 | +| Responsible for adding tokens to the multi-bridge. |
| 42 | + |
| 43 | +An interface is available through https://github.com/starknet-io/starkgate-contracts/tree/v2.0.1/src/solidity/IStarkgateManager.sol[`IStarkgateManager.sol`]. |
| 44 | + |
| 45 | +| https://github.com/starknet-io/starkgate-contracts/tree/v2.0.1/src/solidity/StarkgateRegistry.sol[`StarkgateRegistry.sol`^] |
| 46 | +| Contains the addresses of all supported bridges and tokens and enables to stop servicing an existing bridge. |
| 47 | + |
| 48 | +An interface is available through https://github.com/starknet-io/starkgate-contracts/tree/v2.0.1/src/solidity/IStarkgateRegistry.sol[`IStarkgateRegistry.sol`]. |
| 49 | + |
| 50 | +| https://github.com/starknet-io/starkgate-contracts/tree/v2.0.1/src/solidity/StarknetTokenBridge.sol[`StarknetTokenBridge.sol`] |
| 51 | +| The primary StarkGate bridge contract, where the main user bridge functionality are defined. |
| 52 | + |
| 53 | +| https://github.com/starknet-io/starkgate-contracts/tree/v2.0.1/src/solidity/IStarkgateService.sol[`IStarkgateService.sol`] |
| 54 | +| An interface to check if a contract is servicing a token. |
| 55 | +|=== |
| 56 | + |
| 57 | +== Lifecycles |
| 58 | + |
| 59 | +=== Deposit lifecycle |
| 60 | + |
| 61 | +==== Step 1: Initiating a deposit on L1 |
| 62 | + |
| 63 | +. A call to the L1 `deposit` function initiates a deposit. |
| 64 | +. The function does the following: |
| 65 | ++ |
| 66 | +-- |
| 67 | +* Transfers the funds from the user's account to the Starknet bridge. |
| 68 | +* Emits a `Deposit` event that includes the L1 and L2 addresses of the user, and the amount deposited. |
| 69 | +* Sends a message to the corresponding L2 bridge with the amount deposited, and the recipient's address. |
| 70 | +-- |
| 71 | ++ |
| 72 | +Starknet's sequencer is now aware of the deposit transaction. |
| 73 | + |
| 74 | +. The sequencer waits for enough L1 block confirmations to fill its quota to run before the corresponding deposit transaction is initiated on L2. During this period of time, the status of the L2 deposit transaction is xref:architecture-and-concepts:transactions.adoc#transaction_lifecycle[`NOT_RECEIVED`]. |
| 75 | + |
| 76 | +==== Step 2: Triggering a deposit on L2 |
| 77 | + |
| 78 | +. The sequencers refer to the deposit |
| 79 | +request by triggering the L1 handler using the |
| 80 | +https://github.com/starkware-libs/starkgate-contracts/blob/28f4032b101003b2c6682d753ea61c86b732012c/src/starkware/starknet/apps/starkgate/cairo/token_bridge.cairo#L135[`handle_deposit`] function on the L2 bridge. |
| 81 | + |
| 82 | +. The `handle_deposit` function verifies that the deposit indeed came from the corresponding L1 bridge. It then calls the relevant token's contract on Starknet and mints the specified amount of the token on L2 for the user. |
| 83 | + |
| 84 | +. The sequencers complete constructing the block. |
| 85 | + |
| 86 | +The status of the deposit request is now xref:architecture-and-concepts:transactions.adoc#transaction_lifecycle[`ACCEPTED_ON_L2`]. |
| 87 | + |
| 88 | +==== Step 3: Proving the block that includes the deposit |
| 89 | + |
| 90 | +. Starknet's provers prove the validity of the block and submit a state update to L1. |
| 91 | + |
| 92 | +. The message confirming transfer of the funds is cleared from the Starknet Core Contract, and the fact that the user has transferred their funds is part of the now finalized state of Starknet. |
| 93 | + |
| 94 | +[NOTE] |
| 95 | +==== |
| 96 | +If the message wasn't on L1 to begin with, that is, if the deposit request was fraudulently created on Starknet, the state update fails. |
| 97 | +==== |
| 98 | + |
| 99 | +=== Withdrawal lifecycle |
| 100 | + |
| 101 | +==== Step 1: Initiating a withdrawal on L2 |
| 102 | + |
| 103 | +. A call to the L2 `initiate_token_withdraw` function initiates a withdrawal. |
| 104 | +. The function does the following: |
| 105 | +* Burns the transferred amount of tokens from the balance of the withdrawal's initiator. |
| 106 | +* Sends a message to the relevant L1 bridge with the amount to be transferred and the recipient's address. |
| 107 | + |
| 108 | +==== Step 2: Proving the block that includes the withdrawal |
| 109 | + |
| 110 | +// Once the sequencer completes the block construction, Starknet's provers prove the validity of the block and submit a state update to L1. The message from the previous step is then stored in the Starknet Core Contract. |
| 111 | + |
| 112 | +. The sequencer completes the block construction |
| 113 | +. Starknet's provers prove the validity of the block and submit a state update to L1. |
| 114 | +. The message from the previous step is stored in the Starknet Core Contract. |
| 115 | + |
| 116 | +==== Step 3: Transferring the funds on L1 |
| 117 | + |
| 118 | +After the withdrawal message has been recorded on the Starknet Core Contract, anyone can finalize the transfer on L1 from the bridge back to the user, by calling the xref:resources:starkgate-reference.adoc#withdraw[`withdraw`] function. |
| 119 | + |
| 120 | +[NOTE] |
| 121 | +==== |
| 122 | +This step is permissionless, anyone can do it. The recipient's address is part of the recorded message on L1, so they receive the funds regardless of who calls the `withdraw` function on L1. |
| 123 | +==== |
| 124 | + |
| 125 | +[#stark_gate_withdrawal_limit] |
| 126 | +==== Withdrawal limit |
| 127 | + |
| 128 | +By default, StarkGate imposes no limit on withdrawals. However, in order to mitigate risks associated with critical vulnerabilities that could result in the loss of user funds, StarkGate can enable a withdrawal limit. |
| 129 | + |
| 130 | +If a serious security issue arises, the security agent in the StarkGate contract can limit withdrawals to 5% of the Total Value Locked (TVL) per day for any affected token by calling the `setWithdrawLimitPCT()` function in the `WithdrawalLimit.sol` contract. A dedicated team can then investigate and resolve the issue. |
| 131 | + |
| 132 | +Only a security admin quorum can disable the withdrawal limit. The quorum will consist of Starknet Foundation members, Starknet ecosystem contributors, and StarkWare representatives. This diverse group will ensure that decisions reflect the Starknet community's broad interests. |
| 133 | + |
| 134 | +This approach, blending manual oversight with automated detection, aims to minimize potential losses. |
0 commit comments