StarkNet interpretation of DAI token and basic DAI bridge.
Bridge provides two main functions: deposit
and withdraw
. On L1 deposit
, bridge parks funds on address of L1Escrow
contract, then sends finalize_deposit
message to L2 side of the bridge where L2 DAI is minted to the destination address. On L2 withdrawal
, L2 DAI is burned and a finalizeWithdraw
message is send to L1 where withdrawal should be finalized with finalizeWithdrawal
method which will transfer DAI from escrow contract to the destination.
L1DAIBridge
- L1 side of the bridgeL1Escrow
- holds bridge funds on L1L1GovernanceRelay
- relays governance action to L2dai
- Cairo interpretation of DAI contractl2_dai_bridge
- L2 side of the bridgel2_governance_delay
- executes governance action relayed from L1registry
- provides L2 to L1 address mapping
The amount of bridged DAI can be restricted by setting a ceiling property(setCeiling
) on the L1DAIBridge. Setting it to Uint256.max will make it effectively unlimited, setting it to anything lower than the amount currently bridged will temporarily disable deposits.
To make DAI bridge compatible with generic StarkNet token bridges a single deposit limit(setMaxDeposit
) was added. Setting it to a value above the ceiling will make deposits unlimited, setting it to 0 will temporarily disable the bridge.
In case for some reason deposit transactions can't be included in L2 state users can cancel deposits on L1. It is a two step process:
- first call
startDepositCancellation
on L1DAIBridge - second, after
messageCancellationDelay
(l1ToL2MessageNonce StarkNet core contract) finalize cancellation withcancelDeposit
Since StarkNet execution environment is significantly different than EVM, Starknet DAI is not a one to one copy of L1 DAI. Here are the diferences:
uint256
to represent balances, for compatibility with L1- no permit function - StarkNet account abstraction should be used for UX optimizations
increase_allowance
,decrease_allowance
- extra methods to prevent approval front running
Several contracts here use a very simple multi-owner authentication system, that restricts access to certain functions of the contract interface:
- L1DAIBridge:
rely
,deny
,setCeiling
,setMaxDeposit
,close
- L1Escrow:
relay
,deny
,approve
- L1GovernanceRelay:
rely
,deny
,approve
- dai:
rely
,deny
,mint
- l2_dai_bridge:
rely
,deny
,close
Allowance on L1Escrow should be managed by approve method on L1Escrow
contract.
It is expected that admin rights to the bridge contracts will be given to the Maker Governance.
L1GovernanceRelay
allows to relay L1 governance actions to a spell contract on the StarkNet via l2_governance_relay
.
Maker PauseProxy should be relied on: L1DAIBridge
, L1Escrow
, l2_dai_bridge
, dai
, L1GovernanceRelay
. Unlimited allowance on L1Escrow
should be given to L1DAIBridge
.
In order to withdraw allowance needs to be given to the l2_dai_bridge
individually by each L2 DAI user.
Since bridge funds are stored in a separate escrow contract, multiple bridge instances can share the escrow and operate independently.
After new version of the bridge is up, old version can be closed. Due to the asynchronous nature of L1 <> L2 communication, it is a two step procedure. First close
method on l2_dai_bridge
and L1DAIBridge
should be called, so no new deposit or withdrawal requests can be initiated. Then after all async messages that were in transit are processed, bridge is effectively closed. Now, escrow approval on L1 and token minting rights on L2 can be revoked.
In this section, we describe various risks caused by software bugs.
Bug allowing direct access to mint
method on L2 dai
or to finalize_deposit
on l2_dai_bridge
will result in a creation of uncollateralized L2 DAI. Withdrawal finalization to L1 is expected to take several hours on StarkNet. Maker governance with its 2 day delay won't be able to respond in time to coordinate preventive action if a malicious user mints uncollateralized DAI on L2 and withdraw DAI on L1.
Getting direct access to L1Escrow
via incorectly assigned allowance or getting indirect access by having fake entry in L2toL1 message queue will allow to immediately drain L1 DAI from L1Escrow
.
In its current stage of development, StarkNet is a centralized operation. Until it is fully decentralized, the sequencer operator has a right to censor transactions. What is more, if for some reason the operator goes down, no future updates of the state of the rollup will be possible. Both of those situations might result in L2 user not being able to transact L2 DAI or withdraw it back to L1.
In case of rollup emergency that would result in funds being frozen governance assisted escape hatch mechanism is planned. It consists of two phases:
- DAO needs to detect or be informed about rollup emergency, be it either inidividual censorship or rollup unavailability
- governance assisted evacuation procedure is initiated, DAI escrowed in the
L1Escrow
is distributed on L1 back to users, effectively L2 DAI is abandoned
In the case that a user believes they are censored, there is a forceWithdraw
helper method on L1DAIBridge
that initiates withdrawal from L1. If the withdrawal request is not handled, then the user might request the DAO to initiate an evacuation procedure. The DAO can verify the withdrawal request was not fulfilled by checking the L1toL2 message queue. It is important to note that in order for the forceWithdraw
to effectively work, L2 user needs to give allowance to l2_dai_bridge
and register its L1 reimbuse adress prior to calling forceWithdraw
. This may no longer be possible when the L2 network is acting maliciously, hence this should be done by the users before receiving DAI on L2.
To reimburse L2 DAI users on L1, the last valid L2 state of DAI balances needs to be calculated. Since at that moment rollup data might be unavailable, L2 state needs to be reconstructed from state diffs available on L1. It is important to note that there is no general way to map StarkNet addresses to Ethereum addresses and that only L2 addresses that registered an L1 reimburse address in the L2 registry contract will be included in the evacuation procedure. What is more there might be pending deposits that have not reached L2. Those should also be included in evacuation and returned based on state of L1toL2 message queue.
If DEPOSIT
message for some reason is not processed by the sequencer, user funds will be stucked in the L1 escrow. Since this situation is detectable from data available on L1(L1 to L2 message queue is in the L1 StarkNet contract) Governance Assisted Escape Hatch described above will work. Another, simpler solution is to use deposit cancelation.
Bridge consists of several interacting contracts and it is possible to misconfigure the construction which will render bridge non functional. There are at least two ways to do that:
- remove allowance from
L1DAIBridge
toL1Escrow
- withdrawals won't be finalized on L1, easy to fix by resetting the allowance and repeatingfinalizeWithdrawal
operation - remove authorization to mint L2 DAI from
l2_dai_bridge
- deposits won't be finalized on L2, probably possible to fix deposit cancelation: cancel the deposit, reauthorize bridge to mint, then retry the deposit operation.
Since StarkNet is expected to finalize its state on L1 at most every several hours, there is very little time to organize any preventive action in case of uncollateralized DAI is minted on L2. Maker Governance with its 2 day delay won't be able to respond in time. L1EscrowMom
provides refuse
method that sets L1Escrow allowance to 0. It can be used to freeze withdrawals immediately.
As soon as problem is fixed Governance could increase allowance. Refuse
access is controlled by AuthorityLike
contract. It is expected to be set to: DSChief to bypass the governance delay.